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

`.number` leaves the stylesheet: an issue's number in a heading draws from base utilities #5273

Merged opened this

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

Merged

mason/forge:mason/5253-number-leaves-the-stylesheet-an-issue-s → main 6 commits fork 1 thread · 1 unresolved

  • Merged. mason/5253-number-leaves-the-stylesheet-an-issue-s was merged into main as a98fdf4.

Review

Sign in to review this change.
4 files changed +83 −3
src/web/pages/browse.ts +1 −1
@@ -713,7 +713,7 @@ async function browseThread(
713713 const body = html`<div class="page-head">
714714 <h1>
715715 ${detail.issue.title}
716 <span class="number">#${detail.issue.number}</span>
716 <span class="num">#${detail.issue.number}</span>
717717 </h1>
718718 <div class="page-head-sub bar muted small">
719719 ${stateBadge(state)}
src/web/studio/change.ts +1 −1
@@ -193,7 +193,7 @@ export function changeHead(ctx: Ctx, repo: Repo, pull: Pull): Html {
193193 const who = toldBy(ctx.app.db, pull);
194194 const marks = marksByName(ctx.app.db, [pull.authorName, who ?? ""]);
195195 return html`<div class="page-head">
196 <h1>${pull.title} <span class="number">#${pull.number}</span></h1>
196 <h1>${pull.title} <span class="num">#${pull.number}</span></h1>
197197 <div class="page-head-sub bar muted small">
198198 ${stateBadge(
199199 pullState(pull),
src/web/studio/tell.ts +1 −1
@@ -466,7 +466,7 @@ async function studioTell(
466466
467467 const marks = marksByName(db, [issue.authorName, issue.assigneeName ?? ""]);
468468 const head = html`<div class="page-head">
469 <h1>${issue.title} <span class="number">#${issue.number}</span></h1>
469 <h1>${issue.title} <span class="num">#${issue.number}</span></h1>
470470 <div class="page-head-sub bar muted small">
471471 ${direction
472472 ? html`<span class="muted small"
test/number-retired.test.ts added +80
@@ -0,0 +1,80 @@
1 /** An issue's or pull's number in a heading draws from base's `.num`; `.number` left the stylesheet (#5253). */
2 import { afterAll, beforeAll, expect, test } from "bun:test";
3 import { mkdtemp, rm } from "node:fs/promises";
4 import { tmpdir } from "node:os";
5 import { join } from "node:path";
6 import { createApp, type App } from "../src/app.ts";
7 import { createIssue, type Issue } from "../src/core/issues.ts";
8 import type { Pull } from "../src/core/pulls.ts";
9 import { createRepo, type Repo } from "../src/core/repos.ts";
10 import { createUser } from "../src/core/users.ts";
11 import type { Ctx } from "../src/http/context.ts";
12 import { serve, type Servers } from "../src/http/server.ts";
13 import { changeHead } from "../src/web/studio/change.ts";
14 import { css } from "../src/web/style";
outdated

Matching raw source text is brittle: a Prettier reflow or a changed attribute order breaks it. Render one heading and assert on the HTML instead.

15
16 let dataDir: string;
17 let app: App;
18 let servers: Servers;
19 let base: string;
20 let repo: Repo;
21 let opened: Issue;
22
23 beforeAll(async () => {
24 dataDir = await mkdtemp(join(tmpdir(), "forge-num-"));
25 app = createApp({ dataDir, port: 0 });
26 servers = await serve(app);
27 base = servers.url;
28 const user = await createUser(app.db, {
29 origin: "seed",
30 trusted: true,
31 username: "n",
32 email: "[email protected]",
33 password: "numbers-please",
34 });
35 if (!user.ok) throw new Error("user");
36 const made = await createRepo(app.db, app.reposRoot, { ownerId: user.value.id, name: "r", visibility: "public" });
37 if (!made.ok) throw new Error("repo");
38 repo = made.value;
39 for (const kind of ["issue", "pull"] as const) {
40 const made = createIssue(app.db, { repoId: repo.id, authorId: user.value.id, title: `a ${kind}`, kind });
41 if (!made.ok) throw new Error(kind);
42 opened = made.value;
43 }
44 });
45
46 afterAll(async () => {
47 servers.stop();
48 app.close();
49 await rm(dataDir, { recursive: true, force: true });
50 });
51
52 test("the stylesheet no longer contains .number", () => {
53 expect(css).not.toMatch(/\.number\b/);
54 });
55
56 test("the issue heading marks its number with .num", async () => {
57 const page = await (await fetch(`${base}/n/r/issues/1`)).text();
58 expect(page).toMatch(/<h1>a issue\s*<span class="num">#1<\/span><\/h1>/);
59 expect(page).not.toContain('class="number"');
60 });
61
62 test("the pull heading marks its number with .num", () => {
63 const pull: Pull = {
64 ...opened,
65 baseBranch: "main",
66 headBranch: "change",
67 baseOid: "",
68 headOid: "",
69 mergedAt: null,
70 mergedOid: null,
71 headRepoId: repo.id,
72 crossRepo: false,
73 originHeadRepo: null,
74 revertsPullId: null,
75 variantGroup: null,
76 };
77 const head = String(changeHead({ app, auth: { user: undefined, scope: undefined, via: "none" } } as Ctx, repo, pull));
78 expect(head).toContain('<h1>a pull <span class="num">#2</span></h1>');
79 expect(head).not.toContain('class="number"');
80 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs