Skip to content

Commit 04cc8d7

Browse files
committed
feat(@schematics/angular): stabilize refactor-jasmine-vitest schematic
Stabilize `refactor-jasmine-vitest` schematic by covering the known remaining test patterns and cases.
1 parent 2678f5f commit 04cc8d7

8 files changed

Lines changed: 276 additions & 78 deletions

File tree

packages/schematics/angular/refactor/jasmine-vitest/test-file-transformer.integration_spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,8 @@ describe('Jasmine to Vitest Transformer - Integration Tests', () => {
288288
});
289289
290290
it('should handle spy call order', () => {
291-
const spyA = vi.fn();
292-
const spyB = vi.fn();
291+
const spyA = vi.fn().mockName('spyA');
292+
const spyB = vi.fn().mockName('spyB');
293293
spyA();
294294
spyB();
295295
expect(Math.min(...vi.mocked(spyA).mock.invocationCallOrder)).toBeLessThan(Math.min(...vi.mocked(spyB).mock.invocationCallOrder));
@@ -387,7 +387,7 @@ describe('Jasmine to Vitest Transformer - Integration Tests', () => {
387387
});
388388
389389
it('should handle spies throwing errors', () => {
390-
const spy = vi.fn().mockImplementation(() => { throw new Error('Test Error') });
390+
const spy = vi.fn().mockName('mySpy').mockImplementation(() => { throw new Error('Test Error') });
391391
expect(() => spy()).toThrowError('Test Error');
392392
});
393393
});

