# LLM Agent Guide: Using cremote for Web Application Testing

This document provides comprehensive guidance for LLM coding agents on how to use **cremote** (Chrome Remote Daemon) as a testing tool for web applications. cremote enables automated browser testing of public web interfaces through programmatic control of Chrome browser tabs.

## What is cremote?

**cremote** is a browser automation tool that allows you to:
- Control Chromium browser tabs programmatically
- Fill forms and interact with web elements
- Navigate web pages and wait for content to load
- Extract page content and element HTML
- Test user workflows end-to-end

It uses a daemon-client architecture where a background daemon maintains persistent connections to Chromium, and a command-line client sends testing commands.

## Prerequisites for Testing

Before using cremote for web application testing, ensure:

0. **Check to see if everything is already running, if so you can skip the steps to start it:**
   ```bash
   cremote status
   ```
   **Note**: `cremote status` always exits with code 0, whether the daemon is running or not. Check the output message to determine status.

1. **Chromium/Chrome is running with remote debugging enabled:**
   ```bash
   # Create a temporary user data directory for the debug instance
   chromium --remote-debugging-port=9222 --user-data-dir=/tmp/chromium-debug &
   # or
   google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug &

   # Alternative: Use a random temporary directory
   chromium --remote-debugging-port=9222 --user-data-dir=$(mktemp -d) &
   ```

   **Important**: The `--user-data-dir` flag is required to prevent Chromium from trying to use an existing window. Without it, Chromium will attempt to connect to an already running instance instead of starting a new debug-enabled instance.

2. **cremote daemon is running:**
   ```bash
   cremotedaemon &
   ```

   **Note**: The daemon will automatically check if Chromium is running and provide helpful error messages if:
   - Chromium is not running on port 9222
   - Something else is using port 9222 (not Chromium DevTools)
   - Chromium is running but not accepting connections

3. **Verify connectivity:**
   ```bash
   cremote status
   ```

## Core Testing Workflow

### 1. Basic Test Session Setup

Every testing session follows this pattern:

```bash
# 1. Open a new browser tab for testing
TAB_ID=$(cremote open-tab)

# 2. Navigate to the application under test
cremote load-url --url="https://your-app.com"

# 3. Perform test actions (forms, clicks, navigation)
# ... testing commands ...

# 4. Clean up (optional)
cremote close-tab --tab="$TAB_ID"
```

### 2. Current Tab Feature

cremote automatically tracks the "current tab" - the most recently used tab. This means you can omit the `--tab` flag in most commands:

```bash
# Open tab (becomes current tab)
cremote open-tab

# All subsequent commands use current tab automatically
cremote load-url --url="https://example.com"
cremote fill-form --selector="#username" --value="testuser"
cremote click-element --selector="#login-btn"
```

## Essential Testing Commands

### Navigation and Page Loading

```bash
# Load a specific URL
cremote load-url --url="https://your-app.com/login"

# Wait for navigation to complete (useful after form submissions)
cremote wait-navigation --timeout=10

# Note: wait-navigation is smart - it returns immediately if no navigation is happening

# Get current page source for verification
cremote get-source
```

### Form Testing

```bash
# Fill text inputs
cremote fill-form --selector="#username" --value="testuser"
cremote fill-form --selector="#password" --value="testpass123"

# Handle checkboxes (check)
cremote fill-form --selector="#remember-me" --value="true"
cremote fill-form --selector="#terms-agreed" --value="checked"

# Handle checkboxes (uncheck)
cremote fill-form --selector="#newsletter" --value="false"

# Handle radio buttons
cremote fill-form --selector="#payment-credit" --value="true"

# Submit forms
cremote submit-form --selector="form#login-form"
```

**Checkbox/Radio Button Values:**
- To check/select: `true`, `1`, `yes`, `on`, `checked`
- To uncheck/deselect: `false`, `0`, `no`, `off`, or any other value

### File Upload Testing

```bash
# Upload files to file inputs (automatically transfers to daemon container first)
cremote upload-file --selector="input[type=file]" --file="/path/to/test-file.pdf"
cremote upload-file --selector="#profile-photo" --file="/home/user/test-image.jpg"

# The command automatically:
# 1. Transfers the file from local machine to daemon container
# 2. Uploads the file to the web form input element
```

### Element Interaction

```bash
# Click buttons, links, or any clickable elements
cremote click-element --selector="button.submit"
cremote click-element --selector="a[href='/dashboard']"
cremote click-element --selector="#save-changes"

# Get HTML content of specific elements for verification
cremote get-element --selector=".error-message"
cremote get-element --selector="#user-profile"
```

### JavaScript Execution

