Files
edentext/tests/unit/recent-files.test.ts
Steffen Becker ca29ff780b fix: make the recent-files list only offer files it can reopen
A file opened without a File System Access handle (no API — Firefox,
Safari, Brave — or a template) is no longer recorded: nothing could
ever reopen it, so every click failed and dropped the entry. A startup
prune clears such stale entries. Reopening now asks for 'read' instead
of 'readwrite' (Save re-prompts on its own), and a declined permission
prompt keeps the entry — only a moved or deleted file drops it.
2026-08-23 18:54:52 +00:00

66 lines
2.8 KiB
TypeScript

// The recent-files list (storage/recentFiles.ts): dedupe, newest first, capped at
// eight, tolerant of corrupt localStorage, and never recording a handle-less file —
// nothing could reopen it. jsdom has no IndexedDB, so the handle store no-ops.
import { describe, it, expect, beforeEach } from 'vitest';
import { loadRecentFiles, rememberRecentFile, forgetRecentFile, forgetRecentFiles, readRecentFile } from '../../src/lib/storage/recentFiles';
const KEY = 'edentext-recent-files';
// A stand-in for a picker handle; without IndexedDB it is matched by name only.
const stubHandle = () => ({ isSameEntry: async () => false }) as unknown as FileSystemFileHandle;
describe('recent files', () => {
beforeEach(() => localStorage.clear());
it('starts empty and survives corrupt or foreign values under its key', () => {
expect(loadRecentFiles()).toEqual([]);
localStorage.setItem(KEY, 'not json{');
expect(loadRecentFiles()).toEqual([]);
localStorage.setItem(KEY, '{"a":1}');
expect(loadRecentFiles()).toEqual([]);
localStorage.setItem(KEY, '[{"id":"x","name":"ok.odt","at":1},{"id":"y","at":2},null]');
expect(loadRecentFiles().map((f) => f.name)).toEqual(['ok.odt']);
});
it('records nothing without a handle — there is nothing to reopen from', async () => {
await rememberRecentFile('a.odt', null);
expect(loadRecentFiles()).toEqual([]);
expect(localStorage.getItem(KEY)).toBeNull();
});
it('remembers newest first and dedupes a same-named file, keeping its id', async () => {
await rememberRecentFile('a.odt', stubHandle());
await rememberRecentFile('b.odt', stubHandle());
expect(loadRecentFiles().map((f) => f.name)).toEqual(['b.odt', 'a.odt']);
const idA = loadRecentFiles()[1].id;
await rememberRecentFile('a.odt', stubHandle());
const list = loadRecentFiles();
expect(list.map((f) => f.name)).toEqual(['a.odt', 'b.odt']);
expect(list[0].id).toBe(idA);
});
it('keeps at most eight entries, dropping the oldest', async () => {
for (let i = 1; i <= 10; i++) await rememberRecentFile(`f${i}.odt`, stubHandle());
const names = loadRecentFiles().map((f) => f.name);
expect(names).toHaveLength(8);
expect(names[0]).toBe('f10.odt');
expect(names).not.toContain('f1.odt');
expect(names).not.toContain('f2.odt');
});
it('forgetRecentFile drops one entry, forgetRecentFiles removes the key', async () => {
await rememberRecentFile('a.odt', stubHandle());
await rememberRecentFile('b.odt', stubHandle());
const idB = loadRecentFiles()[0].id;
expect(forgetRecentFile(idB).map((f) => f.name)).toEqual(['a.odt']);
forgetRecentFiles();
expect(loadRecentFiles()).toEqual([]);
expect(localStorage.getItem(KEY)).toBeNull();
});
it('readRecentFile reports a missing handle as gone', async () => {
expect(await readRecentFile('nope')).toBe('gone');
});
});