Files
tyx_AI_xhs/tests/unit/wp4-05-export-compositor.test.ts
T

74 lines
3.1 KiB
TypeScript

import { describe, expect, it } from "vitest";
import type { CanvasState } from "@dada/shared-contracts";
import { CanvasEditHistory } from "../../apps/web/src/editor-canvas.js";
import {
EXPORT_DIMENSIONS,
completePendingTextForExport,
resolveExportSettings,
sha256Blob,
} from "../../apps/web/src/export-compositor.js";
import { P0A_TEXT_TEMPLATES, TextEditSession, createTextTemplateElement } from "../../apps/web/src/text-assets.js";
function canvasWithText(): CanvasState {
return {
background: {
adjustments: { brightness: 0, contrast: 0, crop: null, filter: "none", fit: "fill", saturation: 0, sharpness: 0, temperature: 0 },
asset_id: null,
},
elements: [createTextTemplateElement(P0A_TEXT_TEMPLATES[0]!, {
createdAt: "2026-08-03T06:00:00.000Z",
elementId: "00000000-0000-4000-8000-000000000901",
}, 0)],
pixel_height: 1440,
pixel_width: 1080,
ratio: "3:4",
schema_version: 1,
};
}
describe("TASK-WP4-05 export compositor contract", () => {
it("freezes exact output pixels for all four ratios", () => {
expect(EXPORT_DIMENSIONS).toEqual({
"1:1": { height: 1080, width: 1080 },
"3:4": { height: 1440, width: 1080 },
"4:3": { height: 1080, width: 1440 },
"9:16": { height: 1920, width: 1080 },
});
});
it("uses JPG 92 by default, accepts only 80-100, and removes PNG quality", () => {
expect(resolveExportSettings({ format: "jpg", ratio: "3:4" })).toEqual({
format: "jpg", height: 1440, mimeType: "image/jpeg", quality: 92, width: 1080,
});
expect(resolveExportSettings({ format: "jpg", quality: 80, ratio: "1:1" }).quality).toBe(80);
expect(resolveExportSettings({ format: "jpg", quality: 100, ratio: "4:3" }).quality).toBe(100);
expect(resolveExportSettings({ format: "png", quality: 80, ratio: "9:16" })).toEqual({
format: "png", height: 1920, mimeType: "image/png", width: 1080,
});
expect(() => resolveExportSettings({ format: "jpg", quality: 79, ratio: "3:4" })).toThrowError("export_quality_invalid");
expect(() => resolveExportSettings({ format: "jpg", quality: 100.5, ratio: "3:4" })).toThrowError("export_quality_invalid");
});
it("turns one pending text draft into exactly one history operation", () => {
const before = canvasWithText();
const draftSession = new TextEditSession(before.elements[0]!, P0A_TEXT_TEMPLATES);
draftSession.setContent("待提交导出文字");
const draft = draftSession.value;
const history = new CanvasEditHistory(before);
const confirmed = completePendingTextForExport(before, draft);
history.commit(confirmed);
expect(confirmed.elements[0]?.content).toBe("待提交导出文字");
expect(before.elements[0]?.content).toBe("春日计划");
expect(history.undo()?.elements[0]?.content).toBe("春日计划");
expect(history.redo()?.elements[0]?.content).toBe("待提交导出文字");
});
it("hashes the exact Blob bytes used by download and latest persistence", async () => {
const blob = new Blob(["same-export-blob"], { type: "image/png" });
expect(await sha256Blob(blob)).toBe("ef710020af56830015263fa74537d28601fd0fb03f4a69d1cde63ff8722a9fd6");
});
});