import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import test from "node:test"; import { BIRTH_SKY_FILENAME, saveBirthSkyImage } from "../src/lib/birth-sky/export.ts"; import { waitForHeadingSerif } from "../src/lib/birth-sky/render.ts"; const exportSource = readFileSync(new URL("../src/lib/birth-sky/export.ts", import.meta.url), "utf8"); function environment(share: "ok" | "cancel" | "fail" | "unsupported") { const downloads: string[] = []; const shared: ShareData[] = []; const nav = share === "unsupported" ? { canShare: () => false, share: async () => { throw new Error("must not share"); } } : { canShare: (data: ShareData) => Array.isArray(data.files) && data.files.length === 1, share: async (data: ShareData) => { shared.push(data); if (share === "cancel") throw Object.assign(new Error("dismissed"), { name: "AbortError" }); if (share === "fail") throw Object.assign(new Error("denied"), { name: "NotAllowedError" }); }, }; return { downloads, shared, env: { navigator: nav, makeFile: (blob: Blob, name: string) => new File([blob], name, { type: "image/png" }), download: (_blob: Blob, name: string) => { downloads.push(name); }, }, }; } const png = new Blob([new Uint8Array([137, 80, 78, 71])], { type: "image/png" }); test("the file name carries no name and no date", () => { assert.equal(BIRTH_SKY_FILENAME, "jyotisha-sky.png"); assert.match(exportSource, /toBlob\([\s\S]*"image\/png"\)/); }); test("share-capable browsers get the system share sheet with the PNG file", async () => { const { env, downloads, shared } = environment("ok"); assert.equal(await saveBirthSkyImage(png, env), "shared"); assert.equal(shared.length, 1); const file = shared[0]!.files![0]!; assert.equal(file.name, "jyotisha-sky.png"); assert.equal(file.type, "image/png"); assert.deepEqual(downloads, []); }); test("without file sharing it downloads through Blob + a.download", async () => { const { env, downloads } = environment("unsupported"); assert.equal(await saveBirthSkyImage(png, env), "downloaded"); assert.deepEqual(downloads, ["jyotisha-sky.png"]); const bare = environment("unsupported"); assert.equal(await saveBirthSkyImage(png, { ...bare.env, navigator: null }), "downloaded"); assert.match(exportSource, /anchor\.download = name/); assert.match(exportSource, /URL\.revokeObjectURL/); }); test("a dismissed share sheet is not an error and does not fall back to a download", async () => { const { env, downloads } = environment("cancel"); assert.equal(await saveBirthSkyImage(png, env), "cancelled"); assert.deepEqual(downloads, []); const failing = environment("fail"); assert.equal(await saveBirthSkyImage(png, failing.env), "downloaded"); assert.deepEqual(failing.downloads, ["jyotisha-sky.png"]); }); test("the heading serif wait gives up after its budget instead of hanging", async () => { const never = { load: () => new Promise(() => {}) }; const started = Date.now(); assert.equal(await waitForHeadingSerif("那一刻", never, 30), false); assert.ok(Date.now() - started < 1_000); assert.equal(await waitForHeadingSerif("那一刻", { load: async () => [{}] }, 30), true); assert.equal(await waitForHeadingSerif("那一刻", { load: async () => [] }, 30), false); assert.equal(await waitForHeadingSerif("那一刻", { load: async () => { throw new Error("x"); } }, 30), false); assert.equal(await waitForHeadingSerif("那一刻", null, 30), false); });