feat: complete TASK-WP4-05 client export
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
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");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user