Tests predated the 2026-05-24 management-surfaces revamp (047df6e): popup
devices pane now shows SHA-256 fingerprint + added-by + inline two-step
revoke confirm, and the SW revokeDevice signature may have shifted to
match. Mocks + assertions updated accordingly.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
72 lines
2.9 KiB
TypeScript
72 lines
2.9 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { readDevices, addDevice, revokeDevice } from '../devices';
|
|
import type { GitHost } from '../git-host';
|
|
|
|
function makeGitHost(devicesJson = '{"devices":[]}'): GitHost {
|
|
// Per-path storage — revokeDevice writes devices.json AND revoked.json,
|
|
// so a single slot would corrupt the second read.
|
|
const files = new Map<string, string>();
|
|
files.set('.relicario/devices.json', devicesJson);
|
|
return {
|
|
readFile: vi.fn().mockImplementation(async (path: string) => {
|
|
const content = files.get(path);
|
|
if (content === undefined) throw new Error(`404: ${path}`);
|
|
return new TextEncoder().encode(content);
|
|
}),
|
|
writeFile: vi.fn().mockImplementation(async (path: string, bytes: Uint8Array) => {
|
|
files.set(path, new TextDecoder().decode(bytes));
|
|
}),
|
|
deleteFile: vi.fn(),
|
|
listDir: vi.fn(),
|
|
putBlob: vi.fn(),
|
|
getBlob: vi.fn(),
|
|
deleteBlob: vi.fn(),
|
|
};
|
|
}
|
|
|
|
describe('devices', () => {
|
|
it('readDevices returns empty array when file missing', async () => {
|
|
const host = makeGitHost();
|
|
(host.readFile as ReturnType<typeof vi.fn>).mockRejectedValueOnce(new Error('404'));
|
|
const result = await readDevices(host);
|
|
expect(result).toEqual([]);
|
|
});
|
|
|
|
it('readDevices parses existing devices', async () => {
|
|
const host = makeGitHost('{"devices":[{"name":"CLI","public_key":"abc123","added_at":1000}]}');
|
|
const result = await readDevices(host);
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0].name).toBe('CLI');
|
|
});
|
|
|
|
it('addDevice appends to list', async () => {
|
|
const host = makeGitHost();
|
|
await addDevice(host, { name: 'Chrome', public_key: 'def456', added_at: 2000 });
|
|
expect(host.writeFile).toHaveBeenCalled();
|
|
const written = (host.writeFile as ReturnType<typeof vi.fn>).mock.calls[0][1];
|
|
const parsed = JSON.parse(new TextDecoder().decode(written));
|
|
expect(parsed.devices).toHaveLength(1);
|
|
expect(parsed.devices[0].name).toBe('Chrome');
|
|
});
|
|
|
|
it('addDevice rejects duplicate name', async () => {
|
|
const host = makeGitHost('{"devices":[{"name":"Chrome","public_key":"abc","added_at":1000}]}');
|
|
await expect(addDevice(host, { name: 'Chrome', public_key: 'xyz', added_at: 2000 }))
|
|
.rejects.toThrow(/already exists/);
|
|
});
|
|
|
|
it('revokeDevice removes by name', async () => {
|
|
const host = makeGitHost('{"devices":[{"name":"CLI","public_key":"a","added_at":1},{"name":"Chrome","public_key":"b","added_at":2}]}');
|
|
await revokeDevice(host, 'CLI');
|
|
const written = (host.writeFile as ReturnType<typeof vi.fn>).mock.calls[0][1];
|
|
const parsed = JSON.parse(new TextDecoder().decode(written));
|
|
expect(parsed.devices).toHaveLength(1);
|
|
expect(parsed.devices[0].name).toBe('Chrome');
|
|
});
|
|
|
|
it('revokeDevice throws if not found', async () => {
|
|
const host = makeGitHost();
|
|
await expect(revokeDevice(host, 'nonexistent')).rejects.toThrow(/not found/);
|
|
});
|
|
});
|