packages/schematics/angular/refactor/jasmine-vitest/test-file-transformer.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import {
2929
transformSyntacticSugarMatchers,
3030
transformToHaveClass,
3131
transformWithContext,
32-
transformtoHaveBeenCalledBefore,
32+
transformToHaveBeenCalledBefore,
3333
} from './transformers/jasmine-matcher';
3434
import {
3535
transformDefaultTimeoutInterval,
@@ -40,6 +40,7 @@ import {
4040
transformUnsupportedJasmineCalls,
4141
} from './transformers/jasmine-misc';
4242
import {
43+
transformCreateSpy,
4344
transformCreateSpyObj,
4445
transformSpies,
4546
transformSpyCallInspection,
@@ -116,10 +117,11 @@ const callExpressionTransformers = [
116117
transformSyntacticSugarMatchers,
117118
transformComplexMatchers,
118119
transformSpies,
120+
transformCreateSpy,
119121
transformCreateSpyObj,
120122
transformSpyReset,
121123
transformSpyCallInspection,
122-
transformtoHaveBeenCalledBefore,
124+
transformToHaveBeenCalledBefore,
123125
transformToHaveClass,
124126

125127
// **Stage 3: Global Functions & Cleanup**

packages/schematics/angular/refactor/jasmine-vitest/transformers/jasmine-matcher.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export function transformAsymmetricMatchers(
121121
return node;
122122
}
123123

124-
export function transformtoHaveBeenCalledBefore(
124+
export function transformToHaveBeenCalledBefore(
125125
node: ts.Node,
126126
{ sourceFile, reporter }: RefactorContext,
127127
): ts.Node {

packages/schematics/angular/refactor/jasmine-vitest/transformers/jasmine-misc.ts

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,20 @@ export function transformTimerMocks(
5252
case 'mockDate':
5353
newMethodName = 'setSystemTime';
5454
break;
55+
case 'autoTick': {
56+
const category = 'clockAutoTick';
57+
reporter.recordTodo(category, sourceFile, node);
58+
addTodoComment(node, category);
59+
60+
return node;
61+
}
62+
case 'withMock': {
63+
const category = 'clockWithMock';
64+
reporter.recordTodo(category, sourceFile, node);
65+
addTodoComment(node, category);
66+
67+
return node;
68+
}
5569
}
5670

5771
if (newMethodName) {
@@ -85,15 +99,21 @@ export function transformFail(node: ts.Node, { sourceFile, reporter }: RefactorC
8599
node.expression.expression.text === 'fail'
86100
) {
87101
reporter.reportTransformation(sourceFile, node, 'Transformed `fail()` to `throw new Error()`.');
88-
const reason = node.expression.arguments[0];
89102

90-
const replacement = ts.factory.createThrowStatement(
91-
ts.factory.createNewExpression(
103+
const arg = node.expression.arguments[0];
104+
let throwExpression: ts.Expression;
105+
106+
if (arg && ts.isNewExpression(arg)) {
107+
throwExpression = arg;
108+
} else {
109+
throwExpression = ts.factory.createNewExpression(
92110
ts.factory.createIdentifier('Error'),
93111
undefined,
94-
reason ? [reason] : [],
95-
),
96-
);
112+
arg ? [arg] : [],
113+
);
114+
}
115+
116+
const replacement = ts.factory.createThrowStatement(throwExpression);
97117

98118
return ts.setOriginalNode(ts.setTextRange(replacement, node), node);
99119
}
@@ -163,15 +183,25 @@ export function transformGlobalFunctions(
163183

164184
const UNSUPPORTED_JASMINE_CALLS_CATEGORIES = new Set<TodoCategory>([
165185
'addMatchers',
186+
'addAsyncMatchers',
166187
'addCustomEqualityTester',
188+
'addCustomObjectFormatter',
167189
'mapContaining',
168190
'setContaining',
191+
'addSpyStrategy',
169192
]);
170193

171194
// A type guard to ensure that the methodName is one of the categories handled by this transformer.
172195
function isUnsupportedJasmineCall(
173196
methodName: string,
174-
): methodName is 'addMatchers' | 'addCustomEqualityTester' | 'mapContaining' | 'setContaining' {
197+
): methodName is
198+
| 'addMatchers'
199+
| 'addAsyncMatchers'
200+
| 'addCustomEqualityTester'
201+
| 'addCustomObjectFormatter'
202+
| 'mapContaining'
203+
| 'setContaining'
204+
| 'addSpyStrategy' {
175205
return UNSUPPORTED_JASMINE_CALLS_CATEGORIES.has(methodName as TodoCategory);
176206
}
177207

@@ -200,6 +230,7 @@ const HANDLED_JASMINE_PROPERTIES = new Set([
200230
'createSpy',
201231
'createSpyObj',
202232
'spyOnAllFunctions',
233+
'addSpyStrategy',
203234
// Clock
204235
'clock',
205236
// Matchers
@@ -218,7 +249,9 @@ const HANDLED_JASMINE_PROPERTIES = new Set([
218249
// Other
219250
'DEFAULT_TIMEOUT_INTERVAL',
220251
'addMatchers',
252+
'addAsyncMatchers',
221253
'addCustomEqualityTester',
254+
'addCustomObjectFormatter',
222255
]);
223256

224257
export function transformUnknownJasmineProperties(

packages/schematics/angular/refactor/jasmine-vitest/transformers/jasmine-misc_spec.ts

Lines changed: 70 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ describe('Jasmine to Vitest Transformer - transformTimerMocks', () => {
3535
input: `jasmine.clock().mockDate();`,
3636
expected: `vi.setSystemTime(new Date());`,
3737
},
38+
{
39+
description: 'should add a TODO for jasmine.clock().autoTick()',
40+
input: 'jasmine.clock().autoTick();',
41+
expected: `// TODO: vitest-migration: Vitest does not have a direct equivalent for jasmine.clock().autoTick(). Please migrate this manually. See: https://vitest.dev/api/vi.html#fake-timers
42+
jasmine.clock().autoTick();`,
43+
},
44+
{
45+
description: 'should add a TODO for jasmine.clock().withMock()',
46+
input: 'jasmine.clock().withMock(noop);',
47+
expected: `// TODO: vitest-migration: Vitest does not have a direct equivalent for jasmine.clock().withMock(). Please migrate this manually via vi.useFakeTimers() and vi.useRealTimers(). See: https://vitest.dev/api/vi.html#vi-usefaketimers
48+
jasmine.clock().withMock(noop);`,
49+
},
3850
];
3951

4052
testCases.forEach(({ description, input, expected }) => {
@@ -56,6 +68,11 @@ describe('transformFail', () => {
5668
input: `fail();`,
5769
expected: `throw new Error();`,
5870
},
71+
{
72+
description: 'should transform fail() with an Error object',
73+
input: `fail(new TypeError('Invalid input'));`,
74+
expected: `throw new TypeError('Invalid input');`,
75+
},
5976
];
6077

6178
testCases.forEach(({ description, input, expected }) => {
@@ -81,7 +98,7 @@ describe('transformDefaultTimeoutInterval', () => {
8198
});
8299
});
83100

84-
describe('transformAddMatchers', () => {
101+
describe('transformUnsupportedJasmineCalls', () => {
85102
const testCases = [
86103
{
87104
description: 'should add a TODO for jasmine.addMatchers',
@@ -113,17 +130,24 @@ describe('transformAddMatchers', () => {
113130
});
114131
`,
115132
},
116-
];
117-
118-
testCases.forEach(({ description, input, expected }) => {
119-
it(description, async () => {
120-
await expectTransformation(input, expected);
121-
});
122-
});
123-
});
124-
125-
describe('transformAddCustomEqualityTester', () => {
126-
const testCases = [
133+
{
134+
description: 'should add a TODO for jasmine.addAsyncMatchers',
135+
input: `
136+
jasmine.addAsyncMatchers({
137+
toEventuallyEqual: () => ({
138+
compare: async (actual, expected) => ({ pass: actual === expected }),
139+
}),
140+
});
141+
`,
142+
expected: `
143+
// TODO: vitest-migration: jasmine.addAsyncMatchers is not supported. Please manually migrate to expect.extend(). See: https://vitest.dev/api/expect.html#expect-extend
144+
jasmine.addAsyncMatchers({
145+
toEventuallyEqual: () => ({
146+
compare: async (actual, expected) => ({ pass: actual === expected }),
147+
}),
148+
});
149+
`,
150+
},
127151
{
128152
description: 'should add a TODO for jasmine.addCustomEqualityTester',
129153
input: `
@@ -137,6 +161,40 @@ describe('transformAddCustomEqualityTester', () => {
137161
});
138162
`,
139163
},
164+
{
165+
description: 'should add a TODO for jasmine.addCustomObjectFormatter',
166+
input: `
167+
jasmine.addCustomObjectFormatter((val) => {
168+
if (val instanceof MyClass) return 'MyClass(' + val.id + '})';
169+
});
170+
`,
171+
expected: `// TODO: vitest-migration: jasmine.addCustomObjectFormatter is not supported. May be possible to migrate to expect.addSnapshotSerializer(). See: https://vitest.dev/api/expect.html#expect-addsnapshotserializer
172+
jasmine.addCustomObjectFormatter((val) => {
173+
if (val instanceof MyClass) return 'MyClass(' + val.id + '})';
174+
});
175+
`,
176+
},
177+
{
178+
description: 'should add a TODO for jasmine.mapContaining',
179+
input: `expect(myMap).toEqual(jasmine.mapContaining(new Map()));`,
180+
// eslint-disable-next-line max-len
181+
expected: `// TODO: vitest-migration: jasmine.mapContaining is not supported. Vitest does not have a built-in matcher for Maps. Please manually assert the contents of the Map.
182+
expect(myMap).toEqual(jasmine.mapContaining(new Map()));`,
183+
},
184+
{
185+
description: 'should add a TODO for jasmine.setContaining',
186+
input: `expect(mySet).toEqual(jasmine.setContaining(new Set()));`,
187+
// eslint-disable-next-line max-len
188+
expected: `// TODO: vitest-migration: jasmine.setContaining is not supported. Vitest does not have a built-in matcher for Sets. Please manually assert the contents of the Set.
189+
expect(mySet).toEqual(jasmine.setContaining(new Set()));`,
190+
},
191+
{
192+
description: 'should add a TODO for jasmine.addSpyStrategy',
193+
input: `jasmine.addSpyStrategy('returnZero', () => () => 0);`,
194+
expected: `// TODO: vitest-migration: jasmine.addSpyStrategy is not supported. Please manually migrate to spy.mockImplementation(). See: https://vitest.dev/api/mock.html#mockimplementation
195+
jasmine.addSpyStrategy('returnZero', () => () => 0);
196+
`,
197+
},
140198
];
141199

142200
testCases.forEach(({ description, input, expected }) => {
@@ -192,28 +250,3 @@ setSuiteProperty('myKey', 'myValue');`,
192250
});
193251
});
194252
});
195-
196-
describe('transformUnsupportedJasmineCalls', () => {
197-
const testCases = [
198-
{
199-
description: 'should add a TODO for jasmine.mapContaining',
200-
input: `expect(myMap).toEqual(jasmine.mapContaining(new Map()));`,
201-
// eslint-disable-next-line max-len
202-
expected: `// TODO: vitest-migration: jasmine.mapContaining is not supported. Vitest does not have a built-in matcher for Maps. Please manually assert the contents of the Map.
203-
expect(myMap).toEqual(jasmine.mapContaining(new Map()));`,
204-
},
205-
{
206-
description: 'should add a TODO for jasmine.setContaining',
207-
input: `expect(mySet).toEqual(jasmine.setContaining(new Set()));`,
208-
// eslint-disable-next-line max-len
209-
expected: `// TODO: vitest-migration: jasmine.setContaining is not supported. Vitest does not have a built-in matcher for Sets. Please manually assert the contents of the Set.
210-
expect(mySet).toEqual(jasmine.setContaining(new Set()));`,
211-
},
212-
];
213-
214-
testCases.forEach(({ description, input, expected }) => {
215-
it(description, async () => {
216-
await expectTransformation(input, expected);
217-
});
218-
});
219-
});

0 commit comments

Comments
 (0)