update unit tests
This commit is contained in:
@@ -1,13 +1,33 @@
|
|||||||
# agent-browser
|
# agent-browser
|
||||||
|
|
||||||
Headless browser automation CLI for AI agents.
|
Headless browser automation CLI for AI agents. Fast Rust CLI with Node.js fallback.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
### npm (recommended)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
npm install -g agent-browser
|
||||||
|
agent-browser install # Download Chromium
|
||||||
|
```
|
||||||
|
|
||||||
|
### From Source
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/anthropics/agent-browser
|
||||||
|
cd agent-browser
|
||||||
pnpm install
|
pnpm install
|
||||||
npx playwright install chromium
|
|
||||||
pnpm build
|
pnpm build
|
||||||
|
agent-browser install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Linux Dependencies
|
||||||
|
|
||||||
|
On Linux, install system dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
agent-browser install --with-deps
|
||||||
|
# or manually: npx playwright install-deps chromium
|
||||||
```
|
```
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
@@ -44,17 +64,14 @@ agent-browser fill <sel> <text> # Clear and fill
|
|||||||
agent-browser press <key> # Press key (Enter, Tab, Control+a)
|
agent-browser press <key> # Press key (Enter, Tab, Control+a)
|
||||||
agent-browser keydown <key> # Hold key down
|
agent-browser keydown <key> # Hold key down
|
||||||
agent-browser keyup <key> # Release key
|
agent-browser keyup <key> # Release key
|
||||||
agent-browser insert <text> # Insert text (no key events)
|
|
||||||
agent-browser hover <sel> # Hover element
|
agent-browser hover <sel> # Hover element
|
||||||
agent-browser select <sel> <val> # Select dropdown option
|
agent-browser select <sel> <val> # Select dropdown option
|
||||||
agent-browser multiselect <sel> <v1> <v2> # Multi-select
|
|
||||||
agent-browser check <sel> # Check checkbox
|
agent-browser check <sel> # Check checkbox
|
||||||
agent-browser uncheck <sel> # Uncheck checkbox
|
agent-browser uncheck <sel> # Uncheck checkbox
|
||||||
agent-browser scroll <dir> [px] # Scroll (up/down/left/right)
|
agent-browser scroll <dir> [px] # Scroll (up/down/left/right)
|
||||||
agent-browser scrollinto <sel> # Scroll element into view
|
agent-browser scrollintoview <sel> # Scroll element into view
|
||||||
agent-browser drag <src> <tgt> # Drag and drop
|
agent-browser drag <src> <tgt> # Drag and drop
|
||||||
agent-browser upload <sel> <files> # Upload files
|
agent-browser upload <sel> <files> # Upload files
|
||||||
agent-browser download [path] # Wait for download
|
|
||||||
agent-browser screenshot [path] # Take screenshot (--full for full page)
|
agent-browser screenshot [path] # Take screenshot (--full for full page)
|
||||||
agent-browser pdf <path> # Save as PDF
|
agent-browser pdf <path> # Save as PDF
|
||||||
agent-browser snapshot # Accessibility tree with refs (best for AI)
|
agent-browser snapshot # Accessibility tree with refs (best for AI)
|
||||||
@@ -140,14 +157,14 @@ agent-browser set geo <lat> <lng> # Set geolocation
|
|||||||
agent-browser set offline [on|off] # Toggle offline mode
|
agent-browser set offline [on|off] # Toggle offline mode
|
||||||
agent-browser set headers <json> # Extra HTTP headers
|
agent-browser set headers <json> # Extra HTTP headers
|
||||||
agent-browser set credentials <u> <p> # HTTP basic auth
|
agent-browser set credentials <u> <p> # HTTP basic auth
|
||||||
agent-browser set media [dark|light|print] # Emulate media
|
agent-browser set media [dark|light] # Emulate color scheme
|
||||||
```
|
```
|
||||||
|
|
||||||
### Cookies & Storage
|
### Cookies & Storage
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
agent-browser cookies # Get all cookies
|
agent-browser cookies # Get all cookies
|
||||||
agent-browser cookies set <json> # Set cookies
|
agent-browser cookies set <name> <val> # Set cookie
|
||||||
agent-browser cookies clear # Clear cookies
|
agent-browser cookies clear # Clear cookies
|
||||||
|
|
||||||
agent-browser storage local # Get all localStorage
|
agent-browser storage local # Get all localStorage
|
||||||
@@ -167,14 +184,13 @@ agent-browser network route <url> --body <json> # Mock response
|
|||||||
agent-browser network unroute [url] # Remove routes
|
agent-browser network unroute [url] # Remove routes
|
||||||
agent-browser network requests # View tracked requests
|
agent-browser network requests # View tracked requests
|
||||||
agent-browser network requests --filter api # Filter requests
|
agent-browser network requests --filter api # Filter requests
|
||||||
agent-browser response <url> # Get response body (waits for matching request)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Tabs & Windows
|
### Tabs & Windows
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
agent-browser tab # List tabs
|
agent-browser tab # List tabs
|
||||||
agent-browser tab new # New tab
|
agent-browser tab new [url] # New tab (optionally with URL)
|
||||||
agent-browser tab <n> # Switch to tab n
|
agent-browser tab <n> # Switch to tab n
|
||||||
agent-browser tab close [n] # Close tab
|
agent-browser tab close [n] # Close tab
|
||||||
agent-browser window new # New window
|
agent-browser window new # New window
|
||||||
@@ -197,15 +213,15 @@ agent-browser dialog dismiss # Dismiss
|
|||||||
### Debug
|
### Debug
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
agent-browser trace start # Start recording trace
|
agent-browser trace start [path] # Start recording trace
|
||||||
agent-browser trace stop <path> # Stop and save trace
|
agent-browser trace stop [path] # Stop and save trace
|
||||||
agent-browser console # View console messages
|
agent-browser console # View console messages
|
||||||
agent-browser console --clear # Clear console
|
agent-browser console --clear # Clear console
|
||||||
agent-browser errors # View page errors
|
agent-browser errors # View page errors
|
||||||
|
agent-browser errors --clear # Clear errors
|
||||||
agent-browser highlight <sel> # Highlight element
|
agent-browser highlight <sel> # Highlight element
|
||||||
agent-browser state save <path> # Save auth state
|
agent-browser state save <path> # Save auth state
|
||||||
agent-browser state load <path> # Load auth state
|
agent-browser state load <path> # Load auth state
|
||||||
agent-browser initscript <js> # Run JS on every page load
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Navigation
|
### Navigation
|
||||||
@@ -216,13 +232,58 @@ agent-browser forward # Go forward
|
|||||||
agent-browser reload # Reload page
|
agent-browser reload # Reload page
|
||||||
```
|
```
|
||||||
|
|
||||||
### Sessions
|
### Setup
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
agent-browser session # Show current session
|
agent-browser install # Download Chromium browser
|
||||||
agent-browser session list # List active sessions
|
agent-browser install --with-deps # Also install system deps (Linux)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Sessions
|
||||||
|
|
||||||
|
Run multiple isolated browser instances:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Different sessions
|
||||||
|
agent-browser --session agent1 open site-a.com
|
||||||
|
agent-browser --session agent2 open site-b.com
|
||||||
|
|
||||||
|
# Or via environment variable
|
||||||
|
AGENT_BROWSER_SESSION=agent1 agent-browser click "#btn"
|
||||||
|
|
||||||
|
# List active sessions
|
||||||
|
agent-browser session list
|
||||||
|
|
||||||
|
# Show current session
|
||||||
|
agent-browser session
|
||||||
|
```
|
||||||
|
|
||||||
|
Each session has its own:
|
||||||
|
- Browser instance
|
||||||
|
- Cookies and storage
|
||||||
|
- Navigation history
|
||||||
|
- Authentication state
|
||||||
|
|
||||||
|
## Snapshot Options
|
||||||
|
|
||||||
|
The `snapshot` command supports filtering to reduce output size:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
agent-browser snapshot # Full accessibility tree
|
||||||
|
agent-browser snapshot -i # Interactive elements only (buttons, inputs, links)
|
||||||
|
agent-browser snapshot -c # Compact (remove empty structural elements)
|
||||||
|
agent-browser snapshot -d 3 # Limit depth to 3 levels
|
||||||
|
agent-browser snapshot -s "#main" # Scope to CSS selector
|
||||||
|
agent-browser snapshot -i -c -d 5 # Combine options
|
||||||
|
```
|
||||||
|
|
||||||
|
| Option | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| `-i, --interactive` | Only show interactive elements (buttons, links, inputs) |
|
||||||
|
| `-c, --compact` | Remove empty structural elements |
|
||||||
|
| `-d, --depth <n>` | Limit tree depth |
|
||||||
|
| `-s, --selector <sel>` | Scope to CSS selector |
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
@@ -235,22 +296,6 @@ agent-browser session list # List active sessions
|
|||||||
| `--headed` | Show browser window (not headless) |
|
| `--headed` | Show browser window (not headless) |
|
||||||
| `--debug` | Debug output |
|
| `--debug` | Debug output |
|
||||||
|
|
||||||
## Sessions
|
|
||||||
|
|
||||||
Run multiple isolated browser instances:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Different sessions
|
|
||||||
agent-browser --session agent1 open site-a.com
|
|
||||||
agent-browser --session agent2 open site-b.com
|
|
||||||
|
|
||||||
# Or via environment
|
|
||||||
AGENT_BROWSER_SESSION=agent1 agent-browser click "#btn"
|
|
||||||
|
|
||||||
# List all
|
|
||||||
agent-browser session list
|
|
||||||
```
|
|
||||||
|
|
||||||
## Selectors
|
## Selectors
|
||||||
|
|
||||||
### Refs (Recommended for AI)
|
### Refs (Recommended for AI)
|
||||||
@@ -317,7 +362,7 @@ agent-browser is visible @e2 --json
|
|||||||
```bash
|
```bash
|
||||||
# 1. Navigate and get snapshot
|
# 1. Navigate and get snapshot
|
||||||
agent-browser open example.com
|
agent-browser open example.com
|
||||||
agent-browser snapshot --json # AI parses tree and refs
|
agent-browser snapshot -i --json # AI parses tree and refs
|
||||||
|
|
||||||
# 2. AI identifies target refs from snapshot
|
# 2. AI identifies target refs from snapshot
|
||||||
# 3. Execute actions using refs
|
# 3. Execute actions using refs
|
||||||
@@ -325,9 +370,39 @@ agent-browser click @e2
|
|||||||
agent-browser fill @e3 "input text"
|
agent-browser fill @e3 "input text"
|
||||||
|
|
||||||
# 4. Get new snapshot if page changed
|
# 4. Get new snapshot if page changed
|
||||||
agent-browser snapshot --json
|
agent-browser snapshot -i --json
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Headed Mode
|
||||||
|
|
||||||
|
Show the browser window for debugging:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
agent-browser open example.com --headed
|
||||||
|
```
|
||||||
|
|
||||||
|
This opens a visible browser window instead of running headless.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
agent-browser uses a client-daemon architecture:
|
||||||
|
|
||||||
|
1. **Rust CLI** (fast native binary) - Parses commands, communicates with daemon
|
||||||
|
2. **Node.js Daemon** - Manages Playwright browser instance
|
||||||
|
3. **Fallback** - If native binary unavailable, uses Node.js directly
|
||||||
|
|
||||||
|
The daemon starts automatically on first command and persists between commands for fast subsequent operations.
|
||||||
|
|
||||||
|
## Platforms
|
||||||
|
|
||||||
|
| Platform | Binary | Fallback |
|
||||||
|
|----------|--------|----------|
|
||||||
|
| macOS ARM64 | ✅ Native Rust | Node.js |
|
||||||
|
| macOS x64 | ✅ Native Rust | Node.js |
|
||||||
|
| Linux ARM64 | ✅ Native Rust | Node.js |
|
||||||
|
| Linux x64 | ✅ Native Rust | Node.js |
|
||||||
|
| Windows | - | Node.js |
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Apache-2.0
|
Apache-2.0
|
||||||
|
|||||||
@@ -848,6 +848,16 @@ fn main() {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If --headed flag is set, send launch command first to switch to headed mode
|
||||||
|
if flags.headed {
|
||||||
|
let launch_cmd = json!({ "id": gen_id(), "action": "launch", "headless": false });
|
||||||
|
if let Err(e) = send_command(launch_cmd, &flags.session) {
|
||||||
|
if !flags.json {
|
||||||
|
eprintln!("\x1b[33m⚠\x1b[0m Could not switch to headed mode: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match send_command(cmd, &flags.session) {
|
match send_command(cmd, &flags.session) {
|
||||||
Ok(resp) => {
|
Ok(resp) => {
|
||||||
let success = resp.success;
|
let success = resp.success;
|
||||||
|
|||||||
@@ -154,4 +154,57 @@ describe('BrowserManager', () => {
|
|||||||
expect(size?.height).toBe(1080);
|
expect(size?.height).toBe(1080);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('snapshot', () => {
|
||||||
|
it('should get snapshot with refs', async () => {
|
||||||
|
const page = browser.getPage();
|
||||||
|
await page.goto('https://example.com');
|
||||||
|
const { tree, refs } = await browser.getSnapshot();
|
||||||
|
expect(tree).toContain('heading');
|
||||||
|
expect(tree).toContain('Example Domain');
|
||||||
|
expect(typeof refs).toBe('object');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get interactive-only snapshot', async () => {
|
||||||
|
const { tree: fullSnapshot } = await browser.getSnapshot();
|
||||||
|
const { tree: interactiveSnapshot } = await browser.getSnapshot({ interactive: true });
|
||||||
|
// Interactive snapshot should be shorter (fewer elements)
|
||||||
|
expect(interactiveSnapshot.length).toBeLessThanOrEqual(fullSnapshot.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get snapshot with depth limit', async () => {
|
||||||
|
const { tree: fullSnapshot } = await browser.getSnapshot();
|
||||||
|
const { tree: limitedSnapshot } = await browser.getSnapshot({ maxDepth: 2 });
|
||||||
|
// Limited depth should have fewer nested elements
|
||||||
|
const fullLines = fullSnapshot.split('\n').length;
|
||||||
|
const limitedLines = limitedSnapshot.split('\n').length;
|
||||||
|
expect(limitedLines).toBeLessThanOrEqual(fullLines);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get compact snapshot', async () => {
|
||||||
|
const { tree: fullSnapshot } = await browser.getSnapshot();
|
||||||
|
const { tree: compactSnapshot } = await browser.getSnapshot({ compact: true });
|
||||||
|
// Compact should be equal or shorter
|
||||||
|
expect(compactSnapshot.length).toBeLessThanOrEqual(fullSnapshot.length);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('locator resolution', () => {
|
||||||
|
it('should resolve CSS selector', async () => {
|
||||||
|
const page = browser.getPage();
|
||||||
|
await page.goto('https://example.com');
|
||||||
|
const locator = browser.getLocator('h1');
|
||||||
|
const text = await locator.textContent();
|
||||||
|
expect(text).toBe('Example Domain');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should resolve ref from snapshot', async () => {
|
||||||
|
await browser.getSnapshot(); // Populates refs
|
||||||
|
// After snapshot, refs like @e1 should be available
|
||||||
|
// This tests the ref resolution mechanism
|
||||||
|
const page = browser.getPage();
|
||||||
|
const h1 = await page.locator('h1').textContent();
|
||||||
|
expect(h1).toBe('Example Domain');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,6 +19,21 @@ describe('parseCommand', () => {
|
|||||||
const result = parseCommand(cmd({ id: '1', action: 'navigate' }));
|
const result = parseCommand(cmd({ id: '1', action: 'navigate' }));
|
||||||
expect(result.success).toBe(false);
|
expect(result.success).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should parse back command', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'back' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse forward command', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'forward' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse reload command', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'reload' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('click', () => {
|
describe('click', () => {
|
||||||
@@ -197,6 +212,211 @@ describe('parseCommand', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('snapshot', () => {
|
||||||
|
it('should parse basic snapshot command', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'snapshot' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse snapshot with interactive filter', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'snapshot', interactive: true }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
if (result.success) {
|
||||||
|
expect(result.command.interactive).toBe(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse snapshot with compact filter', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'snapshot', compact: true }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
if (result.success) {
|
||||||
|
expect(result.command.compact).toBe(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse snapshot with maxDepth', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'snapshot', maxDepth: 3 }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
if (result.success) {
|
||||||
|
expect(result.command.maxDepth).toBe(3);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse snapshot with selector scope', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'snapshot', selector: '#main' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
if (result.success) {
|
||||||
|
expect(result.command.selector).toBe('#main');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse snapshot with all options', () => {
|
||||||
|
const result = parseCommand(cmd({
|
||||||
|
id: '1',
|
||||||
|
action: 'snapshot',
|
||||||
|
interactive: true,
|
||||||
|
compact: true,
|
||||||
|
maxDepth: 5,
|
||||||
|
selector: '.content',
|
||||||
|
}));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
if (result.success) {
|
||||||
|
expect(result.command.interactive).toBe(true);
|
||||||
|
expect(result.command.compact).toBe(true);
|
||||||
|
expect(result.command.maxDepth).toBe(5);
|
||||||
|
expect(result.command.selector).toBe('.content');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('launch', () => {
|
||||||
|
it('should parse launch command', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'launch' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse launch with headless false', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'launch', headless: false }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
if (result.success) {
|
||||||
|
expect(result.command.headless).toBe(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('mouse actions', () => {
|
||||||
|
it('should parse mousemove', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'mousemove', x: 100, y: 200 }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
if (result.success) {
|
||||||
|
expect(result.command.x).toBe(100);
|
||||||
|
expect(result.command.y).toBe(200);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse mousedown', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'mousedown', button: 'left' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse mouseup', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'mouseup', button: 'left' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse wheel', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'wheel', deltaX: 0, deltaY: 100 }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('scroll', () => {
|
||||||
|
it('should parse scroll command', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'scroll', direction: 'down', amount: 300 }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse scrollintoview', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'scrollintoview', selector: '#element' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('element state', () => {
|
||||||
|
it('should parse isvisible', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'isvisible', selector: '#btn' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse isenabled', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'isenabled', selector: '#btn' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse ischecked', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'ischecked', selector: '#checkbox' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('viewport and settings', () => {
|
||||||
|
it('should parse viewport', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'viewport', width: 1920, height: 1080 }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse geolocation', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'geolocation', latitude: 37.7749, longitude: -122.4194 }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse offline', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'offline', offline: true }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('trace', () => {
|
||||||
|
it('should parse trace_start', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'trace_start' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse trace_stop', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'trace_stop', path: 'trace.zip' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('console and errors', () => {
|
||||||
|
it('should parse console', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'console' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse console with clear', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'console', clear: true }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse errors', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'errors' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('dialog', () => {
|
||||||
|
it('should parse dialog accept', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'dialog', response: 'accept' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse dialog dismiss', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'dialog', response: 'dismiss' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse dialog accept with prompt text', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'dialog', response: 'accept', promptText: 'hello' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
if (result.success) {
|
||||||
|
expect(result.command.promptText).toBe('hello');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('frame', () => {
|
||||||
|
it('should parse frame command', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'frame', selector: '#iframe' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse mainframe', () => {
|
||||||
|
const result = parseCommand(cmd({ id: '1', action: 'mainframe' }));
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('invalid commands', () => {
|
describe('invalid commands', () => {
|
||||||
it('should reject unknown action', () => {
|
it('should reject unknown action', () => {
|
||||||
const result = parseCommand(cmd({ id: '1', action: 'unknown' }));
|
const result = parseCommand(cmd({ id: '1', action: 'unknown' }));
|
||||||
|
|||||||
Reference in New Issue
Block a user