Hacktoberfest 2026 : les issues que les mainteneurs ont marquées pour octobre, ouvertes et accessibles aux débutants. Parcourir les issues Hacktoberfest

`@angular/build:unit-test` virtual `init-testbed.js` guards `initTestEnvironment()` behind a once-per-worker symbol → stale DomAdapter under vitest ≥4.0.5 + `isolate: false`

Ouverte
#33,047 0 commentaires 1 réaction 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Évaluation

Difficulté
4/5
Temps estimé
3-5 jours
Accessibilité débutants
55/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
Calme
Stack technique
angular, typescript

Piste de recherche

Commencez par packages/angular/build/src/builders/unit-test/runners/vitest/build-options.ts et plugins.ts, puis exécutez à plusieurs reprises la suite jsdom signalée avec ng test --force, isolate: false et vitest 4.x. Vérifiez que l'erreur stale-DomAdapter ne se produit plus entre les fichiers de spec, tout en préservant le comportement de configuration des unit-tests du builder ; l'issue propose le pattern reset-and-reinitialize de analogjs/analog#2244 et indique la documentation comme suivi secondaire.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

angular/build:unit-test area: @angular/build gemini-triaged

This is a follow-up to the now-closed/auto-locked #32754 with the missing details. That issue was dismissed as potentially analog-specific because the reporter had @analogjs/vitest-angular in their deps. This report uses @angular/build:unit-test only and pins the bug to specific lines in @angular/build's own source.

Which @angular/* package(s) are the source of the bug?

@angular/build

Is this a regression?

Yes — surfaces with vitest ≥4.0.5 (see vitest-dev/vitest#8944).

Description

@angular/build:unit-test's vitest runner combines two defaults that interact badly under vitest ≥4.0.5:

  • plugins.ts:254 hardcodes isolate: false for the vitest pool (intentional, "align with the Karma/Jasmine experience"). Worker module graphs are therefore reused across spec files.
  • build-options.ts:73-89 — the injected virtual init-testbed.js wraps getTestBed().initTestEnvironment(...) in an if (!globalThis[ANGULAR_TESTBED_SETUP]) guard. The comment on line 79 explicitly says "the guard condition above ensures that the setup is only performed once". That's the anti-pattern.

The first spec file in a worker initializes a platformBrowserTesting whose DomAdapter captures the jsdom document as a closure reference. Subsequent spec files in the same worker skip the init block entirely, so the DomAdapter keeps being reused. When jsdom's document swaps between spec files — and vitest ≥4.0.5 no longer re-executes setup files between spec files under isolate: false (vitest-dev/vitest#8944) — _getDOM().getDefaultDocument().createElement(tagName) returns something that is not a real HTMLElement, and DOMTestComponentRenderer.insertRootElement crashes:

```
TypeError: rootElement.setAttribute is not a function
at DOMTestComponentRenderer.insertRootElement (@angular/platform-browser/testing)
at _TestBedImpl.createComponent
```

Different spec files fail each run; each failing spec passes in isolation. Classic test-isolation bug.

The analog project had the analogous pattern in setupTestBed() and fixed it in analogjs/analog#2244 by calling resetTestEnvironment() + initTestEnvironment() on every setup invocation instead of guarding with a once-only singleton.

Reproduction

I can put up a public minimal repro if helpful, but the bug is visible from the builder source alone — the conditions are:

  • Angular 22 (or 21 with vitest ≥4.0.5) monorepo using @angular/build:unit-test with jsdom.
  • runnerConfig unset, so the builder's default isolate: false applies.
  • Suite of ~50+ spec files to make the race frequent.
  • Run ng test --force (or equivalent) several times. A different 1–10 specs crash each run with the setAttribute trace.

Confirmed environment:

```
Angular CLI: 22.0.0-next.6
@angular/build: 22.0.0-next.6
@angular/core: 22.0.0-next.9
vitest: 4.1.4 (via ^4.0.17)
Environment: jsdom
Runtime: Node 22 / Bun 1.x
OS: Windows 11 (also reported on Ubuntu CI via analogjs/analog#2222)
```

Exception

```
TypeError: rootElement.setAttribute is not a function
❯ DOMTestComponentRenderer.insertRootElement node_modules/@angular/platform-browser/fesm2022/testing.mjs:24
❯ _TestBedImpl.createComponent packages/core/testing/src/test_bed.ts:420
```

(The #32754 variant Cannot set base providers because it has already been called is the same root cause but a different downstream symptom — it fires when the user's own test-setup.ts re-calls initTestEnvironment. Projects that don't re-call it land on setAttribute is not a function instead.)

Proposed fix

Primary — mirror analogjs/analog#2244. Replace the if (!globalThis[ANGULAR_TESTBED_SETUP]) guard in build-options.ts:73-89 with a reset-and-reinit pattern:

```ts
getTestBed().resetTestEnvironment();
getTestBed().initTestEnvironment([BrowserTestingModule, TestModule], platformBrowserTesting(), {
errorOnUnknownElements: true,
errorOnUnknownProperties: true,
// ...
});
```

Even under isolate: false, if the setup file re-runs (or a user hook calls it), each spec file gets a fresh platform targeting the current jsdom.

Secondary (defensive) — either flip the default to isolate: true with a documented opt-out for projects that want the Karma-style speed, or make DOMTestComponentRenderer.insertRootElement throw a clearer error when rootElement.setAttribute is not callable (e.g. "TestBed's DOM adapter is referencing a document that has been torn down — check your vitest `isolate` setting"). Today the TypeError has no breadcrumb to the root cause.

Docs — the unit-test builder docs should warn that isolate: false + vitest ≥4.0.5 + jsdom silently bleeds DOM state across spec files.

Local workaround

Override to isolate: true via a project-level vitest-base.config.ts (possible because runnerConfig: true merges user config on top of the builder defaults). 10 consecutive ng test --force runs then pass deterministically. Wall-time cost is ~10–30%. This is a workaround, not a fix — the builder's guard is what should change.

References
Langage dominant
TypeScript
Étoiles
27k
Forks
11.8k
Merge moyen
17 h 25 min
PR mergées (30 j)
183

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de angular/angular-cli

Toutes les issues de angular/angular-cli

Issues similaires

Plus d'issues TypeScript

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.