agentchrome 1.43.0

A CLI tool for browser automation via the Chrome DevTools Protocol
Documentation
# File: tests/features/js-execution.feature
#
# Generated from: .claude/specs/13-javascript-execution/requirements.md
# Issues: #13, #183

Feature: JavaScript execution in page context
  As a developer / automation engineer
  I want to execute arbitrary JavaScript in the browser page context via the CLI
  So that I can perform custom automation and data extraction from scripts

  Background:
    Given Chrome is running with CDP enabled

  # --- Happy Path ---

  Scenario: Execute a JavaScript expression
    Given a page is loaded at "https://example.com"
    When I run "agentchrome js exec 'document.title'"
    Then stdout contains JSON with keys "result", "type"
    And the "result" field is "Example Domain"
    And the "type" field is "string"

  Scenario: Execute a JavaScript function
    Given a page is loaded at "https://example.com"
    When I run "agentchrome js exec '() => { return 2 + 2; }'"
    Then the "result" field is 4
    And the "type" field is "number"

  Scenario Outline: Return all JavaScript value types
    Given a page is loaded at "https://example.com"
    When I run "agentchrome js exec '<expression>'"
    Then the "type" field is "<expected_type>"

    Examples:
      | expression            | expected_type |
      | 'hello'               | string        |
      | 42                    | number        |
      | true                  | boolean       |
      | null                  | object        |
      | undefined             | undefined     |
      | ({key: 'val'})        | object        |
      | [1, 2, 3]             | object        |

  # --- Tab Targeting ---

  Scenario: Target a specific tab with --tab
    Given multiple tabs are open
    And the second tab is loaded at "https://example.org"
    When I run "agentchrome js exec --tab <SECOND_TAB_ID> 'document.title'"
    Then the "result" field reflects the second tab's title

  # --- Promise Handling ---

  Scenario: Await promise results by default
    Given a page is loaded at "https://example.com"
    When I run "agentchrome js exec 'new Promise(r => setTimeout(() => r(\"done\"), 100))'"
    Then the "result" field is "done"
    And the "type" field is "string"

  Scenario: Disable promise awaiting with --no-await
    Given a page is loaded at "https://example.com"
    When I run "agentchrome js exec --no-await 'new Promise(r => r(42))'"
    Then the "type" field is "object"

  # --- Timeout ---

  Scenario: Execution timeout with --timeout
    Given a page is loaded at "https://example.com"
    When I run "agentchrome js exec --timeout 100 'new Promise(() => {})'"
    Then stderr contains a JSON error indicating timeout
    And the exit code is non-zero

  # --- File and Stdin Input ---

  Scenario: Execute JavaScript from a file
    Given a page is loaded at "https://example.com"
    And a temporary file contains "document.title"
    When I run "agentchrome js exec --file <TEMP_FILE>"
    Then the "result" field is "Example Domain"
    And the "type" field is "string"

  Scenario: Read code from stdin with dash argument
    Given a page is loaded at "https://example.com"
    When I pipe "document.title" to "agentchrome js exec -"
    Then the "result" field is "Example Domain"
    And the "type" field is "string"

  # --- Element Context ---

  Scenario: Element context execution with --uid
    Given a page is loaded at "https://example.com"
    And a snapshot has been taken with "agentchrome page snapshot"
    And element "s1" exists in the snapshot
    When I run "agentchrome js exec --uid s1 '(el) => el.textContent'"
    Then the "result" field contains the element's text content
    And the "type" field is "string"

  # --- Error Handling ---

  Scenario: JavaScript exception returned as structured error
    Given a page is loaded at "https://example.com"
    When I run "agentchrome js exec 'throw new Error(\"test error\")'"
    Then stderr contains a JSON error with key "error"
    And the error message contains "Error: test error"
    And the exit code is non-zero

  Scenario: Reference error for undefined variable
    Given a page is loaded at "https://example.com"
    When I run "agentchrome js exec 'nonExistentVariable'"
    Then stderr contains a JSON error
    And the error message contains "ReferenceError"
    And the exit code is non-zero

  Scenario: UID not found error
    Given a page is loaded at "https://example.com"
    When I run "agentchrome js exec --uid s999 '(el) => el.textContent'"
    Then stderr contains a JSON error about UID not found
    And the exit code is non-zero

  Scenario: File not found error
    Given a page is loaded at "https://example.com"
    When I run "agentchrome js exec --file /nonexistent/script.js"
    Then stderr contains a JSON error about file not found
    And the exit code is non-zero

  # --- Truncation ---

  Scenario: Large result truncation with --max-size
    Given a page is loaded at "https://example.com"
    When I run "agentchrome js exec --max-size 100 \"'x'.repeat(10000)\""
    Then the JSON output contains a "truncated" field set to true
    And the "result" field is shorter than 10000 characters

  # --- Console Capture ---

  Scenario: Console output captured during execution
    Given a page is loaded at "https://example.com"
    When I run "agentchrome js exec 'console.log(\"hello\"); 42'"
    Then the "result" field is 42
    And the "console" field is an array
    And the "console" array contains an entry with level "log" and text "hello"

  # --- Scope Isolation (Added by issue #183) ---

  # Added by issue #183
  Scenario: Clean scope per invocation with let declarations
    Given a page is loaded at "https://example.com"
    When I run "agentchrome js exec --code 'let x = 1; x'"
    Then the "result" field is 1
    When I run "agentchrome js exec --code 'let x = 2; x'"
    Then the "result" field is 2
    And no re-declaration error occurred

  # Added by issue #183
  Scenario: Clean scope per invocation with const declarations
    Given a page is loaded at "https://example.com"
    When I run "agentchrome js exec --code 'const y = 10; y'"
    Then the "result" field is 10
    When I run "agentchrome js exec --code 'const y = 20; y'"
    Then the "result" field is 20
    And no re-declaration error occurred

  # --- Explicit --stdin Flag (Added by issue #183) ---

  # Added by issue #183
  Scenario: Read code from stdin with --stdin flag
    Given a page is loaded at "https://example.com"
    When I pipe "document.title" to "agentchrome js exec --stdin"
    Then the "result" field is "Example Domain"
    And the "type" field is "string"

  # --- Cross-Platform --code Flag (Added by issue #183) ---

  # Added by issue #183
  Scenario: Execute code via --code named argument
    Given a page is loaded at "https://example.com"
    When I run "agentchrome js exec --code \"document.querySelector('html').tagName\""
    Then the "result" field is "HTML"
    And the "type" field is "string"

  # Added by issue #183
  Scenario: --code flag with simple expression
    Given a page is loaded at "https://example.com"
    When I run "agentchrome js exec --code 'document.title'"
    Then the "result" field is "Example Domain"
    And the "type" field is "string"