commit 63b897e283b16ad2cfa14392b43d43583555cc73
parent 9149b013eb1d32e4d5ed413b1480a0411fe5571b
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Wed, 30 Sep 2026 23:22:22 -0400
umtool e2e: timeline-row locators name the timeline, not every [data-entry]
The On-screen section (deck S5) marks its table rows with data-entry, one per
timeline entry, on the same report page as the timeline. An unscoped
[data-entry=<id>] now resolves two elements: a strict-mode violation for
every per-row assertion and a doubled count in projects.spec. The timeline's
rows carry data-kind and the table's do not, so the locators add [data-kind].
No assertion changed what it checks.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
3 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/umtool/e2e/clip-bench.spec.ts b/umtool/e2e/clip-bench.spec.ts
@@ -271,7 +271,7 @@ test("a bench save shows up on the project page", async ({ page, request }) => {
});
await page.goto(`/browse/${PROJECT}`);
- const row = page.locator("[data-entry=c01]");
+ const row = page.locator("[data-entry=c01][data-kind]");
await expect(row).toContainText("end pinned");
// lockEnd is the acknowledgement, so the row's warning goes with it.
await expect(row).toHaveAttribute("data-mid-sentence", "0");
@@ -404,9 +404,9 @@ test("`ready N of M` counts the fetched clips that still need judgement", async
await page.goto(`/browse/${WALK}`);
await expect(page.locator("[data-ready-count]")).toHaveText("ready 2 of 3 needing judgement");
// The pill is the same question the walk asks, per row.
- await expect(page.locator("[data-entry=w02]")).toHaveAttribute("data-fetched", "0");
- await expect(page.locator("[data-entry=w02]")).toContainText("not fetched yet");
- await expect(page.locator("[data-entry=w01]")).toHaveAttribute("data-fetched", "1");
+ await expect(page.locator("[data-entry=w02][data-kind]")).toHaveAttribute("data-fetched", "0");
+ await expect(page.locator("[data-entry=w02][data-kind]")).toContainText("not fetched yet");
+ await expect(page.locator("[data-entry=w01][data-kind]")).toHaveAttribute("data-fetched", "1");
// And the walk starts where the walk actually goes.
await expect(page.locator("[data-walk-start=w01]")).toHaveAttribute(
"href",
diff --git a/umtool/e2e/projects.spec.ts b/umtool/e2e/projects.spec.ts
@@ -490,14 +490,19 @@ test("a timeline entry of an unknown type renders, rather than crashing the page
const res = await page.goto("/browse/reports/report-fixture");
expect(res?.status()).toBe(200);
- await expect(page.locator("[data-entry=z01]")).toHaveAttribute("data-kind", "zz-unknown");
- await expect(page.locator("[data-entry=z01]")).toContainText("An entry type from the future");
- await expect(page.locator("[data-entry=k01]")).toHaveAttribute("data-kind", "card");
+ // The TIMELINE's entries, which carry a kind. The On-screen section's table
+ // marks its rows with data-entry too (one per entry, any type), so an
+ // unscoped [data-entry] counts every entry twice.
+ const entry = (id?: string) => page.locator(id ? `[data-entry=${id}][data-kind]` : "[data-entry][data-kind]");
+
+ await expect(entry("z01")).toHaveAttribute("data-kind", "zz-unknown");
+ await expect(entry("z01")).toContainText("An entry type from the future");
+ await expect(entry("k01")).toHaveAttribute("data-kind", "card");
// And it is COUNTED, not silently dropped: a card saying "4 clips ยท 1 card"
// about a 6-entry timeline would be lying by omission.
- await expect(page.locator("[data-entry]")).toHaveCount(6);
- await expect(page.locator("[data-entry=c01]")).toHaveAttribute("data-kind", "clip");
+ await expect(entry()).toHaveCount(6);
+ await expect(entry("c01")).toHaveAttribute("data-kind", "clip");
});
// The brand preset (report-to-video/brand.mjs, `render.brand`) is offered where
diff --git a/umtool/e2e/report-fetch-via-editor.spec.ts b/umtool/e2e/report-fetch-via-editor.spec.ts
@@ -130,7 +130,7 @@ test("the fetch route asks the editor, carries the provenance, and runs no yt-dl
// The page reads the corpus window as cached, so the walk stops skipping it.
await page.goto(`/browse/${PROJECT}`);
- await expect(page.locator('[data-entry="e01"]')).toHaveAttribute(
+ await expect(page.locator('[data-entry="e01"][data-kind]')).toHaveAttribute(
"data-fetched",
"1",
);
@@ -181,7 +181,7 @@ test("the project page fetches the unfetched clips one at a time, and Stop halts
// bytes in the corpus instead of in one project's out/.
await page.reload();
await expect(page.locator("[data-ready-count]")).toContainText("ready 2 of 2");
- await expect(page.locator('[data-entry="f02"]')).toHaveAttribute(
+ await expect(page.locator('[data-entry="f02"][data-kind]')).toHaveAttribute(
"data-fetched",
"1",
);