mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-21 06:26:26 +00:00
test(client): keep the sign-in background work out of the auth specs
login, completeMfaLogin and register start tripSyncManager.syncAll() and the system notice fetch without waiting for them, and every sign-in, loadUser included, registers the sync triggers with their 30 s heartbeat. #2613 stubbed the sync in the push spec after it was caught logging while the worker shut down ("Closing rpc while onUserConsoleLog was pending"); the same shape was left in the other specs that sign in for real. authStore.test.ts ran the real sync on every successful sign-in and logged DatabaseClosedError from it, and its notice fetch went past MSW to the network and logged a failed fetch, both after the tests that started them. The sync is now stubbed there, and the login, MFA and register tests assert that it was started. The notice store is reset before each test, since FE-STORE-AUTH-024 left a stubbed fetch behind. LoginPage.test.tsx signs in through the form, and AccountTab.test.tsx and MSettingsAccount.test.tsx reload the user after an MFA change; they now stub the sync triggers (and the login spec the trip sync), which none of them is about. GET /api/system-notices/active gets a default MSW handler returning no notices, so a login or a mounted notice host anywhere in the suite settles that fetch in the test instead of on the network. The notice store's own tests still override it.
This commit is contained in:
@@ -10,6 +10,12 @@ import { buildUser, buildSettings } from '../../../tests/helpers/factories';
|
||||
import AccountTab from './AccountTab';
|
||||
import { ToastContainer } from '../shared/Toast';
|
||||
|
||||
// Enabling or disabling MFA reloads the user, and loadUser registers the
|
||||
// background sync triggers: a 30 s heartbeat and window listeners that nothing
|
||||
// here unregisters, so they outlive the test and can fire, and log, while the
|
||||
// file's worker shuts down. Nothing here is about sync.
|
||||
vi.mock('../../sync/syncTriggers', () => ({ registerSyncTriggers: vi.fn(), unregisterSyncTriggers: vi.fn() }));
|
||||
|
||||
beforeEach(() => {
|
||||
resetAllStores();
|
||||
server.use(
|
||||
|
||||
@@ -13,6 +13,18 @@ import LoginPage from './LoginPage';
|
||||
// made FE-PAGE-LOGIN-014 fail intermittently in CI while passing in isolation.
|
||||
vi.mock('./login/LoginWorld', () => ({ default: () => null }));
|
||||
|
||||
// A successful sign-in registers the background sync triggers (a 30 s heartbeat
|
||||
// and window listeners that nothing here unregisters) and starts a full trip
|
||||
// sync it does not wait for. Left real, both outlive the test that started them
|
||||
// and can still be logging when the file's worker shuts down, which vitest
|
||||
// reports as an unhandled error although every test passed. Nothing here is
|
||||
// about sync.
|
||||
vi.mock('../sync/syncTriggers', () => ({ registerSyncTriggers: vi.fn(), unregisterSyncTriggers: vi.fn() }));
|
||||
vi.mock('../sync/tripSyncManager', async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import('../sync/tripSyncManager')>()),
|
||||
tripSyncManager: { syncAll: vi.fn(async () => {}) },
|
||||
}));
|
||||
|
||||
// LoginPage uses inline styles for labels (no htmlFor/id pairing).
|
||||
// We find inputs by placeholder text.
|
||||
const EMAIL_PLACEHOLDER = 'your@email.com';
|
||||
|
||||
@@ -91,4 +91,9 @@ export const notificationHandlers = [
|
||||
},
|
||||
});
|
||||
}),
|
||||
|
||||
// A login and the notice host both start this fetch without waiting for it.
|
||||
// Unhandled, MSW let it through to the network, where it could fail after the
|
||||
// test had ended and log a warning into a worker that was shutting down.
|
||||
http.get('/api/system-notices/active', () => HttpResponse.json([])),
|
||||
];
|
||||
|
||||
@@ -22,6 +22,12 @@ vi.mock('react-router', async (importOriginal) => {
|
||||
|
||||
vi.mock('@simplewebauthn/browser', () => ({ startRegistration: vi.fn() }));
|
||||
|
||||
// Enabling or disabling MFA reloads the user, and loadUser registers the
|
||||
// background sync triggers: a 30 s heartbeat and window listeners that nothing
|
||||
// here unregisters, so they outlive the test and can fire, and log, while the
|
||||
// file's worker shuts down. Nothing here is about sync.
|
||||
vi.mock('../../../../src/sync/syncTriggers', () => ({ registerSyncTriggers: vi.fn(), unregisterSyncTriggers: vi.fn() }));
|
||||
|
||||
const webauthn = startRegistration as unknown as ReturnType<typeof vi.fn>;
|
||||
|
||||
const BACKUP_KEY = 'trek_mfa_backup_codes_pending';
|
||||
|
||||
@@ -20,6 +20,18 @@ const syncTriggers = vi.hoisted(() => ({
|
||||
}));
|
||||
vi.mock('../../../src/sync/syncTriggers', () => syncTriggers);
|
||||
|
||||
// login, completeMfaLogin and register start a full trip sync they do not wait
|
||||
// for. Left real, it outlives the test that started it and can still be logging
|
||||
// when the file's worker shuts down, which vitest reports as an unhandled error
|
||||
// although every test passed (the authStore.push spec had the same flake). The
|
||||
// stub keeps the sync out and lets the tests assert that it was started.
|
||||
const tripSync = vi.hoisted(() => ({ syncAll: vi.fn(async () => {}) }));
|
||||
vi.mock('../../../src/sync/tripSyncManager', () => ({ tripSyncManager: tripSync }));
|
||||
|
||||
// The notice store is not part of resetAllStores, and FE-STORE-AUTH-024 swaps
|
||||
// its fetch for a stub; each test starts from the real, unloaded store again.
|
||||
const initialNoticeState = useSystemNoticeStore.getState();
|
||||
|
||||
// The user-scoped offline DB is real (fake-indexeddb); only the reopen step is
|
||||
// made failable so the "auth still succeeds when the DB won't open" path runs.
|
||||
const dbControl = vi.hoisted(() => ({ reopenFails: false, reopenedFor: null as number | string | null }));
|
||||
@@ -37,6 +49,7 @@ vi.mock('../../../src/db/offlineDb', async (importOriginal) => {
|
||||
|
||||
beforeEach(() => {
|
||||
resetAllStores();
|
||||
useSystemNoticeStore.setState(initialNoticeState, true);
|
||||
vi.clearAllMocks();
|
||||
dbControl.reopenFails = false;
|
||||
dbControl.reopenedFor = null;
|
||||
@@ -63,6 +76,7 @@ describe('authStore', () => {
|
||||
expect(state.isAuthenticated).toBe(true);
|
||||
expect(state.isLoading).toBe(false);
|
||||
expect(state.error).toBeNull();
|
||||
expect(tripSync.syncAll).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -194,6 +208,7 @@ describe('authStore', () => {
|
||||
expect(state.user).toEqual(user);
|
||||
expect(state.isAuthenticated).toBe(true);
|
||||
expect(state.isLoading).toBe(false);
|
||||
expect(tripSync.syncAll).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -273,6 +288,7 @@ describe('authStore', () => {
|
||||
expect(state.isAuthenticated).toBe(true);
|
||||
expect(state.isLoading).toBe(false);
|
||||
expect(connect).toHaveBeenCalledOnce();
|
||||
expect(tripSync.syncAll).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user