test(ext): vault-tab Backup & Restore panel
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
// backup-panel.ts only imports { sendMessage } from '../../shared/state'.
|
||||
// We provide the full shared/state surface so TypeScript is satisfied.
|
||||
vi.mock('../../../shared/state', () => ({
|
||||
sendMessage: vi.fn(),
|
||||
openVaultTab: vi.fn(),
|
||||
registerHost: vi.fn(),
|
||||
getState: vi.fn(),
|
||||
setState: vi.fn(),
|
||||
navigate: vi.fn(),
|
||||
escapeHtml: (s: string) => s,
|
||||
popOutToTab: vi.fn(),
|
||||
isInTab: vi.fn(() => false),
|
||||
}));
|
||||
|
||||
import { sendMessage } from '../../../shared/state';
|
||||
import { renderBackupPanel, teardown } from '../backup-panel';
|
||||
|
||||
const mockSendMessage = sendMessage as ReturnType<typeof vi.fn>;
|
||||
|
||||
describe('backup panel — export', () => {
|
||||
let app: HTMLElement;
|
||||
|
||||
beforeEach(() => {
|
||||
mockSendMessage.mockReset();
|
||||
teardown();
|
||||
document.body.innerHTML = '<div id="app"></div>';
|
||||
app = document.getElementById('app')!;
|
||||
});
|
||||
|
||||
it('clicking export with no passphrase is a no-op', async () => {
|
||||
renderBackupPanel(app);
|
||||
vi.spyOn(window, 'prompt').mockReturnValue(null);
|
||||
|
||||
(app.querySelector('#export-btn') as HTMLButtonElement).click();
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
|
||||
expect(mockSendMessage).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('clicking export with a passphrase fires export_backup', async () => {
|
||||
renderBackupPanel(app);
|
||||
vi.spyOn(window, 'prompt').mockReturnValue('test-backup-pass');
|
||||
mockSendMessage.mockResolvedValue({ ok: true, data: { bytes: new ArrayBuffer(123) } });
|
||||
|
||||
(app.querySelector('#include-image') as HTMLInputElement).checked = true;
|
||||
(app.querySelector('#export-btn') as HTMLButtonElement).click();
|
||||
await new Promise((r) => setTimeout(r, 50));
|
||||
|
||||
expect(mockSendMessage).toHaveBeenCalledWith({
|
||||
type: 'export_backup',
|
||||
passphrase: 'test-backup-pass',
|
||||
includeImage: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('export error surfaces in the status pre', async () => {
|
||||
renderBackupPanel(app);
|
||||
vi.spyOn(window, 'prompt').mockReturnValue('p');
|
||||
mockSendMessage.mockResolvedValue({ ok: false, error: 'no reference image stored locally' });
|
||||
|
||||
(app.querySelector('#export-btn') as HTMLButtonElement).click();
|
||||
await new Promise((r) => setTimeout(r, 50));
|
||||
|
||||
const status = app.querySelector('#export-status') as HTMLElement;
|
||||
expect(status.textContent).toContain('Failed');
|
||||
expect(status.textContent).toContain('no reference image');
|
||||
});
|
||||
});
|
||||
|
||||
describe('backup panel — restore', () => {
|
||||
let app: HTMLElement;
|
||||
|
||||
beforeEach(() => {
|
||||
mockSendMessage.mockReset();
|
||||
teardown();
|
||||
document.body.innerHTML = '<div id="app"></div>';
|
||||
app = document.getElementById('app')!;
|
||||
});
|
||||
|
||||
it('clicking restore without filling new-remote shows an error', async () => {
|
||||
renderBackupPanel(app);
|
||||
vi.spyOn(window, 'prompt').mockReturnValue('p');
|
||||
|
||||
// Simulate file picked — this reveals the fieldset with the restore button.
|
||||
const fakeFile = new File([new Uint8Array([0x52, 0x42, 0x41, 0x4b, 0x01])], 'v.relbak');
|
||||
const input = app.querySelector('#restore-file') as HTMLInputElement;
|
||||
Object.defineProperty(input, 'files', { value: [fakeFile] });
|
||||
input.dispatchEvent(new Event('change'));
|
||||
|
||||
(app.querySelector('#restore-btn') as HTMLButtonElement).click();
|
||||
await new Promise((r) => setTimeout(r, 50));
|
||||
|
||||
const status = app.querySelector('#restore-status') as HTMLElement;
|
||||
expect(status.textContent).toContain('fill in');
|
||||
expect(mockSendMessage).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user