mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
57 lines
2.4 KiB
TypeScript
57 lines
2.4 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import JSZip from 'jszip';
|
|
import type { FileNode } from '@/lib/jmap/types';
|
|
import { buildZip, planZip } from '../files-zip';
|
|
|
|
const dir = (id: string, name: string, parentId: string | null): FileNode => ({
|
|
id, parentId, name, type: '', blobId: null, size: 0, created: '', modified: '',
|
|
});
|
|
const file = (id: string, name: string, parentId: string | null, size = 4): FileNode => ({
|
|
id, parentId, name, type: 'text/plain', blobId: `b-${id}`, size, created: '', modified: '2026-10-01T10:00:00Z',
|
|
});
|
|
|
|
const DRIVE = [
|
|
dir('taxes', 'Taxes', null),
|
|
dir('y25', '2025', 'taxes'),
|
|
dir('empty', 'Drafts', 'taxes'),
|
|
file('ret', 'return.pdf', 'y25'),
|
|
file('note', 'notes.txt', 'taxes'),
|
|
file('other', 'other.txt', null),
|
|
];
|
|
|
|
const fetchFile = async (node: FileNode) => new Blob([`body of ${node.id}`]);
|
|
|
|
describe('folder zip', () => {
|
|
it('packs a folder with everything in it under its own name, empty folders included', () => {
|
|
const plan = planZip(DRIVE, ['taxes']);
|
|
expect(plan.files.map(f => f.path).sort()).toEqual(['Taxes/2025/return.pdf', 'Taxes/notes.txt']);
|
|
expect(plan.emptyFolders).toEqual(['Taxes/Drafts']);
|
|
expect(plan.totalBytes).toBe(8);
|
|
});
|
|
|
|
it('numbers two picked items of the same name instead of overwriting one', () => {
|
|
const plan = planZip([file('a', 'x.txt', null), file('b', 'x.txt', 'taxes'), dir('taxes', 'Taxes', null)], ['a', 'b']);
|
|
expect(plan.files.map(f => f.path)).toEqual(['x.txt', 'x (1).txt']);
|
|
});
|
|
|
|
it('builds a zip that holds the files', async () => {
|
|
const progress: number[] = [];
|
|
const blob = await buildZip(planZip(DRIVE, ['taxes', 'other']), fetchFile, { onProgress: (p) => progress.push(p.progress) });
|
|
const zip = await JSZip.loadAsync(await blob.arrayBuffer());
|
|
expect(await zip.file('Taxes/2025/return.pdf')!.async('string')).toBe('body of ret');
|
|
expect(await zip.file('other.txt')!.async('string')).toBe('body of other');
|
|
expect(zip.folder('Taxes/Drafts')).not.toBeNull();
|
|
expect(progress[progress.length - 1]).toBeCloseTo(1);
|
|
});
|
|
|
|
it('stops when canceled', async () => {
|
|
const controller = new AbortController();
|
|
const plan = planZip(DRIVE, ['taxes']);
|
|
const slowFetch = async (node: FileNode) => {
|
|
controller.abort();
|
|
return fetchFile(node);
|
|
};
|
|
await expect(buildZip(plan, slowFetch, { signal: controller.signal })).rejects.toMatchObject({ name: 'AbortError' });
|
|
});
|
|
});
|