Files
sen d6464dcef3 [playground/actionbook-web-test]feat: add browser web testing skill with json-ui reports
Add actionbook-web-test skill — a declarative YAML-driven browser testing
framework for Claude Code. Includes:

- SKILL.md with full execution flow, selector strategy, and recovery logic
- YAML workflow format with 17+ assertion types
- json-ui report generation with per-test collapsible sections and
  base64-embedded screenshots for every test (PASS/FAIL/SKIP)
- generate-report.mjs script for building report JSON from execution results
- Reference docs for workflow format, assertion types, and report structure
2026-03-13 21:35:25 +08:00

17 KiB

Workflow YAML Format Reference

Complete schema reference for actionbook-web-test workflow files (.test.yml).

Schema Overview

A workflow file defines a declarative browser test — a sequence of steps executed against a live website via the Actionbook CLI. Every workflow is a single YAML document with the following top-level fields:

Field Type Required Default Description
name string yes — Human-readable test name. Must be unique within a directory.
description string yes — What this test validates. Shown in reports.
url string no — Starting URL. Opened before the first step.
tags string[] no [] Arbitrary labels for filtering (smoke, auth, regression).
timeout number no 30000 Global step timeout in milliseconds. Individual steps can override.
actions string[] no [] Actionbook action IDs to pre-fetch verified selectors before execution. Use actionbook search to discover IDs, then actionbook get to retrieve page structure with selectors.
env object no {} Key-value pairs injected as template variables. Values support {{template}} syntax and $ENV_VAR shell expansion.
setup object no see below Browser launch configuration.
matrix object[] no — Parameterized test data. The workflow runs once per matrix entry.
steps Step[] yes — Ordered list of browser actions and assertions.

Minimal Example

name: Google search smoke test
description: Verify Google search returns results for a known query
url: https://www.google.com
tags: [smoke]

steps:
  - name: Search for actionbook
    action: fill
    selector: "textarea[name='q']"
    value: "actionbook browser automation"

  - name: Submit search
    action: press
    key: Enter

  - name: Wait for results
    action: wait
    selector: "#search"

  - name: Verify results loaded
    action: assert
    assert:
      - type: element-exists
        selector: "#search .g"
      - type: text-contains
        selector: "#search"
        value: "actionbook"

Step Schema

Each entry in steps is an object describing a single browser interaction or assertion.

Field Type Required Default Description
name string yes — Human-readable step description. Appears in test output.
action string yes — Action type (see Action Types below).
selector string conditional — CSS selector targeting the element. Required for element-interaction actions.
value string conditional — Input value for fill, type, and select actions.
url string conditional — Target URL for open and goto actions.
key string conditional — Key name for press action (e.g. Enter, Tab, Escape).
expression string conditional — JavaScript expression for eval action.
timeout number no inherits global Step-level timeout override in milliseconds.
assert Assertion[] no [] Assertions to check after this step completes.
on_fail string no "abort" Failure behavior: "abort", "skip", or "continue".
retry number no 0 Number of times to retry this step on failure before applying on_fail.
condition string no — Conditional expression. Step is skipped if condition evaluates to false.
wait_after number no 0 Milliseconds to wait after step completes (debounce for animations, network).
sensitive boolean no false When true, the step's value is redacted in verbose logs. Use for password/secret fields.
file_path string conditional — File path for upload action.

Action Types

Action Required Fields CLI Command Description
open url actionbook browser open <url> Open URL in a new tab
goto url actionbook browser goto <url> Navigate current tab to URL
click selector actionbook browser click "<selector>" Click an element
fill selector, value actionbook browser fill "<selector>" "<value>" Clear field, then type text
type selector, value actionbook browser type "<selector>" "<value>" Append text (no clear)
select selector, value actionbook browser select "<selector>" "<value>" Select dropdown option by value
hover selector actionbook browser hover "<selector>" Hover over element
focus selector actionbook browser focus "<selector>" Focus an element
press key actionbook browser press <key> Press a keyboard key
wait selector actionbook browser wait "<selector>" Wait for element to appear
wait-fn expression actionbook browser wait-fn "<expression>" Wait for JS condition to be truthy
wait-idle — actionbook browser wait-idle Wait for network idle (not supported in extension mode)
wait-nav — actionbook browser wait-nav Wait for navigation to complete
screenshot — actionbook browser screenshot Capture screenshot
text selector (optional) actionbook browser text "<selector>" Get element or page text content
eval expression actionbook browser eval "<expression>" Execute JavaScript
upload selector, file_path actionbook browser upload "<selector>" "<file_path>" Upload a file via file input
scroll direction actionbook browser scroll <direction> Scroll page (up/down/top/bottom/to)
back — actionbook browser back Navigate back
forward — actionbook browser forward Navigate forward
reload — actionbook browser reload Reload current page
snapshot — actionbook browser snapshot Capture accessibility tree (for fallback selector resolution)
emulate device actionbook browser emulate <device> Emulate device (iphone-14, ipad, etc.)
info selector actionbook browser info "<selector>" Get element details (box, visibility, attrs)
console — actionbook browser console --level error Capture console messages
assert assert — Pure assertion step (no browser interaction, only checks)
close — actionbook browser close Close the browser session

