feat(mobile): userIdentity orchestrator (setup/unlock/cache/change-PIN/reset)
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import { crypto } from '@chat-app/shared';
|
||||
import { makeWasmTestBackend } from '@chat-app/shared/crypto/testBackend';
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
// We mock react-native modules so this Vitest file can run in Node without
|
||||
// loading native code. The mocks live next to the test for clarity.
|
||||
vi.mock('expo-secure-store', () => {
|
||||
const store = new Map<string, string>();
|
||||
return {
|
||||
getItemAsync: vi.fn(async (k: string) => store.get(k) ?? null),
|
||||
setItemAsync: vi.fn(async (k: string, v: string) => {
|
||||
store.set(k, v);
|
||||
}),
|
||||
deleteItemAsync: vi.fn(async (k: string) => {
|
||||
store.delete(k);
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
const rpcImpl = vi.fn();
|
||||
vi.mock('./supabase', () => ({
|
||||
supabase: {
|
||||
rpc: (name: string, params: unknown) => rpcImpl(name, params),
|
||||
from: () => ({
|
||||
select: () => ({ in: () => Promise.resolve({ data: [], error: null }) }),
|
||||
}),
|
||||
},
|
||||
}));
|
||||
|
||||
beforeAll(async () => {
|
||||
crypto.setCryptoBackend(await makeWasmTestBackend());
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
rpcImpl.mockReset();
|
||||
});
|
||||
|
||||
describe('mobile userIdentity', () => {
|
||||
it('setupNewUserIdentity uploads + caches', async () => {
|
||||
rpcImpl.mockResolvedValue({ data: 0, error: null });
|
||||
const { setupNewUserIdentity, cachedUserKey } = await import('./userIdentity');
|
||||
const out = await setupNewUserIdentity({
|
||||
userId: 'user-1',
|
||||
pin: '123456',
|
||||
withRecovery: true,
|
||||
});
|
||||
expect(out.publicKey.length).toBe(32);
|
||||
expect(out.recoveryCode).toMatch(/^[A-Z0-9-]+$/);
|
||||
const cached = await cachedUserKey('user-1');
|
||||
expect(cached).not.toBeNull();
|
||||
expect(cached!.length).toBe(32);
|
||||
expect(rpcImpl).toHaveBeenCalledWith('upsert_user_key', expect.any(Object));
|
||||
});
|
||||
|
||||
it('loadOrUnlockUserKey returns `missing` when blob does not exist', async () => {
|
||||
rpcImpl.mockResolvedValue({ data: { exists: false }, error: null });
|
||||
const { loadOrUnlockUserKey } = await import('./userIdentity');
|
||||
const out = await loadOrUnlockUserKey({ userId: 'user-2', pin: '000000' });
|
||||
expect(out.kind).toBe('missing');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user