Skip to content

Testing

Kangentic uses a three-tier testing strategy. Each tier targets a different layer of the application, and each has its own tradeoffs between speed, coverage, and realism.

The four test tiers and the captures project, from pure logic to a real Electron window.

Terminal window
npm run test:unit
  • Runner: Vitest
  • Speed: Sub-second
  • What to test: Pure logic - parsers, filters, state machines, utility functions
  • No build needed, no browser, no Electron

Unit tests live in tests/unit/. They’re fast and focused - test a function’s input/output without any framework overhead.

There is also an opt-in integration tier in tests/integration/. Those tests hit real CLIs, the file system, or the network, so while vitest.config.ts includes them, npm run test:unit pins the tests/unit path and skips them. Run them on demand with npx vitest run tests/integration/.

Terminal window
npx playwright test --project=ui
  • Runner: Playwright with headless Chromium
  • Speed: Fast - hundreds of tests run headless in parallel
  • What to test: React components, forms, dialogs, drag-and-drop, board interactions
  • No build needed - runs against the Vite dev server (auto-started by Playwright)

UI tests live in tests/ui/. They use a full in-memory mock of window.electronAPI (injected via addInitScript()) that supports complete CRUD for projects, tasks, swimlanes, automations, sessions, config, and attachments.

Use window.__mockPreConfigure(fn) to set up mock state before React mounts.

Terminal window
npm run build
npx playwright test --project=electron
  • Runner: Playwright with _electron.launch()
  • Speed: Slower - opens real windows (no headless mode on Windows)
  • What to test: PTY sessions, terminal rendering, session lifecycle, shell detection, config persistence
  • Build required before running

E2E tests live in tests/e2e/. These exercise the full Electron application with real IPC, real file I/O, and real terminal sessions.

Terminal window
npm run build:demo
npm run test:demo

Playwright’s config also declares a demo project (tests/demo/), the fourth alongside ui, electron, and captures, since v0.42.0. It is a small smoke tier for the static web build of the renderer that the website embeds: npm run build:demo writes dist/demo/, and the spec serves that folder itself on an ephemeral port and loads it in headless Chromium at the site frame’s 1600x1000 viewport, one worker, a handful of page loads. It has no entry in the shared webServer block on purpose, so a missing demo build surfaces as one named error rather than breaking the UI tier. CI runs it as its own always-on job, Web demo (build + smoke).

Terminal window
npm run capture

Playwright also declares a captures project (tests/captures/, *.capture.ts files). It is not a test tier: it produces screenshots and screen recordings of staged app states for marketing and documentation. npm run capture builds the web demo first; the scene captures render against that static build, while the walkthrough and orchestration captures drive the same mocked renderer as the UI tier through the Vite dev server. Run it on demand.

What you’re testingTier
Pure function, parser, utilityUnit
Component rendering, user interaction, form validationUI
Real IPC, PTY spawning, terminal output, file I/OE2E
Terminal window
npm run test:unit # Unit tests (Vitest)
npx playwright test --project=ui --project=electron # UI + E2E tests (Playwright)

Every push to main and every pull request runs the full suite on GitHub Actions. Lint, type check, and a production build run as three independently reported steps of one Lint, Typecheck, Build job, so a failing lint step never hides a type error. The web demo builds and smokes in its own job. The three test tiers run as sharded matrices on Linux (Node 24 since v0.44.0), each behind a thin gate job that is the required status check:

TierWhere it runs in CIShards
Unit (Vitest)Linux3
UI (Playwright, headless Chromium)Linux11
E2E (Electron)Linux under xvfb5

The UI tier is the critical path: every other job finishes in about two minutes while the slowest UI shard runs closer to four, which is why it has the most shards. Playwright balances shards by test count, not by cost, so splitting a heavy spec file does not move it.

The E2E tier runs only on Linux in CI. The suite is platform-neutral, so Linux covers the macOS and Linux users while the team dogfoods the Windows build locally. On CI each E2E shard runs at workers=8; any local (non-CI) run, on every OS, pins the E2E project to workers=1 - Windows cannot run concurrent electron.launch(), and a local run on any platform should not spawn a swarm of app windows - so a local E2E run is serial and opens real windows.

Kangentic is free and open source. A star helps other people find it.

Star on GitHub