
Jest, TypeScript und Mock-Scopes: Warum dein undefined nicht zurückkommt
Jest richtig verstehen: So funktionieren describe-, beforeEach- und Mock-Scopes in TypeScript – und warum dein Mock kein undefined liefert.
Beitrag teilen auf
Jest, TypeScript und Mock-Scopes: Warum dein undefined nicht zurückkommt
Beim Schreiben von Unit-Tests in TypeScript mit Jest stolpert man häufig über ein merkwürdiges Verhalten: Man setzt einen Mock auf undefined, aber der Test liefert trotzdem ein Objekt. Das Problem liegt nicht im Mock selbst, sondern im Scope und der Lebenszeit von Variablen und Mock-Rückgaben.
1. Der typische Fehler
Viele schreiben Mocks direkt in einem describe-Block:
describe("Given a user", () => {
describe("That is logged out", () => {
sessionMock.mockReturnValue(undefined);
it("recognizes the user as logged out", async () => {
const result = await isLoggedIn();
expect(result).toBe(false);
});
});
describe("That is logged in as a user", () => {
sessionMock.mockReturnValue({
session: {},
user: {
role: "user"
}
});
it("recognizes the user as logged in", async () => {
const result: boolean = await isLoggedIn();
expect(result).toBe(true);
});
});
});
Intuitiv könnte man denken: „Beim Betreten des Describe-Blocks wird der Mock gesetzt.“ Tatsächlich wird der gesamte Code im Describe-Block nur einmal beim Laden des Moduls ausgeführt, nicht vor jedem Test. Das kann dazu führen, dass vorherige Mocks oder andere Initialisierungen den Wert überschreiben.
2. Richtiger Umgang mit Mocks in Jest
Verwende beforeEach für dynamische Rückgaben.
describe("That is logged out", () => {
beforeEach(() => {
// Async-Funktion korrekt mocken
sessionMock.mockResolvedValue(undefined);
});
it("recognizes the user as logged out", async () => {
const result = await isLoggedIn();
expect(result).toBe(false);
});
});
Für einen „eingeloggten“ Nutzer:
describe("Logged in as a user", () => {
beforeEach(() => {
sessionMock.mockResolvedValue({
session: {},
user: { role: "patient" },
});
});
it("recognizes the user as logged in", async () => {
const result = await isLoggedIn();
expect(result).toBe(true);
});
});
Tipp: Für async-Funktionen immer mockResolvedValue() statt mockReturnValue() verwenden, sonst bekommst du nur ein ungelöstes Promise.
3. Jest-Test-Lebenszyklus im Überblick
| Phase | Wann ausgeführt? |
|---|---|
| describe | Einmal beim Laden der Test-Datei |
| beforeAll | Einmal vor allen Tests in describe |
| beforeEach | Vor jedem it / Test |
| it / test | Jeder einzelne Test |
| afterEach | Nach jedem Test |
| afterAll | Einmal nach allen Tests in describe |
So wird klar, warum ein Mock, der direkt in describe gesetzt wird, nicht für jeden Test neu gilt.
4. Fazit
- Nie Mocks direkt in describe setzen, wenn sie sich zwischen Tests ändern.
- beforeEach ist dein Freund – hier kannst du Mock-Werte sauber vorbereiten.
- Async-Funktionen richtig mocken mit mockResolvedValue().
- Jest-Testlauf: describe wird einmal ausgeführt, it-Blöcke mehrfach – der Scope entscheidet, welche Werte sichtbar sind.
- Mit diesem Verständnis vermeidest du typische Stolperfallen und stellst sicher, dass deine Tests deterministisch laufen.