Files
deepseek-harness/examples/desktop/test/renderer-diff-card-fallback.test.js
T

137 lines
5.7 KiB
JavaScript
Raw Normal View History

// Diff-card rendering must survive the wire meta shape today's runtime emits.
//
// # Why this test exists
//
// Two facts about the current runtime (see docs/upstream-ledger.md
// "runtime should emit presented view"):
//
// 1. `agent-loop` persists the tool's raw `execute()` meta verbatim on the
// `tool/result` event. For `fs.edit`, that shape is `{diffs: [...]}` —
// NO `card` field. (packages/fs/tool-fs/src/edit.ts:92-96,
// packages/core/agent-loop/src/loop.ts around the tool/result emit.)
// 2. The tool's `presentResult()` — which WOULD add `card: 'diff'` — is a
// display-time callback the runtime does not invoke. So the renderer
// never sees a `card: 'diff'` for fs.edit on the wire today.
//
// The dispatch at src/renderer/renderer.js:4744 primarily routes by
// `view.card === 'diff'`; without a fallback the diff card is unreachable
// on the shipped default profile — as observed in lane-showcase 12/12 run
// (check 5_diff_card_fs = fail, 2026-07-18).
//
// # What this test locks
//
// - Given the real wire shape (fixture pinned in-repo — see the fixture's
// own header for provenance), driving `tool/call` + `tool/result` through
// the renderer's reducer must produce a `.card-diff` element inside the
// result box.
// - The primary path (`view.card === 'diff'`) still works — a second
// assertion drives the same fs.edit callId but with the `card:'diff'`
// shape a future runtime seam would emit. Both routes render the card.
//
// If the wire shape ever gains a `card` discriminant natively, the fallback
// becomes dead code but this test still passes via the primary branch, so
// there is no rush to prune it.
'use strict'
const test = require('node:test')
const assert = require('node:assert/strict')
const fs = require('node:fs')
const path = require('node:path')
const { loadRenderer } = require('./renderer-harness')
const FIXTURE = JSON.parse(
fs.readFileSync(path.join(__dirname, 'fixtures', 'fs-edit-wire-shape.json'), 'utf8'),
)
// Locate a descendant element by CSS class name. Mirrors the renderer's
// probe hook approach (see docs/renderer-probe.md); the shim in
// renderer-harness.js only supports simple class selectors so we walk
// the tree by hand to be robust across nested structures.
function findByClass(root, className) {
if (!root) return null
const classList = root.classList
if (classList && typeof classList.contains === 'function' && classList.contains(className)) {
return root
}
if (Array.isArray(root.children)) {
for (const child of root.children) {
const hit = findByClass(child, className)
if (hit) return hit
}
}
return null
}
test('diff card renders when the wire meta has {diffs} but no card discriminant (fs family fallback)', async () => {
const { renderer, window, document: doc } = await loadRenderer()
// tool-cards.js is preloaded as a CommonJS module (see renderer-harness.js
// preloadPure). Its `renderDiffCard` reads `document` from the module's
// enclosing scope; when triggered from a Node test rather than inside the
// renderer wrapper, that reference is the global `document`. The
// convention (see tool-cards.test.js) is to set it globally per-test.
global.document = doc
renderer.ensureSession('s1', { title: 's', header: {} })
await renderer.selectSession('s1')
// The real runtime always emits tool/call before tool/result — the
// renderer allocates the resBox on tool/call. Drive that sequence.
renderer.onSessionEvent('s1', FIXTURE.toolCall)
renderer.onSessionEvent('s1', FIXTURE.toolResult)
const meta = renderer.getSessionMeta('s1')
const resBox = meta.toolCalls.get(FIXTURE.toolCall.data.callId)
assert.ok(resBox, 'renderer must allocate a result box on tool/call')
const diffCard = findByClass(resBox, 'card-diff')
assert.ok(
diffCard,
'fs.edit tool/result with {diffs:[...]} (no card field) must still render '
+ 'a .card-diff — see docs/upstream-ledger.md "runtime should emit presented view"',
)
// Sanity: the raw text fallback branch must NOT have swallowed the box.
// If the fallback misfires, resBox.textContent gets the flat text content
// instead of the diff card being appended.
assert.doesNotMatch(
(resBox.textContent || ''),
/Edited \/tmp\/dsh-showcase\/seed-3lines\.txt/,
'fallback text must not fire when the diff card renders',
)
// Reference the window stub so the harness knows it's live — silences
// the lint about the unused destructured var and documents that this
// test intentionally observes DOM state through the shared shim.
assert.ok(window)
})
test('diff card renders on the primary path when the wire ever emits card:"diff" natively', async () => {
const { renderer, document: doc } = await loadRenderer()
global.document = doc
renderer.ensureSession('s1', { title: 's', header: {} })
await renderer.selectSession('s1')
renderer.onSessionEvent('s1', FIXTURE.toolCall)
// Same fixture, but simulate the future-good wire shape by re-wrapping
// the meta with the discriminant a presentResult-emitting runtime would
// author. If the primary branch ever regresses, this catches it before
// the fallback ever runs.
const primaryResult = {
...FIXTURE.toolResult,
data: {
...FIXTURE.toolResult.data,
meta: {
card: 'diff',
title: 'Edit /tmp/dsh-showcase/seed-3lines.txt',
diffs: FIXTURE.toolResult.data.meta.diffs,
},
},
}
renderer.onSessionEvent('s1', primaryResult)
const meta = renderer.getSessionMeta('s1')
const resBox = meta.toolCalls.get(FIXTURE.toolCall.data.callId)
const diffCard = findByClass(resBox, 'card-diff')
assert.ok(diffCard, 'primary card:"diff" dispatch must render .card-diff')
})