Template Variables

String values in url, value, expression, selector, and env fields support template interpolation using double-brace syntax.

Built-in Variables

Variable Type Description Example Output
{{timestamp}} number Current Unix timestamp (seconds) 1710345600
{{timestamp_ms}} number Current Unix timestamp (milliseconds) 1710345600000
{{date}} string ISO 8601 date string 2026-03-13T10:30:00Z
{{date_short}} string Short date (YYYY-MM-DD) 2026-03-13
{{random}} string Random 8-character hex string a3f7b2c1
{{uuid}} string UUID v4 550e8400-e29b-41d4-a716-446655440000

Environment Variables

Variables defined in the env block are accessed via {{env.VAR_NAME}}:

env:
  BASE_URL: https://staging.example.com
  TEST_USER: testuser-{{random}}@example.com
  TEST_PASSWORD: $TEST_PASSWORD  # Resolved from shell environment

steps:
  - name: Open staging site
    action: open
    url: "{{env.BASE_URL}}/login"

  - name: Fill username
    action: fill
    selector: "#email"
    value: "{{env.TEST_USER}}"

Shell environment variables are expanded with $VAR or ${VAR} syntax in env values only. This allows secrets to be injected from CI without appearing in the YAML file.

Matrix Variables

When using matrix, each key in the matrix entry is available as {{matrix.KEY}}:

matrix:
  - { query: "typescript", min_results: 5 }
  - { query: "rust lang", min_results: 3 }

steps:
  - name: Search for {{matrix.query}}
    action: fill
    selector: "#search-input"
    value: "{{matrix.query}}"

Browser Setup Options

The setup block configures how the browser is launched. All fields are optional.

setup:
  headless: true                    # Run without visible window (default: false, CI auto-detects)
  stealth: false                    # Enable stealth mode to avoid bot detection (default: false)
  block_images: false               # Block image loading for faster tests (default: false)
  auto_dismiss_dialogs: true        # Auto-dismiss alert/confirm/prompt dialogs (default: true)
  no_animations: true               # Inject CSS to disable transitions/animations (default: true)
  rewrite_urls: false               # Reserved for URL rewriting rules (default: false)
  viewport:                         # Browser viewport dimensions
    width: 1280                     # Default: 1280
    height: 720                     # Default: 720
  user_agent: "custom UA string"    # Override user agent (default: browser default)
  profile: "myapp"                  # Use a named Actionbook browser profile for session persistence
  timeout: 60000                    # Browser launch timeout in ms (default: 30000)

Field details:

Field Type Default Description
headless boolean false (local), auto in CI No visible browser window. CI environments auto-enable.
stealth boolean false Patches browser fingerprinting signals. Use for sites with bot detection.
block_images boolean false Blocks image requests. Speeds up page loads for non-visual tests.
auto_dismiss_dialogs boolean true Automatically dismisses alert(), confirm(), prompt() dialogs.
no_animations boolean true Injects * { transition: none !important; animation: none !important; }. Prevents flaky waits.
rewrite_urls boolean false Reserved for future URL rewriting/proxy support.
viewport object {width: 1280, height: 720} Viewport size. Some assertions (e.g., element-visible) depend on viewport.
user_agent string browser default Custom User-Agent header.
profile string — Named Actionbook profile. Persists cookies/storage across runs.
timeout number 30000 Browser launch timeout. Increase for slow CI environments.

Conditional Steps

Steps can include a condition field. The step executes only if the condition evaluates to true. If false, the step is silently skipped (not counted as a failure).

Condition Syntax

Conditions reuse the assertion type system with a compact string format:

<assertion-type> [parameters...]

Examples

# Click cookie banner only if it exists
- name: Accept cookies if banner present
  action: click
  selector: "[data-testid='cookie-accept']"
  condition: element-exists "[data-testid='cookie-banner']"
  on_fail: continue

# Skip step if already on the right page
- name: Navigate to dashboard
  action: goto
  url: https://app.example.com/dashboard
  condition: url-not-contains "/dashboard"

# Only fill field if it's visible (some forms progressively disclose fields)
- name: Fill optional company field
  action: fill
  selector: "#company"
  value: "Acme Corp"
  condition: element-visible "#company"

Supported Condition Types

Condition Parameters True when...
element-exists "<selector>" CSS selector Element is in the DOM
element-not-exists "<selector>" CSS selector Element is not in the DOM
element-visible "<selector>" CSS selector Element is visible in viewport
url-contains "<substring>" URL substring Current URL contains substring
url-not-contains "<substring>" URL substring Current URL does not contain substring
eval-truthy "<expression>" JS expression Expression returns truthy value