```bash
# Execute JavaScript code directly in the page (default 5 second timeout)
cremote eval-js --code="document.getElementById('tinymce').innerHTML='Foo!'"

# Get values from the page
cremote eval-js --code="document.querySelector('#result').textContent"

# Manipulate page elements
cremote eval-js --code="document.body.style.backgroundColor = 'red'"

# Trigger JavaScript events
cremote eval-js --code="document.getElementById('submit-btn').click()"

# Work with complex objects (returns JSON string)
cremote eval-js --code="document.querySelectorAll('.item').length"

# Set form values programmatically (statement - returns "undefined")
cremote eval-js --code="document.getElementById('hidden-field').value = 'secret-value'"

# Get form values (expression - returns the value)
cremote eval-js --code="document.getElementById('hidden-field').value"

# Use custom timeout for long-running JavaScript
cremote eval-js --code="await new Promise(resolve => setTimeout(resolve, 8000))" --timeout=10
```

### Screenshots

```bash
# Take a viewport screenshot (default)
cremote screenshot --output="/tmp/page-screenshot.png"

# Take a full page screenshot
cremote screenshot --output="/tmp/full-page.png" --full-page

# Screenshot with custom timeout
cremote screenshot --output="/tmp/slow-page.png" --timeout=10

# Screenshot of specific tab
cremote screenshot --tab="$TAB_ID" --output="/tmp/tab-screenshot.png"
```

**Use Cases for JavaScript Execution:**
- Interact with rich text editors (TinyMCE, CKEditor, etc.)
- Trigger JavaScript events that aren't accessible via normal clicks
- Extract computed values or complex data structures
- Manipulate hidden form fields
- Test JavaScript functionality directly
- Set up test data or page state

**Expression vs Statement Handling:**
- **Expressions** return values: `document.title`, `element.textContent`, `array.length`
- **Statements** perform actions and return "undefined": `element.click()`, `variable = value`
- Both types are supported seamlessly in the same command

### Working with Iframes

```bash
# Switch to iframe context
cremote switch-iframe --selector="iframe#payment-form"

# All subsequent commands now operate within the iframe
cremote fill-form --selector="#card-number" --value="4111111111111111"
cremote fill-form --selector="#cvv" --value="123"
cremote click-element --selector="#submit-payment"

# Switch back to main page context
cremote switch-main

# Commands now operate on the main page again
cremote get-element --selector=".payment-success"
```

**Common Iframe Scenarios:**
- **Payment Forms**: Credit card processing iframes
- **Embedded Widgets**: Social media, maps, chat widgets
- **Third-party Content**: Ads, analytics, external forms
- **Security Contexts**: Sandboxed content, cross-origin frames

**Important Notes:**
- Iframe context is maintained per tab
- All commands (fill-form, click-element, eval-js, etc.) work within iframe context
- Must explicitly switch back to main context with `switch-main`
- Iframe context persists until switched back or tab is closed

### Tab Management

```bash
# List all open tabs (current tab marked with *)
cremote list-tabs

# Open multiple tabs for complex testing
TAB1=$(cremote open-tab)
TAB2=$(cremote open-tab)

# Work with specific tabs
cremote load-url --tab="$TAB1" --url="https://app.com/admin"
cremote load-url --tab="$TAB2" --url="https://app.com/user"

# Close specific tabs
cremote close-tab --tab="$TAB1"
```

## Timeout Configuration

Many commands support timeout parameters for robust testing:

```bash
# Wait up to 10 seconds for element to appear, then 5 seconds for action
cremote fill-form --selector="#slow-loading-field" --value="test" \
  --selection-timeout=10 --action-timeout=5

# Wait for elements that load dynamically
cremote click-element --selector=".ajax-button" \
  --selection-timeout=15 --action-timeout=10

# Get elements that may take time to render
cremote get-element --selector=".dynamic-content" --selection-timeout=20
```

**Timeout Parameters:**
- `--selection-timeout`: Seconds to wait for element to appear in DOM (default: 5 seconds)
- `--action-timeout`: Seconds to wait for action to complete (default: 5 seconds)
- `--timeout`: General timeout for operations (default: 5 seconds)

**Smart Navigation Waiting:**
The `wait-navigation` command intelligently detects if navigation is actually happening:
- Returns immediately if the page is already stable and loaded
- Monitors for 2 seconds to detect if navigation starts
- Only waits for the full timeout if navigation is actually in progress
- This prevents hanging when no navigation occurs

## Common Testing Patterns

### 1. Login Flow Testing

```bash
#!/bin/bash
# Test user login functionality

# Setup
cremote open-tab
cremote load-url --url="https://myapp.com/login"

# Test valid login
cremote fill-form --selector="#email" --value="user@example.com"
cremote fill-form --selector="#password" --value="validpassword"
cremote click-element --selector="#login-button"

# Wait for redirect and verify success
cremote wait-navigation --timeout=10
PAGE_SOURCE=$(cremote get-source)

if echo "$PAGE_SOURCE" | grep -q "Welcome"; then
    echo "✓ Login successful"
else
    echo "✗ Login failed"
    exit 1
fi
```

