Public: anyone can read this; the crew can change it.

The repository page's "Moved from" line is escaped and wraps at 390px, proven by a test and a phone look #10177

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

mason/forge:mason/10156-the-repository-page-s-moved-from-line-is → main 2 commits fork

  • Merged. mason/10156-the-repository-page-s-moved-from-line-is was merged into main as 293a078.

Review

Sign in to review this change.
1 file changed +84 −0
test/moved-from-fit.test.ts added +84
@@ -0,0 +1,84 @@
1 /**
2 * The repository page's "Moved from" line (#10156): an old path holding markup
3 * is escaped, and a long old path wraps instead of widening a 390 px phone.
4 */
5 import { afterAll, beforeAll, describe, expect, test } from "bun:test";
6 import { mkdtemp, rm } from "node:fs/promises";
7 import { tmpdir } from "node:os";
8 import { join } from "node:path";
9 import { createApp, type App } from "../src/app.ts";
10 import { createRepo, type Repo } from "../src/core/repos.ts";
11 import { transferRepo } from "../src/core/transfer.ts";
12 import { createUser } from "../src/core/users.ts";
13 import { serve, type Servers } from "../src/http/server.ts";
14 import { findChromium } from "../src/looks/capture.ts";
15 import { chromiumRuns, evaluateLoaded } from "./helpers/chrome.ts";
16
17 const OLD = `<b>&"/${"n".repeat(200)}`;
18 let dir: string;
19 let app: App;
20 let servers: Servers;
21 let page: string;
22
23 beforeAll(async () => {
24 dir = await mkdtemp(join(tmpdir(), "forge-moved-fit-"));
25 app = createApp({ dataDir: dir, port: 0 });
26 servers = await serve(app);
27 const mk = async (username: string) => {
28 const u = await createUser(app.db, { origin: "seed", trusted: true, username, email: `${username}@forge.local`, password: "a-long-moved-passphrase", adminIfFirst: username === "alice" });
29 if (!u.ok) throw new Error(u.error);
30 return u.value;
31 };
32 const alice = await mk("alice");
33 const lab = await mk("lab");
34 const made = await createRepo(app.db, app.reposRoot, { ownerId: alice.id, name: "demo", visibility: "public" });
35 if (!made.ok) throw new Error(made.error);
36 const moved = await transferRepo(app.db, app.reposRoot, made.value as Repo, lab, alice.id);
37 if (!moved.ok) throw new Error(moved.error);
38 app.db.query("UPDATE repo_transfer SET from_path = ?1 WHERE repo_id = ?2").run(OLD, made.value.id);
39 page = await (await fetch(`${servers.url}/lab/demo`)).text();
40 }, 30_000);
41
42 afterAll(async () => {
43 servers.stop();
44 app.close();
45 await rm(dir, { recursive: true, force: true });
46 });
47
48 describe("the moved-from line", () => {
49 test("an old path holding markup is escaped in the line", () => {
50 const line = page.match(/<p class="muted small moved-from">[\s\S]*?<\/p>/)?.[0] ?? "";
51 expect(line).toContain("Moved from &lt;b&gt;&amp;&quot;/nnnn");
52 expect(line).not.toContain("<b>");
53 expect(page).not.toContain("<b>&");
54 });
55
56 test("the line is server-rendered, plain, and carries no inline style", () => {
57 expect(page).toMatch(/<p class="muted small moved-from">Moved from /);
58 expect(page).not.toMatch(/<p class="muted small moved-from"[^>]*style=/);
59 });
60 });
61
62 /** Measured in a real Chromium at 390x844; skipped where none starts (the forge's check runs it). */
63 const found = findChromium();
64 const chromium = found !== undefined && chromiumRuns(found) ? found : undefined;
65 if (chromium === undefined) console.log("SKIPPING: no chromium that starts here, so the moved-from phone look is not measured");
66
67 describe.skipIf(chromium === undefined)("the moved-from line, measured at 390x844", () => {
68 const measure = `(() => {
69 const el = document.querySelector(".moved-from");
70 const r = el ? el.getBoundingClientRect() : { right: -1, height: 0 };
71 return JSON.stringify({
72 scrollWidth: document.documentElement.scrollWidth, innerWidth: window.innerWidth,
73 right: Math.round(r.right), height: Math.round(r.height), lineHeight: parseFloat(getComputedStyle(el).lineHeight),
74 });
75 })()`;
76 test("a long old path wraps: the page does not scroll sideways", async () => {
77 const m = JSON.parse(await evaluateLoaded(chromium!, `${servers.url}/lab/demo`, { width: 390, height: 844 }, [], measure)) as { scrollWidth: number; innerWidth: number; right: number; height: number; lineHeight: number };
78 console.log(`moved-from 390x844: ${JSON.stringify(m)}`);
79 expect(m.right).toBeGreaterThan(0);
80 expect(m.right).toBeLessThanOrEqual(m.innerWidth);
81 expect(m.height).toBeGreaterThan(m.lineHeight * 1.5);
82 expect(m.scrollWidth).toBeLessThanOrEqual(m.innerWidth);
83 }, 30_000);
84 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs