76 lines
2.1 KiB
TypeScript
76 lines
2.1 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { readFileSync } from "node:fs";
|
|
|
|
const source = new Bun.Transpiler({ loader: "ts" })
|
|
.transformSync(readFileSync(new URL("../src/download.ts", import.meta.url), "utf8"))
|
|
.replace("export function", "function");
|
|
|
|
test("download keeps direct link after blocked automatic click and releases replaced/detached blobs", () => {
|
|
const revoked: string[] = [],
|
|
observers: Array<{ callback(): void; disconnect(): void }> = [];
|
|
let sequence = 0,
|
|
clicks = 0,
|
|
disconnected = 0;
|
|
const links: any[] = [];
|
|
const outlet = {
|
|
replaceChildren: (link: unknown) => {
|
|
links.splice(0, links.length, link);
|
|
},
|
|
};
|
|
const host = {
|
|
isConnected: true,
|
|
querySelector: () => outlet,
|
|
ownerDocument: {
|
|
documentElement: {},
|
|
createElement: () => ({
|
|
href: "",
|
|
download: "",
|
|
textContent: "",
|
|
click() {
|
|
clicks++;
|
|
throw new Error("blocked");
|
|
},
|
|
remove() {
|
|
const index = links.indexOf(this);
|
|
if (index >= 0) links.splice(index, 1);
|
|
},
|
|
}),
|
|
},
|
|
};
|
|
const offer = new Function(
|
|
"URL",
|
|
"Blob",
|
|
"MutationObserver",
|
|
source + ";return offerBuilderDownload;",
|
|
)(
|
|
{
|
|
createObjectURL: () => `blob:${++sequence}`,
|
|
revokeObjectURL: (url: string) => revoked.push(url),
|
|
},
|
|
Blob,
|
|
class {
|
|
constructor(public callback: () => void) {
|
|
observers.push(this);
|
|
}
|
|
observe() {}
|
|
disconnect() {
|
|
disconnected++;
|
|
}
|
|
},
|
|
);
|
|
offer(host, "html", "text/html", "draft.html");
|
|
expect(links[0].href).toBe("blob:1");
|
|
expect(links[0].download).toBe("draft.html");
|
|
expect(revoked).toEqual([]);
|
|
expect(clicks).toBe(1);
|
|
offer(host, "text", "text/plain", "draft.txt");
|
|
expect(revoked).toEqual(["blob:1"]);
|
|
expect(links[0].download).toBe("draft.txt");
|
|
host.isConnected = false;
|
|
observers[1]!.callback();
|
|
observers[1]!.callback();
|
|
expect(revoked).toEqual(["blob:1", "blob:2"]);
|
|
expect(links).toEqual([]);
|
|
expect(disconnected).toBe(2);
|
|
});
|