mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
7a74717a81
Multi-agent implementation of browser automation integration: Adapters: - BrowserResultAdapter: Transform browser results to QE format - TrajectoryAdapter: Capture learning patterns from browser sessions Services: - BrowserSecurityScanner: OWASP-based security scanning with browser - BrowserSwarmCoordinator: Multi-viewport parallel testing Workflows: - 9 browser workflow templates (login, OAuth, accessibility, etc.) - WorkflowLoader for dynamic template loading Skills: - security-visual-testing: Combined security + visual regression skill Tests: - Unit tests for adapters and services - Integration tests for parallel viewports and trajectory learning Documentation: - API docs for all new components - Integration guide for claude-flow-browser Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
787 lines
16 KiB
Markdown
787 lines
16 KiB
Markdown
# Browser Workflow Templates Reference
|
|
|
|
**Package:** `@agentic-qe/v3/workflows/browser`
|
|
**Source:** `/v3/src/workflows/browser/templates/`
|
|
**Format:** YAML
|
|
|
|
## Overview
|
|
|
|
Workflow templates provide pre-built, reusable patterns for common browser testing scenarios. Each template is a YAML file defining steps, variables, and execution order. Templates are designed to be parameterized and composable.
|
|
|
|
---
|
|
|
|
## Template List
|
|
|
|
| Template | Purpose | Complexity | Avg Duration |
|
|
|----------|---------|------------|--------------|
|
|
| [login-flow](#login-flow) | Authentication testing | Low | 5s |
|
|
| [oauth-flow](#oauth-flow) | OAuth2/OIDC testing | Medium | 15s |
|
|
| [scraping-workflow](#scraping-workflow) | Data extraction | Medium | 10s |
|
|
| [visual-regression](#visual-regression) | Screenshot comparison | Low | 8s |
|
|
| [form-validation](#form-validation) | Input validation | Low | 7s |
|
|
| [navigation-flow](#navigation-flow) | Multi-page navigation | Medium | 12s |
|
|
| [api-integration](#api-integration) | Browser-API hybrid | High | 20s |
|
|
| [performance-audit](#performance-audit) | Lighthouse-style | High | 30s |
|
|
| [accessibility-audit](#accessibility-audit) | WCAG compliance | Medium | 15s |
|
|
|
|
---
|
|
|
|
## YAML Schema
|
|
|
|
All templates follow this schema:
|
|
|
|
```yaml
|
|
# Template metadata
|
|
name: string # Template name (kebab-case)
|
|
version: string # Semantic version
|
|
description: string # Human-readable description
|
|
tags: string[] # Categorization tags
|
|
|
|
# Variables (template parameters)
|
|
variables:
|
|
- name: string # Variable name
|
|
type: string | number | boolean | array | object
|
|
required: boolean # Is this variable required?
|
|
default: any # Default value (if not required)
|
|
description: string # Usage description
|
|
|
|
# Steps (execution sequence)
|
|
steps:
|
|
- id: string # Unique step identifier
|
|
type: string # Step type (see below)
|
|
description: string # What this step does
|
|
config: object # Step-specific configuration
|
|
continueOnError: boolean # Continue if step fails?
|
|
timeout: number # Step timeout (ms)
|
|
retry: object # Retry configuration
|
|
maxAttempts: number
|
|
backoff: 'linear' | 'exponential'
|
|
|
|
# Assertions (validation)
|
|
assertions:
|
|
- condition: string # Assertion condition (JS expression)
|
|
message: string # Failure message
|
|
|
|
# Cleanup (always runs)
|
|
cleanup:
|
|
- type: string
|
|
config: object
|
|
```
|
|
|
|
---
|
|
|
|
## Step Types
|
|
|
|
### Navigation Steps
|
|
|
|
#### `navigate`
|
|
|
|
Navigate to a URL.
|
|
|
|
```yaml
|
|
- id: goto-login
|
|
type: navigate
|
|
config:
|
|
url: "{{baseUrl}}/login"
|
|
waitUntil: domcontentloaded # load, domcontentloaded, networkidle
|
|
```
|
|
|
|
#### `click`
|
|
|
|
Click an element.
|
|
|
|
```yaml
|
|
- id: click-submit
|
|
type: click
|
|
config:
|
|
selector: 'button[type="submit"]'
|
|
waitForNavigation: true
|
|
```
|
|
|
|
#### `fill`
|
|
|
|
Fill an input field.
|
|
|
|
```yaml
|
|
- id: enter-username
|
|
type: fill
|
|
config:
|
|
selector: '#username'
|
|
value: "{{username}}"
|
|
clear: true # Clear field first
|
|
```
|
|
|
|
#### `select`
|
|
|
|
Select from dropdown.
|
|
|
|
```yaml
|
|
- id: select-country
|
|
type: select
|
|
config:
|
|
selector: '#country'
|
|
value: "US"
|
|
```
|
|
|
|
### Capture Steps
|
|
|
|
#### `screenshot`
|
|
|
|
Capture a screenshot.
|
|
|
|
```yaml
|
|
- id: capture-page
|
|
type: screenshot
|
|
config:
|
|
path: "{{screenshotsDir}}/{{pageName}}.png"
|
|
fullPage: true
|
|
viewport:
|
|
width: 1920
|
|
height: 1080
|
|
```
|
|
|
|
#### `extract`
|
|
|
|
Extract data from page.
|
|
|
|
```yaml
|
|
- id: extract-prices
|
|
type: extract
|
|
config:
|
|
selector: '.price'
|
|
attribute: textContent
|
|
multiple: true # Extract all matches
|
|
output: prices # Store in variable
|
|
```
|
|
|
|
### Validation Steps
|
|
|
|
#### `assert`
|
|
|
|
Assert a condition.
|
|
|
|
```yaml
|
|
- id: verify-login
|
|
type: assert
|
|
config:
|
|
condition: "page.url().includes('/dashboard')"
|
|
message: "Failed to reach dashboard after login"
|
|
```
|
|
|
|
#### `waitFor`
|
|
|
|
Wait for condition.
|
|
|
|
```yaml
|
|
- id: wait-for-element
|
|
type: waitFor
|
|
config:
|
|
selector: '#content-loaded'
|
|
state: visible # attached, detached, visible, hidden
|
|
timeout: 5000
|
|
```
|
|
|
|
### API Steps
|
|
|
|
#### `apiCall`
|
|
|
|
Make API request.
|
|
|
|
```yaml
|
|
- id: fetch-user-data
|
|
type: apiCall
|
|
config:
|
|
method: GET
|
|
url: "{{apiUrl}}/users/{{userId}}"
|
|
headers:
|
|
Authorization: "Bearer {{token}}"
|
|
output: userData
|
|
```
|
|
|
|
### Control Flow
|
|
|
|
#### `condition`
|
|
|
|
Conditional execution.
|
|
|
|
```yaml
|
|
- id: check-login-required
|
|
type: condition
|
|
config:
|
|
condition: "page.url().includes('/login')"
|
|
then:
|
|
- type: fill
|
|
config:
|
|
selector: '#username'
|
|
value: "{{username}}"
|
|
else:
|
|
- type: skip
|
|
```
|
|
|
|
#### `loop`
|
|
|
|
Iterate over items.
|
|
|
|
```yaml
|
|
- id: test-all-pages
|
|
type: loop
|
|
config:
|
|
items: "{{urls}}"
|
|
variable: url
|
|
steps:
|
|
- type: navigate
|
|
config:
|
|
url: "{{url}}"
|
|
- type: screenshot
|
|
config:
|
|
path: "{{screenshotsDir}}/{{url}}.png"
|
|
```
|
|
|
|
---
|
|
|
|
## Template: login-flow
|
|
|
|
**Purpose:** Test authentication flows with username/password.
|
|
|
|
**File:** `login-flow.yaml`
|
|
|
|
```yaml
|
|
name: login-flow
|
|
version: "1.0.0"
|
|
description: |
|
|
Standard username/password login flow with validation.
|
|
Supports error handling and success verification.
|
|
tags:
|
|
- authentication
|
|
- login
|
|
- security
|
|
|
|
variables:
|
|
- name: baseUrl
|
|
type: string
|
|
required: true
|
|
description: "Base URL of the application"
|
|
|
|
- name: username
|
|
type: string
|
|
required: true
|
|
description: "Username for login"
|
|
|
|
- name: password
|
|
type: string
|
|
required: true
|
|
description: "Password for login"
|
|
|
|
- name: successSelector
|
|
type: string
|
|
required: false
|
|
default: '[data-testid="dashboard"]'
|
|
description: "Selector to verify successful login"
|
|
|
|
steps:
|
|
- id: navigate-to-login
|
|
type: navigate
|
|
description: "Navigate to login page"
|
|
config:
|
|
url: "{{baseUrl}}/login"
|
|
waitUntil: networkidle
|
|
|
|
- id: enter-username
|
|
type: fill
|
|
description: "Enter username"
|
|
config:
|
|
selector: 'input[name="username"], input[type="email"], #username'
|
|
value: "{{username}}"
|
|
|
|
- id: enter-password
|
|
type: fill
|
|
description: "Enter password"
|
|
config:
|
|
selector: 'input[name="password"], input[type="password"], #password'
|
|
value: "{{password}}"
|
|
|
|
- id: click-submit
|
|
type: click
|
|
description: "Click login button"
|
|
config:
|
|
selector: 'button[type="submit"], button:has-text("Log in"), button:has-text("Sign in")'
|
|
waitForNavigation: true
|
|
timeout: 10000
|
|
|
|
- id: wait-for-success
|
|
type: waitFor
|
|
description: "Wait for successful login indicator"
|
|
config:
|
|
selector: "{{successSelector}}"
|
|
state: visible
|
|
timeout: 5000
|
|
|
|
assertions:
|
|
- condition: "!page.url().includes('/login')"
|
|
message: "Still on login page after authentication"
|
|
|
|
- condition: "page.locator('{{successSelector}}').isVisible()"
|
|
message: "Success indicator not visible"
|
|
```
|
|
|
|
**Usage:**
|
|
|
|
```typescript
|
|
import { WorkflowLoader } from '@agentic-qe/v3/workflows/browser';
|
|
|
|
const loader = new WorkflowLoader();
|
|
const workflow = await loader.load('login-flow', {
|
|
baseUrl: 'https://example.com',
|
|
username: 'testuser@example.com',
|
|
password: 'secure-password',
|
|
});
|
|
|
|
const result = await workflow.execute();
|
|
```
|
|
|
|
---
|
|
|
|
## Template: oauth-flow
|
|
|
|
**Purpose:** Test OAuth2/OIDC authentication flows.
|
|
|
|
**File:** `oauth-flow.yaml`
|
|
|
|
```yaml
|
|
name: oauth-flow
|
|
version: "1.0.0"
|
|
description: |
|
|
OAuth2/OIDC authentication flow testing.
|
|
Handles provider redirect and callback.
|
|
tags:
|
|
- authentication
|
|
- oauth
|
|
- oidc
|
|
|
|
variables:
|
|
- name: appUrl
|
|
type: string
|
|
required: true
|
|
|
|
- name: provider
|
|
type: string
|
|
required: true
|
|
description: "OAuth provider (google, github, etc.)"
|
|
|
|
- name: providerUsername
|
|
type: string
|
|
required: true
|
|
|
|
- name: providerPassword
|
|
type: string
|
|
required: true
|
|
|
|
steps:
|
|
- id: initiate-oauth
|
|
type: navigate
|
|
config:
|
|
url: "{{appUrl}}/auth/{{provider}}"
|
|
waitUntil: networkidle
|
|
|
|
- id: wait-for-provider-redirect
|
|
type: waitFor
|
|
config:
|
|
condition: "page.url().includes('{{provider}}')"
|
|
timeout: 5000
|
|
|
|
- id: provider-login
|
|
type: fill
|
|
config:
|
|
selector: 'input[type="email"], input[name="username"]'
|
|
value: "{{providerUsername}}"
|
|
|
|
- id: provider-password
|
|
type: fill
|
|
config:
|
|
selector: 'input[type="password"]'
|
|
value: "{{providerPassword}}"
|
|
|
|
- id: provider-submit
|
|
type: click
|
|
config:
|
|
selector: 'button[type="submit"]'
|
|
waitForNavigation: true
|
|
|
|
- id: wait-for-callback
|
|
type: waitFor
|
|
config:
|
|
condition: "page.url().includes('{{appUrl}}')"
|
|
timeout: 10000
|
|
|
|
- id: verify-authenticated
|
|
type: assert
|
|
config:
|
|
condition: "page.locator('[data-user-authenticated]').isVisible()"
|
|
message: "User not authenticated after OAuth flow"
|
|
|
|
assertions:
|
|
- condition: "page.url().startsWith('{{appUrl}}')"
|
|
message: "Did not return to application after OAuth"
|
|
```
|
|
|
|
---
|
|
|
|
## Template: visual-regression
|
|
|
|
**Purpose:** Capture and compare screenshots for visual regression testing.
|
|
|
|
**File:** `visual-regression.yaml`
|
|
|
|
```yaml
|
|
name: visual-regression
|
|
version: "1.0.0"
|
|
description: |
|
|
Capture screenshots across viewports and compare with baselines.
|
|
Supports multiple pages and responsive testing.
|
|
tags:
|
|
- visual-testing
|
|
- regression
|
|
- screenshots
|
|
|
|
variables:
|
|
- name: urls
|
|
type: array
|
|
required: true
|
|
description: "List of URLs to test"
|
|
|
|
- name: viewports
|
|
type: array
|
|
required: false
|
|
default:
|
|
- { width: 320, height: 568, name: "mobile" }
|
|
- { width: 1920, height: 1080, name: "desktop" }
|
|
|
|
- name: baselineDir
|
|
type: string
|
|
required: true
|
|
description: "Directory containing baseline images"
|
|
|
|
- name: outputDir
|
|
type: string
|
|
required: true
|
|
description: "Directory for new screenshots"
|
|
|
|
- name: threshold
|
|
type: number
|
|
required: false
|
|
default: 0.01
|
|
description: "Difference threshold (0-1)"
|
|
|
|
steps:
|
|
- id: test-all-urls
|
|
type: loop
|
|
config:
|
|
items: "{{urls}}"
|
|
variable: url
|
|
steps:
|
|
- id: test-all-viewports
|
|
type: loop
|
|
config:
|
|
items: "{{viewports}}"
|
|
variable: viewport
|
|
steps:
|
|
- id: set-viewport
|
|
type: setViewport
|
|
config:
|
|
width: "{{viewport.width}}"
|
|
height: "{{viewport.height}}"
|
|
|
|
- id: navigate
|
|
type: navigate
|
|
config:
|
|
url: "{{url}}"
|
|
waitUntil: networkidle
|
|
|
|
- id: capture
|
|
type: screenshot
|
|
config:
|
|
path: "{{outputDir}}/{{url}}-{{viewport.name}}.png"
|
|
fullPage: true
|
|
|
|
- id: compare
|
|
type: compareScreenshots
|
|
config:
|
|
baseline: "{{baselineDir}}/{{url}}-{{viewport.name}}.png"
|
|
current: "{{outputDir}}/{{url}}-{{viewport.name}}.png"
|
|
threshold: "{{threshold}}"
|
|
output: "{{outputDir}}/diff-{{url}}-{{viewport.name}}.png"
|
|
```
|
|
|
|
---
|
|
|
|
## Template: accessibility-audit
|
|
|
|
**Purpose:** Comprehensive WCAG accessibility testing.
|
|
|
|
**File:** `accessibility-audit.yaml`
|
|
|
|
```yaml
|
|
name: accessibility-audit
|
|
version: "1.0.0"
|
|
description: |
|
|
Run Axe-core accessibility audit with WCAG 2.1 AA compliance.
|
|
Generates detailed report with violations and recommendations.
|
|
tags:
|
|
- accessibility
|
|
- wcag
|
|
- compliance
|
|
|
|
variables:
|
|
- name: url
|
|
type: string
|
|
required: true
|
|
|
|
- name: wcagLevel
|
|
type: string
|
|
required: false
|
|
default: "AA"
|
|
description: "WCAG level: A, AA, AAA"
|
|
|
|
- name: reportPath
|
|
type: string
|
|
required: true
|
|
|
|
steps:
|
|
- id: navigate
|
|
type: navigate
|
|
config:
|
|
url: "{{url}}"
|
|
waitUntil: networkidle
|
|
|
|
- id: run-axe
|
|
type: axeAudit
|
|
config:
|
|
standard: "WCAG21{{wcagLevel}}"
|
|
rules:
|
|
- color-contrast
|
|
- image-alt
|
|
- label
|
|
- link-name
|
|
- button-name
|
|
output: auditResults
|
|
|
|
- id: generate-report
|
|
type: generateReport
|
|
config:
|
|
template: accessibility
|
|
data: "{{auditResults}}"
|
|
path: "{{reportPath}}"
|
|
|
|
assertions:
|
|
- condition: "auditResults.violations.length === 0"
|
|
message: "Accessibility violations found"
|
|
```
|
|
|
|
---
|
|
|
|
## Variable Substitution
|
|
|
|
Templates support variable substitution using `{{variableName}}` syntax:
|
|
|
|
```yaml
|
|
# Direct substitution
|
|
url: "{{baseUrl}}/login"
|
|
|
|
# Nested property access
|
|
url: "{{config.api.baseUrl}}"
|
|
|
|
# Array indexing
|
|
url: "{{urls[0]}}"
|
|
|
|
# Conditional
|
|
text: "{{isProduction ? 'prod' : 'dev'}}"
|
|
```
|
|
|
|
**JavaScript Context:**
|
|
|
|
Variables are evaluated in a safe JavaScript context with access to:
|
|
- All provided variables
|
|
- `page` object (Playwright page)
|
|
- `expect` assertion library
|
|
- Common utilities (`encodeURIComponent`, `JSON.parse`, etc.)
|
|
|
|
---
|
|
|
|
## Custom Workflow Creation
|
|
|
|
### 1. Create Template File
|
|
|
|
```bash
|
|
# Create new template
|
|
touch v3/src/workflows/browser/templates/my-workflow.yaml
|
|
```
|
|
|
|
### 2. Define Workflow
|
|
|
|
```yaml
|
|
name: my-workflow
|
|
version: "1.0.0"
|
|
description: "My custom workflow"
|
|
tags: ["custom"]
|
|
|
|
variables:
|
|
- name: myParam
|
|
type: string
|
|
required: true
|
|
|
|
steps:
|
|
- id: my-step
|
|
type: navigate
|
|
config:
|
|
url: "{{myParam}}"
|
|
```
|
|
|
|
### 3. Load and Execute
|
|
|
|
```typescript
|
|
const workflow = await loader.load('my-workflow', {
|
|
myParam: 'https://example.com',
|
|
});
|
|
|
|
const result = await workflow.execute();
|
|
```
|
|
|
|
---
|
|
|
|
## Workflow Composition
|
|
|
|
Workflows can be composed by referencing other workflows:
|
|
|
|
```yaml
|
|
name: complex-flow
|
|
steps:
|
|
- id: authenticate
|
|
type: workflow
|
|
config:
|
|
template: login-flow
|
|
variables:
|
|
baseUrl: "{{baseUrl}}"
|
|
username: "{{username}}"
|
|
password: "{{password}}"
|
|
|
|
- id: run-test
|
|
type: workflow
|
|
config:
|
|
template: my-test-flow
|
|
variables:
|
|
authenticated: true
|
|
```
|
|
|
|
---
|
|
|
|
## Error Handling
|
|
|
|
### Continue on Error
|
|
|
|
```yaml
|
|
steps:
|
|
- id: optional-step
|
|
type: click
|
|
config:
|
|
selector: '.optional-element'
|
|
continueOnError: true # Proceed even if click fails
|
|
```
|
|
|
|
### Retry Configuration
|
|
|
|
```yaml
|
|
steps:
|
|
- id: flaky-step
|
|
type: apiCall
|
|
config:
|
|
url: "{{apiUrl}}"
|
|
retry:
|
|
maxAttempts: 3
|
|
backoff: exponential
|
|
backoffFactor: 2
|
|
```
|
|
|
|
### Cleanup Steps
|
|
|
|
```yaml
|
|
cleanup:
|
|
- type: screenshot
|
|
config:
|
|
path: "./failure-screenshot.png"
|
|
|
|
- type: saveHtml
|
|
config:
|
|
path: "./failure-page.html"
|
|
```
|
|
|
|
---
|
|
|
|
## Performance Optimization
|
|
|
|
### Parallel Execution
|
|
|
|
```yaml
|
|
steps:
|
|
- id: parallel-screenshots
|
|
type: parallel
|
|
config:
|
|
steps:
|
|
- type: screenshot
|
|
config:
|
|
selector: '#header'
|
|
- type: screenshot
|
|
config:
|
|
selector: '#content'
|
|
- type: screenshot
|
|
config:
|
|
selector: '#footer'
|
|
```
|
|
|
|
### Resource Caching
|
|
|
|
```yaml
|
|
steps:
|
|
- id: cache-api-response
|
|
type: apiCall
|
|
config:
|
|
url: "{{apiUrl}}/data"
|
|
cache:
|
|
enabled: true
|
|
ttl: 300 # 5 minutes
|
|
```
|
|
|
|
---
|
|
|
|
## Testing Workflows
|
|
|
|
```typescript
|
|
import { describe, it, expect } from 'vitest';
|
|
import { WorkflowLoader } from './workflow-loader';
|
|
|
|
describe('login-flow', () => {
|
|
it('should execute successfully', async () => {
|
|
const loader = new WorkflowLoader();
|
|
const workflow = await loader.load('login-flow', {
|
|
baseUrl: 'http://localhost:3000',
|
|
username: 'test@example.com',
|
|
password: 'password',
|
|
});
|
|
|
|
const result = await workflow.execute();
|
|
|
|
expect(result.ok).toBe(true);
|
|
expect(result.value.success).toBe(true);
|
|
expect(result.value.steps).toHaveLength(5);
|
|
});
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## See Also
|
|
|
|
- [Main Integration Guide](../integration/claude-flow-browser.md)
|
|
- [Security Scanner API](./security-scanner.md)
|
|
- [Trajectory Learning Guide](./trajectory-learning.md)
|
|
- [Browser Testing Best Practices](../guides/browser-testing.md)
|