Skip to content

Commit 4ba775f

Browse files
committed
PR feedback
1 parent 70c0af3 commit 4ba775f

2 files changed

Lines changed: 131 additions & 111 deletions

File tree

packages/expo/src/trusted-devices/__tests__/useTrustedDevices.test.ts

Lines changed: 58 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { renderHook } from '@testing-library/react';
12
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
23

34
import {
@@ -20,7 +21,7 @@ const mocks = vi.hoisted(() => ({
2021
resetPassword: vi.fn(),
2122
},
2223
jsSignedInSessions: [{ id: 'sess_123' }],
23-
getClerkInstance: vi.fn(),
24+
useClerk: vi.fn(),
2425
setActive: vi.fn(),
2526
synchronizeNativeClientToJs: vi.fn(),
2627
nativeModule: {
@@ -32,8 +33,8 @@ const mocks = vi.hoisted(() => ({
3233
},
3334
}));
3435

35-
vi.mock('../../provider/singleton', () => ({
36-
getClerkInstance: mocks.getClerkInstance,
36+
vi.mock('@clerk/react', () => ({
37+
useClerk: mocks.useClerk,
3738
}));
3839

3940
vi.mock('../../utils/native-module', () => ({
@@ -60,13 +61,17 @@ const nativeTrustedDevice = {
6061
revokedAt: null,
6162
};
6263

64+
function renderTrustedDevices(useHook = useTrustedDevicesOnIos) {
65+
return renderHook(() => useHook()).result.current;
66+
}
67+
6368
let unregisterNativeToJsSyncHandler: (() => void) | undefined;
6469

6570
beforeEach(() => {
6671
__internal_resetNativeClientSyncCoordinator();
6772
unregisterNativeToJsSyncHandler = registerNativeToJsSyncHandler(mocks.synchronizeNativeClientToJs);
6873
mocks.synchronizeNativeClientToJs.mockResolvedValue(undefined);
69-
mocks.getClerkInstance.mockReturnValue({
74+
mocks.useClerk.mockReturnValue({
7075
client: { signIn: mocks.jsSignIn, signedInSessions: mocks.jsSignedInSessions },
7176
setActive: mocks.setActive,
7277
});
@@ -94,7 +99,7 @@ describe('useTrustedDevices on iOS', () => {
9499
unavailableReason: null,
95100
});
96101

97-
const trustedDevices = useTrustedDevicesOnIos();
102+
const trustedDevices = renderTrustedDevices();
98103
const availability = await trustedDevices.getAvailability({
99104
id: 'td_123',
100105
identifierHint: 'sean@example.com',
@@ -115,7 +120,7 @@ describe('useTrustedDevices on iOS', () => {
115120
unavailableReason: null,
116121
});
117122

118-
const availability = useTrustedDevicesOnIos().getAvailability();
123+
const availability = renderTrustedDevices().getAvailability();
119124
await Promise.resolve();
120125

121126
expect(mocks.nativeModule.getTrustedDeviceAvailability).not.toHaveBeenCalled();
@@ -133,7 +138,7 @@ describe('useTrustedDevices on iOS', () => {
133138
});
134139
trackPendingJsToNativeSync(nativeSync);
135140

136-
const availability = expect(useTrustedDevicesOnIos().getAvailability()).rejects.toMatchObject({
141+
const availability = expect(renderTrustedDevices().getAvailability()).rejects.toMatchObject({
137142
code: 'environment_unavailable',
138143
});
139144

@@ -146,7 +151,7 @@ describe('useTrustedDevices on iOS', () => {
146151
test('lists trusted devices and converts native timestamps to dates', async () => {
147152
mocks.nativeModule.listTrustedDevices.mockResolvedValue([nativeTrustedDevice]);
148153

149-
const [trustedDevice] = await useTrustedDevicesOnIos().list();
154+
const [trustedDevice] = await renderTrustedDevices().list();
150155

151156
expect(trustedDevice).toEqual({
152157
...nativeTrustedDevice,
@@ -166,7 +171,7 @@ describe('useTrustedDevices on iOS', () => {
166171
},
167172
]);
168173

169-
const [trustedDevice] = await useTrustedDevicesOnIos().list();
174+
const [trustedDevice] = await renderTrustedDevices().list();
170175

171176
expect(trustedDevice.lastUsedAt).toBeNull();
172177
expect(trustedDevice.revokedAt).toBeNull();
@@ -180,7 +185,7 @@ describe('useTrustedDevices on iOS', () => {
180185
trackPendingJsToNativeSync(nativeSync);
181186
mocks.nativeModule.listTrustedDevices.mockResolvedValue([nativeTrustedDevice]);
182187

183-
const listing = useTrustedDevicesOnIos().list();
188+
const listing = renderTrustedDevices().list();
184189
await Promise.resolve();
185190

186191
expect(mocks.nativeModule.listTrustedDevices).not.toHaveBeenCalled();
@@ -191,13 +196,18 @@ describe('useTrustedDevices on iOS', () => {
191196
});
192197

193198
test('returns stable operation identities', () => {
194-
expect(useTrustedDevicesOnIos()).toBe(useTrustedDevicesOnIos());
199+
const { result, rerender } = renderHook(() => useTrustedDevicesOnIos());
200+
const initialTrustedDevices = result.current;
201+
202+
rerender();
203+
204+
expect(result.current).toBe(initialTrustedDevices);
195205
});
196206

197207
test('enrolls with the safe default authentication policy', async () => {
198208
mocks.nativeModule.enrollTrustedDevice.mockResolvedValue(nativeTrustedDevice);
199209

200-
const trustedDevice = await useTrustedDevicesOnIos().enroll({
210+
const trustedDevice = await renderTrustedDevices().enroll({
201211
deviceName: "Sean's iPhone",
202212
identifierHint: 'sean@example.com',
203213
reason: 'Use Face ID to trust this device.',
@@ -220,7 +230,7 @@ describe('useTrustedDevices on iOS', () => {
220230
trackPendingJsToNativeSync(nativeSync);
221231
mocks.nativeModule.enrollTrustedDevice.mockResolvedValue(nativeTrustedDevice);
222232

223-
const enrollment = useTrustedDevicesOnIos().enroll();
233+
const enrollment = renderTrustedDevices().enroll();
224234
await Promise.resolve();
225235

226236
expect(mocks.nativeModule.enrollTrustedDevice).not.toHaveBeenCalled();
@@ -237,7 +247,7 @@ describe('useTrustedDevices on iOS', () => {
237247
revokedAt: 1_700_000_300_000,
238248
});
239249

240-
const trustedDevice = await useTrustedDevicesOnIos().revoke('td_123');
250+
const trustedDevice = await renderTrustedDevices().revoke('td_123');
241251

242252
expect(mocks.nativeModule.revokeTrustedDevice).toHaveBeenCalledWith('td_123');
243253
expect(trustedDevice.status).toBe('revoked');
@@ -255,7 +265,7 @@ describe('useTrustedDevices on iOS', () => {
255265
status: 'revoked',
256266
});
257267

258-
const revocation = useTrustedDevicesOnIos().revoke('td_123');
268+
const revocation = renderTrustedDevices().revoke('td_123');
259269
await Promise.resolve();
260270

261271
expect(mocks.nativeModule.revokeTrustedDevice).not.toHaveBeenCalled();
@@ -272,7 +282,7 @@ describe('useTrustedDevices on iOS', () => {
272282
createdSessionId: 'sess_123',
273283
});
274284

275-
const result = await useTrustedDevicesOnIos().signIn({
285+
const result = await renderTrustedDevices().signIn({
276286
identifierHint: 'sean@example.com',
277287
reason: 'Use Face ID to sign in.',
278288
});
@@ -302,7 +312,7 @@ describe('useTrustedDevices on iOS', () => {
302312
createdSessionId: 'sess_other',
303313
});
304314

305-
const result = await useTrustedDevicesOnIos().signIn();
315+
const result = await renderTrustedDevices().signIn();
306316

307317
expect(result).toMatchObject({
308318
status: 'complete',
@@ -323,7 +333,7 @@ describe('useTrustedDevices on iOS', () => {
323333
createdSessionId: null,
324334
});
325335

326-
const result = await useTrustedDevicesOnIos().signIn();
336+
const result = await renderTrustedDevices().signIn();
327337

328338
expect(result).toMatchObject({
329339
status: 'complete',
@@ -339,7 +349,7 @@ describe('useTrustedDevices on iOS', () => {
339349
createdSessionId: 'sess_missing',
340350
});
341351

342-
await expect(useTrustedDevicesOnIos().signIn()).rejects.toThrow(
352+
await expect(renderTrustedDevices().signIn()).rejects.toThrow(
343353
'Unable to synchronize the trusted-device sign-in with the Clerk JS client: the created session is missing.',
344354
);
345355
});
@@ -356,7 +366,7 @@ describe('useTrustedDevices on iOS', () => {
356366
createdSessionId: 'sess_123',
357367
});
358368

359-
const signIn = useTrustedDevicesOnIos().signIn();
369+
const signIn = renderTrustedDevices().signIn();
360370
await Promise.resolve();
361371

362372
expect(mocks.nativeModule.signInWithTrustedDevice).not.toHaveBeenCalled();
@@ -385,7 +395,7 @@ describe('useTrustedDevices on iOS', () => {
385395
return Promise.resolve();
386396
});
387397

388-
const result = await useTrustedDevicesOnIos().signIn();
398+
const result = await renderTrustedDevices().signIn();
389399

390400
expect(result).toMatchObject({
391401
status,
@@ -409,7 +419,7 @@ describe('useTrustedDevices on iOS', () => {
409419
);
410420

411421
let didResolve = false;
412-
const signIn = useTrustedDevicesOnIos()
422+
const signIn = renderTrustedDevices()
413423
.signIn()
414424
.then(result => {
415425
didResolve = true;
@@ -434,22 +444,34 @@ describe('useTrustedDevices on iOS', () => {
434444
createdSessionId: null,
435445
});
436446

437-
await expect(useTrustedDevicesOnIos().signIn()).rejects.toThrow(
447+
await expect(renderTrustedDevices().signIn()).rejects.toThrow(
438448
'Unable to synchronize the trusted-device sign-in with the Clerk JS client: the sign-in attempt does not match.',
439449
);
440450
});
441451

442-
test('rejects when the Clerk JS instance is unavailable after synchronization', async () => {
452+
test('uses the Clerk instance from the React provider after synchronization', async () => {
453+
const providerSetActive = vi.fn();
454+
const providerSignIn = {
455+
...mocks.jsSignIn,
456+
id: 'sia_provider',
457+
};
443458
mocks.nativeModule.signInWithTrustedDevice.mockResolvedValue({
444-
id: 'sia_native',
459+
id: 'sia_provider',
445460
status: 'complete',
446-
createdSessionId: 'sess_native',
461+
createdSessionId: 'sess_provider',
462+
});
463+
mocks.useClerk.mockReturnValue({
464+
client: {
465+
signIn: providerSignIn,
466+
signedInSessions: [{ id: 'sess_provider' }],
467+
},
468+
setActive: providerSetActive,
447469
});
448-
mocks.getClerkInstance.mockReturnValueOnce(undefined);
449470

450-
await expect(useTrustedDevicesOnIos().signIn()).rejects.toThrow(
451-
'Unable to synchronize the trusted-device sign-in with the Clerk JS client: the Clerk instance is unavailable.',
452-
);
471+
const result = await renderTrustedDevices().signIn();
472+
473+
expect(result.signIn).toBe(providerSignIn);
474+
expect(result.setActive).toBe(providerSetActive);
453475
});
454476

455477
test('rejects when the Clerk JS client is unavailable after synchronization', async () => {
@@ -458,12 +480,12 @@ describe('useTrustedDevices on iOS', () => {
458480
status: 'complete',
459481
createdSessionId: 'sess_native',
460482
});
461-
mocks.getClerkInstance.mockReturnValueOnce({
483+
mocks.useClerk.mockReturnValue({
462484
client: undefined,
463485
setActive: mocks.setActive,
464486
});
465487

466-
await expect(useTrustedDevicesOnIos().signIn()).rejects.toThrow(
488+
await expect(renderTrustedDevices().signIn()).rejects.toThrow(
467489
'Unable to synchronize the trusted-device sign-in with the Clerk JS client: the client sign-in resource is unavailable.',
468490
);
469491
});
@@ -488,7 +510,7 @@ describe('useTrustedDevices on iOS', () => {
488510
createdSessionId: null,
489511
});
490512

491-
const trustedDevices = useTrustedDevicesOnIos();
513+
const trustedDevices = renderTrustedDevices();
492514
const [device] = await trustedDevices.list();
493515
const signIn = await trustedDevices.signIn();
494516

@@ -506,7 +528,7 @@ describe('useTrustedDevices on iOS', () => {
506528
});
507529
mocks.nativeModule.signInWithTrustedDevice.mockRejectedValue(nativeError);
508530

509-
const operation = useTrustedDevicesOnIos().signIn();
531+
const operation = renderTrustedDevices().signIn();
510532

511533
await expect(operation).rejects.toBe(nativeError);
512534
await operation.catch(error => {
@@ -522,7 +544,7 @@ describe('useTrustedDevices on iOS', () => {
522544
Object.assign(mocks.nativeModule, { signInWithTrustedDevice: undefined });
523545

524546
try {
525-
await expect(useTrustedDevicesOnIos().signIn()).rejects.toThrow(
547+
await expect(renderTrustedDevices().signIn()).rejects.toThrow(
526548
'Biometric trusted devices require a development build containing a compatible version of @clerk/expo.',
527549
);
528550
} finally {
@@ -553,7 +575,7 @@ describe('useTrustedDevices on Android', () => {
553575
});
554576
mocks.jsSignedInSessions.splice(0, mocks.jsSignedInSessions.length, { id: 'sess_android' });
555577

556-
const trustedDevices = useTrustedDevicesOnAndroid();
578+
const trustedDevices = renderTrustedDevices(useTrustedDevicesOnAndroid);
557579

558580
await expect(trustedDevices.getAvailability({ identifierHint: 'sean@example.com' })).resolves.toEqual({
559581
isAvailable: true,

0 commit comments

Comments
 (0)