Crafted Node.js browser automation built on W3C WebDriver and BiDi.
Playwright-style ergonomics. WebDriver standards. AI friendly.
CraftDriver is for writing boringly reliable automation against real browsers, with code that reads nicely.
- 🍺 Focused Node.js API - browser automation without a giant framework around it.
- 🧭 Real browsers - drives installed Chrome, Chromium, and Firefox instead of patched browser engine builds, plus real Safari on macOS.
- 🌐 Standards that age well - W3C WebDriver standards stay stable while browser-private protocols change.
- 🚦 Readable, auto-waited flows - role, label, text, test id, CSS, XPath, click, fill, and expect.
- 📡 Network control - mock, block, intercept, and wait for browser requests and responses.
- 🔐 Reusable sessions - save cookies and localStorage, then launch already signed in.
- ⏱️ Virtual clock - freeze or fast-forward
Date, timers, and time-sensitive UI. - ♿ Accessibility audits - find WCAG 2.2 and Section 508 violations with built-in axe-core checks.
- 🖼️ Visual testing - catch visual regressions against baselines, without fighting anti-aliasing flakiness.
- 🧾 Trace evidence - capture actions, console output, errors, network events, and screenshots.
- ☁️ Remote WebDriver - use the Browser API with a self-hosted Selenium Grid or a cloud provider like BrowserStack.
- ⚛️ Electron apps - drive packaged Electron desktop apps and mock native OS dialogs (open/save, message boxes).
- 🤖 Agent-friendly - one command sets up Claude Code, Codex, and Copilot with a CLI, a project-local skill, and optional MCP.
| You want to... | Start here |
|---|---|
| Write browser automation | Getting started |
| Give an AI coding agent a browser | AI agent guide |
npm install craftdriver --save-devimport { Browser } from 'craftdriver';
const browser = await Browser.launch({ browserName: 'chrome' });
await browser.navigateTo('https://example.com/login');
await browser.getByLabel('Username').fill('alice');
await browser.getByLabel('Password').fill('hunter2');
await browser.getByRole('button', { name: 'Sign in' }).click();
await browser.expect('#result').toHaveText('Welcome alice');
await browser.quit();No separate chromedriver or geckodriver setup for normal use. CraftDriver resolves and caches the right driver for your installed browser.
Your coding agent can write tests, but it can't see your app — so it guesses selectors and hands you a test that fails on first run. CraftDriver gives it a real browser to look at the page first.
npm install --save-dev craftdriver
npx craftdriver initinit installs a project-local skill that makes the CraftDriver CLI
discoverable to Claude Code, Codex, and Copilot. It never touches AGENTS.md,
CLAUDE.md, Copilot instructions, or any host's MCP configuration. Then ask:
Use the CraftDriver skill. Explore
http://localhost:3000/loginand add a browser test for a failed sign-in, following this repository's existing test conventions. Verify every locator against the live page, run the focused test, and tell me what you changed.
The agent reads the accessibility tree, checks which locators actually resolve, and writes the test against what it found. Start with Ask Your Agent To Write A Browser Test. The same prompt works over optional MCP when the host has no shell; full setup is in the AI agent guide.
// Mobile emulation
await Browser.launch({
browserName: 'chrome',
mobileEmulation: 'iPhone 14',
});
// Network mocking
await browser.network.mock('**/api/users', {
status: 200,
body: { users: [] },
});
// Save and reuse login state
await browser.saveState('.auth/session.json');
await Browser.launch({
browserName: 'chrome',
storageState: '.auth/session.json',
});
// Built-in accessibility checks via axe-core
await browser.a11y.check();Launch-time state restores cookies plus multi-origin localStorage on supported WebDriver BiDi sessions (Chrome/Chromium and Firefox). WebDriver Classic has an explicit single-active-origin fallback after navigation; see Session management.
| Area | What you get | Learn more |
|---|---|---|
| Getting started | Install, launch a browser, write the first test | Getting started |
| Driver management | Zero-config driver resolution, cache behavior, env vars, offline mode | Driver configuration |
| Browser control | Navigation, tabs, popups, iframes, content helpers, evaluate, init scripts | Browser API |
| Locators | CSS, XPath, text, role, label, test id, and composable locator() chains |
Selectors |
| Open Shadow DOM | Explicit lazy shadowRoot() boundaries over WebDriver Classic and BiDi |
Shadow DOM |
| Element actions | Click, fill, upload, inspect, and interact through element handles | Element API |
| Assertions | Built-in expect(...), retries, visibility, text, attributes, and timing behavior |
Assertions |
| Input | Low-level key presses, mouse movement, hover, drag, and pointer input | Keyboard and mouse |
| Dialogs | alert, confirm, prompt, and beforeunload handling |
Dialogs |
| Sessions | Cookies, localStorage, save/load state, persistent login flows | Session management |
| Network mocking | Mock, block, intercept, and wait for browser requests and responses | Network mocking |
| Console and errors | Capture console output and fail tests on JavaScript errors | Console logs |
| Screenshots | Page and element screenshots for tests and debugging | Screenshots |
| Visual testing | Compare screenshots to baselines with tolerances, retries, and diff artifacts | Visual testing |
| Mobile and emulation | Device presets, viewport, locale, timezone, offline, reduced motion | Mobile emulation, Emulation |
| Browser contexts | Isolated profiles for multi-user and multi-session testing | Browser contexts |
| Tracing | Crash-resilient NDJSON plus Vibium Player compatible trace zips | Tracing |
| Accessibility | Built-in axe-core audits for page, element, and locator scopes | Accessibility |
| Virtual time | Fake Date, setTimeout, and setInterval for time-sensitive flows |
Virtual clock |
| Electron apps | Drive packaged Electron renderers with a version-pinned chromedriver | Electron apps |
| Safari (macOS) | Real desktop Safari via WebDriver Classic — enable once with safaridriver --enable |
Safari |
| Remote WebDriver | Run on a self-hosted Selenium Grid or a cloud provider like BrowserStack | Remote WebDriver |
| AI agents | One-command skill install for Claude Code, Codex, and Copilot; CLI and MCP surfaces | AI agent guide |
- Documentation site
- API reference
- Recipes — recipes for brewing great tests 🍺
- Changelog
- Contributing guide
PRs and issues are welcome. Be kind. Brew great tests.
MIT