You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
vitest: clarify important default behavior difference for spies (#34)
* docs: clarify important default behavior difference for spies
- Changed "almost the same" to "is similar to" for spy concept comparison
- Added new section explaining critical difference in default behavior:
* Jasmine: spyOn() returns undefined by default (stubs the method)
* Vitest: vi.spyOn() executes original implementation by default
- This is crucial information for migration from Jasmine to Vitest
* docs: add section about cleaning up spies
* docs: add context about Angular team's decision on spy behavior
#### Important difference: Default behavior of spies
397
+
398
+
In Jasmine, a spy returns `undefined` by default if no specific return value has been configured.
399
+
In Vitest, however, the **original implementation is executed** unless you explicitly set a mock value:
400
+
401
+
```ts
402
+
const book = { rating: 3 };
403
+
404
+
// Jasmine
405
+
const spy =spyOn(service, 'rateUp');
406
+
const result =service.rateUp(book);
407
+
// result = undefined (Spy stubbed the method)
408
+
409
+
// Vitest
410
+
const spy =vi.spyOn(service, 'rateUp');
411
+
const result =service.rateUp(book);
412
+
// result = { rating: 4 } (Original method is called!)
413
+
```
414
+
415
+
This difference is especially important when migrating existing Jasmine tests to Vitest.
416
+
If you need the original Jasmine behavior (i.e., returning `undefined`), you must explicitly use `.mockReturnValue(undefined)`.
417
+
418
+
#### Cleaning up spies
419
+
420
+
Angular TestBed creates a new test environment before each test.
421
+
This means services are also re-instantiated. Spies on services therefore disappear automatically between tests.
422
+
423
+
However, spies on **global objects** remain active:
424
+
425
+
```ts
426
+
vi.spyOn(Math, 'random').mockReturnValue(0.5);
427
+
vi.spyOn(console, 'log');
428
+
```
429
+
430
+
Without explicit cleanup, such spies would "leak" into subsequent tests and cause unexpected behavior (test pollution).
431
+
432
+
**If** you mock global objects, you should clean up spies in `afterEach()`:
433
+
434
+
```ts
435
+
import { afterEach, vi } from'vitest';
436
+
437
+
afterEach(() => {
438
+
vi.restoreAllMocks();
439
+
});
440
+
```
441
+
442
+
Alternatively, you can set the option `test.restoreMocks: true` in `vitest.config.ts`, and Vitest will handle the cleanup automatically.
443
+
444
+
Unfortunately, this setting is not the default.
445
+
The Angular team has [deliberately chosen the standard Vitest behavior](https://github.com/angular/angular-cli/issues/30478), forgoing maximum Jasmine compatibility.
446
+
396
447
### Asynchrony without Zone.js using Vitest timers
397
448
398
449
Since Angular 21, unit tests run zoneless by default.
0 commit comments