### 2. Form Validation Testing

```bash
#!/bin/bash
# Test form validation

cremote open-tab
cremote load-url --url="https://myapp.com/register"

# Test empty form submission
cremote click-element --selector="#submit-btn"

# Check for validation errors
ERROR_MSG=$(cremote get-element --selector=".error-message" --selection-timeout=5)
if [ -n "$ERROR_MSG" ]; then
    echo "✓ Validation working: $ERROR_MSG"
else
    echo "✗ No validation error shown"
fi

# Test invalid email format
cremote fill-form --selector="#email" --value="invalid-email"
cremote click-element --selector="#submit-btn"

# Verify email validation
EMAIL_ERROR=$(cremote get-element --selector="#email-error" --selection-timeout=5)
if echo "$EMAIL_ERROR" | grep -q "valid email"; then
    echo "✓ Email validation working"
fi

# Test JavaScript validation directly
JS_VALIDATION=$(cremote eval-js --code="document.getElementById('email').validity.valid")
if [ "$JS_VALIDATION" = "false" ]; then
    echo "✓ JavaScript validation also working"
fi
```

### 3. Multi-Step Workflow Testing

```bash
#!/bin/bash
# Test complete user workflow

# Step 1: Registration
cremote open-tab
cremote load-url --url="https://myapp.com/register"
cremote fill-form --selector="#username" --value="newuser123"
cremote fill-form --selector="#email" --value="newuser@test.com"
cremote fill-form --selector="#password" --value="securepass123"
cremote fill-form --selector="#confirm-password" --value="securepass123"
cremote click-element --selector="#register-btn"
cremote wait-navigation --timeout=15

# Step 2: Email verification simulation
cremote load-url --url="https://myapp.com/verify?token=test-token"
cremote wait-navigation --timeout=10

# Step 3: Profile setup
cremote fill-form --selector="#first-name" --value="Test"
cremote fill-form --selector="#last-name" --value="User"
cremote upload-file --selector="#profile-photo" --file="/tmp/avatar.jpg"
cremote click-element --selector="#save-profile"

# Step 4: Verify completion
cremote wait-navigation --timeout=10
PROFILE_PAGE=$(cremote get-source)
if echo "$PROFILE_PAGE" | grep -q "Profile completed"; then
    echo "✓ Complete workflow successful"
fi
```

### 4. Error Handling and Edge Cases

```bash
#!/bin/bash
# Test error scenarios

# Test network timeout handling
cremote open-tab
cremote load-url --url="https://httpbin.org/delay/30"
# This should timeout - test how app handles it

# Test invalid form data
cremote load-url --url="https://myapp.com/contact"
cremote fill-form --selector="#phone" --value="invalid-phone-123abc"
cremote submit-form --selector="#contact-form"

# Check error handling
ERROR_RESPONSE=$(cremote get-element --selector=".validation-error")
echo "Error handling: $ERROR_RESPONSE"

# Test file upload limits
cremote upload-file --selector="#file-upload" --file="/path/to/large-file.zip"
UPLOAD_ERROR=$(cremote get-element --selector=".upload-error" --selection-timeout=10)

# Test iframe interaction (e.g., payment form)
cremote switch-iframe --selector="iframe.payment-widget"
cremote fill-form --selector="#card-number" --value="4111111111111111"
cremote fill-form --selector="#expiry" --value="12/25"
cremote click-element --selector="#pay-now"

# Check for payment processing within iframe
PAYMENT_STATUS=$(cremote get-element --selector=".payment-status" --selection-timeout=10)
echo "Payment status: $PAYMENT_STATUS"

# Switch back to main page to check results
cremote switch-main
MAIN_STATUS=$(cremote get-element --selector=".order-confirmation" --selection-timeout=10)
```

## Testing Best Practices

### 1. Robust Element Selection

Use specific, stable selectors:

```bash
# Good - specific and stable
cremote click-element --selector="#submit-button"
cremote click-element --selector="button[data-testid='login-submit']"
cremote fill-form --selector="input[name='username']" --value="test"

# Avoid - fragile selectors
cremote click-element --selector="div > div:nth-child(3) > button"
cremote click-element --selector=".btn.btn-primary.mt-2"
```

### 2. Wait for Dynamic Content

Always use appropriate timeouts for dynamic content:

```bash
# Wait for AJAX content to load
cremote get-element --selector=".search-results" --selection-timeout=15

# Wait for form submission to complete
cremote submit-form --selector="#payment-form" --action-timeout=30
cremote wait-navigation --timeout=20
```

