Minimal W3C WebDriver HTTP client for the iOS application provider.
Talks directly to a WebDriver-compatible endpoint (Appium) using JDK
java.net.http.HttpClient and charred JSON — no Selenium/Appium Java
client dependency, keeping the GraalVM native-image surface small.
The WebDriverSession record holds data only (base URL, session id,
capabilities, timeout). Process and simulator ownership belongs to the
iOS session layer (com.blockether.spel.ios).
Errors are raised as ex-info with structured keys:
:webdriver/error - W3C error code string (e.g. "no such element")
:webdriver/message - human message from the remote end
:webdriver/stacktrace - remote stacktrace when provided
:webdriver/http-status - HTTP status code
:webdriver/endpoint - request path
Minimal W3C WebDriver HTTP client for the iOS application provider. Talks directly to a WebDriver-compatible endpoint (Appium) using JDK `java.net.http.HttpClient` and charred JSON — no Selenium/Appium Java client dependency, keeping the GraalVM native-image surface small. The `WebDriverSession` record holds data only (base URL, session id, capabilities, timeout). Process and simulator ownership belongs to the iOS session layer (`com.blockether.spel.ios`). Errors are raised as `ex-info` with structured keys: :webdriver/error - W3C error code string (e.g. "no such element") :webdriver/message - human message from the remote end :webdriver/stacktrace - remote stacktrace when provided :webdriver/http-status - HTTP status code :webdriver/endpoint - request path
(activate-app session bundle-id)Activates an installed iOS application by bundle identifier.
Activates an installed iOS application by bundle identifier.
(active-element session)Returns the currently focused element id.
Returns the currently focused element id.
(app-installed? session bundle-id)Returns true when an application is installed.
Returns true when an application is installed.
(app-state session bundle-id)Returns Appium's numeric application state for bundle-id:
0 unknown, 1 not running, 2 background suspended, 3 background, 4 foreground.
Returns Appium's numeric application state for `bundle-id`: 0 unknown, 1 not running, 2 background suspended, 3 background, 4 foreground.
(back session)POST /session/{id}/back — history back.
POST /session/{id}/back — history back.
(background-app session seconds)Moves the active application to the background for seconds.
Moves the active application to the background for `seconds`.
(clear session css)Finds an element by CSS selector and clears its value.
Finds an element by CSS selector and clears its value.
(clear-element session element-id)POST /session/{id}/element/{element}/clear — clears a found element id.
POST /session/{id}/element/{element}/clear — clears a found element id.
(click session css)Finds an element by CSS selector and clicks it via WebDriver.
Finds an element by CSS selector and clicks it via WebDriver.
(click-element session element-id)POST /session/{id}/element/{element}/click — clicks a found element id.
POST /session/{id}/element/{element}/click — clicks a found element id.
(content session)GET /session/{id}/source — returns the page HTML source string.
GET /session/{id}/source — returns the page HTML source string.
(context-details session)Returns Appium's detailed context records when supported. Records may contain id, title, url, bundleId, and page identifiers. Falls back to name-only records on older XCUITest drivers.
Returns Appium's detailed context records when supported. Records may contain id, title, url, bundleId, and page identifiers. Falls back to name-only records on older XCUITest drivers.
(contexts session)Returns the available Appium automation contexts, for example ["NATIVE_APP" "WEBVIEW_1"].
Returns the available Appium automation contexts, for example ["NATIVE_APP" "WEBVIEW_1"].
(cookies session)GET /session/{id}/cookie — returns the cookie list.
GET /session/{id}/cookie — returns the cookie list.
(create-session base-url capabilities)(create-session base-url capabilities {:keys [timeout-ms command-timeout-ms]})POST /session — creates a new WebDriver session.
Params:
base-url - String. WebDriver server root.
capabilities - Map. W3C capabilities (sent as {"capabilities"
{"alwaysMatch" caps "firstMatch" [{}]}}).
opts - Map, optional:
:timeout-ms - Long. Session-creation timeout (WDA install can
take 60-90s on first run). Default 120000.
:command-timeout-ms - Long. Timeout stored on the returned session for
subsequent commands.
Returns a WebDriverSession record. Throws ex-info when no session id can be extracted.
POST /session — creates a new WebDriver session.
Params:
`base-url` - String. WebDriver server root.
`capabilities` - Map. W3C capabilities (sent as {"capabilities"
{"alwaysMatch" caps "firstMatch" [{}]}}).
`opts` - Map, optional:
:timeout-ms - Long. Session-creation timeout (WDA install can
take 60-90s on first run). Default 120000.
:command-timeout-ms - Long. Timeout stored on the returned session for
subsequent commands.
Returns a WebDriverSession record.
Throws ex-info when no session id can be extracted.(current-context session)Returns the current Appium automation context name.
Returns the current Appium automation context name.
Default per-command timeout for WebDriver HTTP requests (milliseconds). Generous because XCUITest commands (session creation aside) can be slow.
Default per-command timeout for WebDriver HTTP requests (milliseconds). Generous because XCUITest commands (session creation aside) can be slow.
Default connect timeout for WebDriver HTTP requests (milliseconds).
Default connect timeout for WebDriver HTTP requests (milliseconds).
(delete-session! session)DELETE /session/{id} — ends the WebDriver session. Idempotent-friendly: callers should tolerate exceptions when the session is already gone.
DELETE /session/{id} — ends the WebDriver session. Idempotent-friendly:
callers should tolerate exceptions when the session is already gone.(element-attribute session element-id attribute)Returns a WebDriver/Appium element attribute.
Returns a WebDriver/Appium element attribute.
(element-displayed? session element-id)Returns whether an element is displayed.
Returns whether an element is displayed.
(element-enabled? session element-id)Returns whether an element is enabled.
Returns whether an element is enabled.
(element-rect session element-id)GET /session/{id}/element/{element}/rect — returns {:x :y :width :height} as doubles.
GET /session/{id}/element/{element}/rect — returns {:x :y :width :height}
as doubles.(element-selected? session element-id)Returns whether an element is selected/checked.
Returns whether an element is selected/checked.
(element-text session element-id)Returns an element's rendered/accessibility text.
Returns an element's rendered/accessibility text.
(element-viewport-center session element-id)Returns {:x :y} — the element's center in web-viewport CSS pixels after scrolling it into view. Returns nil when the script yields no usable coordinates (e.g. unit-test fakes).
Returns {:x :y} — the element's center in web-viewport CSS pixels after
scrolling it into view. Returns nil when the script yields no usable
coordinates (e.g. unit-test fakes).(evaluate session script)(evaluate session script args)POST /session/{id}/execute/sync — executes JavaScript synchronously.
script is treated as an expression and wrapped with return (...) when
it does not already start with return. args (optional vector) is passed
as WebDriver script arguments.
Returns the decoded script return value.
POST /session/{id}/execute/sync — executes JavaScript synchronously.
`script` is treated as an expression and wrapped with `return (...)` when
it does not already start with `return`. `args` (optional vector) is passed
as WebDriver script arguments.
Returns the decoded script return value.(execute-mobile session command args-map)Executes an Appium mobile: extension command (e.g. "mobile: tap",
"mobile: viewportRect") with a single argument map.
Executes an Appium `mobile:` extension command (e.g. "mobile: tap", "mobile: viewportRect") with a single argument map.
(execute-script-raw session script)(execute-script-raw session script args)POST /session/{id}/execute/sync — executes a script body VERBATIM (no
return wrapping). Use for multi-statement scripts that manage their own
return, and for Appium mobile: extension commands.
POST /session/{id}/execute/sync — executes a script body VERBATIM (no
`return` wrapping). Use for multi-statement scripts that manage their own
`return`, and for Appium `mobile:` extension commands.(extract-capabilities parsed)Extracts the capabilities map from a parsed create-session response, handling both W3C and legacy shapes.
Extracts the capabilities map from a parsed create-session response, handling both W3C and legacy shapes.
(extract-element-id value)Extracts an element id from a find-element response value. Handles the W3C key and the legacy "ELEMENT" key.
Extracts an element id from a find-element response value. Handles the W3C key and the legacy "ELEMENT" key.
(extract-session-id parsed)Extracts a session id from a parsed create-session response envelope.
Handles both shapes:
Extracts a session id from a parsed create-session response envelope.
Handles both shapes:
- W3C: {"value" {"sessionId" "..." "capabilities" {...}}}
- Legacy: {"sessionId" "..." "value" {...}}(fill session css value)Finds an element by CSS selector, clears it, then types value.
Finds an element by CSS selector, clears it, then types `value`.
(find-element session using value)POST /session/{id}/element — finds a single element.
using - String. Locator strategy ("css selector", "xpath", ...).
value - String. Selector value.
Returns the element id string. Throws ex-info with :webdriver/error "no such element" when absent.
POST /session/{id}/element — finds a single element.
`using` - String. Locator strategy ("css selector", "xpath", ...).
`value` - String. Selector value.
Returns the element id string.
Throws ex-info with :webdriver/error "no such element" when absent.(find-element-by-css session css)Finds a single element by CSS selector. Returns the element id string.
Finds a single element by CSS selector. Returns the element id string.
(find-element-by-selector session selector)Finds an element using context-aware selector semantics.
Finds an element using context-aware selector semantics.
(find-elements session using value)POST /session/{id}/elements — returns all matching element ids.
POST /session/{id}/elements — returns all matching element ids.
(forward session)POST /session/{id}/forward — history forward.
POST /session/{id}/forward — history forward.
(get-permission session bundle-id service)Returns the current iOS Simulator permission value for a service.
Returns the current iOS Simulator permission value for a service.
(hide-keyboard session)Dismisses the iOS software keyboard.
Dismisses the iOS software keyboard.
(install-app session app-path)Installs a simulator-compatible .app through Appium.
Installs a simulator-compatible .app through Appium.
(launch-app session bundle-id)(launch-app session bundle-id {:keys [arguments environment]})Launches an installed application. Optional opts may include :arguments and :environment.
Launches an installed application. Optional opts may include :arguments and :environment.
(native-context? session)Returns true when the session currently targets NATIVE_APP. Plain W3C servers that do not implement contexts are treated as web sessions.
Returns true when the session currently targets NATIVE_APP. Plain W3C servers that do not implement contexts are treated as web sessions.
Semantic native roles mapped to XCTest element class names.
Semantic native roles mapped to XCTest element class names.
Explicit selector prefixes accepted by the iOS application provider.
Explicit selector prefixes accepted by the iOS application provider.
(navigate session url)POST /session/{id}/url — navigates to url.
POST /session/{id}/url — navigates to `url`.
(open-url session url bundle-id)Opens a deep/universal URL for an application.
Opens a deep/universal URL for an application.
(perform-actions session payload)POST /session/{id}/actions — performs a raw W3C actions payload.
POST /session/{id}/actions — performs a raw W3C actions payload.
(press-key session key)(press-key session element-id key)Sends a named WebDriver key to a selector or the focused element.
Sends a named WebDriver key to a selector or the focused element.
(ready? base-url)Returns true when GET /status reports the server ready, false otherwise (including connection failures — safe for startup polling).
Returns true when GET /status reports the server ready, false otherwise (including connection failures — safe for startup polling).
(release-actions session)DELETE /session/{id}/actions — releases all pressed inputs.
DELETE /session/{id}/actions — releases all pressed inputs.
(reload session)POST /session/{id}/refresh — reloads the page.
POST /session/{id}/refresh — reloads the page.
(remove-app session bundle-id)Uninstalls an application by bundle identifier through Appium.
Uninstalls an application by bundle identifier through Appium.
(request {:keys [base-url method path body timeout-ms]})Performs a WebDriver HTTP request and returns the decoded value field.
Params:
opts - Map:
:base-url - String. WebDriver server root (e.g. http://127.0.0.1:4901).
:method - Keyword. :get, :post, or :delete.
:path - String. Endpoint path starting with /.
:body - Map, optional. JSON-encoded for :post requests.
:timeout-ms - Long, optional. Per-request timeout.
Returns the decoded JSON value (may be nil) plus the full parsed body
under metadata is NOT used — callers needing the envelope use
request-envelope.
Throws ex-info with :webdriver/* keys on HTTP or W3C errors.
Performs a WebDriver HTTP request and returns the decoded `value` field. Params: `opts` - Map: :base-url - String. WebDriver server root (e.g. http://127.0.0.1:4901). :method - Keyword. :get, :post, or :delete. :path - String. Endpoint path starting with /. :body - Map, optional. JSON-encoded for :post requests. :timeout-ms - Long, optional. Per-request timeout. Returns the decoded JSON `value` (may be nil) plus the full parsed body under metadata is NOT used — callers needing the envelope use `request-envelope`. Throws ex-info with :webdriver/* keys on HTTP or W3C errors.
(screenshot session)GET /session/{id}/screenshot — returns PNG bytes (decoded from base64).
GET /session/{id}/screenshot — returns PNG bytes (decoded from base64).
(scroll-element session element-id direction amount smooth?)Scrolls a DOM element in a semantic direction through WebDriver script arguments. Returns the requested direction and amount.
Scrolls a DOM element in a semantic direction through WebDriver script arguments. Returns the requested direction and amount.
(selector-strategy selector native?)Converts a user selector into a WebDriver locator strategy.
In web contexts, unprefixed selectors are CSS. In NATIVE_APP, unprefixed
selectors are accessibility identifiers. Explicit forms work in native
context, for example accessibility-id=Login, id=username,
xpath=//XCUIElementTypeButton, class-chain=..., and predicate=....
Converts a user selector into a WebDriver locator strategy. In web contexts, unprefixed selectors are CSS. In NATIVE_APP, unprefixed selectors are accessibility identifiers. Explicit forms work in native context, for example `accessibility-id=Login`, `id=username`, `xpath=//XCUIElementTypeButton`, `class-chain=...`, and `predicate=...`.
(send-keys session element-id text)POST /session/{id}/element/{element}/value — types text into an element.
POST /session/{id}/element/{element}/value — types text into an element.
(set-permission session bundle-id service access)Sets an iOS Simulator permission using XCUITest's mobile: setPermission.
access is yes, no, or unset for the requested service.
Sets an iOS Simulator permission using XCUITest's mobile: setPermission. `access` is yes, no, or unset for the requested service.
(status base-url)(status base-url {:keys [timeout-ms]})GET /status — returns the decoded value map ({"ready" true ...}). Throws on connection failure or non-2xx response.
GET /status — returns the decoded value map ({"ready" true ...}).
Throws on connection failure or non-2xx response.(swipe session {:keys [from to duration]})Performs a native touch swipe.
Params:
session - WebDriverSession.
opts - Map:
:from - [x y] start coordinates.
:to - [x y] end coordinates.
:duration - Long ms, default 800.
Performs a native touch swipe. Params: `session` - WebDriverSession. `opts` - Map: :from - [x y] start coordinates. :to - [x y] end coordinates. :duration - Long ms, default 800.
(swipe-actions-payload from to)(swipe-actions-payload [fx fy] [tx ty] duration)Builds a W3C pointer-actions payload for a touch swipe.
Params:
from - [x y] start coordinates.
to - [x y] end coordinates.
duration - Long. Move duration in ms (default 800).
Builds a W3C pointer-actions payload for a touch swipe. Params: `from` - [x y] start coordinates. `to` - [x y] end coordinates. `duration` - Long. Move duration in ms (default 800).
(swipe-screen session {:keys [from to duration]})Performs a native touch swipe using absolute screen coordinates.
Performs a native touch swipe using absolute screen coordinates.
(switch-context session context-name)Switches the Appium session to context-name. Native element commands
operate in NATIVE_APP; DOM, CSS, and JavaScript commands operate in a
WEBVIEW context.
Switches the Appium session to `context-name`. Native element commands operate in NATIVE_APP; DOM, CSS, and JavaScript commands operate in a WEBVIEW context.
(tap session x y)Performs a native tap at web-viewport coordinates (x, y).
Coordinates are translated to absolute screen points via viewport-offset,
then executed with Appium's mobile: tap — a genuine XCUITest tap
gesture. W3C touch actions are deliberately NOT the primary path: WDA
synthesizes them at the IOHID level, which fires touchstart/touchend in
Safari but frequently fails the system tap recognizer, so no click is
ever synthesized. Falls back to the W3C payload only when mobile: tap
is unavailable (non-Appium WebDriver servers).
No click-verification/retap is attempted: legitimate mobile pages preventDefault() the synthetic click in touch handlers, so a retap would double-fire their touch events. Note that iOS hit-tests the synthesized click ~100ms AFTER touchstart — pages whose touch handlers mutate layout will retarget the click exactly as they would for a real finger.
Performs a native tap at web-viewport coordinates (x, y). Coordinates are translated to absolute screen points via `viewport-offset`, then executed with Appium's `mobile: tap` — a genuine XCUITest tap gesture. W3C touch actions are deliberately NOT the primary path: WDA synthesizes them at the IOHID level, which fires touchstart/touchend in Safari but frequently fails the system tap recognizer, so no `click` is ever synthesized. Falls back to the W3C payload only when `mobile: tap` is unavailable (non-Appium WebDriver servers). No click-verification/retap is attempted: legitimate mobile pages preventDefault() the synthetic click in touch handlers, so a retap would double-fire their touch events. Note that iOS hit-tests the synthesized click ~100ms AFTER touchstart — pages whose touch handlers mutate layout will retarget the click exactly as they would for a real finger.
(tap-actions-payload x y)Builds a W3C pointer-actions payload for a single touch tap at (x, y).
Builds a W3C pointer-actions payload for a single touch tap at (x, y).
(tap-element session css)Taps the center of the element matching a CSS selector using a native touch gesture.
Flow: find element → scroll into view + viewport-relative center (via getBoundingClientRect) → translate to screen points → tap. Falls back to the W3C element rect when the center script yields nothing (unit-test fakes). Returned :x/:y are web-viewport CSS coordinates.
Taps the center of the element matching a CSS selector using a native touch gesture. Flow: find element → scroll into view + viewport-relative center (via getBoundingClientRect) → translate to screen points → tap. Falls back to the W3C element rect when the center script yields nothing (unit-test fakes). Returned :x/:y are web-viewport CSS coordinates.
(tap-screen session x y)Performs a native tap at absolute screen coordinates without applying a web-viewport chrome offset. Use this in NATIVE_APP context.
Performs a native tap at absolute screen coordinates without applying a web-viewport chrome offset. Use this in NATIVE_APP context.
(terminate-app session bundle-id)Terminates an installed application. Returns Appium's result.
Terminates an installed application. Returns Appium's result.
(title session)GET /session/{id}/title — returns the page title string.
GET /session/{id}/title — returns the page title string.
(type-keys session text)Types text into the currently focused native or web element.
Types text into the currently focused native or web element.
(url session)GET /session/{id}/url — returns the current URL string.
GET /session/{id}/url — returns the current URL string.
(viewport-offset session)Returns {:x :y} — the native-point offset of the web viewport within the device screen.
W3C pointer actions on Appium's XCUITest driver ALWAYS run in the native context using absolute screen points, while DOM rects are web-viewport CSS pixels. Without this offset, taps computed from DOM coordinates land in Safari's chrome (status bar + URL bar) instead of the page content.
Derived from mobile: viewportRect (physical pixels) divided by the
screen scale from mobile: deviceScreenInfo. Falls back to {:x 0 :y 0}
when the Appium extensions are unavailable (plain WebDriver servers,
unit-test fakes).
Returns {:x :y} — the native-point offset of the web viewport within the
device screen.
W3C pointer actions on Appium's XCUITest driver ALWAYS run in the native
context using absolute screen points, while DOM rects are web-viewport CSS
pixels. Without this offset, taps computed from DOM coordinates land in
Safari's chrome (status bar + URL bar) instead of the page content.
Derived from `mobile: viewportRect` (physical pixels) divided by the
screen scale from `mobile: deviceScreenInfo`. Falls back to {:x 0 :y 0}
when the Appium extensions are unavailable (plain WebDriver servers,
unit-test fakes).Common WebDriver key names mapped to Unicode key values.
Common WebDriver key names mapped to Unicode key values.
(window-rect session)Returns the current native window rectangle as {:x :y :width :height}.
Returns the current native window rectangle as {:x :y :width :height}.
(wrap-expression-script script)Wraps an expression-oriented script for W3C execute-script semantics.
W3C execute-script runs a function BODY and only returns values from an
explicit return. Playwright-style expressions (including spel's snapshot
IIFE) therefore need wrapping:
(wrap-expression-script "document.title") ;; => "return (document.title);"
Scripts that already start with return (after trimming) pass through.
Wraps an expression-oriented script for W3C execute-script semantics. W3C execute-script runs a function BODY and only returns values from an explicit `return`. Playwright-style expressions (including spel's snapshot IIFE) therefore need wrapping: (wrap-expression-script "document.title") ;; => "return (document.title);" Scripts that already start with `return` (after trimming) pass through.
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 |