import { describe, expect, it } from 'vitest'; import { captureGpoFolderFiles, captureReadableGpoSelectedFiles, collectGpoDirectoryFiles } from '../../src/features/project-import/GpoFolderImport'; describe('GPO folder browser file capture', () => { it('starts every selected file read before the transport requests the first result', async () => { const started: string[] = []; const selected = ['first', 'second', 'third'].map(name => ({ webkitRelativePath: `Synthetic/${name}.xml`, size: name.length, arrayBuffer: async () => { started.push(name); return new TextEncoder().encode(name).buffer; } })) as unknown as File[]; const sources = captureGpoFolderFiles(selected); expect(started).toEqual(['first', 'second', 'third']); expect(new TextDecoder().decode(await sources[0].readBytes())).toBe('first'); }); it('turns an inaccessible browser file into the bounded local-read error', async () => { const selected = [{ webkitRelativePath: 'Synthetic/unavailable.xml', size: 1, arrayBuffer: async () => { throw new DOMException('unavailable', 'NotFoundError'); } }] as unknown as File[]; const [source] = captureGpoFolderFiles(selected); await expect(source.readBytes()).rejects.toThrow('konnte nicht lokal gelesen werden'); }); it('rejects oversized metadata before starting any browser file read', () => { let started = 0; const selected = [{ webkitRelativePath: 'Synthetic/oversized.bin', size: 513 * 1024 * 1024, arrayBuffer: async () => { started += 1; return new ArrayBuffer(0); } }] as unknown as File[]; expect(() => captureGpoFolderFiles(selected)).toThrow('ungültige oder zu große Dateigröße'); expect(started).toBe(0); }); it('collects a directly granted directory recursively with stable relative paths', async () => { const file = { size: 3, arrayBuffer: async () => new TextEncoder().encode('gpo').buffer } as unknown as File; const nested = { kind: 'directory', name: 'DomainSysvol', async *values() { yield { kind: 'file', name: 'gpt.ini', getFile: async () => file }; } }; const root = { kind: 'directory', name: 'SyntheticBackup', async *values() { yield nested; } }; const selected = await collectGpoDirectoryFiles(root as never); expect(selected.unreadableEntries).toBe(0); expect(selected.files.map(entry => entry.relativePath)).toEqual([ 'SyntheticBackup/DomainSysvol/gpt.ini' ]); }); it('keeps readable entries and counts inaccessible handles and file bodies', async () => { const readable = { size: 3, arrayBuffer: async () => new TextEncoder().encode('gpo').buffer } as File; const unreadableBody = { size: 1, arrayBuffer: async () => { throw new DOMException('unavailable', 'NotFoundError'); } } as unknown as File; const root = { kind: 'directory', name: 'SyntheticBackup', async *values() { yield { kind: 'file', name: 'gpt.ini', getFile: async () => readable }; yield { kind: 'file', name: 'missing.xml', getFile: async () => { throw new DOMException('missing', 'NotFoundError'); } }; yield { kind: 'file', name: 'locked.xml', getFile: async () => unreadableBody }; } }; const collected = await collectGpoDirectoryFiles(root as never); const captured = await captureReadableGpoSelectedFiles(collected.files); expect(collected.unreadableEntries).toBe(1); expect(captured.unreadableEntries).toBe(1); expect(captured.sources.map(source => source.relativePath)).toEqual([ 'SyntheticBackup/gpt.ini' ]); }); });