import { test } from 'node:test'; import assert from 'node:assert/strict'; import { filesFromEntries } from './fileEntries'; const fileEntry = (name: string): FileSystemFileEntry => ({ isFile: true, isDirectory: false, name, file: (success: (file: File) => void) => { success(new File(['x'], name, { type: 'text/plain' })); }, }) as unknown as FileSystemFileEntry; /** * A directory whose reader yields its children in several batches (mirroring * Chromium's `readEntries`, which caps each call) and finally an empty batch. */ const dirEntry = (name: string, children: FileSystemEntry[]): FileSystemDirectoryEntry => { const batches = [children.slice(0, 1), children.slice(1), [] as FileSystemEntry[]]; return { isFile: false, isDirectory: true, name, createReader: () => { let call = 0; return { readEntries: (success: (entries: FileSystemEntry[]) => void) => { const batch = batches[call] ?? []; call += 1; success(batch); }, } as unknown as FileSystemDirectoryReader; }, } as unknown as FileSystemDirectoryEntry; }; test('filesFromEntries flattens nested folders and prefixes relative paths', async () => { const entries: FileSystemEntry[] = [ fileEntry('top.txt'), dirEntry('photos', [ fileEntry('a.jpg'), dirEntry('2024', [fileEntry('b.jpg'), fileEntry('c.jpg')]), ]), ]; const files = await filesFromEntries(entries); const names = files.map((f) => f.name).sort(); assert.deepEqual(names, ['photos/2024/b.jpg', 'photos/2024/c.jpg', 'photos/a.jpg', 'top.txt']); }); test('filesFromEntries reads directory entries in batches until empty', async () => { const entries: FileSystemEntry[] = [ dirEntry('docs', [fileEntry('one.txt'), fileEntry('two.txt')]), ]; const files = await filesFromEntries(entries); assert.equal(files.length, 2); }); test('filesFromEntries respects the maxFiles cap', async () => { const entries: FileSystemEntry[] = [ dirEntry('many', [fileEntry('a.txt'), fileEntry('b.txt')]), fileEntry('c.txt'), ]; const files = await filesFromEntries(entries, 2); assert.equal(files.length, 2); });