Visual testing for CLI/TUI applications. Like Playwright, but for terminals.
import { Terminal } from 'tui-driver'
let term = await Terminal.launch({ cols: 100, rows: 35 })
await term.type('vizzly --help')
await term.press('Enter')
await term.waitForStable()
await term.screenshot({ name: 'vizzly-help' })
await term.close()npm install tui-driverFor the pty driver (pure JS, works everywhere):
npm install tui-driver node-pty @xterm/headless canvasFor the x11 driver (Linux, CI-friendly):
apt-get install xvfb xterm xdotool x11-apps imagemagickCreate tui-driver.config.js:
import { defineConfig } from 'tui-driver'
export default defineConfig({
driver: 'pty', // or 'x11'
cols: 80,
rows: 24,
screenshotDir: '.tui-driver/screenshots'
})Launch a terminal session.
let term = await Terminal.launch({
cols: 100, // Terminal width
rows: 35, // Terminal height
cwd: '/app', // Working directory
env: { ... } // Environment variables
})Type text into the terminal.
await term.type('npm test')Press a key or key combination.
await term.press('Enter')
await term.press('ctrl+c')
await term.press('F1')Wait for terminal output to stop changing.
await term.waitForStable()
await term.waitForStable({ timeout: 5000 })Wait for specific text to appear.
await term.waitForText('Build complete')Capture a screenshot.
// Save to specific path
await term.screenshot({ path: './screenshots/output.png' })
// Save with name (to screenshotDir)
await term.screenshot({ name: 'my-screenshot' })
// Get buffer
let buffer = await term.screenshot()Close the terminal session.
await term.close()Pure JavaScript driver using node-pty and @xterm/headless. Works on all platforms.
Dependencies: node-pty, @xterm/headless, canvas
Linux driver using Xvfb and xterm. Great for CI environments.
System dependencies: xvfb, xterm, xdotool, imagemagick
tui-driver produces PNG screenshots. Vizzly compares them.
// tests/cli-visual.test.js
import { test } from 'node:test'
import { Terminal } from 'tui-driver'
test('help renders correctly', async () => {
let term = await Terminal.launch()
await term.type('myapp --help')
await term.press('Enter')
await term.waitForStable()
await term.screenshot({ name: 'help' })
await term.close()
})Run with Vizzly:
vizzly tdd run "node --test tests/cli-visual.test.js"MIT