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