Skip to content

Commit 372247d

Browse files
committed
docs(blog): Update Vitest and Angular 22 posts with metadata and formatting fixes
- Add Angular 22 keyword to Vitest migration post - Add fakeAsync keyword to Vitest migration post - Update lastModified date to 2026-06-01 in Vitest post - Fix trailing whitespace throughout both blog posts - Improve consistency in formatting and punctuation across documentation
1 parent e59072f commit 372247d

2 files changed

Lines changed: 114 additions & 44 deletions

File tree

blog/2025-11-zu-vitest-migrieren/README.md

Lines changed: 51 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ title: 'Vitest in Angular 21: Was ist neu und wie kann man migrieren?'
33
author: Johannes Hoppe
44
mail: johannes.hoppe@haushoppe-its.de
55
published: 2025-11-18
6-
lastModified: 2025-11-20
6+
lastModified: 2026-06-01
77
keywords:
88
- Angular
99
- Angular 21
10+
- Angular 22
1011
- Vitest
1112
- Karma
1213
- Jasmine
14+
- fakeAsync
1315
language: de
1416
header: angular-vitest.jpg
1517
---
@@ -29,7 +31,7 @@ In diesem Artikel zeigen wir, was Vitest für dich bedeutet, wie du bestehende A
2931
## Warum Angular Karma und Jasmine ersetzt
3032

