109 lines
5.2 KiB
TypeScript
109 lines
5.2 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { predictLayout } from "../adapters/prediction.ts";
|
|
|
|
test("prediction measures desktop and mobile geometry and restores closed disclosure", async () => {
|
|
const html =
|
|
'<!doctype html><html><head><style>.panel { width: 400px; height: 180px; } @media(max-width:48rem) { .panel { width: 200px; height: 240px; } }</style></head><body><details><summary>Menu</summary><div class="panel" data-muddle-anchor="panel">Content</div></details></body></html>';
|
|
const result = await predictLayout(html, {
|
|
selectors: [".panel"],
|
|
strict: true,
|
|
});
|
|
expect(result.predictions.map((prediction) => prediction.width)).toEqual([
|
|
400, 200,
|
|
]);
|
|
expect(result.predictions.map((prediction) => prediction.height)).toEqual([
|
|
180, 240,
|
|
]);
|
|
expect(result.html).not.toContain("<details open");
|
|
expect(result.html).toContain('data-muddle-predicted="predict-0"');
|
|
expect(result.html).toContain("--muddle-predicted-desktop-width: 400px");
|
|
expect(result.html).toContain("--muddle-predicted-mobile-width: 200px");
|
|
expect(result.html).toContain("--muddle-relate-panel-desktop-width: 400px");
|
|
expect(result.html).toContain("--muddle-relate-panel-mobile-width: 200px");
|
|
expect(result.html).toContain("@media (max-width: 48rem)");
|
|
});
|
|
|
|
test("prediction resolves a target that is sized from an ahead-of-time relation", async () => {
|
|
const html = `<!doctype html><html><head><style>
|
|
.source { position: absolute; left: 100px; top: 20px; width: 240px; height: 32px; }
|
|
.target { position: absolute; left: var(--muddle-relate-source-x); top: 80px; width: var(--muddle-relate-source-width); height: 24px; }
|
|
@media (max-width: 48rem) {
|
|
.source { left: 24px; width: 160px; }
|
|
}
|
|
</style></head><body>
|
|
<div class="source" data-muddle-anchor="source"></div>
|
|
<div class="target"></div>
|
|
</body></html>`;
|
|
const result = await predictLayout(html, {
|
|
selectors: [".target"],
|
|
strict: true,
|
|
});
|
|
const target = result.predictions.filter(
|
|
(prediction) =>
|
|
prediction.selector === '[data-muddle-predicted="predict-0"]',
|
|
);
|
|
expect(target.map((prediction) => prediction.width)).toEqual([240, 160]);
|
|
expect(target.map((prediction) => prediction.x)).toEqual([100, 24]);
|
|
expect(result.html).toContain("--muddle-predicted-desktop-width: 240px");
|
|
expect(result.html).toContain("--muddle-predicted-mobile-width: 160px");
|
|
});
|
|
|
|
test("prediction settles chained relations before writing the static page", async () => {
|
|
const html = `<!doctype html><html><head><style>
|
|
.source { position: absolute; left: 72px; top: 20px; width: 216px; height: 24px; }
|
|
.middle { position: absolute; left: var(--muddle-relate-source-x); top: 60px; width: var(--muddle-relate-source-width); height: 24px; }
|
|
.target { position: absolute; left: var(--muddle-relate-middle-x); top: 100px; width: var(--muddle-relate-middle-width); height: 24px; }
|
|
</style></head><body>
|
|
<div class="source" data-muddle-anchor="source"></div>
|
|
<div class="middle" data-muddle-anchor="middle"></div>
|
|
<div class="target"></div>
|
|
</body></html>`;
|
|
const result = await predictLayout(html, {
|
|
selectors: [".target"],
|
|
strict: true,
|
|
});
|
|
const target = result.predictions.filter(
|
|
(prediction) =>
|
|
prediction.selector === '[data-muddle-predicted="predict-0"]',
|
|
);
|
|
expect(target.map((prediction) => prediction.width)).toEqual([216, 216]);
|
|
expect(target.map((prediction) => prediction.x)).toEqual([72, 72]);
|
|
});
|
|
|
|
test("prediction follows the page's widest mobile breakpoint", async () => {
|
|
const html =
|
|
'<!doctype html><html><head><style>.panel { width: 500px; height: 24px; } @media (max-width: 40rem) { .panel { width: 280px; } }</style></head><body><div class="panel" data-muddle-anchor="panel"></div></body></html>';
|
|
const result = await predictLayout(html, {
|
|
selectors: [".panel"],
|
|
strict: true,
|
|
});
|
|
expect(result.predictions.map((prediction) => prediction.width)).toEqual([
|
|
500, 280,
|
|
]);
|
|
expect(result.html).toContain("@media (max-width: 40rem)");
|
|
});
|
|
|
|
test("prediction emits each selected breakpointAcc relation layer", async () => {
|
|
const html =
|
|
'<!doctype html><html><head><style>.panel { width: 600px; height: 24px; } @media (max-width: 64rem) { .panel { width: 420px; } } @media (max-width: 48rem) { .panel { width: 300px; } }</style></head><body><div class="panel" data-muddle-anchor="panel"></div></body></html>';
|
|
const result = await predictLayout(html, {
|
|
selectors: [".panel"],
|
|
breakpointAcc: ["LG", "MD"],
|
|
strict: true,
|
|
});
|
|
expect(result.html).toContain("--muddle-relate-panel-lg-width: 420px");
|
|
expect(result.html).toContain("--muddle-relate-panel-md-width: 300px");
|
|
expect(result.html).toContain("@media (max-width: 64rem)");
|
|
expect(result.html).toContain("@media (max-width: 48rem)");
|
|
});
|
|
|
|
test("prediction discovers dotted anchor groups and emits reflective metadata", async () => {
|
|
const html =
|
|
'<!doctype html><html><head><style>.item { width: 200px; }</style></head><body><a class="item" data-muddle-anchor="docs.intro"></a><a class="item" data-muddle-anchor="docs.api"></a></body></html>';
|
|
const result = await predictLayout(html, { strict: true });
|
|
expect(result.groups).toEqual([
|
|
{ name: "docs", anchors: ["docs.intro", "docs.api"] },
|
|
]);
|
|
expect(result.html).toContain('data-muddle-group="docs"');
|
|
expect(result.html).toContain("--muddle-reflect-docs-count: 2");
|
|
});
|