Skip to content

Commit c973bb9

Browse files
committed
fix(@schematics/angular): add mock names to createSpyObj transformation
This commit enhances the jasmine-vitest schematic by adding mock names to `vi.fn()` instances created from `jasmine.createSpyObj`. This improves debugging in Vitest by providing meaningful names for mock functions, making test failures easier to understand and trace. (cherry picked from commit f38fade)
1 parent 54d5427 commit c973bb9

File tree

4 files changed

+57
-26
lines changed

4 files changed

+57
-26
lines changed

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,14 +255,15 @@ describe('Jasmine to Vitest Transformer - Integration Tests', () => {
255255
});
256256
`;
257257

258+
/* eslint-disable max-len */
258259
const vitestCode = `
259260
describe('Complex Scenarios', () => {
260261
let serviceMock;
261262
262263
beforeEach(() => {
263264
serviceMock = {
264-
getData: vi.fn().mockReturnValue(expect.any(String)),
265-
process: vi.fn().mockReturnValue(undefined),
265+
getData: vi.fn().mockName("MyService.getData").mockReturnValue(expect.any(String)),
266+
process: vi.fn().mockName("MyService.process").mockReturnValue(undefined),
266267
};
267268
});
268269
@@ -299,6 +300,7 @@ describe('Jasmine to Vitest Transformer - Integration Tests', () => {
299300
});
300301
});
301302
`;
303+
/* eslint-enable max-len */
302304

303305
await expectTransformation(jasmineCode, vitestCode);
304306
});

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ describe('Jasmine to Vitest Transformer', () => {
7878
input: `const spy = jasmine.createSpyObj('MyService', { getPromise: Promise.resolve(jasmine.any(String)) });`,
7979
expected: `
8080
const spy = {
81-
getPromise: vi.fn().mockReturnValue(Promise.resolve(expect.any(String))),
81+
getPromise: vi.fn().mockName("MyService.getPromise").mockReturnValue(Promise.resolve(expect.any(String))),
8282
};
8383
`,
8484
},
@@ -105,8 +105,8 @@ describe('Jasmine to Vitest Transformer', () => {
105105
`,
106106
expected: `
107107
const myService = {
108-
methodA: vi.fn(),
109-
propA: 'valueA'
108+
methodA: vi.fn().mockName("MyService.methodA"),
109+
propA: 'valueA',
110110
};
111111
vi.spyOn(myService, 'methodA').mockReturnValue('mocked value');
112112
myService.methodA('test');

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

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,12 @@ export function transformCreateSpyObj(
227227
'Transformed `jasmine.createSpyObj()` to an object literal with `vi.fn()`.',
228228
);
229229

230+
const baseNameArg = node.arguments[0];
231+
const baseName = ts.isStringLiteral(baseNameArg) ? baseNameArg.text : undefined;
232+
const methods = node.arguments[1];
233+
const propertiesArg = node.arguments[2];
234+
let properties: ts.PropertyAssignment[] = [];
235+
230236
if (node.arguments.length < 2) {
231237
const category = 'createSpyObj-single-argument';
232238
reporter.recordTodo(category);
@@ -235,14 +241,10 @@ export function transformCreateSpyObj(
235241
return node;
236242
}
237243

238-
const methods = node.arguments[1];
239-
const propertiesArg = node.arguments[2];
240-
let properties: ts.PropertyAssignment[] = [];
241-
242244
if (ts.isArrayLiteralExpression(methods)) {
243-
properties = createSpyObjWithArray(methods);
245+
properties = createSpyObjWithArray(methods, baseName);
244246
} else if (ts.isObjectLiteralExpression(methods)) {
245-
properties = createSpyObjWithObject(methods);
247+
properties = createSpyObjWithObject(methods, baseName);
246248
} else {
247249
const category = 'createSpyObj-dynamic-variable';
248250
reporter.recordTodo(category);
@@ -264,13 +266,28 @@ export function transformCreateSpyObj(
264266
return ts.factory.createObjectLiteralExpression(properties, true);
265267
}
266268

267-
function createSpyObjWithArray(methods: ts.ArrayLiteralExpression): ts.PropertyAssignment[] {
269+
function createSpyObjWithArray(
270+
methods: ts.ArrayLiteralExpression,
271+
baseName: string | undefined,
272+
): ts.PropertyAssignment[] {
268273
return methods.elements
269274
.map((element) => {
270275
if (ts.isStringLiteral(element)) {
276+
const mockFn = createViCallExpression('fn');
277+
const methodName = element.text;
278+
let finalExpression: ts.Expression = mockFn;
279+
280+
if (baseName) {
281+
finalExpression = ts.factory.createCallExpression(
282+
createPropertyAccess(finalExpression, 'mockName'),
283+
undefined,
284+
[ts.factory.createStringLiteral(`${baseName}.${methodName}`)],
285+
);
286+
}
287+
271288
return ts.factory.createPropertyAssignment(
272-
ts.factory.createIdentifier(element.text),
273-
createViCallExpression('fn'),
289+
ts.factory.createIdentifier(methodName),
290+
finalExpression,
274291
);
275292
}
276293

@@ -279,13 +296,25 @@ function createSpyObjWithArray(methods: ts.ArrayLiteralExpression): ts.PropertyA
279296
.filter((p): p is ts.PropertyAssignment => !!p);
280297
}
281298

282-
function createSpyObjWithObject(methods: ts.ObjectLiteralExpression): ts.PropertyAssignment[] {
299+
function createSpyObjWithObject(
300+
methods: ts.ObjectLiteralExpression,
301+
baseName: string | undefined,
302+
): ts.PropertyAssignment[] {
283303
return methods.properties
284304
.map((prop) => {
285305
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
286306
const methodName = prop.name.text;
287307
const returnValue = prop.initializer;
288-
const mockFn = createViCallExpression('fn');
308+
let mockFn = createViCallExpression('fn');
309+
310+
if (baseName) {
311+
mockFn = ts.factory.createCallExpression(
312+
createPropertyAccess(mockFn, 'mockName'),
313+
undefined,
314+
[ts.factory.createStringLiteral(`${baseName}.${methodName}`)],
315+
);
316+
}
317+
289318
const mockReturnValue = createPropertyAccess(mockFn, 'mockReturnValue');
290319

291320
return ts.factory.createPropertyAssignment(

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,8 @@ vi.spyOn(service, 'myMethod').and.unknownStrategy();`,
118118
description: 'should transform jasmine.createSpyObj with an array of methods',
119119
input: `const myService = jasmine.createSpyObj('MyService', ['methodA', 'methodB']);`,
120120
expected: `const myService = {
121-
methodA: vi.fn(),
122-
methodB: vi.fn()
121+
methodA: vi.fn().mockName("MyService.methodA"),
122+
methodB: vi.fn().mockName("MyService.methodB"),
123123
};`,
124124
},
125125
{
@@ -134,16 +134,16 @@ vi.spyOn(service, 'myMethod').and.unknownStrategy();`,
134134
description: 'should transform jasmine.createSpyObj with an object of return values',
135135
input: `const myService = jasmine.createSpyObj('MyService', { methodA: 'foo', methodB: 42 });`,
136136
expected: `const myService = {
137-
methodA: vi.fn().mockReturnValue('foo'),
138-
methodB: vi.fn().mockReturnValue(42)
137+
methodA: vi.fn().mockName("MyService.methodA").mockReturnValue('foo'),
138+
methodB: vi.fn().mockName("MyService.methodB").mockReturnValue(42),
139139
};`,
140140
},
141141
{
142142
description:
143143
'should transform jasmine.createSpyObj with an object of return values containing an asymmetric matcher',
144144
input: `const myService = jasmine.createSpyObj('MyService', { methodA: jasmine.any(String) });`,
145145
expected: `const myService = {
146-
methodA: vi.fn().mockReturnValue(expect.any(String))
146+
methodA: vi.fn().mockName("MyService.methodA").mockReturnValue(expect.any(String)),
147147
};`,
148148
},
149149
{
@@ -158,23 +158,23 @@ vi.spyOn(service, 'myMethod').and.unknownStrategy();`,
158158
description: 'should transform jasmine.createSpyObj with a property map',
159159
input: `const myService = jasmine.createSpyObj('MyService', ['methodA'], { propA: 'valueA' });`,
160160
expected: `const myService = {
161-
methodA: vi.fn(),
162-
propA: 'valueA'
161+
methodA: vi.fn().mockName("MyService.methodA"),
162+
propA: 'valueA',
163163
};`,
164164
},
165165
{
166166
description: 'should transform jasmine.createSpyObj with a method map and a property map',
167167
input: `const myService = jasmine.createSpyObj('MyService', { methodA: 'foo' }, { propA: 'valueA' });`,
168168
expected: `const myService = {
169-
methodA: vi.fn().mockReturnValue('foo'),
170-
propA: 'valueA'
169+
methodA: vi.fn().mockName("MyService.methodA").mockReturnValue('foo'),
170+
propA: 'valueA',
171171
};`,
172172
},
173173
{
174174
description: 'should ignore non-string literals in the method array',
175175
input: `const myService = jasmine.createSpyObj('MyService', ['methodA', 123, someVar]);`,
176176
expected: `const myService = {
177-
methodA: vi.fn()
177+
methodA: vi.fn().mockName("MyService.methodA"),
178178
};`,
179179
},
180180
];

0 commit comments

Comments
 (0)