tk-flow Pro
JSON-defined E2E test flow runner powered by Playwright. Define user journeys as simple JSON files — no code required. Supports 12 actions and 7 assertion types.
bash
npm install -g @tk-tis/tk-flow
npx playwright install chromium
Usage
bash
# Run a flow file
tk-flow tests/login.json
# Run with Firefox in headed mode (visible browser)
tk-flow tests/login.json --browser firefox --headed
# JSON output for CI
tk-flow tests/login.json --json
# Custom screenshots directory and timeout
tk-flow tests/login.json --screenshots-dir ./results --timeout 15000
CLI Options
| Flag | Description | Default |
|---|---|---|
--browser, -b |
Browser engine: chromium, firefox, webkit |
chromium |
--headed |
Show the browser window (useful for debugging) | false |
--json |
Output results as JSON | false |
--screenshots-dir |
Directory for screenshots | ./screenshots |
--no-color |
Disable ANSI color codes | false |
--timeout, -t |
Per-step timeout in milliseconds | 30000 |
Flow File Format
Flow files are JSON documents that describe one or more user journeys. Each flow has a name and a list of steps executed in sequence.
JSON Schema
json
{
"project": "string (optional) — project identifier",
"baseUrl": "string (required) — base URL for relative routes",
"flows": [
{
"name": "string (required) — flow name for reports",
"steps": [
{
"action": "string (required) — one of the 12 supported actions",
"selector": "string (optional) — CSS selector for the target element",
"value": "string (optional) — value for type, assert, wait, etc.",
"url": "string (optional) — URL for navigate action",
"duration": "number (optional) — milliseconds for wait action",
"name": "string (optional) — name for screenshot files",
"type": "string (optional) — assertion type for assert action",
"key": "string (optional) — keyboard key for press action",
"x": "number (optional) — x coordinate for scroll",
"y": "number (optional) — y coordinate for scroll"
}
]
}
]
}
Complete Example
json
{
"project": "my-app",
"baseUrl": "https://myapp.com",
"flows": [
{
"name": "Login",
"steps": [
{ "action": "navigate", "url": "/" },
{ "action": "assert", "type": "title_equals", "value": "My App" },
{ "action": "type", "selector": "input[name=email]", "value": "test@test.com" },
{ "action": "type", "selector": "input[name=password]", "value": "secret123" },
{ "action": "click", "selector": "button[type=submit]" },
{ "action": "assert", "type": "url_contains", "value": "/dashboard" }
]
},
{
"name": "Dashboard Elements",
"steps": [
{ "action": "navigate", "url": "/dashboard" },
{ "action": "assert", "type": "element_exists", "selector": ".sidebar" },
{ "action": "assert", "type": "text_visible", "value": "Welcome" },
{ "action": "hover", "selector": ".user-menu" },
{ "action": "screenshot", "name": "dashboard-hover" },
{ "action": "assert", "type": "element_not_exists", "selector": ".error-banner" }
]
},
{
"name": "Settings Form",
"steps": [
{ "action": "navigate", "url": "/settings" },
{ "action": "clear", "selector": "input[name=displayName]" },
{ "action": "type", "selector": "input[name=displayName]", "value": "Test User" },
{ "action": "select", "selector": "select[name=language]", "value": "en" },
{ "action": "assert", "type": "value_equals", "selector": "input[name=displayName]", "value": "Test User" },
{ "action": "scroll", "selector": "#save-section" },
{ "action": "press", "selector": "input[name=displayName]", "key": "Tab" },
{ "action": "click", "selector": "button#save" },
{ "action": "wait", "duration": 1000 },
{ "action": "assert", "type": "text_visible", "value": "Settings saved" }
]
}
]
}
Supported Actions (12)
| Action | Required Fields | Description |
|---|---|---|
navigate |
url |
Navigate to a URL (relative to baseUrl or absolute) |
click |
selector |
Click an element matching the CSS selector |
type |
selector, value |
Type text into an input field (replaces existing content) |
clear |
selector |
Clear an input field's content |
wait |
duration or value |
Wait for a specified number of milliseconds |
waitForNavigation |
value (optional) |
Wait for navigation to complete, optionally matching a URL pattern |
screenshot |
name (optional) |
Capture a screenshot with an optional filename |
assert |
type + varies |
Assert a condition (see assertion types below) |
select |
selector, value |
Select a dropdown option by value |
scroll |
selector or x/y |
Scroll to an element or by pixel coordinates |
hover |
selector |
Hover over an element |
press |
value or key |
Press a keyboard key, optionally focused on a selector |
Assert Types (7)
| Type | Required Fields | Description |
|---|---|---|
url_contains |
value |
Current URL contains the given string |
text_visible |
value |
Text is visible on the page |
element_exists |
selector |
Element matching selector exists in the DOM |
element_not_exists |
selector |
Element matching selector does NOT exist |
title_equals |
value |
Page title exactly equals the given string |
element_count |
selector, value |
Number of matching elements equals value (as number) |
value_equals |
selector, value |
Input element's value property equals the given string |
Execution Behavior
- Each flow gets its own browser instance for isolation
- Steps execute sequentially within a flow
- If a step fails, remaining steps in that flow are skipped
- Execution continues to the next flow in the file
- On failure, an automatic screenshot is captured at the failure point
- All screenshots are saved to the
--screenshots-dirdirectory
Exit Codes
| Code | Meaning |
|---|---|
0 | All flows and all steps passed |
1 | One or more steps failed |
HTK-Cloud Integration
Set environment variables to report flow results:
bash
export HTK_CLOUD_URL=https://htk-cloud-v4.enzu-agent.workers.dev
export HTK_CLOUD_TOKEN=your-api-key
tk-flow tests/login.json
Results are POSTed to /api/flow-results after each run.