Something went wrong. Try again.
Node.js & Bun bindings for Zed’s GPUI. Build memory efficient native apps with React or Solid.js
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360/** * Visual tests for the GPUIX diff viewer example. * * Uses the native GPUI test renderer (real Metal rendering on macOS) to * validate diff rendering end-to-end: React → Rust RetainedTree → GpuixView → * GPUI layout → Metal → screenshot. * * Each test renders a diff, takes a screenshot, and verifies text content. * Screenshots are saved to `examples/screenshots/` for manual inspection. * * @ts-nocheck */
import fs from "fs"import path from "path"import { fileURLToPath } from "url"import { describe, it, expect, beforeEach } from "vitest"import React from "react"import { createTestRoot, hasNativeTestRenderer, type TestRoot } from "@gpuix/react/testing"import type { StructuredPatchHunk as Hunk } from "diff"import { DiffViewer } from "./diff"
const describeNative = hasNativeTestRenderer ? describe : describe.skip
// Not `/tmp`: that path does not exist on Windows, and native never creates// the parent directory, so every capture failed the test there.const SCREENSHOT_DIR = path.resolve( path.dirname(fileURLToPath(import.meta.url)), "screenshots",)fs.mkdirSync(SCREENSHOT_DIR, { recursive: true })
// Background for the scroll container — matches the diff viewer's unchanged line bg// so the area below content doesn't look different.const DIFF_BG = "rgba(15, 15, 15, 1)"
// ── Test fixtures ────────────────────────────────────────────────────
const simpleHunks: Hunk[] = [ { oldStart: 1, oldLines: 4, newStart: 1, newLines: 4, lines: [ " const x = 1;", "-const y = 2;", "+const y = 3;", " const z = x + y;", ], },]
const multiHunkPatch: Hunk[] = [ { oldStart: 1, oldLines: 5, newStart: 1, newLines: 7, lines: [ " import React from 'react'", " import { useState } from 'react'", " ", "-function Counter({ initial }: { initial: number }) {", "- const [count, setCount] = useState(initial)", "+interface CounterProps {", "+ initial: number", "+ step?: number", "+}", "+", "+function Counter({ initial, step = 1 }: CounterProps) {", "+ const [count, setCount] = useState(initial)", ], }, { oldStart: 10, oldLines: 4, newStart: 12, newLines: 6, lines: [ " <span>{count}</span>", "- <button onClick={() => setCount(c => c + 1)}>+</button>", "- <button onClick={() => setCount(c => c - 1)}>-</button>", "+ <button onClick={() => setCount(c => c + step)}>", "+ Increment by {step}", "+ </button>", "+ <button onClick={() => setCount(c => c - step)}>", "+ Decrement by {step}", "+ </button>", " </div>", ], },]
const longHunk: Hunk[] = [ { oldStart: 1, oldLines: 30, newStart: 1, newLines: 32, lines: [ " // Line 1: imports", " import fs from 'fs'", " import path from 'path'", " ", "-const VERSION = '1.0.0'", "+const VERSION = '2.0.0'", " ", " function readFile(name: string) {", " const full = path.join(__dirname, name)", " return fs.readFileSync(full, 'utf-8')", " }", " ", " function writeFile(name: string, data: string) {", "- fs.writeFileSync(name, data)", "+ const full = path.join(__dirname, name)", "+ fs.writeFileSync(full, data, 'utf-8')", " }", " ", " function processAll() {", " const files = fs.readdirSync('.')", " for (const file of files) {", " const content = readFile(file)", "- console.log(file, content.length)", "+ const processed = content.trim()", "+ console.log(file, processed.length)", " }", " }", " ", " export { readFile, writeFile, processAll }", " export default { VERSION }", ], },]
// ── Tests ────────────────────────────────────────────────────────────
describeNative("diff viewer", () => { let testRoot: TestRoot
beforeEach(() => { testRoot = createTestRoot() })
describe("unified view", () => { it("renders a simple unified diff with syntax highlighting", () => { function UnifiedSimple() { return ( <div style={{ width: "100%", height: "100%", backgroundColor: DIFF_BG, overflow: "scroll", }} > <DiffViewer hunks={simpleHunks} filePath="test.ts" splitView={false} /> </div> ) }
testRoot.render(<UnifiedSimple />)
// Verify key text content is present const allText = testRoot.renderer.getAllText() // Line numbers and code should be present expect(allText.some((t) => t.includes("const"))).toBe(true)
const path = `${SCREENSHOT_DIR}/gpuix-diff-unified-simple.png` if (fs.existsSync(path)) fs.unlinkSync(path) testRoot.renderer.captureScreenshot(path) expect(fs.existsSync(path)).toBe(true) expect(fs.statSync(path).size).toBeGreaterThan(0) })
it("renders multi-hunk diff with hunk separators", () => { function UnifiedMultiHunk() { return ( <div style={{ width: "100%", height: "100%", backgroundColor: DIFF_BG, overflow: "scroll", }} > <DiffViewer hunks={multiHunkPatch} filePath="counter.tsx" splitView={false} /> </div> ) }
testRoot.render(<UnifiedMultiHunk />)
const allText = testRoot.renderer.getAllText() // Should contain both hunks' content expect(allText.some((t) => t.includes("import"))).toBe(true) expect(allText.some((t) => t.includes("button"))).toBe(true) // Should have hunk separator expect(allText.some((t) => t.includes("..."))).toBe(true)
const path = `${SCREENSHOT_DIR}/gpuix-diff-unified-multi.png` if (fs.existsSync(path)) fs.unlinkSync(path) testRoot.renderer.captureScreenshot(path) expect(fs.existsSync(path)).toBe(true) expect(fs.statSync(path).size).toBeGreaterThan(0) }) })
describe("split view", () => { it("renders split diff with left/right panes", () => { function SplitSimple() { return ( <div style={{ width: "100%", height: "100%", backgroundColor: DIFF_BG, overflow: "scroll", }} > <DiffViewer hunks={simpleHunks} filePath="test.ts" splitView={true} /> </div> ) }
testRoot.render(<SplitSimple />)
const allText = testRoot.renderer.getAllText() expect(allText.some((t) => t.includes("const"))).toBe(true)
const path = `${SCREENSHOT_DIR}/gpuix-diff-split-simple.png` if (fs.existsSync(path)) fs.unlinkSync(path) testRoot.renderer.captureScreenshot(path) expect(fs.existsSync(path)).toBe(true) expect(fs.statSync(path).size).toBeGreaterThan(0) })
it("renders multi-hunk split diff", () => { function SplitMultiHunk() { return ( <div style={{ width: "100%", height: "100%", backgroundColor: DIFF_BG, overflow: "scroll", }} > <DiffViewer hunks={multiHunkPatch} filePath="counter.tsx" splitView={true} /> </div> ) }
testRoot.render(<SplitMultiHunk />)
const path = `${SCREENSHOT_DIR}/gpuix-diff-split-multi.png` if (fs.existsSync(path)) fs.unlinkSync(path) testRoot.renderer.captureScreenshot(path) expect(fs.existsSync(path)).toBe(true) expect(fs.statSync(path).size).toBeGreaterThan(0) }) })
describe("scrolling", () => { it("scrolls through a long diff and produces different screenshots", () => { function LongDiff() { // Constrained height so content overflows and scrolling is needed. // Full width fills the canvas, but short height forces scroll. return ( <div style={{ width: "100%", height: 300, backgroundColor: DIFF_BG, overflow: "scroll", }} > <DiffViewer hunks={longHunk} filePath="utils.ts" splitView={false} /> </div> ) }
testRoot.render(<LongDiff />)
const pathBefore = `${SCREENSHOT_DIR}/gpuix-diff-scroll-before.png` const pathAfter = `${SCREENSHOT_DIR}/gpuix-diff-scroll-after.png` if (fs.existsSync(pathBefore)) fs.unlinkSync(pathBefore) if (fs.existsSync(pathAfter)) fs.unlinkSync(pathAfter)
// Screenshot before scrolling testRoot.renderer.captureScreenshot(pathBefore)
// Scroll down 200px inside the container testRoot.renderer.nativeSimulateScrollWheel(450, 150, 0, -200)
// Screenshot after scrolling testRoot.renderer.captureScreenshot(pathAfter)
// Both should exist with content expect(fs.existsSync(pathBefore)).toBe(true) expect(fs.existsSync(pathAfter)).toBe(true) expect(fs.statSync(pathBefore).size).toBeGreaterThan(0) expect(fs.statSync(pathAfter).size).toBeGreaterThan(0)
// Before and after scroll should produce different pixels expect( fs.readFileSync(pathBefore).equals(fs.readFileSync(pathAfter)), ).toBe(false) }) })
describe("empty state", () => { it("renders 'No changes' for empty hunks", () => { function EmptyDiff() { return ( <div style={{ width: "100%", height: "100%", backgroundColor: DIFF_BG, }} > <DiffViewer hunks={[]} filePath="empty.ts" /> </div> ) }
testRoot.render(<EmptyDiff />)
const allText = testRoot.renderer.getAllText() expect(allText.some((t) => t.includes("No changes"))).toBe(true)
const path = `${SCREENSHOT_DIR}/gpuix-diff-empty.png` if (fs.existsSync(path)) fs.unlinkSync(path) testRoot.renderer.captureScreenshot(path) expect(fs.existsSync(path)).toBe(true) }) })})