From 7da9c227cc78a55efb13dcf27b6a173ec76a1629 Mon Sep 17 00:00:00 2001 From: rk Date: Sat, 24 Oct 2026 02:21:04 +0500 Subject: [PATCH] fix(@schematics/angular): migrate spy.calls.first().args in refactor-jasmine-vitest `spy.calls.first()` is migrated to `vi.mocked(spy).mock.calls[0]`, which is alredy arguments array of first call, but `.args` after it was kept so `spy.calls.first().args[0]` became `vi.mocked(spy).mock.calls[0].args[0]`, which fails with TS2339 and throws at runtime `.args` after `first()` is now dropped same way as after `mostRecent()` and `all()[i]` --- .../jasmine-vitest/transformers/jasmine-spy.ts | 15 +++++++++++++-- .../transformers/jasmine-spy_spec.ts | 10 ++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/schematics/angular/refactor/jasmine-vitest/transformers/jasmine-spy.ts b/packages/schematics/angular/refactor/jasmine-vitest/transformers/jasmine-spy.ts index 740628d41fcd..1b1d075bbcea 100644 --- a/packages/schematics/angular/refactor/jasmine-vitest/transformers/jasmine-spy.ts +++ b/packages/schematics/angular/refactor/jasmine-vitest/transformers/jasmine-spy.ts @@ -527,11 +527,11 @@ function transformMostRecentArgs( return node; } - // Check 3: Is it a call to `.mostRecent`? + // Check 3: Is it a call to `.mostRecent` or `.first`? const mostRecentPae = mostRecentCall.expression; if ( !ts.isIdentifier(mostRecentPae.name) || - mostRecentPae.name.text !== 'mostRecent' || + (mostRecentPae.name.text !== 'mostRecent' && mostRecentPae.name.text !== 'first') || !ts.isPropertyAccessExpression(mostRecentPae.expression) ) { return node; @@ -543,6 +543,17 @@ function transformMostRecentArgs( return node; } + if (mostRecentPae.name.text === 'first') { + reporter.reportTransformation( + sourceFile, + node, + 'Transformed `spy.calls.first().args` to `vi.mocked(spy).mock.calls[0]`.', + ); + const mockProperty = createMockedSpyMockProperty(spyIdentifier, pendingVitestValueImports); + + return ts.factory.createElementAccessExpression(createPropertyAccess(mockProperty, 'calls'), 0); + } + // If all checks pass, perform the transformation. reporter.reportTransformation( sourceFile, diff --git a/packages/schematics/angular/refactor/jasmine-vitest/transformers/jasmine-spy_spec.ts b/packages/schematics/angular/refactor/jasmine-vitest/transformers/jasmine-spy_spec.ts index 81ae0ff02bb8..17e84120dcab 100644 --- a/packages/schematics/angular/refactor/jasmine-vitest/transformers/jasmine-spy_spec.ts +++ b/packages/schematics/angular/refactor/jasmine-vitest/transformers/jasmine-spy_spec.ts @@ -322,6 +322,16 @@ describe('transformSpyCallInspection', () => { input: `const firstCall = mySpy.calls.first();`, expected: `const firstCall = vi.mocked(mySpy).mock.calls[0];`, }, + { + description: 'should transform spy.calls.first().args', + input: `const firstArgs = mySpy.calls.first().args;`, + expected: `const firstArgs = vi.mocked(mySpy).mock.calls[0];`, + }, + { + description: 'should transform spy.calls.first().args[i]', + input: `expect(mySpy.calls.first().args[0]).toBe(1);`, + expected: `expect(vi.mocked(mySpy).mock.calls[0][0]).toBe(1);`, + }, { description: 'should add a TODO for spy.calls.mostRecent() without .args', input: `const mostRecent = mySpy.calls.mostRecent();`,