src/lib/dropped-files.test.ts
Rama main · réplica de lectura del repositorio original.
import { describe, expect, it } from "vitest";
import { takeDrop, walkDrop } from "./dropped-files";
// jsdom has no entries API, so the entries are fakes of its callback shape - the
// part under test is the walk: every file of every folder, with its path, read
// through `readEntries`' batches to the empty one that ends them.
function fileEntry(fullPath: string) {
const name = fullPath.split("/").pop()!;
return {
isFile: true,
isDirectory: false,
name,
fullPath,
file: (resolve: (file: File) => void) => resolve(new File(["x"], name)),
};
}
function folderEntry(fullPath: string, children: unknown[], batch = 2) {
return {
isFile: false,
isDirectory: true,
name: fullPath.split("/").pop()!,
fullPath,
createReader: () => {
let offset = 0;
return {
readEntries: (resolve: (entries: unknown[]) => void) => {
resolve(children.slice(offset, offset + batch));
offset += batch;
},
};
},
};
}
function transfer(entries: unknown[], files: File[] = []): DataTransfer {
return {
items: entries.map((entry) => ({
kind: "file",
webkitGetAsEntry: () => entry,
})),
files,
} as unknown as DataTransfer;
}
describe("a dropped folder", () => {
it("is walked to its last file, past more than one batch, with each file's path", async () => {
const drop = transfer([
folderEntry("/Suunto", [
fileEntry("/Suunto/1.fit"),
fileEntry("/Suunto/1.json"),
fileEntry("/Suunto/2.fit"),
folderEntry("/Suunto/Old", [fileEntry("/Suunto/Old/0.fit")]),
]),
fileEntry("/logbook.uddf"),
]);
const { picked, unreadable } = await walkDrop(takeDrop(drop));
expect(unreadable).toEqual([]);
expect(picked.map(({ path }) => path)).toEqual([
"Suunto/1.fit",
"Suunto/1.json",
"Suunto/2.fit",
"Suunto/Old/0.fit",
"logbook.uddf",
]);
expect(picked[0].file.name).toBe("1.fit");
});
});
describe("an entry the browser cannot read", () => {
it("is noted and passed over, and the rest of the drop still arrives", async () => {
const moved = {
...fileEntry("/Suunto/moved.fit"),
file: (_: unknown, reject: (error: unknown) => void) =>
reject(new Error("NotFoundError")),
};
const locked = {
...folderEntry("/Suunto/Locked", []),
createReader: () => ({
readEntries: (_: unknown, reject: (error: unknown) => void) =>
reject(new Error("SecurityError")),
}),
};
const drop = transfer([
folderEntry("/Suunto", [moved, locked, fileEntry("/Suunto/1.fit")], 5),
]);
const { picked, unreadable } = await walkDrop(takeDrop(drop));
expect(picked.map(({ path }) => path)).toEqual(["Suunto/1.fit"]);
expect(unreadable).toEqual(["Suunto/moved.fit", "Suunto/Locked"]);
});
});
describe("a drop from a browser without entries", () => {
it("falls back to the drop's own file list", async () => {
const files = [new File(["x"], "1.fit"), new File(["y"], "1.json")];
const drop = {
items: files.map(() => ({ kind: "file" })),
files,
} as unknown as DataTransfer;
const { picked } = await walkDrop(takeDrop(drop));
expect(picked.map(({ path }) => path)).toEqual(["1.fit", "1.json"]);
});
});