diff --git a/apps/web/tests/diff-context.e2e.ts b/apps/web/tests/diff-context.e2e.ts index 2296ef6552..e032a1dd84 100644 --- a/apps/web/tests/diff-context.e2e.ts +++ b/apps/web/tests/diff-context.e2e.ts @@ -2,12 +2,12 @@ import { readFile } from 'node:fs/promises' import { fileURLToPath } from 'node:url' import { chromium, type Browser, type Page } from 'playwright' -import { afterAll, beforeAll, describe, expect, it } from 'vitest' +import { afterAll, beforeAll, describe, expect, it, onTestFailed } from 'vitest' import { assertFixtureInventory, captureStableAria, compareOrRefreshGolden, - launchWebScaffold, seedSession, webSnapshotMode, type WebScaffold, + launchWebScaffold, seedSession, watchConsole, webSnapshotMode, type WebScaffold, } from './scaffold.ts' -import { expandTurnProcesses, newEnglishPage } from './support.ts' +import { expandTurnProcesses, newEnglishPage, saveFailureShot } from './support.ts' const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/diff-context', import.meta.url)) const SOURCE = fileURLToPath(new URL('../../../snapshots/session/fs-edit/session.v3.jsonl', import.meta.url)) @@ -17,12 +17,14 @@ describe.skipIf(MODE === 'record')('web e2e: contextual edit diff', () => { let scaffold: WebScaffold let browser: Browser let page: Page + let tripwire: ReturnType beforeAll(async () => { scaffold = await launchWebScaffold({}) await seedSession(scaffold, await readFile(SOURCE, 'utf8'), 'diff-context') browser = await chromium.launch() page = await newEnglishPage(browser) + tripwire = watchConsole(page) await page.goto(scaffold.authenticatedUrl, { waitUntil: 'load' }) }) @@ -35,6 +37,7 @@ describe.skipIf(MODE === 'record')('web e2e: contextual edit diff', () => { }) it('shows true totals before expansion and neutral shared context after expansion', async () => { + onTestFailed(() => saveFailureShot(page, 'web-e2e-diff-context')) const group = page.locator('[role="treeitem"]').first() await group.waitFor({ timeout: 15_000 }) await group.click() @@ -52,5 +55,7 @@ describe.skipIf(MODE === 'record')('web e2e: contextual edit diff', () => { await compareOrRefreshGolden(`${SNAPSHOT_DIR}/ui.expected.md`, await captureStableAria(page, '[data-variant="edit"]', scaffold.workspaceCwd), MODE) await assertFixtureInventory(SNAPSHOT_DIR, ['ui.expected.md']) + expect(tripwire.pageErrors).toEqual([]) + expect(tripwire.warnings).toEqual([]) }) }) diff --git a/packages/client/ui-primitives/src/DiffBlock.tsx b/packages/client/ui-primitives/src/DiffBlock.tsx index af701db0c8..821e16ab6d 100644 --- a/packages/client/ui-primitives/src/DiffBlock.tsx +++ b/packages/client/ui-primitives/src/DiffBlock.tsx @@ -92,12 +92,9 @@ export function diffTotals(diffs: DiffHunk[]): { added: number; removed: number } /** - * Flatten the hunks into the body's rows plus the footer counts. A path header - * opens each new file; a same-file second hunk (a scattered edit) opens with a - * `⋯` gap instead of repeating the path. The +/- totals are - * {@link diffTotals}'s. The file count is of DISTINCT paths, matching the TUI - * diff card's footer, so two hunks in one file read as `1 file` on both front - * ends. + * Flatten local patches into rows and count only added and removed lines. + * A path header opens each new file. A `⋯` gap separates consecutive same-file + * fragments and distant patches within a fragment. File counts use distinct paths. * @param diffs - the hunks to render. * @returns the body rows, the +/- totals, and the distinct-file count. */ @@ -142,9 +139,8 @@ function contentLines(text: string): string[] { } /** - * The diff text a reader copies: each row's `-`/`+`/path/gap prefix and its - * content, exactly what the card shows. The removed and added blocks are the - * change; the path headers keep a multi-file copy attributable. + * Copy the full local diff, including folded rows: removed/added lines have + * `- `/`+ ` prefixes, context has two spaces, and paths and gaps stay verbatim. * @param rows - the flattened body rows. * @returns the diff as plain text. */