Skip to main content

Getting started

SPART-Desk automates Windows desktop applications from TypeScript: lazy locators, strict mode, auto-waiting actions and retrying assertions, through the accessibility tree first and the screen where a locator asks for it. This page takes a new user from installation to a first script. The Windows backend is SPART-Desk's own helper executable, which ships inside the package, behind SPART-Desk's own abstractions (backend-windows.md).

1. Install​

npm install @spartaficial/spart-desk
npx spart-desk init # spart-desk.config.ts + an example test (asks first; --yes takes the defaults)
npx spart-desk doctor # what this machine can do, capability by capability

init writes spart-desk.config.ts, the project's defaults (runtime, timeouts, expect.timeout, where failure screenshots go) and an example test for Vitest or node:test. Nothing has to be installed beside the package: the Windows backend ships inside it, and reading text off the screen and matching a picture are the engine's own work (see resolution.md); doctor says whether the helper runs on this machine. Requirements: Node.js 24+, Windows 10 1809 or later, Windows 11, or Windows Server 2025 (Desktop Experience) for running automation (the package installs and type-checks anywhere). Offline machines: distribution.md.

2. First script​

import { Desktop, expectDesk } from "@spartaficial/spart-desk";

await using desktop = await Desktop.create(); // reads spart-desk.config.ts; options passed here win over it
const app = await desktop.launch({ executable: "C:\\Windows\\System32\\charmap.exe" });
const main = app.window();

await main.getByLabel("Characters to copy").fill("Hello");
await main.getByRole("checkbox", { name: "Advanced view" }).click();
await expectDesk(main.getByLabel("Characters to copy")).toHaveValue("Hello");
const text = await expectDesk.poll(() => main.getByLabel("Characters to copy").textContent()).toContain("Hello"); // poll returns the value

console.log(desktop.actions.records.map((r) => `${r.action} via ${r.strategy}`));
// fill via uia.set-value, click via uia.invoke, expect.toHaveValue via observe

What happened:

  • Desktop.create read spart-desk.config.ts from the working directory (without one, or with Desktop.create({ timeout: 10_000 }), the options apply directly) and chose the local runtime and the Windows backend (the helper).
  • launch started the process and waited for its first window.
  • Every locator is lazy: getByLabel(...) describes a control; only fill() resolved it — UI Automation first — and auto-waited until it was visible and enabled.
  • Actions prefer accessibility patterns (uia.set-value, uia.invoke) and fall back to real mouse/keyboard input only when a control has no pattern.
  • await using closed the application when the scope ended.

3. Run it​

Node 24 runs TypeScript directly: node script.ts. Any test runner works; expectDesk does not depend on one. For Vitest/Jest/Mocha, create the desktop in a before hook and dispose it in after, as the example test init wrote does (npx vitest run or node --test tests/example.test.ts).

4. Where to go next​

TopicPage
The configuration file and spart-desk initconfiguration.md
Finding controlslocators.md
Acting on them, input strategies, the foreground ruleactions.md
Waiting, timeouts, cancellationauto-waiting.md
Assertionsassertions.md
What went wrong: records, traces, screenshotsassertions-diagnostics.md
Windows Sandbox runtime (experimental)runtime-windows-sandbox.md
Resolving what UIA cannot seeresolution.md
AI agents over MCPagentic-mcp.md
Installation, offline, mirrorsdistribution.md, ci.md
Running tests in parallel (workers, runner projects)parallelism.md
Something does not worktroubleshooting.md
Complete referenceapi.md

5. Testing your own automation code without Windows​

import { Desktop } from "@spartaficial/spart-desk";
import { FakeDriver, FakeRuntime } from "@spartaficial/spart-desk/testing";

const driver = new FakeDriver([{ role: "window", name: "Demo", children: [{ role: "button", name: "OK" }] }]);
const desktop = await Desktop.create({ runtime: new FakeRuntime(driver) });
const app = await desktop.launch({ executable: "demo.exe" });
const main = app.window();
await main.getByRole("button", { name: "OK" }).click();
console.log(driver.performed); // [{ action: { type: "click", ... }, controlId: "0.0" }]

The fake backend runs the same locator, waiting and recording code as the real one, so page objects and helpers can be unit-tested on any machine.