Conversation
…o jest Remove all sinon and proxyquire usage from fxa-auth-server test files, replacing with Jest built-in mocking (jest.fn, jest.spyOn, jest.mock). Key changes: - Replace sinon.stub/spy with jest.fn/jest.spyOn across 118 files - Replace proxyquire with jest.mock for module mocking - Convert sinon assertions (calledOnce, calledWith, etc.) to Jest equivalents (toHaveBeenCalledTimes, toHaveBeenCalledWith, etc.) - Fix test/mocks.js: use targeted Account.metricsEnabled patch instead of global jest.mock that clobbered other test files' module mocks - Rename jest.setup-proxyquire.js to jest.setup-resolve.js (TS module resolution patch still needed for jest.mock with .ts index files) - Fix beforeAll/beforeEach interactions with clearMocks:true config - Fix sinon.onCall(n) patterns to jest.mockResolvedValueOnce chains - Fix jest.spyOn on jest.fn() + restoreAllMocks implementation wipe All 150 test suites pass (3343/3343 tests).
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Refactors the fxa-auth-server Jest test suite to migrate from sinon/proxyquire-style stubbing to Jest mocks/spies, and updates Jest setup to improve TypeScript module resolution during mocking.
Changes:
- Replaced sinon stubs/spies/fakes with
jest.fn()/jest.spyOn()across many unit tests. - Updated assertions from sinon call inspection (
callCount,args, etc.) to Jest mock assertions (toHaveBeenCalledTimes,.mock.calls, etc.). - Replaced Jest setup file usage from a proxyquire-focused resolver to a
.ts-awareresolve.syncpatch.
Reviewed changes
Copilot reviewed 56 out of 118 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/fxa-auth-server/lib/routes/ip-profiling.spec.ts | Migrates request/mailer/redis/Container stubs from sinon to Jest. |
| packages/fxa-auth-server/lib/routes/geo-location.spec.ts | Updates log assertions to Jest .mock.calls patterns. |
| packages/fxa-auth-server/lib/routes/cloud-tasks.spec.ts | Converts cloud task handler tests from sinon sandbox to Jest mocks. |
| packages/fxa-auth-server/lib/routes/cloud-scheduler.spec.ts | Replaces sinon method stubbing with jest.spyOn(...).mockResolvedValue(...). |
| packages/fxa-auth-server/lib/routes/auth-schemes/verified-session-token.spec.ts | Converts auth scheme unit tests to Jest mocks and assertions. |
| packages/fxa-auth-server/lib/routes/auth-schemes/shared-secret.spec.ts | Replaces sinon fake with Jest mock and updates assertions. |
| packages/fxa-auth-server/lib/routes/auth-schemes/refresh-token.spec.ts | Updates spies/assertions to Jest equivalents. |
| packages/fxa-auth-server/lib/routes/auth-schemes/mfa.spec.ts | Migrates MFA auth scheme tests to Jest mocks/spies. |
| packages/fxa-auth-server/lib/routes/auth-schemes/hawk-fxa-token.spec.ts | Replaces sinon fakes with Jest mocks for hawk strategy tests. |
| packages/fxa-auth-server/lib/routes/auth-schemes/google-oidc.spec.ts | Updates Google OIDC strategy test stubbing to Jest. |
| packages/fxa-auth-server/lib/routes/attached-clients.spec.ts | Converts OAuth/DB/devices mocks + assertions from sinon to Jest. |
| packages/fxa-auth-server/lib/pushbox/index.spec.ts | Reworks PushboxDB stubbing away from sinon sandbox toward Jest mocks. |
| packages/fxa-auth-server/lib/profile/updates.spec.ts | Migrates push notification + message delete spies to Jest. |
| packages/fxa-auth-server/lib/payments/iap/iap-formatter.spec.ts | Updates entitlement checks to Jest mocks. |
| packages/fxa-auth-server/lib/payments/iap/iap-config.spec.ts | Replaces sinon sandbox and Firestore stubs with Jest mocks. |
| packages/fxa-auth-server/lib/payments/iap/google-play/user-manager.spec.ts | Migrates Firestore query/method stubs to Jest. |
| packages/fxa-auth-server/lib/payments/iap/google-play/subscriptions.spec.ts | Converts Play subscriptions tests to Jest mocks and assertions. |
| packages/fxa-auth-server/lib/payments/iap/google-play/purchase-manager.spec.ts | Replaces sinon fakes/stubs with Jest fn/spy patterns. |
| packages/fxa-auth-server/lib/payments/iap/google-play/play-billing.spec.ts | Migrates Firestore collection stubbing to Jest. |
| packages/fxa-auth-server/lib/payments/iap/apple-app-store/subscriptions.spec.ts | Converts App Store subscriptions tests to Jest mocks. |
| packages/fxa-auth-server/lib/payments/iap/apple-app-store/apple-iap.spec.ts | Replaces sinon stub usage with Jest mocks for Firestore collection. |
| packages/fxa-auth-server/lib/payments/iap/apple-app-store/app-store-helper.spec.ts | Migrates API/client stubs from sinon sandbox to Jest. |
| packages/fxa-auth-server/lib/oauth/jwt_access_token.spec.ts | Updates JWT signing spy assertions to Jest. |
| packages/fxa-auth-server/lib/oauth/grant.spec.ts | Converts DB/JWT/capability service stubs to Jest mocks. |
| packages/fxa-auth-server/lib/notifier.spec.ts | Replaces sinon spies with Jest mocks for SNS publish/logging. |
| packages/fxa-auth-server/lib/metrics/events.spec.ts | Updates glean + metricsContext mock usage to Jest conventions. |
| packages/fxa-auth-server/lib/metrics/amplitude.spec.ts | Migrates log assertions to Jest mock APIs. |
| packages/fxa-auth-server/lib/google-maps-services.spec.ts | Converts geocode + Sentry stubbing from sinon to Jest. |
| packages/fxa-auth-server/lib/geodb.spec.ts | Switches mock logger methods from sinon stubs to Jest fns. |
| packages/fxa-auth-server/lib/features.spec.ts | Migrates crypto hashing spies to Jest and updates assertions. |
| packages/fxa-auth-server/lib/email/utils/helpers.spec.ts | Moves amplitude/log assertions and AccountEventsManager stubs to Jest. |
| packages/fxa-auth-server/lib/email/notifications.spec.ts | Converts queue/db/log spies and Date.now stubbing to Jest. |
| packages/fxa-auth-server/lib/email/delivery.spec.ts | Migrates email delivery handler tests to Jest mocks/assertions. |
| packages/fxa-auth-server/lib/email/delivery-delay.spec.ts | Migrates delivery delay handler tests to Jest mocks/assertions. |
| packages/fxa-auth-server/lib/email-cloud-tasks.spec.ts | Replaces sinon sandbox stubs for cloud tasks scheduling with Jest fn mocks. |
| packages/fxa-auth-server/lib/devices.spec.ts | Converts DB/log/push/pushbox assertions from sinon to Jest .mock.calls. |
| packages/fxa-auth-server/lib/db.spec.ts | Migrates redis/model stubs and call assertions to Jest. |
| packages/fxa-auth-server/lib/customs.spec.ts | Replaces sinon sandbox stubs with Jest spies; updates matching assertions. |
| packages/fxa-auth-server/lib/cad-reminders.in.spec.ts | Updates log error assertions from sinon to Jest. |
| packages/fxa-auth-server/lib/authMethods.spec.ts | Converts DB totpToken stubs and assertions to Jest. |
| packages/fxa-auth-server/lib/account-events.spec.ts | Migrates Firestore + statsd stubs and assertions to Jest. |
| packages/fxa-auth-server/lib/account-delete.spec.ts | Converts account deletion tests from sinon sandbox to Jest mocks. |
| packages/fxa-auth-server/jest.setup-resolve.js | Updates resolver patch documentation to focus on Jest/TS module resolution. |
| packages/fxa-auth-server/jest.config.js | Switches Jest setup file from jest.setup-proxyquire.js to jest.setup-resolve.js. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| beforeAll(() => { | ||
| sinon.stub(authMethods, 'availableAuthenticationMethods'); | ||
| jest.spyOn(authMethods, 'availableAuthenticationMethods'); |
There was a problem hiding this comment.
Overwriting authMethods.availableAuthenticationMethods after calling jest.spyOn(...) breaks the spy (the spy is attached to the original function, but the export is then replaced). This can cause jest.restoreAllMocks() to not restore the module function correctly and can make assertions on the spy unreliable. Prefer keeping the spy and setting its implementation via mockResolvedValue(...) on the spy instance (or use jest.spyOn(...).mockResolvedValue(...) in beforeEach) instead of reassigning the exported function.
| jest.clearAllMocks(); | ||
|
|
||
| authMethods.availableAuthenticationMethods = sinon.fake.resolves( | ||
| new Set(['pwd', 'email']) | ||
| ); | ||
| authMethods.availableAuthenticationMethods = jest | ||
| .fn() | ||
| .mockResolvedValue(new Set(['pwd', 'email'])); |
There was a problem hiding this comment.
Overwriting authMethods.availableAuthenticationMethods after calling jest.spyOn(...) breaks the spy (the spy is attached to the original function, but the export is then replaced). This can cause jest.restoreAllMocks() to not restore the module function correctly and can make assertions on the spy unreliable. Prefer keeping the spy and setting its implementation via mockResolvedValue(...) on the spy instance (or use jest.spyOn(...).mockResolvedValue(...) in beforeEach) instead of reassigning the exported function.
| const mockEmailTasks = { | ||
| scheduleFirstEmail: sandbox.stub(), | ||
| scheduleSecondEmail: sandbox.stub(), | ||
| scheduleFinalEmail: sandbox.stub(), | ||
| scheduleFirstEmail: jest.fn(), | ||
| scheduleSecondEmail: jest.fn(), | ||
| scheduleFinalEmail: jest.fn(), | ||
| }; |
There was a problem hiding this comment.
mockEmailTasks.* are module-level jest.fn() mocks, but the suite no longer resets/clears them between tests. jest.restoreAllMocks() does not clear call history for standalone jest.fn() values, so call counts can leak across tests and make them order-dependent. Add an explicit reset (e.g., jest.clearAllMocks() in beforeEach/afterEach, or mockEmailTasks.scheduleFirstEmail.mockClear() etc.) to ensure isolation.
| jest.restoreAllMocks(); | ||
| Container.reset(); |
There was a problem hiding this comment.
mockEmailTasks.* are module-level jest.fn() mocks, but the suite no longer resets/clears them between tests. jest.restoreAllMocks() does not clear call history for standalone jest.fn() values, so call counts can leak across tests and make them order-dependent. Add an explicit reset (e.g., jest.clearAllMocks() in beforeEach/afterEach, or mockEmailTasks.scheduleFirstEmail.mockClear() etc.) to ensure isolation.
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
| const pushboxDbModule = require('./db'); |
There was a problem hiding this comment.
Disabling the lint rule for an intentionally unused require makes the test harder to maintain and can hide real unused-variable issues nearby. If this import is only needed for typing, consider converting it to a type-only import (or using import type) and removing the runtime require; if it isn’t needed at all with the new constructor injection approach, remove it entirely.
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | |
| const pushboxDbModule = require('./db'); |
| sinon.assert.calledOnceWithExactly( | ||
| mockProcessAccountDeletionInRange, | ||
| expect(mockProcessAccountDeletionInRange).toHaveBeenCalledTimes(1); | ||
| expect(mockProcessAccountDeletionInRange).toHaveBeenCalledWith( |
There was a problem hiding this comment.
The previous assertion (calledOnceWithExactly) verified both the arguments and that there were no extra parameters. toHaveBeenCalledWith does not enforce “exactly” in the same way if additional args are passed. If exactness matters here, also assert the call’s arity (e.g., check mock.calls[0].length) or use toHaveBeenNthCalledWith(1, ...) together with an explicit length check.
| expect(mockProcessAccountDeletionInRange).toHaveBeenCalledWith( | |
| expect(mockProcessAccountDeletionInRange.mock.calls[0]).toHaveLength(7); | |
| expect(mockProcessAccountDeletionInRange).toHaveBeenNthCalledWith( | |
| 1, |
Because
This pull request
Issue that this pull request solves
Closes: (issue number)
Checklist
Put an
xin the boxes that applyHow to review (Optional)
Screenshots (Optional)
Please attach the screenshots of the changes made in case of change in user interface.
Other information (Optional)
Any other information that is important to this pull request.