### 3. Verify Test Results

Always verify that actions had the expected effect:

```bash
# After login, verify we're on the dashboard
cremote click-element --selector="#login-btn"
cremote wait-navigation --timeout=10
CURRENT_URL=$(cremote get-source | grep -o 'https://[^"]*dashboard[^"]*')
if [ -n "$CURRENT_URL" ]; then
    echo "✓ Successfully redirected to dashboard"
fi

# After form submission, check for success message
cremote submit-form --selector="#contact-form"
SUCCESS_MSG=$(cremote get-element --selector=".success-message" --selection-timeout=10)
if echo "$SUCCESS_MSG" | grep -q "Thank you"; then
    echo "✓ Form submitted successfully"
fi
```

### 4. Clean Test Environment

```bash
# Start each test with a fresh tab
cremote open-tab

# Clear any existing state if needed
cremote load-url --url="https://myapp.com/logout"
cremote wait-navigation --timeout=5

# Begin actual test
cremote load-url --url="https://myapp.com/test-page"
```

### 5. Iframe Context Management

Always manage iframe context properly:

```bash
# Good - explicit context management
cremote switch-iframe --selector="iframe.payment-form"
cremote fill-form --selector="#card-number" --value="4111111111111111"
cremote switch-main  # Always switch back

# Good - verify iframe exists before switching
IFRAME_EXISTS=$(cremote get-element --selector="iframe.payment-form" --selection-timeout=5)
if [ -n "$IFRAME_EXISTS" ]; then
    cremote switch-iframe --selector="iframe.payment-form"
    # ... iframe operations ...
    cremote switch-main
fi

# Avoid - forgetting to switch back to main context
cremote switch-iframe --selector="iframe.widget"
cremote fill-form --selector="#field" --value="test"
# Missing: cremote switch-main
```

## Debugging Failed Tests

### 1. Inspect Current State

```bash
# Check what's currently on the page
cremote get-source > debug-page-source.html

# Check specific elements
cremote get-element --selector=".error-message"
cremote get-element --selector="form"

# List all tabs to verify state
cremote list-tabs
```

### 2. Verify Element Selectors

```bash
# Test if element exists before interacting
ELEMENT=$(cremote get-element --selector="#target-button" --selection-timeout=5)
if [ -n "$ELEMENT" ]; then
    cremote click-element --selector="#target-button"
else
    echo "Element not found - check selector"
fi
```

### 3. Increase Timeouts for Slow Pages

```bash
# For slow-loading applications
cremote fill-form --selector="#username" --value="test" \
  --selection-timeout=30 --action-timeout=15

cremote wait-navigation --timeout=60
```

## Troubleshooting Chromium Connection Issues

### Chromium Not Running
If you see: "Chromium is not running with remote debugging enabled on port 9222"

**Solution**: Start Chromium with the correct flags:
```bash
chromium --remote-debugging-port=9222 --user-data-dir=/tmp/chromium-debug &
```

### Port Conflict
If you see: "Something is listening on port 9222 but it's not Chromium DevTools protocol"

**Cause**: Another application is using port 9222
**Solution**:
1. Find what's using the port: `netstat -tlnp | grep 9222`
2. Stop the conflicting process
3. Start Chromium with the correct flags

### Chromium Running But Not Connecting
If Chromium appears to be running but cremotedaemon can't connect:

**Possible causes**:
- Chromium started without `--remote-debugging-port=9222`
- Chromium started with a different port
- Firewall blocking connections

**Solution**: Restart Chromium with the correct command:
```bash
pkill -f chromium  # Stop existing Chromium
chromium --remote-debugging-port=9222 --user-data-dir=/tmp/chromium-debug &
```

### Verify Chromium DevTools is Working
You can manually check if Chromium DevTools is responding:
```bash
curl http://localhost:9222/json/version
```
This should return JSON with Chromium version information.

## Integration with Test Suites

cremote can be integrated into larger test suites:

```bash
#!/bin/bash
# test-suite.sh

# Setup
echo "Starting Chromium with remote debugging..."
chromium --remote-debugging-port=9222 --user-data-dir=$(mktemp -d) &
CHROMIUM_PID=$!
sleep 3

echo "Starting cremote daemon..."
cremotedaemon &
DAEMON_PID=$!
sleep 2

# Run tests
echo "Running login tests..."
./test-login.sh

echo "Running form tests..."
./test-forms.sh

echo "Running workflow tests..."
./test-workflows.sh

# Cleanup
echo "Stopping daemon..."
kill $DAEMON_PID
echo "Stopping Chromium..."
kill $CHROMIUM_PID
```

This guide provides the foundation for using cremote as a comprehensive web application testing tool. Focus on testing real user workflows, handling edge cases, and verifying expected behaviors through the browser interface.
