5b0aa24a8d
Extend DeviceRecord with revokedAt field, update registerDevice and listOwnDevices selects to include revoked_at, add revokeDevice RPC helper, update db-types to reflect T1 migration schema, and add vitest coverage for all new behaviour. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
53 lines
2.2 KiB
TypeScript
53 lines
2.2 KiB
TypeScript
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/);
|
|
});
|
|
});
|