chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdtemp, mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import test from "node:test";
|
||||
|
||||
import { convertPresentationTemplate } from "./convert-presentation-template.mjs";
|
||||
|
||||
function component(id, data, extra = {}) {
|
||||
return {
|
||||
id,
|
||||
description: `${id} description`,
|
||||
position: { x: 0, y: 0 },
|
||||
size: { width: 100, height: 100 },
|
||||
elements: [
|
||||
{
|
||||
type: "image",
|
||||
data,
|
||||
decorative: true,
|
||||
is_icon: false,
|
||||
},
|
||||
],
|
||||
...extra,
|
||||
};
|
||||
}
|
||||
|
||||
test("converts presentation UI edits into bundled layouts and merged variants", async () => {
|
||||
const root = await mkdtemp(path.join(os.tmpdir(), "presentation-template-converter-"));
|
||||
const appData = path.join(root, "app_data");
|
||||
const inputDirectory = path.join(root, "templates", "dynamic");
|
||||
const input = path.join(inputDirectory, "presentation.json");
|
||||
const output = path.join(inputDirectory, "template.json");
|
||||
await mkdir(path.join(appData, "images"), { recursive: true });
|
||||
await mkdir(path.join(appData, "fonts"), { recursive: true });
|
||||
await mkdir(inputDirectory, { recursive: true });
|
||||
await writeFile(path.join(appData, "images", "updated.png"), "updated");
|
||||
await writeFile(path.join(appData, "images", "untouched.png"), "untouched");
|
||||
await writeFile(path.join(appData, "images", "added.png"), "added");
|
||||
await writeFile(path.join(appData, "images", "thumbnail.png"), "thumbnail");
|
||||
await writeFile(path.join(appData, "fonts", "custom.ttf"), "font");
|
||||
|
||||
const originalHero = component("hero", "/app_data/images/original.png");
|
||||
const originalRemoved = component("removed", "/app_data/images/removed.png");
|
||||
const untouched = component("untouched", "/app_data/images/untouched.png");
|
||||
const updatedHero = component("hero", "/app_data/images/updated.png", {
|
||||
position: { x: 25, y: 30 },
|
||||
});
|
||||
const added = component("added", "/app_data/images/added.png");
|
||||
|
||||
await writeFile(
|
||||
input,
|
||||
JSON.stringify({
|
||||
id: "presentation-id",
|
||||
layout: {
|
||||
layouts: [
|
||||
{
|
||||
id: "edited-layout",
|
||||
description: "Original layout",
|
||||
components: [originalHero, originalRemoved],
|
||||
},
|
||||
{
|
||||
id: "unused-layout",
|
||||
description: "Unused layout",
|
||||
components: [untouched],
|
||||
},
|
||||
],
|
||||
},
|
||||
merged_components: {
|
||||
components: [
|
||||
{
|
||||
id: "hero-group",
|
||||
description: "Hero variants",
|
||||
variants: [originalHero, untouched],
|
||||
},
|
||||
{
|
||||
id: "removed",
|
||||
description: "Removed variants",
|
||||
variants: [originalRemoved],
|
||||
},
|
||||
],
|
||||
},
|
||||
slides: [
|
||||
{
|
||||
layout: "edited-layout",
|
||||
ui: {
|
||||
id: "edited-layout",
|
||||
description: "Updated layout",
|
||||
components: [updatedHero, added],
|
||||
},
|
||||
},
|
||||
],
|
||||
fonts: { Custom: "/app_data/fonts/custom.ttf" },
|
||||
thumbnail: "/app_data/images/thumbnail.png",
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await convertPresentationTemplate({
|
||||
input,
|
||||
output,
|
||||
appData,
|
||||
name: "Dynamic",
|
||||
});
|
||||
const converted = JSON.parse(await readFile(output, "utf8"));
|
||||
|
||||
assert.deepEqual(Object.keys(converted), [
|
||||
"id",
|
||||
"name",
|
||||
"description",
|
||||
"thumbnail",
|
||||
"merged_components",
|
||||
"layouts",
|
||||
"fonts",
|
||||
]);
|
||||
assert.equal(converted.name, "Dynamic");
|
||||
assert.equal(converted.layouts.length, 2);
|
||||
assert.equal(converted.layouts[0].description, "Updated layout");
|
||||
assert.equal(converted.layouts[0].components[0].position.x, 25);
|
||||
assert.equal(converted.layouts[0].components[0].elements[0].data, "static/updated.png");
|
||||
assert.equal(converted.layouts[1].components[0].elements[0].data, "static/untouched.png");
|
||||
|
||||
const variants = converted.merged_components.flatMap((group) => group.variants);
|
||||
assert.equal(variants.some((variant) => variant.id === "removed"), false);
|
||||
assert.equal(
|
||||
variants.find((variant) => variant.id === "hero").elements[0].data,
|
||||
"static/updated.png",
|
||||
);
|
||||
assert.equal(
|
||||
variants.find((variant) => variant.id === "added").elements[0].data,
|
||||
"static/added.png",
|
||||
);
|
||||
assert.equal(converted.thumbnail, "static/thumbnail.png");
|
||||
assert.equal(converted.fonts.Custom, "static/custom.ttf");
|
||||
assert.equal(result.updatedLayoutCount, 1);
|
||||
assert.equal(result.updatedVariantCount, 1);
|
||||
assert.equal(result.removedVariantCount, 1);
|
||||
assert.equal(result.addedVariantCount, 1);
|
||||
assert.equal(result.assetCount, 5);
|
||||
});
|
||||
|
||||
test("fails when an original layout component cannot be mapped to merged_components", async () => {
|
||||
const root = await mkdtemp(path.join(os.tmpdir(), "presentation-template-invalid-"));
|
||||
const input = path.join(root, "presentation.json");
|
||||
const output = path.join(root, "template.json");
|
||||
const original = component("missing", "/static/images/replaceable_template_image.png");
|
||||
await writeFile(
|
||||
input,
|
||||
JSON.stringify({
|
||||
layout: { layouts: [{ id: "layout", components: [original] }] },
|
||||
merged_components: { components: [] },
|
||||
slides: [{ layout: "layout", ui: { id: "layout", components: [original] } }],
|
||||
}),
|
||||
);
|
||||
|
||||
await assert.rejects(
|
||||
convertPresentationTemplate({ input, output, appData: path.join(root, "app_data") }),
|
||||
/was not found in merged_components/,
|
||||
);
|
||||
await assert.rejects(readFile(output), /ENOENT/);
|
||||
});
|
||||
Reference in New Issue
Block a user