import { describe, expect, it, vi } from 'vitest'; import { listOwnDevices, revokeDevice } from './device'; function makeClient(overrides: { user?: { id: string } | null; selectData?: Array<{ id: string; name: string; platform: string; last_seen_at: string; revoked_at: string | null }>; rpcImpl?: (fn: string, params: unknown) => Promise<{ data: unknown; error: unknown }>; }): any { const builder: any = { select: vi.fn().mockReturnThis(), eq: vi.fn().mockReturnThis(), order: vi.fn().mockResolvedValue({ data: overrides.selectData ?? [], error: null }), }; return { auth: { getUser: vi.fn().mockResolvedValue({ data: { user: overrides.user ?? { id: 'u-1' } } }) }, from: vi.fn().mockReturnValue(builder), rpc: vi.fn().mockImplementation(overrides.rpcImpl ?? (async () => ({ data: null, error: null }))), }; } describe('listOwnDevices', () => { it('maps revoked_at into revokedAt', async () => { const client = makeClient({ selectData: [ { id: 'd-1', name: 'Laptop', platform: 'desktop', last_seen_at: '2026-05-16T00:00:00Z', revoked_at: null }, { id: 'd-2', name: 'Old phone', platform: 'mobile', last_seen_at: '2026-05-10T00:00:00Z', revoked_at: '2026-05-15T12:00:00Z' }, ], }); const out = await listOwnDevices(client); expect(out).toEqual([ { id: 'd-1', name: 'Laptop', platform: 'desktop', lastSeenAt: '2026-05-16T00:00:00Z', revokedAt: null }, { id: 'd-2', name: 'Old phone', platform: 'mobile', lastSeenAt: '2026-05-10T00:00:00Z', revokedAt: '2026-05-15T12:00:00Z' }, ]); }); }); describe('revokeDevice', () => { it('invokes the revoke_device RPC with the device id', async () => { const rpc = vi.fn().mockResolvedValue({ data: null, error: null }); const client = makeClient({ rpcImpl: rpc }); await revokeDevice(client, 'd-42'); expect(rpc).toHaveBeenCalledWith('revoke_device', { p_device_id: 'd-42' }); }); it('throws when the RPC returns an error', async () => { const client = makeClient({ rpcImpl: async () => ({ data: null, error: { message: 'not authorized', code: '42501' } as any }), }); await expect(revokeDevice(client, 'd-99')).rejects.toThrow(/not authorized/); }); });