Liking cljdoc? Tell your friends :D

com.blockether.spel.allure

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"))))
raw docstring

com.blockether.spel.allure-reporter

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
raw docstring

com.blockether.spel.annotate

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
raw docstring

com.blockether.spel.api

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")
raw docstring

com.blockether.spel.assertions

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.
raw docstring

com.blockether.spel.cli

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
raw docstring

com.blockether.spel.codegen

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.
raw docstring

com.blockether.spel.core

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.
raw docstring

com.blockether.spel.daemon

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!)                                         ;; cleanup
raw docstring

com.blockether.spel.data

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
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
raw docstring

No vars found in this namespace.

com.blockether.spel.driver

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>/
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>/
raw docstring

com.blockether.spel.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

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
raw docstring

com.blockether.spel.init-agents

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

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
raw docstring

com.blockether.spel.junit-reporter

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
raw docstring

com.blockether.spel.native

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

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
raw docstring

com.blockether.spel.network

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.
raw docstring

com.blockether.spel.options

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.
raw docstring

com.blockether.spel.sci-env

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!)")
raw docstring

com.blockether.spel.snapshot

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 element
raw docstring

com.blockether.spel.test-fixtures

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)))))

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*)))))
raw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close