feat : dreamgineer ask me try to use this and now im ran out of token sad [no ci]
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
import sharp from "sharp";
|
||||
import { beforeAll, afterAll, describe, expect, it, vi } from "vitest";
|
||||
import { init, Renderer } from "takumi-js/wasm/no-init";
|
||||
import { exportFixtures } from "./fixtures";
|
||||
import { renderExport } from "./render";
|
||||
import { exportTemplate } from "./templates";
|
||||
import { imageSources, loadImageSources } from "./assets";
|
||||
|
||||
let renderer: Renderer;
|
||||
beforeAll(async () => {
|
||||
await init({ module_or_path: await readFile("public/takumi.wasm") });
|
||||
renderer = new Renderer();
|
||||
for (const [name, path] of [
|
||||
["Anuphan", "Anuphan.ttf"],
|
||||
["Genshin Overview", "zh-cn.ttf"],
|
||||
["Kanit Overview", "Kanit-SemiBold.ttf"],
|
||||
["Kanit Poster", "Kanit-ExtraBoldItalic.ttf"],
|
||||
]) {
|
||||
await renderer.registerFont({
|
||||
name,
|
||||
data: await readFile(`public/${path}`),
|
||||
});
|
||||
}
|
||||
});
|
||||
afterAll(() => renderer.free());
|
||||
|
||||
describe("browser WASM export templates", () => {
|
||||
it.each(exportFixtures.map((request) => [request.kind, request] as const))(
|
||||
"renders %s with intended dimensions and visible content",
|
||||
async (_, request) => {
|
||||
const art = await sharp({
|
||||
create: { width: 500, height: 700, channels: 4, background: "#786a9c" },
|
||||
})
|
||||
.png()
|
||||
.toBuffer();
|
||||
const fetchMock = vi
|
||||
.spyOn(globalThis, "fetch")
|
||||
.mockImplementation(async (input) => {
|
||||
const path = new URL(String(input)).pathname;
|
||||
const bytes =
|
||||
path === "/test-art.png" ? art : await readFile(`public${path}`);
|
||||
return new Response(bytes);
|
||||
});
|
||||
try {
|
||||
const bytes = await renderExport(
|
||||
renderer,
|
||||
request,
|
||||
"http://export.test",
|
||||
);
|
||||
const metadata = await sharp(bytes).metadata();
|
||||
expect(metadata.width).toBe(request.width);
|
||||
if (request.height) expect(metadata.height).toBe(request.height);
|
||||
else expect(metadata.height).toBeGreaterThan(200);
|
||||
expect(bytes.length).toBeGreaterThan(10000);
|
||||
const { stdev } = (await sharp(bytes).stats()).channels[0];
|
||||
expect(stdev).toBeGreaterThan(5);
|
||||
if (request.kind === "constellation") {
|
||||
const topBar = await sharp(bytes)
|
||||
.extract({ left: 200, top: 250, width: 1, height: 1 })
|
||||
.removeAlpha()
|
||||
.raw()
|
||||
.toBuffer();
|
||||
expect([...topBar]).toEqual([255, 255, 255]);
|
||||
const highlightedBar = await sharp(bytes)
|
||||
.extract({ left: 200, top: 750, width: 1, height: 1 })
|
||||
.removeAlpha()
|
||||
.raw()
|
||||
.toBuffer();
|
||||
expect(highlightedBar[0]).toBeGreaterThan(highlightedBar[1]);
|
||||
expect(highlightedBar[1]).toBeGreaterThan(highlightedBar[2]);
|
||||
}
|
||||
} finally {
|
||||
fetchMock.mockRestore();
|
||||
}
|
||||
},
|
||||
30000,
|
||||
);
|
||||
it.each(["tierlist", "best-stats", "target-stats", "talents"] as const)(
|
||||
"renders artifact %s selection",
|
||||
async (section) => {
|
||||
const fixture = exportFixtures.find(
|
||||
(request) => request.kind === "artifact",
|
||||
)!;
|
||||
if (fixture.kind !== "artifact")
|
||||
throw new Error("Missing artifact fixture");
|
||||
const art = await sharp({
|
||||
create: { width: 50, height: 50, channels: 4, background: "#786a9c" },
|
||||
})
|
||||
.png()
|
||||
.toBuffer();
|
||||
const fetchMock = vi
|
||||
.spyOn(globalThis, "fetch")
|
||||
.mockImplementation(async (input) => {
|
||||
const path = new URL(String(input)).pathname;
|
||||
return new Response(
|
||||
path === "/test-art.png" ? art : await readFile(`public${path}`),
|
||||
);
|
||||
});
|
||||
try {
|
||||
const width =
|
||||
section === "best-stats" ? 700 : section === "tierlist" ? 1200 : 800;
|
||||
const height = section === "best-stats" ? 700 : undefined;
|
||||
const bytes = await renderExport(
|
||||
renderer,
|
||||
{
|
||||
...fixture,
|
||||
width,
|
||||
height,
|
||||
withoutNotes: true,
|
||||
data: { ...fixture.data, sections: [section], includeNote: false },
|
||||
},
|
||||
"http://export.test",
|
||||
);
|
||||
const metadata = await sharp(bytes).metadata();
|
||||
expect(metadata.width).toBe(width);
|
||||
if (height) expect(metadata.height).toBe(height);
|
||||
expect(metadata.height).toBeGreaterThan(150);
|
||||
} finally {
|
||||
fetchMock.mockRestore();
|
||||
}
|
||||
},
|
||||
30000,
|
||||
);
|
||||
it("encodes a WebP export", async () => {
|
||||
const fetchMock = vi
|
||||
.spyOn(globalThis, "fetch")
|
||||
.mockImplementation(async (input) => {
|
||||
const path = new URL(String(input)).pathname;
|
||||
return new Response(
|
||||
await readFile(
|
||||
path === "/test-art.png"
|
||||
? "public/icon/Watermark.png"
|
||||
: `public${path}`,
|
||||
),
|
||||
);
|
||||
});
|
||||
try {
|
||||
const bytes = await renderExport(
|
||||
renderer,
|
||||
{ ...exportFixtures[0], format: "webp", withoutNotes: true },
|
||||
"http://export.test",
|
||||
);
|
||||
expect((await sharp(bytes).metadata()).format).toBe("webp");
|
||||
} finally {
|
||||
fetchMock.mockRestore();
|
||||
}
|
||||
}, 30000);
|
||||
it("omits Thai notes before layout", () => {
|
||||
const request = exportFixtures[0];
|
||||
expect(renderToStaticMarkup(exportTemplate(request))).toContain(
|
||||
"โน้ตภาษาไทย",
|
||||
);
|
||||
expect(
|
||||
renderToStaticMarkup(exportTemplate({ ...request, withoutNotes: true })),
|
||||
).not.toContain("โน้ตภาษาไทย");
|
||||
});
|
||||
it("filters artifact sections and conditions before layout", () => {
|
||||
const request = exportFixtures.find((item) => item.kind === "artifact")!;
|
||||
if (request.kind !== "artifact")
|
||||
throw new Error("Missing artifact fixture");
|
||||
const html = renderToStaticMarkup(
|
||||
exportTemplate({
|
||||
...request,
|
||||
data: {
|
||||
...request.data,
|
||||
sections: ["best-stats"],
|
||||
recommendedCondition: 1,
|
||||
includeNote: false,
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(html).toContain("Second");
|
||||
expect(html).not.toContain("First");
|
||||
expect(html).not.toContain("Late Game");
|
||||
expect(html).not.toContain("Talent Priority");
|
||||
expect(html).not.toContain("artifact-export-right");
|
||||
expect(html).not.toContain("โน้ตโปรไฟล์");
|
||||
});
|
||||
it("collects mask sources and deduplicates artwork", () => {
|
||||
expect(
|
||||
imageSources({
|
||||
type: "container",
|
||||
style: { maskImage: "url('/mask.png')" },
|
||||
children: [{ type: "image", src: "/mask.png" }],
|
||||
}),
|
||||
).toEqual(["/mask.png"]);
|
||||
});
|
||||
it("rejects missing artwork instead of producing an incomplete image", async () => {
|
||||
const fetchMock = vi
|
||||
.spyOn(globalThis, "fetch")
|
||||
.mockResolvedValue(new Response(null, { status: 404 }));
|
||||
try {
|
||||
await expect(
|
||||
loadImageSources(
|
||||
{ type: "image", src: "/missing.png" },
|
||||
"http://export.test",
|
||||
),
|
||||
).rejects.toThrow("Image load failed");
|
||||
} finally {
|
||||
fetchMock.mockRestore();
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user