Skip to content

Commit cff9a2c

Browse files
committed
frontend: fix tests
1 parent c84317b commit cff9a2c

File tree

4 files changed

+24
-78
lines changed

4 files changed

+24
-78
lines changed

frontend/src/__tests__/utils.test.ts

Lines changed: 21 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,16 @@ function withServiceWorker(controller: Partial<ServiceWorker> & { postMessage: (
3434
active: controller as ServiceWorker,
3535
}));
3636

37+
const ready = Promise.resolve({
38+
active: controller as ServiceWorker,
39+
} as ServiceWorkerRegistration);
40+
3741
Object.defineProperty(navigator, 'serviceWorker', {
3842
value: {
39-
controller,
4043
addEventListener,
4144
removeEventListener,
4245
getRegistration,
46+
ready,
4347
},
4448
configurable: true,
4549
});
@@ -97,33 +101,22 @@ describe('utils', () => {
97101

98102
describe('Service Worker secret key helpers', () => {
99103
it('stores secret in service worker if controller exists', async () => {
100-
const postMessage = vi.fn();
104+
const postMessage = vi.fn((msg) => {
105+
if (msg.type === MessageType.StoreSecret) {
106+
triggerSWMessage({ type: MessageType.StoreSecret, data: "stored" });
107+
}
108+
});
101109
withServiceWorker({ postMessage } as any);
102110
await utils.storeSecretKeyInServiceWorker('abc');
103111
expect(postMessage).toHaveBeenCalledWith({ type: MessageType.StoreSecret, data: 'abc' });
104112
});
105113

106-
it('does nothing when no service worker controller (store)', async () => {
107-
Object.defineProperty(navigator, 'serviceWorker', {
108-
value: {
109-
controller: null,
110-
getRegistration: vi.fn(async () => null),
111-
},
112-
configurable: true
113-
});
114-
await utils.storeSecretKeyInServiceWorker('abc');
115-
// no error thrown
116-
});
117-
118114
it('requests secret and resolves with response (getSecretKeyFromServiceWorker)', async () => {
119115
const postMessage = vi.fn((msg: any) => {
120116
// When the service worker receives a RequestSecret message,
121117
// simulate it responding with the secret
122118
if (msg.type === MessageType.RequestSecret) {
123-
// Use queueMicrotask to ensure the message handler is set up first
124-
queueMicrotask(() => {
125-
triggerSWMessage({ type: MessageType.StoreSecret, data: 'encoded' });
126-
});
119+
triggerSWMessage({ type: MessageType.RequestSecret, data: 'encoded' });
127120
}
128121
});
129122
withServiceWorker({ postMessage } as any);
@@ -136,20 +129,6 @@ describe('utils', () => {
136129
expect(key).toBe('encoded');
137130
});
138131

139-
it('returns null when no service worker controller available', async () => {
140-
// Setup no controller scenario - will retry 3 times with 500ms delays each = 1500ms total
141-
Object.defineProperty(navigator, 'serviceWorker', {
142-
value: {
143-
controller: null,
144-
getRegistration: vi.fn(async () => null),
145-
},
146-
configurable: true,
147-
});
148-
149-
const result = await utils.getSecretKeyFromServiceWorker();
150-
expect(result).toBeNull();
151-
}, 10000); // Generous timeout to allow for multiple retries
152-
153132
it('clears secret key via service worker', async () => {
154133
const postMessage = vi.fn();
155134
withServiceWorker({ postMessage } as any);
@@ -161,10 +140,7 @@ describe('utils', () => {
161140
// Create a mock service worker that immediately responds
162141
const postMessage = vi.fn((msg: any) => {
163142
if (msg.type === MessageType.RequestSecret) {
164-
// Immediately trigger the response
165-
setTimeout(() => {
166-
triggerSWMessage({ type: MessageType.StoreSecret, data: 'immediate-response' });
167-
}, 0);
143+
triggerSWMessage({ type: MessageType.RequestSecret, data: 'immediate-response' });
168144
}
169145
});
170146

@@ -183,14 +159,8 @@ describe('utils', () => {
183159
it('nulls secret and pub_key and calls clearSecretKeyFromServiceWorker', () => {
184160
// Provide a mock service worker controller to observe the clear message
185161
const postMessage = vi.fn();
186-
Object.defineProperty(navigator, 'serviceWorker', {
187-
value: {
188-
controller: { postMessage },
189-
getRegistration: vi.fn(async () => ({ active: { postMessage } })),
190-
},
191-
configurable: true,
192-
});
193162

163+
withServiceWorker({ postMessage });
194164
// Ensure calling resetSecret sets them to null state and triggers postMessage with ClearSecret
195165
utils.resetSecret();
196166
expect((utils as any).secret).toBeNull();
@@ -227,7 +197,7 @@ describe('utils', () => {
227197
// Mock service worker so getSecretKeyFromServiceWorker resolves with value
228198
const postMessage = vi.fn((msg: any) => {
229199
if (msg.type === MessageType.RequestSecret) {
230-
triggerSWMessage({ type: MessageType.StoreSecret, data: 'SGVjcmV0' });
200+
triggerSWMessage({ type: MessageType.RequestSecret, data: 'SGVjcmV0' });
231201
}
232202
});
233203
withServiceWorker({ postMessage } as any);
@@ -266,7 +236,7 @@ describe('utils', () => {
266236
(window.localStorage.getItem as any).mockImplementation((key: string) => key === 'loginSalt' ? 'salty' : null);
267237
const postMessage = vi.fn((msg: any) => {
268238
if (msg.type === MessageType.RequestSecret) {
269-
triggerSWMessage({ type: MessageType.StoreSecret, data: 'ANY' });
239+
triggerSWMessage({ type: MessageType.RequestSecret, data: 'ANY' });
270240
}
271241
});
272242
withServiceWorker({ postMessage } as any);
@@ -297,14 +267,13 @@ describe('utils', () => {
297267

298268
it('catch block resets secret if tokens missing', async () => {
299269
(window.localStorage.getItem as any).mockImplementation(() => null);
300-
// Ensure no service worker controller - will retry 3 times with 500ms delays each
301-
Object.defineProperty(navigator, 'serviceWorker', {
302-
value: {
303-
controller: null,
304-
getRegistration: vi.fn(async () => null),
305-
},
306-
configurable: true
270+
const postMessage = vi.fn((event) => {
271+
if (event.type === MessageType.RequestSecret) {
272+
triggerSWMessage({ type: MessageType.RequestSecret, data: null });// No secret
273+
}
307274
});
275+
withServiceWorker({ postMessage });
276+
308277
// Start from LoggedOut so we can ensure it does not become LoggedIn
309278
utils.loggedIn.value = utils.AppState.LoggedOut;
310279
(utils.fetchClient as any).GET = vi.fn(async (path: string) => {

frontend/src/index.test.tsx

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -95,30 +95,6 @@ describe('index.tsx', () => {
9595
nativeSpy.mockRestore();
9696
});
9797

98-
it('migrates secret key to service worker and shows loading state', async () => {
99-
(utils.loggedIn as { value: number }).value = utils.AppState.Loading;
100-
localStorage.setItem('secretKey', 'abc');
101-
// Ensure a controller exists for postMessage path
102-
// @ts-expect-error extend navigator
103-
navigator.serviceWorker = { controller: { postMessage: vi.fn() } };
104-
// Ensure ServiceWorker is present to avoid early return branch
105-
// @ts-expect-error define presence flag
106-
window.ServiceWorker = {};
107-
// Avoid network calls from version checker
108-
vi.spyOn(globalThis, 'fetch').mockResolvedValue(new Response('{}', { status: 200 }));
109-
110-
vi.resetModules();
111-
vi.doMock('preact', async (importOriginal) => {
112-
const actual = await importOriginal<typeof import('preact')>();
113-
return { ...actual, render: vi.fn() };
114-
});
115-
const { App } = await import('./index');
116-
render(<App />);
117-
118-
expect(window.localStorage.getItem('secretKey')).toBeNull();
119-
expect(screen.getByText('Loading...')).toBeInTheDocument();
120-
});
121-
12298
it('renders Recovery state without Footer when running in native app', async () => {
12399
(utils.loggedIn as { value: number }).value = utils.AppState.Recovery;
124100
// Ensure ServiceWorker is present to avoid early return

frontend/src/sw.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ self.addEventListener("message", async (e: ExtendableMessageEvent) => {
226226
const secretKey = await getSecretKeyFromCache();
227227
if (secretKey) {
228228
const responseMsg: Message = {
229-
type: MessageType.StoreSecret,
229+
type: MessageType.RequestSecret,
230230
data: secretKey
231231
};
232232
e.source?.postMessage(responseMsg);

frontend/src/utils.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ export async function refresh_access_token() {
117117
}
118118
} catch (e) {
119119
//This means we are logged in but the refresh failed
120+
console.log("Failed to refresh access token:", e);
120121
const hasLoginSalt = localStorage.getItem("loginSalt");
121122
const hasSecret = await getSecretKeyFromServiceWorker();
122123
if (hasLoginSalt && hasSecret) {
@@ -198,7 +199,7 @@ export async function getSecretKeyFromServiceWorker(): Promise<string> {
198199

199200
const handleMessage = (event: MessageEvent) => {
200201
const msg = event.data as Message;
201-
if (msg.type === MessageType.StoreSecret) {
202+
if (msg.type === MessageType.RequestSecret) {
202203
clearTimeout(timeout);
203204
navigator.serviceWorker.removeEventListener('message', handleMessage);
204205
secretKeyPromise = null;

0 commit comments

Comments
 (0)