1
0
Эх сурвалжийг харах

test(web): scope the aria age normalizer to the region that needs it

Collapsing every relative-time bucket to `{{age}}` reached the session-tree
goldens, where a literal age is the assertion: a fresh row reads `now` and an
older one does not. Six e2e files failed, two of them by aborting mid-scenario
and leaving their replay fixtures half-consumed.

`captureStableAria` now takes the rule as an opt-in, and only the reference
menu — whose rows are dated from the live Host list — asks for it.

Refs #3154
Yichen Jiang 1 сар өмнө
parent
commit
db14361372

+ 5 - 1
apps/web/tests/reference-composer.e2e.ts

@@ -147,7 +147,11 @@ describe.skipIf(MODE === 'record')('web e2e: file and session references through
 
     await input.fill('@')
     await expect.poll(() => menu.getByRole('option').count(), { timeout: 15_000 }).toBeGreaterThanOrEqual(2)
-    const snapshot = await captureStableAria(page, '[role="listbox"]', scaffold.workspaceCwd)
+    // Session rows are dated from the live Host list, so their age bucket
+    // advances while the suite runs.
+    const snapshot = await captureStableAria(
+      page, '[role="listbox"]', scaffold.workspaceCwd, { normalizeAge: true },
+    )
     await compareOrRefreshGolden(MENU_EXPECTED, snapshot, MODE)
     expect(snapshot).toContain('Files & folders')
     expect(snapshot).toContain('Sessions')

+ 25 - 13
apps/web/tests/scaffold.ts

@@ -1094,22 +1094,26 @@ async function persistSeedSession(
  * on one machine (measured 69 → 70 tok/s) and swings wildly on a fast replay
  * (26333 tok/s for a 3 ms stream).
  */
-function normalizeAria(snapshot: string, workspaceCwd: string): string {
+/**
+ * Relative-time buckets rendered by a dated row, in both dictionaries.
+ *
+ * Opt-in per capture: a session-tree golden asserts its own literal age (a
+ * fresh row reads `now`, an older one does not), so collapsing the vocabulary
+ * everywhere would delete that assertion. A region whose rows are dated from
+ * live wall-clock state asks for it instead. Anchored on an aria label's
+ * closing quote, where the bucket is always last.
+ */
+const ARIA_AGE =
+  /(?:now|\d+min|\d+h|\d+d|\d+mo|\d+y|刚刚|\d+分钟|\d+小时|\d+天|\d+个月|\d+年)(?=")/g
+
+function normalizeAria(snapshot: string, workspaceCwd: string, age: boolean): string {
   // The session heading renders the workspace's basename, not the full
   // path, so both spellings must collapse to the token.
   const base = workspaceCwd.split('/').pop()!
-  return snapshot
+  return (age ? snapshot.replace(ARIA_AGE, '{{age}}') : snapshot)
     .split(workspaceCwd).join('{{cwd}}')
     .split(base).join('{{workspace}}')
     .replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, '{{uuid}}')
-    // Rows dating a session render the shared relative-time bucket, which
-    // advances while the suite runs. Anchored on an aria label's closing
-    // quote, where the bucket is always last, and applied before the duration
-    // rules so the whole vocabulary collapses to one token.
-    .replace(
-      /(?:now|\d+min|\d+h|\d+d|\d+mo|\d+y|刚刚|\d+分钟|\d+小时|\d+天|\d+个月|\d+年)(?=")/g,
-      '{{age}}',
-    )
     // The optional space in `\d+m ?\d+s` covers both minute spellings: the
     // stats line's compact `2m42s` and the message-chrome template's `2m 42s`.
     .replace(
@@ -1141,13 +1145,21 @@ function normalizeAria(snapshot: string, workspaceCwd: string): string {
  * @param page - the page under test.
  * @param selector - the region locator selector.
  * @param workspaceCwd - normalization input.
+ * @param options - `normalizeAge` collapses relative-time buckets to `{{age}}`
+ *   for a region whose rows are dated from live wall-clock state.
  * @returns the stable normalized snapshot.
  */
-export async function captureStableAria(page: Page, selector: string, workspaceCwd: string): Promise<string> {
+export async function captureStableAria(
+  page: Page,
+  selector: string,
+  workspaceCwd: string,
+  options: { normalizeAge?: boolean } = {},
+): Promise<string> {
   const region = page.locator(selector).first()
-  let previous = normalizeAria(await region.ariaSnapshot(), workspaceCwd)
+  const age = options.normalizeAge === true
+  let previous = normalizeAria(await region.ariaSnapshot(), workspaceCwd, age)
   await expect.poll(async () => {
-    const current = normalizeAria(await region.ariaSnapshot(), workspaceCwd)
+    const current = normalizeAria(await region.ariaSnapshot(), workspaceCwd, age)
     const stable = current === previous
     previous = current
     return stable