Natural Language Tests
Write tests in plain English. CBrowser parses and executes them. (v6.1.0)
Why Natural Language?
Traditional test code:
await page.goto('https://example.com');
await page.locator('[data-testid="login-btn"]').click();
await page.locator('#email').fill('[email protected]');
await expect(page).toHaveURL(/dashboard/);
Natural language equivalent:
go to https://example.com
click the login button
type "[email protected]" in email field
verify url contains "dashboard"
Benefits:
- Readable by non-developers - QA, PMs, stakeholders can write tests
- Self-documenting - The test IS the documentation
- Portable - Not tied to any framework's syntax
- AI-friendly - Easy for AI to generate and modify
Test File Format
Create a .txt file with your tests:
# Test: Login Flow
go to https://example.com
click the login button
type "[email protected]" in email field
type "password123" in password field
click submit
verify url contains "/dashboard"
verify page contains "Welcome back"
# Test: Search Functionality
go to https://example.com/search
type "test query" in search box
click search button
verify page contains "results"
take screenshot
Syntax Rules
- Lines starting with
#are comments or test names # Test: Namestarts a new test case- Empty lines are ignored
- One instruction per line
Supported Instructions
Navigation
| Instruction | Examples |
|---|---|
| Go to URL | go to https://example.com |
| Navigate | navigate to https://example.com/page |
| Open | open https://example.com |
Clicking
| Instruction | Examples |
|---|---|
| Click by text | click the login button |
| Click by description | click submit |
| Click specific | click "Sign Up" |
| Press key | press Enter |
Filling Forms
| Instruction | Examples |
|---|---|
| Type in field | type "[email protected]" in email field |
| Fill field | fill username with "john" |
| Enter value | enter "password123" in password input |
Selecting
| Instruction | Examples |
|---|---|
| Select option | select "Option A" from dropdown |
| Choose | choose "California" from state selector |
Scrolling
| Instruction | Examples |
|---|---|
| Scroll down | scroll down |
| Scroll up | scroll up |
| Scroll multiple | scroll down 5 times |
Waiting
| Instruction | Examples |
|---|---|
| Wait seconds | wait 2 seconds |
| Wait for element | wait for "Loading" to disappear |
| Wait for text | wait for "Success" to appear |
Assertions
| Instruction | Examples |
|---|---|
| Verify content | verify page contains "Welcome" |
| Verify URL | verify url contains "/dashboard" |
| Verify title | verify title is "Home Page" |
| Verify element | verify "Submit" button exists |
Screenshots
| Instruction | Examples |
|---|---|
| Take screenshot | take screenshot |
| Screenshot named | take screenshot "after-login" |
Running Tests
From File
npx cbrowser test-suite tests.txt
Inline Tests
npx cbrowser test-suite --inline "go to https://example.com ; click login ; verify url contains /dashboard"
Options
# Continue after failures
npx cbrowser test-suite tests.txt \
--continue-on-failure
# Save JSON report
npx cbrowser test-suite tests.txt \
--output results.json
# Generate HTML report
npx cbrowser test-suite tests.txt \
--html
# Visible browser (default: headless)
npx cbrowser test-suite tests.txt \
--no-headless
# Run as a phone, in another timezone
npx cbrowser test-suite tests.txt \
--device iphone-16 \
--timezone Asia/Tokyo
test-suite accepts only the flags it reads. Since 20.0 any other flag, such as --persona, exits 1 and lists the accepted ones instead of being ignored.
Export and Webhooks
Every run is saved under the CBrowser data directory by suite name (the file name without its extension), so you can export the last run:
npx cbrowser test-suite login.txt
npx cbrowser export junit login
npx cbrowser export tap login \
results.tap
A run also sends test.pass or test.fail to the webhooks you have added. The sender posts JSON with a 10 second timeout and no retries, and a failed send never fails the run:
npx cbrowser webhook add ci-alerts \
https://hooks.example.com/cb \
--events test.fail --format slack
Output
Console Output
π Running Test Suite: My Tests
βββββββββββββββββββββββββββββββββββββββββββββ
TEST: Login Flow
βββββββββββββββββββββββββββββββββββββββββββββ
β go to https://example.com (1.2s)
β click the login button (0.3s)
β type "[email protected]" in email field (0.5s)
β type "password123" in password field (0.4s)
β click submit (0.2s)
β verify url contains "/dashboard" (0.1s)
β verify page contains "Welcome back" (0.1s)
β
PASSED (2.8s)
βββββββββββββββββββββββββββββββββββββββββββββ
TEST: Search Functionality
βββββββββββββββββββββββββββββββββββββββββββββ
β go to https://example.com/search (0.9s)
β type "test query" in search box (0.4s)
β click search button (0.2s)
β verify page contains "results"
Expected: page to contain "results"
Actual: page contains "No matches found"
β FAILED (1.5s)
βββββββββββββββββββββββββββββββββββββββββββββ
SUMMARY
βββββββββββββββββββββββββββββββββββββββββββββ
Total: 2 tests
Passed: 1
Failed: 1
Pass Rate: 50%
Duration: 4.3s
JSON Report
{
"suiteName": "My Tests",
"timestamp": "2025-01-30T12:00:00Z",
"duration": 4300,
"summary": {
"total": 2,
"passed": 1,
"failed": 1,
"passRate": 50
},
"tests": [
{
"name": "Login Flow",
"passed": true,
"duration": 2800,
"steps": [...]
}
]
}
API Usage
import { parseNLTestSuite, runNLTestSuite, formatNLTestReport } from 'cbrowser';
// Parse test file content
const suite = parseNLTestSuite(`
# Test: Homepage
go to https://example.com
verify title contains "Example"
click the about link
verify url contains "/about"
`, "My Test Suite");
// Run the tests
const result = await runNLTestSuite(suite, {
continueOnFailure: true,
screenshotOnFailure: true,
headless: true,
});
// Format output
console.log(formatNLTestReport(result));
// Access detailed results
for (const test of result.testResults) {
console.log(`${test.name}: ${test.passed ? 'PASS' : 'FAIL'}`);
for (const step of test.stepResults) {
console.log(` ${step.passed ? 'β' : 'β'} ${step.instruction}`);
}
}
Combining with Other Features
With Flaky Detection
# Run tests multiple times to find unreliable ones
npx cbrowser flaky-check tests.txt --runs 10
With AI Repair
# Automatically fix broken tests
npx cbrowser repair-tests tests.txt --auto-apply
With Personas
test-suite has no persona option (--persona exits 1). To see how different personas get through the same flow, run cognitive journeys instead (needs an Anthropic API key):
npx cbrowser compare-personas \
--start "https://example.com" \
--goal "log in" \
--personas first-timer,elderly-user
Best Practices
- One assertion per test - Makes failures easy to diagnose
- Use descriptive test names -
# Test: User can reset password - Add waits after navigation - Pages need time to load
- Take screenshots at key points - Helps debug failures
- Keep tests independent - Don't rely on previous test state
Related
- AI Test Repair - Fix broken tests automatically
- Flaky Test Detection - Find unreliable tests
- CLI Reference - All test-suite options
Copyright: (c) 2026 Alexa Eden.
License: MIT License
Contact: [email protected]