Skip to content

feat(@schematics/angular): add option to migrate fakeAsync to Vitest fake timers#33111

Merged
clydin merged 1 commit intoangular:mainfrom
yjaaidi:feat/add-refactor-fake-async-migration
May 4, 2026
Merged

feat(@schematics/angular): add option to migrate fakeAsync to Vitest fake timers#33111
clydin merged 1 commit intoangular:mainfrom
yjaaidi:feat/add-refactor-fake-async-migration

Conversation

@yjaaidi
Copy link
Copy Markdown
Contributor

@yjaaidi yjaaidi commented Apr 30, 2026

PR Checklist

Please check to confirm your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

What is the current behavior?

There is no migration from fakeAsync to Vitest fake timer APIs.

Issue Number: N/A

What is the new behavior?

The current migration transforms the following test:

describe('suite', () => {
  it("should work", fakeAsync(() => {
    let value = 0;

    setTimeout(() => value = 42, 100);

    tick(100);
    flushMicrotasks();
    flush();

    expect(value).toBe(42);
  });
);

into:

import { beforeAll, afterAll, vi } from 'vitest';


describe('suite', () => {

  beforeAll(() => {
    vi.useFakeTimers({ advanceTimeDelta: 1, shouldAdvanceTime: true });
  });
  afterAll(() => {
    vi.useRealTimers();
  });

  it("should work", fakeAsync(() => {
    let value = 0;

    setTimeout(() => value = 42, 100);

    await vi.advanceTimersByTimeAsync(100);
    await vi.advanceTimersByTimeAsync(0);
    await vi.runAllTimersAsync();

    expect(value).toBe(42);
  });
});

Does this PR introduce a breaking change?

  • Yes
  • No

Open Questions

  • This migration could be part of the jasmine-vitest migration. Should I moved it there and add an opt-out?
    Moved to jasmine-vitest migration under fakeAsync option which is false by default

  • flushMicrotasks can only be partially reproduced (i.e. explicit queueMicrotask calls), transforming it have high chances of producing a broken test. Should we just skip transforming tests that use it?
    Migrated to await vi.advanceTimersByTimeAsync(0);.

  • Should we generate code that measures time "manually" when the return value of flush is used?
    Generates a TODO.

  • Should we generate an "ad-hoc" function in the test file that reproduces flush's maxTurns option?
    Generates a TODO.

  • What should we do about processNewMacroTasksSynchronously option?
    Ignored.

  • This only migrates flush and tick if used inside fakeAsync but it's probably better to just replace in the whole file as users might create some wrappers. What do you think?
    Replaced everywhere.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds support for migrating Angular fakeAsync tests to Vitest by introducing a new fakeAsync option and corresponding transformers for tick, flush, and flushMicrotasks. The implementation converts these utilities to Vitest's vi fake timer API. Reviewers suggested scoping the fake timer hooks more narrowly to avoid side effects on sibling tests, disabling shouldAdvanceTime to better match fakeAsync semantics, and refining the flush transformer's logic for detecting discarded return values.

@yjaaidi yjaaidi force-pushed the feat/add-refactor-fake-async-migration branch from e90eef2 to fbd8e15 Compare April 30, 2026 14:57
@yjaaidi yjaaidi marked this pull request as draft April 30, 2026 15:01
@yjaaidi yjaaidi force-pushed the feat/add-refactor-fake-async-migration branch 2 times, most recently from cc415cf to 24627cd Compare April 30, 2026 15:21
Comment thread packages/schematics/angular/refactor/jasmine-vitest/schema.json
`,
},
{
description: 'should not replace `fakeAsync` if not used within a describe block',
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This exact scenario is not likely within Jasmine but fakeAsync could be used in some test factory or something similar.
In that case, we just bail.

// > beforeAll(() => {
// > vi.useFakeTimers({
// > advanceTimeDelta: 1,
// > shouldAdvanceTime: true
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably the best alternative to use fake timers without freezing other tests in the suite which rely on rely timers.

@yjaaidi yjaaidi marked this pull request as ready for review April 30, 2026 15:34
@yjaaidi yjaaidi changed the title feat(@schematics/angular): migrate fake async to Vitest fake timers feat(@schematics/angular): add option to migrate fakeAsync to Vitest fake timers Apr 30, 2026
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the fakeAsync transformation to the jasmine-vitest schematic, enabling the migration of Angular fakeAsync tests to Vitest's fake timers. It adds specific transformers for flush, flushMicrotasks, tick, and the fakeAsync wrapper, supported by new utility functions for AST manipulation. Review feedback highlights several areas for improvement: ensuring tick() arguments are preserved even when they are not numeric literals, maintaining parameters and type parameters when converting callbacks to async functions, adjusting Vitest timer settings to better match standard fakeAsync behavior, and correcting misleading comments regarding vi.useRealTimers().

@yjaaidi yjaaidi force-pushed the feat/add-refactor-fake-async-migration branch 2 times, most recently from 874cbe9 to 1ed014b Compare May 1, 2026 20:10
@yjaaidi yjaaidi force-pushed the feat/add-refactor-fake-async-migration branch from 271377b to 978acd4 Compare May 4, 2026 16:07
@clydin clydin added target: minor This PR is targeted for the next minor release action: merge The PR is ready for merge by the caretaker labels May 4, 2026
@clydin clydin merged commit d227e69 into angular:main May 4, 2026
63 of 64 checks passed
@clydin
Copy link
Copy Markdown
Member

clydin commented May 4, 2026

This PR was merged into the repository. The changes were merged into the following branches:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action: merge The PR is ready for merge by the caretaker area: @schematics/angular detected: feature PR contains a feature commit target: minor This PR is targeted for the next minor release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants