# 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"