3133
_Karma und Jasmine_ haben für Angular lange Jahre gute Dienste geleistet, vor allem wegen der Ausführung in einem echten Browser.
32-
Es gab aber Nachteile: die Ausführungsgeschwindigkeit war nie optimal und das Ökosystem ist veraltet ([Karma ist seit 2023 deprecated](https://github.com/karma-runner/karma#karma-is-deprecated-and-is-not-accepting-new-features-or-general-bug-fixes)).
34+
Es gab aber Nachteile: die Ausführungsgeschwindigkeit war nie optimal und das Ökosystem ist veraltet ([Karma ist seit 2023 deprecated](https://github.com/karma-runner/karma#karma-is-deprecated-and-is-not-accepting-new-features-or-general-bug-fixes)).
3335
Über mehrere Jahre prüfte das Angular-Team Alternativen (Jest, Web Test Runner usw.), ohne einen klaren Gewinner zu finden.
3436
[Vitest](https://vitest.dev/) wurde inzwischen äußerst populär und erwies sich als passende Lösung.
3537

@@ -48,7 +50,7 @@ Kurz gesagt: Der Wechsel sorgt für Tempo, eine deutlich bessere Developer Exper
4850

4951
Wenn du ein **neues Projekt** mit Angular 21 erzeugen möchtest, nutzt die Angular CLI standardmäßig den neuen Test-Runner Vitest.
5052
Die Wahl kannst du über die Option `--test-runner` beeinflussen:
51-
Mit `--test-runner=vitest` erhältst du die neue, schnellere und modernere Standardlösung.
53+
Mit `--test-runner=vitest` erhältst du die neue, schnellere und modernere Standardlösung.
5254
Möchtest du dagegen weiterhin bei der bewährten Karma/Jasmine-Kombination bleiben, verwende die Option `--test-runner=karma`.
5355
Ohne explizite Angabe der Option wird automatisch Vitest verwendet.
5456

@@ -64,9 +66,9 @@ Bevor du das automatische Refactoring‑Schematic verwendest, musst du dein Proj
6466

6567
#### 1. Abhängigkeiten installieren
6668

67-
Installiere `vitest` sowie eine DOM‑Emulationsbibliothek.
68-
Obwohl Tests weiterhin im Browser ausgeführt werden können (siehe Schritt 5), verwendet Vitest standardmäßig eine DOM‑Emulation, um eine Browserumgebung in Node.js zu simulieren und Tests schneller auszuführen.
69-
Die CLI erkennt automatisch `happy-dom`, falls es installiert ist; ansonsten greift sie auf `jsdom` zurück.
69+
Installiere `vitest` sowie eine DOM‑Emulationsbibliothek.
70+
Obwohl Tests weiterhin im Browser ausgeführt werden können (siehe Schritt 5), verwendet Vitest standardmäßig eine DOM‑Emulation, um eine Browserumgebung in Node.js zu simulieren und Tests schneller auszuführen.
71+
Die CLI erkennt automatisch `happy-dom`, falls es installiert ist; ansonsten greift sie auf `jsdom` zurück.
7072
Eines der beiden Pakete muss vorhanden sein.
7173

7274
```bash
@@ -91,20 +93,20 @@ Suche in der Datei `angular.json` das `test`-Target deines Projekts und setze de
9193
}
9294
```
9395

94-
Der `unit-test`‑Builder verwendet standardmäßig `"tsConfig": "tsconfig.spec.json"` und `"buildTarget": "::development"`.
96+
Der `unit-test`‑Builder verwendet standardmäßig `"tsConfig": "tsconfig.spec.json"` und `"buildTarget": "::development"`.
9597
Falls dein Projekt andere Werte benötigt, etwa weil die `development`-Konfiguration fehlt oder spezielle Test‑Einstellungen nötig sind, kannst du eine eigene Build-Konfiguration anlegen und zuweisen, z. B. `testing`.
9698

97-
Der vorherige Builder `@angular/build:karma` erlaubte es, Build‑Optionen (wie `polyfills`, `assets`, `styles`) direkt im `test`-Target zu definieren. Der neue Builder `@angular/build:unit-test` unterstützt das nicht.
98-
Falls sich deine Test‑Build‑Optionen von der `development`-Konfiguration unterscheiden, musst du diese Optionen in eine eigene Build-Konfiguration verschieben.
99+
Der vorherige Builder `@angular/build:karma` erlaubte es, Build‑Optionen (wie `polyfills`, `assets`, `styles`) direkt im `test`-Target zu definieren. Der neue Builder `@angular/build:unit-test` unterstützt das nicht.
100+
Falls sich deine Test‑Build‑Optionen von der `development`-Konfiguration unterscheiden, musst du diese Optionen in eine eigene Build-Konfiguration verschieben.
99101
Stimmen sie bereits mit `development` überein, ist kein weiterer Schritt notwendig.
100102

101-
> **Tipp:** Alternativ kannst du einfach ein neues Projekt mittels `ng new` erzeugen und die relevanten Abschnitte aus der neu generierten `angular.json` in dein bestehendes Projekt übernehmen.
103+
> **Tipp:** Alternativ kannst du einfach ein neues Projekt mittels `ng new` erzeugen und die relevanten Abschnitte aus der neu generierten `angular.json` in dein bestehendes Projekt übernehmen.
102104
> So erhältst du automatisch eine saubere Vorlage für die Vitest-Konfiguration.
103105
104106

105107
#### 3. Eigene `karma.conf.js`‑Konfiguration berücksichtigen
106108

107-
Eigene Einstellungen aus der Datei `karma.conf.js` werden nicht automatisch migriert.
109+
Eigene Einstellungen aus der Datei `karma.conf.js` werden nicht automatisch migriert.
108110
Prüfe diese Datei, bevor du sie löschst, und übertrage relevante Optionen manuell.
109111
Viele Karma‑Optionen besitzen Vitest‑Entsprechungen, die du in einer `vitest.config.ts` definieren kannst und dann über `runnerConfig` in der `angular.json` einbindest.
110112

@@ -118,7 +120,7 @@ Weitere Einstellungen findest du in der offiziellen [Vitest‑Dokumentation](htt
118120

119121
#### 4. Karma- und `test.ts`‑Dateien entfernen
120122

121-
Du kannst nun die Dateien `karma.conf.js` sowie `src/test.ts` löschen und alle Karma‑bezogenen Pakete deinstallieren.
123+
Du kannst nun die Dateien `karma.conf.js` sowie `src/test.ts` löschen und alle Karma‑bezogenen Pakete deinstallieren.
122124
Die folgenden Befehle entsprechen einem Standard‑Angular‑Projekt.
123125
In deinem Projekt können weitere Pakete vorhanden sein.
124126

@@ -160,7 +162,7 @@ Der Browsername hängt vom verwendeten Provider ab (z. B. `chromium` bei Playw
160162
}
161163
```
162164

163-
Der Headless‑Modus wird automatisch aktiviert, wenn die Umgebungsvariable `CI` gesetzt ist oder der Browsername "Headless" enthält (z. B. `ChromeHeadless`).
165+
Der Headless‑Modus wird automatisch aktiviert, wenn die Umgebungsvariable `CI` gesetzt ist oder der Browsername "Headless" enthält (z. B. `ChromeHeadless`).
164166
Andernfalls läuft der Browser sichtbar.
165167

166168
### Automatisches Test‑Refactoring per Schematic
@@ -250,8 +252,8 @@ Dabei gibt es zwei mögliche Wege: Entweder verweist du direkt auf eine bestimmt
250252
```
251253

252254
Alternativ kannst du die Angular CLI automatisch suchen lassen.
253-
Bei automatischer Suche setzt du `"runnerConfig": true` in der `angular.json`.
254-
Der Builder sucht dann selbstständig nach einer Datei namens `vitest-base.config.*`, zunächst im Projektverzeichnis und anschließend im Workspace-Root.
255+
Bei automatischer Suche setzt du `"runnerConfig": true` in der `angular.json`.
256+
Der Builder sucht dann selbstständig nach einer Datei namens `vitest-base.config.*`, zunächst im Projektverzeichnis und anschließend im Workspace-Root.
255257
So kannst du beispielsweise gemeinsame Einstellungen zentral definieren und bequem wiederverwenden.
256258

257259

@@ -264,8 +266,8 @@ Neu lernen musst du vor allem Jasmine‑spezifische Stellen.
264266

265267
### Globale Funktionen
266268

267-
Die bekannten globalen Testfunktionen wie `describe`, `it` bzw. `test`, `beforeEach`, `afterEach` und `expect` bleiben in Vitest unverändert erhalten.
268-
Sie stehen ohne weitere Importe zur Verfügung, sofern in deiner `tsconfig.spec.json` der Eintrag `types: ["vitest/globals"]` gesetzt ist.
269+
Die bekannten globalen Testfunktionen wie `describe`, `it` bzw. `test`, `beforeEach`, `afterEach` und `expect` bleiben in Vitest unverändert erhalten.
270+
Sie stehen ohne weitere Importe zur Verfügung, sofern in deiner `tsconfig.spec.json` der Eintrag `types: ["vitest/globals"]` gesetzt ist.
269271
Trotzdem empfehlen wir, diese Funktionen explizit zu importieren.
270272
Dadurch vermeidest du mögliche Namenskollisionen, etwa mit gleichnamigen Funktionen aus Cypress, was in der Vergangenheit regelmäßig zu verwirrenden Problemen geführt hat.
271273

@@ -295,7 +297,7 @@ expect(flag).toBe(false);
295297

296298
#### 2) `toHaveBeenCalledOnceWith()` gibt es in Jest/Vitest nicht
297299

298-
Jasmine hat einen praktischen Matcher für einen Spy mit der Prüfung auf "genau einmal und genau mit diesen Argumenten".
300+
Jasmine hat einen praktischen Matcher für einen Spy mit der Prüfung auf "genau einmal und genau mit diesen Argumenten".
299301
Als Ersatz verwendest du einfach [`toHaveBeenCalledExactlyOnceWith()`](https://vitest.dev/api/expect.html#tohavebeencalledexactlyoncewith):
300302

301303
```ts
@@ -310,8 +312,8 @@ expect(spy).toHaveBeenCalledExactlyOnceWith(book);
310312

311313
#### 3) Asynchrone Matchers: `expectAsync(...)` (Jasmine) vs. `.resolves/.rejects` (Jest/Vitest)
312314

313-
Jasmine hat eine [eigene Async-API](https://jasmine.github.io/api/5.12/async-matchers): `await expectAsync(promise).toBeResolved() / toBeRejectedWith(...)`.
314-
Jest/Vitest nutzen stattdessen das Muster [`await expect(promise).resolves/...`](https://vitest.dev/api/expect.html#resolves) bzw. [`.rejects/...`](https://vitest.dev/api/expect.html#rejects).
315+
Jasmine hat eine [eigene Async-API](https://jasmine.github.io/api/5.12/async-matchers): `await expectAsync(promise).toBeResolved() / toBeRejectedWith(...)`.
316+
Jest/Vitest nutzen stattdessen das Muster [`await expect(promise).resolves/...`](https://vitest.dev/api/expect.html#resolves) bzw. [`.rejects/...`](https://vitest.dev/api/expect.html#rejects).
315317
Beim Umstieg müssen diese Expectations umgeschrieben werden.
316318

317319
```ts
@@ -326,10 +328,10 @@ await expect(doWork()).resolves.toBe('OK');
326328
await expect(doWork()).rejects.toThrow('Boom');
327329
```
328330

329-
Vitest zielt also bei den Matchern auf Jest‑Kompatibilität ab.
330-
Kompatibilität mit Jasmine steht hingegen überhaupt nicht im Fokus.
331-
In der Praxis ist der Anpassungsaufwand meist gering (vor allem bei `toBeTrue`/`toBeFalse` und `toHaveBeenCalledOnceWith`), aber er existiert.
332-
Bei asynchronen Erwartungen unterscheidet sich das Pattern sogar deutlich.
331+
Vitest zielt also bei den Matchern auf Jest‑Kompatibilität ab.
332+
Kompatibilität mit Jasmine steht hingegen überhaupt nicht im Fokus.
333+
In der Praxis ist der Anpassungsaufwand meist gering (vor allem bei `toBeTrue`/`toBeFalse` und `toHaveBeenCalledOnceWith`), aber er existiert.
334+
Bei asynchronen Erwartungen unterscheidet sich das Pattern sogar deutlich.
333335
Aber keine Sorge: Die Wahrscheinlichkeit, dass dein Projekt `expectAsync` verwendet, ist sehr gering, da in der Angular-Dokumentation stattdessen immer Angular-spezifische Hilfsfunktionen gezeigt wurden.
334336
Daher dürfte in den meisten Projekten hier wahrscheinlich gar keine zusätzliche Arbeit anfallen.
335337

@@ -420,8 +422,8 @@ Das Angular-Team hat sich [bewusst für das Standard-Vitest-Verhalten entschiede
420422

421423
### Asynchronität ohne Zone.js mit Vitest Timer
422424

423-
Seit Angular 21 laufen Unit-Tests standardmäßig zoneless.
424-
Das bedeutet: Die früheren Angular-Hilfsfunktionen `waitForAsync()` und `fakeAsync()`/`tick()` funktionieren nicht mehr automatisch, weil sie auf Zone.js basieren.
425+
Seit Angular 21 laufen Unit-Tests standardmäßig zoneless.
426+
Das bedeutet: Die früheren Angular-Hilfsfunktionen `waitForAsync()` und `fakeAsync()`/`tick()` funktionieren nicht mehr automatisch, weil sie auf Zone.js basieren.
425427
Entscheidend ist: Das hat nichts mit Vitest zu tun.
426428
Auch unter Jasmine hätte man in einer zonenlosen Umgebung auf diese Utilitys verzichten müssen.
427429

@@ -450,8 +452,8 @@ Modern ist nur die Schreibweise, bei der es zwischen Jasmine und Vitest keinen U
450452
Der zweite Angular-Klassiker [`fakeAsync()`](https://angular.dev/api/core/testing/fakeAsync) und [`tick()`](https://angular.dev/api/core/testing/tick) braucht hingegen einen echten Ersatz.
451453
(Hinweis: Diese beiden Helfer sind nicht Bestandteil von Jasmine, sondern kommen aus `@angular/core/testing`.)
452454
Vitest bringt ein eigenes [Fake-Timer-System](https://vitest.dev/api/vi.html#fake-timers) mit.
453-
Die Nutzung erfordert etwas Einarbeitung, denn nicht alle Timer funktionieren gleich und nicht jeder Test braucht dieselben Werkzeuge.
454-
Beginnen wir mit einem einfachen zeitbasierten Beispiel.
455+
Die Nutzung erfordert etwas Einarbeitung, denn nicht alle Timer funktionieren gleich und nicht jeder Test braucht dieselben Werkzeuge.
456+
Beginnen wir mit einem einfachen zeitbasierten Beispiel.
455457
Die folgende Funktion erhöht einen Counter nach genau fünf Sekunden:
456458

457459
```ts
@@ -489,7 +491,7 @@ describe('startFiveSecondTimer', () => {
489491
Es eignet sich besonders gut, wenn du eine ganz bestimmte Zeitspanne simulieren oder mehrere Timer in korrekt getakteter Reihenfolge ablaufen lassen möchtest.
490492

491493

492-
Doch nicht alle Timer sind so einfach.
494+
Doch nicht alle Timer sind so einfach.
493495
Manchmal besteht der Code nur aus timerbasierten Aktionen, aber ohne zusätzliche Promises. Das folgende Beispiel inkrementiert einen Counter mehrfach, indem es ausschließlich Timeouts und Intervals nutzt:
494496

495497
```ts
@@ -565,12 +567,25 @@ describe('startAsyncJob', () => {
565567
});
566568
```
567569

568-
`runAllTimersAsync()` ist damit ein guter Ersatz für Tests, bei denen bisher `fakeAsync()` und `tick()` in Kombination mit Microtask-Flushing verwendet wurden.
570+
`runAllTimersAsync()` ist damit ein guter Ersatz für Tests, bei denen bisher `fakeAsync()` und `tick()` in Kombination mit Microtask-Flushing verwendet wurden.
571+
572+
#### Migration mit der Angular CLI
573+
574+
Mit Angular 22 stellt die Angular CLI ein eigenes Schematic bereit, das diese Umstellung weitgehend automatisch erledigt:
575+
576+
```bash
577+
ng generate @schematics/angular:fake-async-to-vitest-fake-timers
578+
```
579+
580+
Das Schematic ersetzt `fakeAsync(...)`-Wrapper durch entsprechende Aufrufe von `vi.useFakeTimers()` bzw. `vi.useRealTimers()`, übersetzt `tick(ms)` in `vi.advanceTimersByTime(ms)` und kümmert sich auch um die nötigen Imports aus `vitest`.
581+
Wo eine eindeutige Übersetzung nicht möglich ist (etwa bei komplexen Microtask-Flows), hinterlässt das Schematic einen TODO-Kommentar – diese Stellen müssen wir dann manuell auf `runAllTimers()` oder `runAllTimersAsync()` umstellen.
582+
583+
So lässt sich die Migration auch in größeren Projekten gut vorantreiben, ohne jeden einzelnen Test von Hand anzufassen.
569584

570585
### TestBed und ComponentFixture
571586

572-
Nach all den kleinen, aber subtilen Unterschieden zwischen Jasmine und Vitest gibt es hier gute Nachrichten:
573-
Die Verwendung von `TestBed` und `ComponentFixture` bleibt vollständig unverändert, da dies kein Thema ist, das Vitest berührt.
587+
Nach all den kleinen, aber subtilen Unterschieden zwischen Jasmine und Vitest gibt es hier gute Nachrichten:
588+
Die Verwendung von `TestBed` und `ComponentFixture` bleibt vollständig unverändert, da dies kein Thema ist, das Vitest berührt.
574589
Du erzeugst weiterhin deine Komponenten oder Services mithilfe von `TestBed`.
575590
Auch der explizite Aufruf von `fixture.detectChanges()` ist unverändert notwendig, um die Change Detection manuell anzustoßen.
576591

@@ -580,15 +595,15 @@ Auch der explizite Aufruf von `fixture.detectChanges()` ist unverändert notwend
580595
Spezielle Karma-Anwendungsfälle wie eigene Karma-Plugins oder individuelle Browser‑Launcher lassen sich erwartungsgemäß nicht direkt auf Vitest übertragen.
581596
Du wirst im Vitest-Ökosystem nach Alternativen suchen müssen.
582597

583-
Bei der Umstellung auf Vitest kann eine kurze Gewöhnungsphase im Team nötig sein, da bestimmte neue API-Konzepte wie `vi.spyOn`, `vi.fn` oder Strategien zum Zurücksetzen von Mocks zwar leicht zu erlernen sind, sich aber dennoch von Jasmine unterscheiden.
598+
Bei der Umstellung auf Vitest kann eine kurze Gewöhnungsphase im Team nötig sein, da bestimmte neue API-Konzepte wie `vi.spyOn`, `vi.fn` oder Strategien zum Zurücksetzen von Mocks zwar leicht zu erlernen sind, sich aber dennoch von Jasmine unterscheiden.
584599
Achte deshalb darauf, dass deine Tests mögliche Manipulationen an globalen Objekten vollständig aufräumen und verwende dafür idealerweise Methoden wie [`afterEach`](https://vitest.dev/api/#aftereach) mit [`vi.restoreAllMocks()`](https://vitest.dev/api/vi.html#vi-restoreallmocks).
585600

586601

587602
## Fazit
588603

589-
Mit Vitest als Standard in Angular 21 wird das Testen deutlich moderner und schneller.
590-
Die Umstellung ist meist unkompliziert, die Migrations‑Schematics helfen beim Einstieg.
591-
Wo früher `fakeAsync` und Zone.js‑Magie nötig waren, reichen heute `async/await` und flexible Fake‑Timer.
604+
Mit Vitest als Standard in Angular 21 wird das Testen deutlich moderner und schneller.
605+
Die Umstellung ist meist unkompliziert, die Migrations‑Schematics helfen beim Einstieg.
606+
Wo früher `fakeAsync` und Zone.js‑Magie nötig waren, reichen heute `async/await` und flexible Fake‑Timer.
592607
Und wenn es realistisch sein muss, steht dir der Browser‑Modus zur Verfügung.
593608
Insgesamt bedeutet das: kürzere Feedback‑Schleifen, robustere Tests und weniger Reibung im Alltag. Viel Spaß beim Testen!
594609

0 commit comments

Comments
 (0)