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

The owner's bets page fits a 390 px phone: no sideways scroll and no proposed bet card taller than the screen #9286

Merged opened this

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

Merged

scout/forge:scout/9275-the-owner-s-bets-page-fits-a-390-px-phon → main 3 commits fork 2 threads · 2 unresolved

  • Merged. scout/9275-the-owner-s-bets-page-fits-a-390-px-phon was merged into main as 8c5bef4.

Review

Sign in to review this change.
2 files changed +30 −1
src/spawn/preview-looks.ts +4
@@ -41,6 +41,9 @@ export const PREVIEW_FORKS: readonly { readonly owner: string; readonly of?: str
4141 { owner: "preview-dee", of: "preview-ada" },
4242 ];
4343
44 /** The owner's bets page, whose seeded proposed bets hold the long-name worst case (#9275). */
45 export const PREVIEW_BETS_PAGE = `${PREVIEW_REPO_HOME}/bets`;
46
4447 /** The Later gate's proposal on the sample (#9212): what the gate holds, grouped by theme. */
4548 export const PREVIEW_HELD_PAGE = `${PREVIEW_REPO_HOME}/held`;
4649 /**
@@ -73,6 +76,7 @@ export const PREVIEW_OWNER_LOOKS: readonly OwnerLook[] = [
7376 PREVIEW_PULL_PAGE,
7477 PREVIEW_ITERATIONS_PAGE,
7578 PREVIEW_HELD_PAGE,
79 PREVIEW_BETS_PAGE,
7680 ].flatMap((page) => (["desktop", "phone"] as const).map((kind) => ({ page, kind })));
7781
7882 /**
test/bets-card-fit.test.ts +26 −1
@@ -11,8 +11,9 @@ import { join } from "node:path";
1111 import { createApp, type App } from "../src/app.ts";
1212 import { serve, type Servers } from "../src/http/server.ts";
1313 import { seedPreview } from "../src/spawn/preview-seed.ts";
14 import { PREVIEW_ADMIN, PREVIEW_REPO } from "../src/spawn/preview-looks.ts";
14 import { PREVIEW_ADMIN, PREVIEW_BETS_PAGE, PREVIEW_REPO, ownerLooksFor } from "../src/spawn/preview-looks.ts";
1515 import { utilities as base } from "../src/web/style/base.ts";
16 import { components } from "../src/web/style/components.ts";
1617 import { content } from "../src/web/style/content.ts";
1718 import { SHOWN_JOURNEYS } from "../src/web/pages/bets.ts";
1819
@@ -21,6 +22,7 @@ let dir: string;
2122 let app: App;
2223 let servers: Servers;
2324 let cards: string[];
25 let page: string;
2426
2527 beforeAll(async () => {
2628 dir = await mkdtemp(join(tmpdir(), "forge-bets-fit-"));
@@ -31,6 +33,7 @@ beforeAll(async () => {
3133 const said = `u1|trevato|admin|${Date.now() + 60_000}`;
3234 const headers = { "x-forge-identity": said, "x-forge-signature": createHmac("sha256", KEY).update(said).digest("base64url") };
3335 const html = await (await fetch(`${servers.url}/${PREVIEW_ADMIN}/${PREVIEW_REPO}/bets`, { headers })).text();
36 page = html;
3437 cards = html.split("<div data-bet-card").slice(1).map((c) => c.slice(0, c.indexOf("Cut it") + 40));
3538 }, 30_000);
3639 afterAll(async () => {
@@ -86,4 +89,26 @@ describe("the owner's bets page, a proposed bet card at rest", () => {
8689 test("long words wrap", () => {
8790 expect(content).toMatch(/\[data-bet-card\][^{]*\{[^}]*overflow-wrap:\s*anywhere/);
8891 });
92
93 test("the long proposed bet is on the page, and no rule or element it ships fixes a width over 390 px (#9275)", () => {
94 expect(page).toContain("Make every long and winding bet name wrap");
outdated

Only HTML attributes and inline styles are scanned. A CSS rule with a fixed width over 390px would pass. Scan the stylesheet the page ships.

95 expect(page).toContain("https://example.com/a/very/long/unbroken/address");
96 for (const m of page.matchAll(/\swidth=["']?(\d+)/gi)) expect(Number(m[1])).toBeLessThanOrEqual(390);
97 // Every stylesheet the layout ships: a width or min-width is a fixed size
outdated

Duplicates the existing 'long words wrap' test above. Remove it and check the page's stylesheet rules for widths over 390px instead.

Allow single quotes too: /\swidth=["']?(\d+)/gi, so width='500' is caught.

98 // (max-width is a cap and shrinks; a "(min-width:" media query is a breakpoint, not a size). px, rem/em at 16 px, ch at 8 px.
99 const over: string[] = [];
100 for (const css of [base, components, content, ...(page.match(/<style[^>]*>[\s\S]*?<\/style>/g) ?? [])]) {
101 for (const m of css.matchAll(/(?<![-\w(])(?:min-)?width\s*:\s*(-?[\d.]+)(px|rem|em|ch)\b/g)) {
102 const px = Number(m[1]) * (m[2] === "px" ? 1 : m[2] === "ch" ? 8 : 16);
103 if (px > 390) over.push(m[0]);
104 }
105 }
106 expect(over).toEqual([]);
107 });
108 });
109
110 test("a forge preview takes the owner's bets page at desk and phone (#9275)", () => {
111 const looks = ownerLooksFor("trevato/forge", { ownerName: "trevato", name: "forge" }, "preview");
112 expect(PREVIEW_BETS_PAGE).toBe("/preview-admin/sample/bets");
113 for (const kind of ["desktop", "phone"] as const) expect(looks).toContainEqual({ page: PREVIEW_BETS_PAGE, kind });
89114 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs