test(opencode/run): skip Windows-only scrollback replay failure (#28261)

This commit is contained in:
Kit Langton
2026-05-19 11:24:23 -04:00
committed by GitHub
parent eec0843ce4
commit b67f5d741f

View File

@@ -403,38 +403,82 @@ test("inserts spacers for new visible groups", async () => {
}
})
test("renders replayed user, reasoning, and assistant output after completion", async () => {
const out = await setup()
// TODO(windows): Re-enable on Windows once the streaming CodeRenderable
// flush race is fixed. The reasoning commit is delivered as a `<code>`
// renderable with `filetype="markdown"`, `streaming=true`, and
// `drawUnstyledText=false`. On Windows the first paragraph of the reasoning
// body (here `_Thinking:_ **Plan**`) is dropped from the committed rows —
// the failing assertion shows only `Say hello.` survives, while Linux
// (where `useThread` is forced off in `@opentui/core/testing`) and macOS
// both pass.
//
// Investigation summary (see PR description for the link to this work):
// 1. `reasoning("Thinking: ...", "progress")` enters `entry.body.ts`
// `reasoningBody`, which becomes a `code` body with filetype="markdown".
// 2. `RunScrollbackStream.writeStreaming` sets `renderable.content = ...`
// while `streaming=true`. `CodeRenderable.set content` short-circuits
// (does NOT call `textBuffer.setText`) when streaming, drawUnstyledText
// is false, and a filetype is set — it relies on the next
// `startHighlight()` cycle to populate the buffer.
// 3. `ScrollbackSurface.settle()` renders the surface, kicks the
// highlight via `renderSelf` → `startHighlight`, waits on
// `highlightingDone`, and re-renders. With `MockTreeSitterClient`
// returning `{highlights: []}`, the final branch (`else
// this.textBuffer.setText(content)`) populates the buffer and
// `_shouldRenderTextBuffer = true`.
// 4. `flushActive` then commits rows `[0, surface.height - 1)` during
// streaming. On Windows the committed rows are blank for the first
// paragraph — suggesting the height/text-buffer state is observed
// before/after the highlight resolution in a way that drops rows on
// that platform.
//
// The Linux pass path takes `useThread = false` (see
// `@opentui/core/testing.js` line ~540) which serializes the FFI render
// thread. macOS passes despite `useThread = true`, so the divergence is
// likely either Bun's microtask scheduling on Windows or a Zig-side
// threading interaction during the second `renderSurface()` pass in
// `settleSurface`. A real fix probably belongs in opentui (either force
// `useThread=false` for testing on Windows, or eagerly call
// `textBuffer.setText` in `CodeRenderable.set content` when streaming
// updates a non-empty body).
//
// Skipping on win32 unblocks unrelated PRs; the assertion is still
// exercised on Linux and macOS in CI.
test.skipIf(process.platform === "win32")(
"renders replayed user, reasoning, and assistant output after completion",
async () => {
const out = await setup()
try {
const lines: string[] = []
const take = () => {
const commits = claim(out.renderer)
try {
lines.push(...commits.flatMap((commit) => renderRows(commit).flatMap((row) => row.split("\n"))))
} finally {
destroy(commits)
try {
const lines: string[] = []
const take = () => {
const commits = claim(out.renderer)
try {
lines.push(...commits.flatMap((commit) => renderRows(commit).flatMap((row) => row.split("\n"))))
} finally {
destroy(commits)
}
}
await out.scrollback.append(user("Hello you"))
take()
await out.scrollback.append(reasoning("Thinking: **Plan**\n\nSay hello.", "progress"))
await out.scrollback.complete()
take()
await out.scrollback.append(assistant("Hello.", "progress"))
await out.scrollback.complete()
take()
const output = lines.join("\n")
expect(output).toContain(" Hello you")
expect(output).toContain("Thinking:")
expect(output).toContain("Plan")
expect(output).toContain("Hello.")
} finally {
out.scrollback.destroy()
}
await out.scrollback.append(user("Hello you"))
take()
await out.scrollback.append(reasoning("Thinking: **Plan**\n\nSay hello.", "progress"))
await out.scrollback.complete()
take()
await out.scrollback.append(assistant("Hello.", "progress"))
await out.scrollback.complete()
take()
const output = lines.join("\n")
expect(output).toContain(" Hello you")
expect(output).toContain("Thinking:")
expect(output).toContain("Plan")
expect(output).toContain("Hello.")
} finally {
out.scrollback.destroy()
}
})
},
)
test("coalesces same-line tool progress into one snapshot", async () => {
const out = await setup()