| Accessibility Snapshots | Inline Clojure via --eval | Visual Annotations | Agent Scaffolding |
![]() | ![]() | ![]() | ![]() |
Playwright's Java API is imperative and verbose — option builders, checked exceptions, manual resource cleanup. Clojure deserves better.
spel wraps the official Playwright Java 1.58.0 library with idiomatic Clojure: maps for options, anomaly maps for errors, with-* macros for lifecycle, and a native CLI binary for instant browser automation from the terminal.
with-* macros for lifecycle management — resources always cleaned up--eval scripting — built for AI agents to see, decide, and act;; deps.edn
{:deps {com.blockether/spel {:mvn/version "0.3.1"}}}
spel install # requires spel CLI — see "Native CLI" below
(require '[com.blockether.spel.core :as core]
'[com.blockether.spel.page :as page]
'[com.blockether.spel.api :as api])
;; Browser automation
(core/with-testing-page [pg]
(page/navigate pg "https://example.com")
(page/title pg))
;; => "Example Domain"
;; API testing — Playwright-backed HTTP with automatic tracing
(api/with-testing-api {:base-url "https://api.example.com"} [ctx]
(api/api-get ctx "/users"))
Pass an opts map for device emulation:
(core/with-testing-page {:device :iphone-14 :locale "fr-FR"} [pg]
(page/navigate pg "https://example.com"))
Need explicit control over lifecycle? with-playwright/with-browser/with-context/with-page nesting is available. The full API reference covers all options.
Download from GitHub releases:
# macOS (Apple Silicon)
curl -LO https://github.com/Blockether/spel/releases/latest/download/spel-macos-arm64
chmod +x spel-macos-arm64 && mv spel-macos-arm64 ~/.local/bin/spel
# Linux (amd64)
curl -LO https://github.com/Blockether/spel/releases/latest/download/spel-linux-amd64
chmod +x spel-linux-amd64 && mv spel-linux-amd64 ~/.local/bin/spel
# Linux (arm64)
curl -LO https://github.com/Blockether/spel/releases/latest/download/spel-linux-arm64
chmod +x spel-linux-arm64 && mv spel-linux-arm64 ~/.local/bin/spel
# Windows (PowerShell)
Invoke-WebRequest -Uri https://github.com/Blockether/spel/releases/latest/download/spel-windows-amd64.exe -OutFile spel.exe
Move-Item spel.exe "$env:LOCALAPPDATA\Microsoft\WindowsApps\spel.exe"
Tip: The examples install to
~/.local/bin/(no sudo needed). Make sure it's on yourPATH:export PATH="$HOME/.local/bin:$PATH" # add to ~/.bashrc or ~/.zshrcYou can also install system-wide with
sudo mv spel-* /usr/local/bin/spelinstead.
The binaries are not signed with an Apple Developer certificate. macOS will block the first run with "spel can't be opened because Apple cannot check it for malicious software". To allow it:
# Remove the quarantine attribute (recommended)
xattr -d com.apple.quarantine ~/.local/bin/spel
Or: System Settings → Privacy & Security → scroll down → click "Allow Anyway" after the first blocked attempt.
Install browsers and verify:
spel install
spel version
Playwright-backed HTTP testing with automatic tracing.
| Function | Description | Auto-Traces? |
|---|---|---|
page-api pg | Extract APIRequestContext from a Page | ✅ Yes |
context-api ctx | Extract APIRequestContext from a BrowserContext | ✅ Yes |
with-testing-api [ctx] body | Standalone API testing with full Playwright stack | ✅ Yes (when Allure active) |
with-page-api pg opts [ctx] body | Page-bound API with custom base-url + cookie sharing | ❌ No |
1. Standalone API testing — creates full Playwright stack:
;; With base-url
(api/with-testing-api {:base-url "https://api.example.com"} [ctx]
(api/api-get ctx "/users"))
;; Without base-url (full URLs required)
(api/with-testing-api [ctx]
(api/api-get ctx "https://api.example.com/users"))
2. API from Page — share browser cookies/session:
(core/with-testing-page [pg]
(page/navigate pg "https://example.com/login")
;; API calls share the browser session
(let [resp (api/api-get (api/page-api pg) "/api/me")]
(api/api-response-status resp)))
3. API from BrowserContext — extract from existing context:
(core/with-playwright [pw]
(core/with-browser [browser (core/launch-chromium pw)]
(core/with-context [ctx (core/new-context browser)]
(let [resp (api/api-get (api/context-api ctx) "/users")]
(api/api-response-status resp)))))
4. Page-bound API with custom base-url — cookies + different domain:
(core/with-testing-page [pg]
(page/navigate pg "https://example.com/login")
;; ... login via UI ...
;; Use different base-url while sharing browser cookies
(api/with-page-api pg {:base-url "https://api.example.com"} [ctx]
(api/api-get ctx "/me")))
[API reference covers the full feature set](.opencode/skills/spel/SKILL.md).
## Allure Test Reporting
Integrates with [Lazytest](https://github.com/noahtheduke/lazytest) for test reports using [Allure](https://allurereport.org/). Generates the HTML report automatically with embedded Playwright traces and trace viewer.
> **[View live test report](https://blockether.github.io/spel/)** — with embedded traces.
<table>
<tr>
<td width="50%" align="center"><b>Allure Report</b></td>
<td width="50%" align="center"><b>Embedded Playwright Traces</b></td>
</tr>
<tr>
<td><a href="https://blockether.github.io/spel/"><img src="docs/screenshots/allure-report.png" alt="Allure Report"/></a></td>
<td><a href="https://blockether.github.io/spel/"><img src="docs/screenshots/allure-trace-viewer.png" alt="Playwright Trace Viewer embedded in Allure"/></a></td>
</tr>
</table>
```clojure
(ns my-app.test
(:require
[com.blockether.spel.locator :as locator]
[com.blockether.spel.page :as page]
[com.blockether.spel.test-fixtures :refer [*page* with-playwright with-browser with-page]]
[com.blockether.spel.allure :refer [defdescribe describe expect it]]))
(defdescribe my-test
(describe "example.com"
{:context [with-playwright with-browser with-page]}
(it "navigates and asserts"
(page/navigate *page* "https://example.com")
(expect (= "Example Domain" (page/title *page*))))))
clojure -M:test --output nested --output com.blockether.spel.allure-reporter/allure
Automatic tracing, trace viewer, and history included. See SKILL.md for fixtures, steps, and attachments.
Record browser sessions as WebM files for debugging and CI artifacts.
(def ctx (core/new-context browser {:record-video-dir "videos"}))
Recording options and test fixtures are documented here.
Record browser sessions and transform to idiomatic Clojure code.
spel codegen record -o recording.jsonl https://example.com
spel codegen recording.jsonl > my_test.clj
Full actions and output formats in the SKILL reference.
Point your AI agent at spel and let it write your E2E tests.
spel init-agents # OpenCode (default)
spel init-agents --loop=claude # Claude Code
spel init-agents --loop=vscode # VS Code / Copilot
spel init-agents --flavour=clojure-test # clojure.test instead of Lazytest
spel init-agents --no-tests # SKILL only (interactive dev)
| File | Purpose |
|---|---|
agents/spel-test-planner | Explores app, writes structured test plans |
agents/spel-test-generator | Reads test plans, generates Clojure test code |
agents/spel-test-healer | Runs failing tests, diagnoses issues, applies fixes |
prompts/spel-test-workflow | Orchestrator: plan → generate → heal cycle |
skills/spel/SKILL.md | API reference for agents |
| Flag | Default | Purpose |
|---|---|---|
--loop TARGET | opencode | Agent format: opencode, claude, vscode |
--ns NS | dir name | Base namespace for generated tests |
--flavour FLAVOUR | lazytest | Test framework: lazytest or clojure-test |
--no-tests | — | Scaffold only the SKILL (API reference) — no test agents |
--dry-run | — | Preview files without writing |
--force | — | Overwrite existing files |
--test-dir DIR | test-e2e | E2E test output directory |
--specs-dir DIR | test-e2e/specs | Test plans directory |
# Install browsers (via Playwright Java CLI)
clojure -M -e "(com.microsoft.playwright.CLI/main (into-array String [\"install\" \"--with-deps\"]))"
# Build JAR
clojure -T:build jar
# Build native image (requires GraalVM)
clojure -T:build native-image
# Run tests
make test
make test-allure
# Start REPL
make repl
See CHANGELOG.md.
Apache License 2.0 — see LICENSE.
Can you improve this documentation? These fine people already did:
Karol Wojcik, blockether-deployer & Michał KrukEdit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |