In-test Allure API for enriching test reports with steps, metadata, screenshots, and attachments.
All functions are no-ops when *context* is nil, meaning they are
safe to call even when not running under the Allure reporter.
Usage in tests:
(ns my-app.login-test (:require [com.blockether.spel.allure :as allure] [com.blockether.spel.page :as page] [com.blockether.spel.locator :as locator]))
(defdescribe login-flow (allure/epic "Authentication") (allure/feature "Login") (allure/severity :critical)
(it "logs in with valid credentials"
(allure/step "Navigate to login page"
(page/navigate page "https://example.com/login"))
(allure/step "Enter credentials"
(allure/parameter "username" "admin")
(locator/fill (locator/locator page "#username") "admin")
(locator/fill (locator/locator page "#password") "secret"))
(allure/step "Submit and verify"
(locator/click (locator/locator page "button[type=submit]"))
(allure/screenshot page "After login"))))
In-test Allure API for enriching test reports with steps, metadata,
screenshots, and attachments.
All functions are no-ops when `*context*` is nil, meaning they are
safe to call even when not running under the Allure reporter.
Usage in tests:
(ns my-app.login-test
(:require [com.blockether.spel.allure :as allure]
[com.blockether.spel.page :as page]
[com.blockether.spel.locator :as locator]))
(defdescribe login-flow
(allure/epic "Authentication")
(allure/feature "Login")
(allure/severity :critical)
(it "logs in with valid credentials"
(allure/step "Navigate to login page"
(page/navigate page "https://example.com/login"))
(allure/step "Enter credentials"
(allure/parameter "username" "admin")
(locator/fill (locator/locator page "#username") "admin")
(locator/fill (locator/locator page "#password") "secret"))
(allure/step "Submit and verify"
(locator/click (locator/locator page "button[type=submit]"))
(allure/screenshot page "After login"))))Allure 3 reporter for Lazytest with embedded Playwright trace viewer.
Writes JSON result files to allure-results/, then automatically generates the full HTML report to allure-report/ using Allure 3 CLI (pinned to 3.1.0 via npx). The report embeds a local Playwright trace viewer so trace attachments load instantly without trace.playwright.dev.
Usage: clojure -M:test --output com.blockether.spel.allure-reporter/allure clojure -M:test --output nested --output com.blockether.spel.allure-reporter/allure
Output directory defaults to allure-results/. Override with: -Dlazytest.allure.output=path/to/dir LAZYTEST_ALLURE_OUTPUT=path/to/dir
Allure 3 reporter for Lazytest with embedded Playwright trace viewer. Writes JSON result files to allure-results/, then automatically generates the full HTML report to allure-report/ using Allure 3 CLI (pinned to 3.1.0 via npx). The report embeds a local Playwright trace viewer so trace attachments load instantly without trace.playwright.dev. Usage: clojure -M:test --output com.blockether.spel.allure-reporter/allure clojure -M:test --output nested --output com.blockether.spel.allure-reporter/allure Output directory defaults to allure-results/. Override with: -Dlazytest.allure.output=path/to/dir LAZYTEST_ALLURE_OUTPUT=path/to/dir
Page annotation with ref labels, bounding boxes, and dimensions.
Injects CSS overlays directly into the page DOM. Overlays persist until
explicitly removed with remove-overlays!. No AWT dependency — works in
GraalVM native-image without any java.awt configuration.
Usage: (def snap (snapshot/capture-snapshot page)) (inject-overlays! page (:refs snap)) ;; overlays now visible on page ;; ... inspect, screenshot, etc. ... (remove-overlays! page) ;; clean up
Page annotation with ref labels, bounding boxes, and dimensions. Injects CSS overlays directly into the page DOM. Overlays persist until explicitly removed with `remove-overlays!`. No AWT dependency — works in GraalVM native-image without any java.awt configuration. Usage: (def snap (snapshot/capture-snapshot page)) (inject-overlays! page (:refs snap)) ;; overlays now visible on page ;; ... inspect, screenshot, etc. ... (remove-overlays! page) ;; clean up
Playwright API testing — APIRequest, APIRequestContext, APIResponse.
Provides idiomatic Clojure wrappers for Playwright's built-in HTTP client.
Supports all HTTP methods, form data, query params, custom headers, and
lifecycle management via with-api-context.
Usage: (require '[com.blockether.spel.core :as pw] '[com.blockether.spel.api :as api])
(core/with-playwright [playwright] (api/with-api-context [ctx (-> playwright api/api-request (api/new-api-context {:base-url "https://api.example.com"}))] (let [resp (api/get ctx "/users" {:params {:page 1 :limit 10}})] (println (api/response->map resp)))))
;; Response map: ;; {:status 200 ;; :status-text "OK" ;; :url "https://api.example.com/users?page=1&limit=10" ;; :ok? true ;; :headers {"content-type" "application/json"} ;; :body "{...}"}
All HTTP methods accept either a RequestOptions object or a Clojure map:
(api/post ctx "/users" {:headers {"Content-Type" "application/json"} :data "{"name": "Alice"}" :timeout 5000})
(api/put ctx "/users/1" {:form (api/map->form-data {:name "Bob" :email "bob@example.com"})})
(api/delete ctx "/users/1")
Playwright API testing — APIRequest, APIRequestContext, APIResponse.
Provides idiomatic Clojure wrappers for Playwright's built-in HTTP client.
Supports all HTTP methods, form data, query params, custom headers, and
lifecycle management via `with-api-context`.
Usage:
(require '[com.blockether.spel.core :as pw]
'[com.blockether.spel.api :as api])
(core/with-playwright [playwright]
(api/with-api-context [ctx (-> playwright api/api-request
(api/new-api-context {:base-url "https://api.example.com"}))]
(let [resp (api/get ctx "/users" {:params {:page 1 :limit 10}})]
(println (api/response->map resp)))))
;; Response map:
;; {:status 200
;; :status-text "OK"
;; :url "https://api.example.com/users?page=1&limit=10"
;; :ok? true
;; :headers {"content-type" "application/json"}
;; :body "{...}"}
All HTTP methods accept either a RequestOptions object or a Clojure map:
(api/post ctx "/users"
{:headers {"Content-Type" "application/json"}
:data "{\"name\": \"Alice\"}"
:timeout 5000})
(api/put ctx "/users/1"
{:form (api/map->form-data {:name "Bob" :email "bob@example.com"})})
(api/delete ctx "/users/1")Playwright test assertions - LocatorAssertions, PageAssertions, APIResponseAssertions.
Entry point is assert-that which returns the appropriate assertions
object for the given Playwright type. Chain with assertion functions
and use not- variants for negation.
All assertion functions wrap calls in safe to return anomaly maps
on assertion failure rather than throwing.
Playwright test assertions - LocatorAssertions, PageAssertions, APIResponseAssertions. Entry point is `assert-that` which returns the appropriate assertions object for the given Playwright type. Chain with assertion functions and use `not-` variants for negation. All assertion functions wrap calls in `safe` to return anomaly maps on assertion failure rather than throwing.
CLI client for the spel daemon.
Parses command-line arguments into JSON commands, sends them to the daemon over a Unix domain socket, and pretty-prints the results.
If the daemon isn't running, it auto-starts one in the background.
Usage: spel open https://example.com spel snapshot spel click @e1 spel fill @e2 "search text" spel screenshot shot.png spel close
CLI client for the spel daemon. Parses command-line arguments into JSON commands, sends them to the daemon over a Unix domain socket, and pretty-prints the results. If the daemon isn't running, it auto-starts one in the background. Usage: spel open https://example.com spel snapshot spel click @e1 spel fill @e2 "search text" spel screenshot shot.png spel close
Transforms Playwright JSONL recordings into idiomatic Clojure test code.
Reads JSONL produced by playwright codegen --target=jsonl and emits
Clojure code using the com.blockether.spel API.
Two usage modes:
A) Library:
(set! warn-on-reflection true)
(require '[com.blockether.spel.codegen :as codegen])
(codegen/jsonl->clojure "recording.jsonl")
(codegen/jsonl-str->clojure jsonl-string {:format :script})
B) CLI: clojure -M -m com.blockether.spel.codegen recording.jsonl clojure -M -m com.blockether.spel.codegen --format=script recording.jsonl cat recording.jsonl | clojure -M -m com.blockether.spel.codegen
Workflow: clojure -M -m com.blockether.spel.cli codegen --target=jsonl -o recording.jsonl https://example.com clojure -M -m com.blockether.spel.codegen recording.jsonl > test/my_test.clj
Any unrecognized action, unsupported signal, or unimplemented feature causes an IMMEDIATE hard error with details about what failed.
Transforms Playwright JSONL recordings into idiomatic Clojure test code.
Reads JSONL produced by `playwright codegen --target=jsonl` and emits
Clojure code using the com.blockether.spel API.
Two usage modes:
A) Library:
(set! *warn-on-reflection* true)
(require '[com.blockether.spel.codegen :as codegen])
(codegen/jsonl->clojure "recording.jsonl")
(codegen/jsonl-str->clojure jsonl-string {:format :script})
B) CLI:
clojure -M -m com.blockether.spel.codegen recording.jsonl
clojure -M -m com.blockether.spel.codegen --format=script recording.jsonl
cat recording.jsonl | clojure -M -m com.blockether.spel.codegen
Workflow:
clojure -M -m com.blockether.spel.cli codegen --target=jsonl -o recording.jsonl https://example.com
clojure -M -m com.blockether.spel.codegen recording.jsonl > test/my_test.clj
Any unrecognized action, unsupported signal, or unimplemented feature
causes an IMMEDIATE hard error with details about what failed.Playwright lifecycle management and browser launching.
Entry point for all Playwright operations. Creates Playwright instances and launches browsers (Chromium, Firefox, WebKit).
Usage: (with-playwright [pw (create)] (with-browser [browser (launch-chromium pw {:headless true})] (with-page [page (new-page browser)] (navigate page "https://example.com") (text-content page "h1"))))
All operations return anomaly maps on failure instead of throwing exceptions.
Playwright lifecycle management and browser launching.
Entry point for all Playwright operations. Creates Playwright instances
and launches browsers (Chromium, Firefox, WebKit).
Usage:
(with-playwright [pw (create)]
(with-browser [browser (launch-chromium pw {:headless true})]
(with-page [page (new-page browser)]
(navigate page "https://example.com")
(text-content page "h1"))))
All operations return anomaly maps on failure instead of throwing exceptions.Background daemon that keeps a Playwright browser alive between CLI calls.
Listens on a Unix domain socket for JSON commands, executes them against the browser, and returns JSON responses. Each command is one JSON line; each response is one JSON line.
Usage: (start-daemon! {:session "default" :headless true}) ;; blocks (daemon-running? "default") ;; check (stop-daemon!) ;; cleanup
Background daemon that keeps a Playwright browser alive between CLI calls.
Listens on a Unix domain socket for JSON commands, executes them against
the browser, and returns JSON responses. Each command is one JSON line;
each response is one JSON line.
Usage:
(start-daemon! {:session "default" :headless true}) ;; blocks
(daemon-running? "default") ;; check
(stop-daemon!) ;; cleanupDatafy/nav extensions for Playwright Java objects.
Require this namespace to enable clojure.core.protocols/Datafiable
for key Playwright classes. After requiring, (clojure.datafy/datafy obj)
returns a Clojure map representation of the object.
Datafied classes:
Datafy/nav extensions for Playwright Java objects. Require this namespace to enable `clojure.core.protocols/Datafiable` for key Playwright classes. After requiring, `(clojure.datafy/datafy obj)` returns a Clojure map representation of the object. Datafied classes: - Page, Browser, BrowserContext, BrowserType - Request, Response, APIResponse - ConsoleMessage, Download, WebError, WebSocketFrame, Worker - ElementHandle, Locator (basic info) - PlaywrightException, TimeoutError
No vars found in this namespace.
External Playwright driver management for native-image builds.
Instead of bundling Playwright's ~600MB Node.js driver in the native binary, this module downloads and caches it on first use.
Cache: ~/.cache/spel/<version>/<platform>/ CDN: https://cdn.playwright.dev/builds/driver/playwright-<version>-<platform>.zip
Configuration (checked in order):
External Playwright driver management for native-image builds. Instead of bundling Playwright's ~600MB Node.js driver in the native binary, this module downloads and caches it on first use. Cache: ~/.cache/spel/<version>/<platform>/ CDN: https://cdn.playwright.dev/builds/driver/playwright-<version>-<platform>.zip Configuration (checked in order): 1. playwright.cli.dir system property — points to pre-installed driver dir 2. SPEL_DRIVER_DIR env var — overrides cache location 3. Default: ~/.cache/spel/<version>/<platform>/
Frame and FrameLocator operations.
Frame and FrameLocator operations.
Generates API reference markdown from source code introspection.
Three categories of API docs:
spel --eval modespel binaryUsage: clojure -T:build gen-docs make gen-docs
Generates API reference markdown from source code introspection. Three categories of API docs: 1. Library API — public vars from all spel namespaces 2. SCI eval API — functions available in `spel --eval` mode 3. CLI commands — commands available via the `spel` binary Usage: clojure -T:build gen-docs make gen-docs
CLI command to scaffold agent definitions for E2E testing.
Supports multiple agent loop targets via --loop:
Also generates:
Usage: spel init-agents --ns my-app spel init-agents --ns my-app --loop=claude spel init-agents --ns my-app --loop=vscode spel init-agents --ns my-app --test-dir test-e2e --specs-dir test-e2e/specs spel init-agents --dry-run
CLI command to scaffold agent definitions for E2E testing. Supports multiple agent loop targets via --loop: - opencode (default) — .opencode/agents/, .opencode/prompts/, .opencode/skills/ - claude — .claude/agents/, .claude/prompts/, .claude/docs/ - vscode — .github/agents/, .github/prompts/, .github/docs/ Also generates: - test-e2e/specs/ — test plans directory (colocated with tests) - test-e2e/<ns>/e2e/ — seed test (path derived from --ns) Usage: spel init-agents --ns my-app spel init-agents --ns my-app --loop=claude spel init-agents --ns my-app --loop=vscode spel init-agents --ns my-app --test-dir test-e2e --specs-dir test-e2e/specs spel init-agents --dry-run
Keyboard, Mouse, and Touchscreen operations.
Keyboard, Mouse, and Touchscreen operations.
JUnit XML reporter for Lazytest.
Produces JUnit XML output fully compliant with the Apache Ant JUnit schema (https://github.com/windyroad/JUnit-Schema) and compatible with CI systems: GitHub Actions, Jenkins, GitLab CI.
Usage: clojure -M:test --output com.blockether.spel.junit-reporter/junit clojure -M:test --output nested --output com.blockether.spel.junit-reporter/junit
Output file defaults to test-results/junit.xml. Override with: -Dlazytest.junit.output=path/to/output.xml LAZYTEST_JUNIT_OUTPUT=path/to/output.xml
JUnit XML reporter for Lazytest. Produces JUnit XML output fully compliant with the Apache Ant JUnit schema (https://github.com/windyroad/JUnit-Schema) and compatible with CI systems: GitHub Actions, Jenkins, GitLab CI. Usage: clojure -M:test --output com.blockether.spel.junit-reporter/junit clojure -M:test --output nested --output com.blockether.spel.junit-reporter/junit Output file defaults to test-results/junit.xml. Override with: -Dlazytest.junit.output=path/to/output.xml LAZYTEST_JUNIT_OUTPUT=path/to/output.xml
Locator and ElementHandle operations.
Locators are the primary way to find and interact with elements. They auto-wait and auto-retry, making them the preferred API.
Locator and ElementHandle operations. Locators are the primary way to find and interact with elements. They auto-wait and auto-retry, making them the preferred API.
Native-image entry point for spel.
Provides a CLI tool (spel) for browser automation with persistent browser sessions.
Modes:
Usage: spel open https://example.com # Navigate (auto-starts browser) spel snapshot # ARIA snapshot with refs spel click @e1 # Click by ref spel fill @e2 "search text" # Fill input by ref spel screenshot shot.png # Take screenshot spel close # Close browser spel --eval '(+ 1 2)' # Evaluate and exit spel install # Install Playwright browsers spel --help # Show help
Native-image entry point for spel. Provides a CLI tool (spel) for browser automation with persistent browser sessions. Modes: - CLI commands (default): Send commands to the browser process - Eval: Evaluate a Clojure expression and exit Usage: spel open https://example.com # Navigate (auto-starts browser) spel snapshot # ARIA snapshot with refs spel click @e1 # Click by ref spel fill @e2 "search text" # Fill input by ref spel screenshot shot.png # Take screenshot spel close # Close browser spel --eval '(+ 1 2)' # Evaluate and exit spel install # Install Playwright browsers spel --help # Show help
Request, Response, Route, WebSocket operations.
All response and request accessor functions participate in the anomaly railway pattern: if passed an anomaly map (e.g. from a failed navigate), they pass it through unchanged instead of throwing ClassCastException.
Request, Response, Route, WebSocket operations. All response and request accessor functions participate in the anomaly railway pattern: if passed an anomaly map (e.g. from a failed navigate), they pass it through unchanged instead of throwing ClassCastException.
Option map to Playwright Java options object conversion.
Converts idiomatic Clojure maps to Playwright's typed option objects. All functions use reflection-free type hints.
Option map to Playwright Java options object conversion. Converts idiomatic Clojure maps to Playwright's typed option objects. All functions use reflection-free type hints.
Page operations - navigation, content, evaluation, screenshots.
The Page class is the central API surface of Playwright. Wraps all Page methods with idiomatic Clojure functions.
Page operations - navigation, content, evaluation, screenshots. The Page class is the central API surface of Playwright. Wraps all Page methods with idiomatic Clojure functions.
SCI (Small Clojure Interpreter) environment for native-image REPL.
Registers all spel functions as SCI namespaces so they can be evaluated in a native-image compiled REPL without JVM startup.
The SCI context wraps a stateful Playwright session with managed atoms for the Playwright, Browser, BrowserContext, and Page instances.
Namespaces available in --eval mode: spel/ - Simplified API (implicit page/context from atoms) snapshot/ - Accessibility snapshot capture annotate/ - Screenshot annotation input/ - Keyboard, Mouse, Touchscreen (raw pass-throughs) frame/ - Frame and FrameLocator operations (raw pass-throughs) net/ - Network request/response/route (raw pass-throughs) loc/ - Locator operations (raw pass-throughs, explicit Locator arg) assert/ - Assertion functions (raw pass-throughs, explicit assertion obj) core/ - Lifecycle stubs + utility pass-throughs
Usage: (def ctx (create-sci-ctx)) (eval-string ctx "(spel/start!)") (eval-string ctx "(spel/goto "https://example.com")") (eval-string ctx "(spel/snapshot)") (eval-string ctx "(spel/stop!)")
SCI (Small Clojure Interpreter) environment for native-image REPL. Registers all spel functions as SCI namespaces so they can be evaluated in a native-image compiled REPL without JVM startup. The SCI context wraps a stateful Playwright session with managed atoms for the Playwright, Browser, BrowserContext, and Page instances. Namespaces available in --eval mode: spel/ - Simplified API (implicit page/context from atoms) snapshot/ - Accessibility snapshot capture annotate/ - Screenshot annotation input/ - Keyboard, Mouse, Touchscreen (raw pass-throughs) frame/ - Frame and FrameLocator operations (raw pass-throughs) net/ - Network request/response/route (raw pass-throughs) loc/ - Locator operations (raw pass-throughs, explicit Locator arg) assert/ - Assertion functions (raw pass-throughs, explicit assertion obj) core/ - Lifecycle stubs + utility pass-throughs Usage: (def ctx (create-sci-ctx)) (eval-string ctx "(spel/start!)") (eval-string ctx "(spel/goto \"https://example.com\")") (eval-string ctx "(spel/snapshot)") (eval-string ctx "(spel/stop!)")
Accessibility snapshot with numbered element refs.
Walks the DOM tree via JavaScript injection and builds a YAML-like
accessibility tree with stable refs (e1, e2, f1_e1 for iframes).
Elements are tagged with data-pw-ref attributes for later interaction.
Usage: (def snap (capture-snapshot page)) (:tree snap) ;; YAML-like string with [@eN] annotations (:refs snap) ;; {"e1" {:role "button" :name "Submit" :bbox {...}} ...} (resolve-ref page "e3") ;; returns Locator for the element
Accessibility snapshot with numbered element refs.
Walks the DOM tree via JavaScript injection and builds a YAML-like
accessibility tree with stable refs (e1, e2, f1_e1 for iframes).
Elements are tagged with `data-pw-ref` attributes for later interaction.
Usage:
(def snap (capture-snapshot page))
(:tree snap) ;; YAML-like string with [@eN] annotations
(:refs snap) ;; {"e1" {:role "button" :name "Submit" :bbox {...}} ...}
(resolve-ref page "e3") ;; returns Locator for the elementShared Playwright test fixtures using Lazytest around hooks.
Provides dynamic vars for Playwright instance, browser, and page, along with around hooks that can be used with Lazytest's :context metadata.
Usage: (ns my-test (:require [com.blockether.spel.test-fixtures :refer [page with-playwright with-browser with-page]] [lazytest.core :refer [defdescribe describe expect it]]))
(defdescribe my-test (describe "with full setup" {:context [with-playwright with-browser with-page]} (it "can access page" (expect (some? page)))))
Shared Playwright test fixtures using Lazytest around hooks.
Provides dynamic vars for Playwright instance, browser, and page,
along with around hooks that can be used with Lazytest's :context metadata.
Usage:
(ns my-test
(:require
[com.blockether.spel.test-fixtures :refer [*page* with-playwright with-browser with-page]]
[lazytest.core :refer [defdescribe describe expect it]]))
(defdescribe my-test
(describe "with full setup" {:context [with-playwright with-browser with-page]}
(it "can access page"
(expect (some? *page*)))))Utility classes: Dialog, Download, ConsoleMessage, CDPSession, Clock, Tracing, Video, WebError, Worker, FileChooser, Selectors.
Utility classes: Dialog, Download, ConsoleMessage, CDPSession, Clock, Tracing, Video, WebError, Worker, FileChooser, Selectors.
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 |