Data-Driven Tests (Matrix)

The matrix field accepts an array of objects. The entire workflow runs once for each entry, with matrix values available as {{matrix.KEY}} template variables.

Basic Matrix

name: Search results validation
description: Verify search returns relevant results for multiple queries
url: https://example.com/search
tags: [smoke, search]

matrix:
  - { query: "typescript", expected_text: "TypeScript" }
  - { query: "rust programming", expected_text: "Rust" }
  - { query: "python tutorial", expected_text: "Python" }

steps:
  - name: Enter search query
    action: fill
    selector: "#search-input"
    value: "{{matrix.query}}"

  - name: Submit search
    action: press
    key: Enter

  - name: Wait for results
    action: wait
    selector: ".search-results"

  - name: Verify results contain expected text
    action: assert
    assert:
      - type: text-contains
        selector: ".search-results"
        value: "{{matrix.expected_text}}"

Matrix with Multiple Assertions

matrix:
  - { path: "/pricing", title: "Pricing", has_cta: true }
  - { path: "/about", title: "About Us", has_cta: false }
  - { path: "/contact", title: "Contact", has_cta: true }

steps:
  - name: Navigate to {{matrix.path}}
    action: goto
    url: "https://example.com{{matrix.path}}"

  - name: Verify page title
    action: assert
    assert:
      - type: page-title-contains
        value: "{{matrix.title}}"

  - name: Check CTA button
    action: assert
    condition: eval-truthy "{{matrix.has_cta}}"
    assert:
      - type: element-exists
        selector: ".cta-button"

Test Report Output with Matrix

Each matrix entry produces a separate test result in the report:

Search results validation [query=typescript]     PASS  (1.2s)
Search results validation [query=rust programming] PASS  (1.4s)
Search results validation [query=python tutorial] FAIL  (2.1s)
  Step: Verify results contain expected text
  Assertion failed: text-contains — expected ".search-results" to contain "Python"
  Screenshot: .actionbook-web-test/failures/search-results-validation-python-tutorial.png

Failure Handling

on_fail Behavior

Value Behavior
"abort" (default) Stop the entire workflow immediately. Mark test as FAIL.
"skip" Skip remaining assertions in this step and move to the next step. Step marked as SKIPPED.
"continue" Record the failure but continue executing subsequent steps. Test still marked FAIL at the end.

Retry Logic

The retry field specifies how many times to retry a failing step before applying on_fail. This is useful for steps that may fail due to timing (animations, lazy loading, network).

- name: Wait for dynamically loaded content
  action: wait
  selector: ".lazy-content"
  timeout: 5000
  retry: 2          # Try up to 3 times total (1 initial + 2 retries)
  on_fail: continue # If still failing after retries, continue test

Between retries, the runner waits 500ms (not configurable). Each retry resets the step timeout.


Complete Workflow Example

name: E-commerce checkout flow
description: Verify a user can search for a product, add to cart, and reach checkout
url: https://shop.example.com
tags: [e2e, checkout, critical]
timeout: 15000

env:
  SEARCH_TERM: "wireless headphones"
  TEST_EMAIL: buyer-{{random}}@test.example.com

setup:
  headless: true
  no_animations: true
  viewport: { width: 1440, height: 900 }

steps:
  - name: Accept cookie consent if present
    action: click
    selector: "[data-testid='cookie-accept']"
    condition: element-exists "[data-testid='cookie-banner']"
    on_fail: continue

  - name: Search for product
    action: fill
    selector: "#search-input"
    value: "{{env.SEARCH_TERM}}"

  - name: Submit search
    action: press
    key: Enter

  - name: Wait for results
    action: wait
    selector: ".product-grid"
    timeout: 10000

  - name: Verify search returned results
    action: assert
    assert:
      - type: element-count
        selector: ".product-card"
        operator: ">="
        value: 1
      - type: text-contains
        selector: ".product-grid"
        value: "headphones"

  - name: Click first product
    action: click
    selector: ".product-card:first-child a"

  - name: Wait for product page
    action: wait-nav

  - name: Add to cart
    action: click
    selector: "[data-testid='add-to-cart']"
    retry: 1

  - name: Open cart
    action: click
    selector: "[data-testid='cart-icon']"

  - name: Wait for cart page
    action: wait-nav

  - name: Verify item in cart
    action: assert
    assert:
      - type: element-count
        selector: ".cart-item"
        operator: ">="
        value: 1
      - type: url-contains
        value: "/cart"

  - name: Proceed to checkout
    action: click
    selector: "[data-testid='checkout-btn']"

  - name: Wait for checkout page
    action: wait-nav

  - name: Verify checkout page loaded
    action: assert
    assert:
      - type: url-contains
        value: "/checkout"
      - type: element-exists
        selector: "#email"

  - name: Capture final state
    action: screenshot