Skip to content

Commit 191de45

Browse files
committed
feat(@schematics/angular): do not transform flush & tick if used outside fakeAsync
1 parent 8beba0c commit 191de45

File tree

6 files changed

+84
-14
lines changed

6 files changed

+84
-14
lines changed

packages/schematics/angular/refactor/fake-async/index_spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,30 @@ it("should work", fakeAsync(() => {
6868

6969
expect(newContent).toContain(`await vi.runAllTimersAsync();`);
7070
});
71+
72+
it('should not transform `tick` if not inside `fakeAsync`', async () => {
73+
const { transformContent } = await setUp();
74+
75+
const newContent = await transformContent(`
76+
it("should work", () => {
77+
tick(100);
78+
}));
79+
`);
80+
81+
expect(newContent).toContain(`tick(100);`);
82+
});
83+
84+
it('should not transform `flush` if not inside `fakeAsync`', async () => {
85+
const { transformContent } = await setUp();
86+
87+
const newContent = await transformContent(`
88+
it("should work", () => {
89+
flush();
90+
}));
91+
`);
92+
93+
expect(newContent).toContain(`flush();`);
94+
});
7195
});
7296

7397
async function setUp() {

packages/schematics/angular/refactor/fake-async/refactor-context.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88

99
export interface RefactorContext {
1010
importedVitestIdentifiers: Set<string>;
11+
isInsideFakeAsync: boolean;
1112
}
1213

1314
export function createRefactorContext(): RefactorContext {
1415
return {
1516
importedVitestIdentifiers: new Set(),
17+
isInsideFakeAsync: false,
1618
};
1719
}

packages/schematics/angular/refactor/fake-async/transform-fake-async.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
import ts from '../../third_party/github.com/Microsoft/TypeScript/lib/typescript';
1010
import { createRefactorContext } from './refactor-context';
1111
import { transformFlush } from './transformers/flush';
12-
import { transformSetupFakeTimers } from './transformers/setup-fake-timers';
12+
import {
13+
isFakeAsyncCallExpression,
14+
transformSetupFakeTimers,
15+
} from './transformers/setup-fake-timers';
1316
import { transformTick } from './transformers/tick';
1417

1518
/**
@@ -31,9 +34,15 @@ export function transformFakeAsync(filePath: string, content: string): string {
3134
const transformer: ts.TransformerFactory<ts.SourceFile> = (context) => {
3235
const visit = (node: ts.Node): ts.Node => {
3336
if (ts.isCallExpression(node)) {
37+
const isFakeAsync = isFakeAsyncCallExpression(node);
38+
3439
for (const transformer of callExpressionTransformers) {
3540
node = transformer(node, refactorContext);
3641
}
42+
43+
if (isFakeAsync) {
44+
refactorContext.isInsideFakeAsync = true;
45+
}
3746
}
3847

3948
return ts.visitEachChild(node, visit, context);

packages/schematics/angular/refactor/fake-async/transformers/flush.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
19
import ts from '../../../third_party/github.com/Microsoft/TypeScript/lib/typescript';
10+
import { RefactorContext } from '../refactor-context';
211

3-
export function transformFlush(node: ts.Node): ts.Node {
12+
export function transformFlush(node: ts.Node, ctx: RefactorContext): ts.Node {
413
if (
14+
ctx.isInsideFakeAsync &&
515
ts.isCallExpression(node) &&
616
ts.isIdentifier(node.expression) &&
717
node.expression.text === 'flush'

packages/schematics/angular/refactor/fake-async/transformers/setup-fake-timers.ts

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,30 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
19
import ts from '../../../third_party/github.com/Microsoft/TypeScript/lib/typescript';
210
import { RefactorContext } from '../refactor-context';
311

412
export function transformSetupFakeTimers(node: ts.Node, ctx: RefactorContext): ts.Node {
5-
if (
6-
ts.isCallExpression(node) &&
7-
ts.isIdentifier(node.expression) &&
8-
node.expression.text === 'fakeAsync' &&
9-
node.arguments.length >= 1 &&
10-
(ts.isArrowFunction(node.arguments[0]) || ts.isFunctionExpression(node.arguments[0]))
11-
) {
13+
if (isFakeAsyncCallExpression(node)) {
1214
ctx.importedVitestIdentifiers.add('onTestFinished');
1315
ctx.importedVitestIdentifiers.add('vi');
16+
ctx.isInsideFakeAsync = true;
1417

1518
const callback = node.arguments[0];
1619
const callbackBody = ts.isBlock(callback.body)
1720
? callback.body
1821
: ts.factory.createBlock([ts.factory.createExpressionStatement(callback.body)]);
1922

2023
// Generate the following code:
21-
// vi.useFakeTimers();
22-
// onTestFinished(() => {
23-
// vi.useRealTimers();
24-
// });
24+
// > vi.useFakeTimers();
25+
// > onTestFinished(() => {
26+
// > vi.useRealTimers();
27+
// > });
2528
const setupStatements: ts.Statement[] = [
2629
ts.factory.createExpressionStatement(
2730
ts.factory.createCallExpression(
@@ -71,3 +74,16 @@ export function transformSetupFakeTimers(node: ts.Node, ctx: RefactorContext): t
7174

7275
return node;
7376
}
77+
78+
export function isFakeAsyncCallExpression(node: ts.Node): node is ts.CallExpression & {
79+
expression: ts.Identifier;
80+
arguments: [ts.ArrowFunction | ts.FunctionExpression];
81+
} {
82+
return (
83+
ts.isCallExpression(node) &&
84+
ts.isIdentifier(node.expression) &&
85+
node.expression.text === 'fakeAsync' &&
86+
node.arguments.length >= 1 &&
87+
(ts.isArrowFunction(node.arguments[0]) || ts.isFunctionExpression(node.arguments[0]))
88+
);
89+
}

packages/schematics/angular/refactor/fake-async/transformers/tick.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
19
import ts from '../../../third_party/github.com/Microsoft/TypeScript/lib/typescript';
210
import { RefactorContext } from '../refactor-context';
311

4-
export function transformTick(node: ts.Node): ts.Node {
12+
export function transformTick(node: ts.Node, ctx: RefactorContext): ts.Node {
513
if (
14+
ctx.isInsideFakeAsync &&
615
ts.isCallExpression(node) &&
716
ts.isIdentifier(node.expression) &&
817
node.expression.text === 'tick'

0 commit comments

Comments
 (0)