explorbot 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/explorbot-cli.ts +7 -1
- package/boat/api-tester/src/config.ts +4 -2
- package/boat/doc-collector/bin/doc-collector-cli.ts +2 -0
- package/boat/doc-collector/src/ai/documentarian.ts +61 -31
- package/boat/doc-collector/src/config.ts +4 -2
- package/boat/prima/bin/prima-cli.ts +0 -0
- package/boat/prima/src/activity-line.ts +33 -0
- package/boat/prima/src/cli.ts +115 -86
- package/boat/prima/src/envelope.ts +80 -52
- package/boat/prima/src/prima.ts +547 -128
- package/boat/prima/src/pw-parser.ts +11 -1
- package/boat/prima/src/pw-registry.ts +4 -5
- package/boat/prima/src/session-log.ts +126 -0
- package/dist/bin/explorbot-cli.js +7 -1
- package/dist/boat/api-tester/bin/apibot-cli.js +2 -0
- package/dist/boat/api-tester/src/config.js +4 -2
- package/dist/boat/doc-collector/bin/doc-collector-cli.js +2 -0
- package/dist/boat/doc-collector/src/ai/documentarian.js +44 -19
- package/dist/boat/doc-collector/src/config.js +4 -2
- package/dist/boat/prima/src/activity-line.js +30 -0
- package/dist/boat/prima/src/cli.js +97 -77
- package/dist/boat/prima/src/envelope.js +70 -44
- package/dist/boat/prima/src/prima.js +515 -119
- package/dist/boat/prima/src/pw-parser.js +13 -1
- package/dist/boat/prima/src/pw-registry.js +4 -5
- package/dist/boat/prima/src/session-log.js +108 -0
- package/dist/package.json +3 -2
- package/dist/rules/navigator/verification-actions.md +20 -0
- package/dist/src/action-result.d.ts +7 -0
- package/dist/src/action-result.js +4 -0
- package/dist/src/action.d.ts +2 -0
- package/dist/src/action.js +36 -1
- package/dist/src/ai/captain/web-mode.js +6 -3
- package/dist/src/ai/captain.js +2 -0
- package/dist/src/ai/navigator.d.ts +7 -0
- package/dist/src/ai/navigator.js +10 -6
- package/dist/src/ai/pilot.d.ts +4 -0
- package/dist/src/ai/pilot.js +48 -2
- package/dist/src/ai/provider.js +2 -2
- package/dist/src/ai/rerunner.js +2 -1
- package/dist/src/ai/researcher.js +1 -1
- package/dist/src/ai/rules.js +17 -10
- package/dist/src/ai/task-agent.js +4 -1
- package/dist/src/ai/tester.d.ts +1 -1
- package/dist/src/ai/tester.js +33 -33
- package/dist/src/ai/tools.d.ts +14 -0
- package/dist/src/ai/tools.js +113 -36
- package/dist/src/config.d.ts +1 -0
- package/dist/src/config.js +13 -4
- package/dist/src/execution-controller.d.ts +2 -0
- package/dist/src/execution-controller.js +6 -0
- package/dist/src/explorbot.d.ts +2 -1
- package/dist/src/explorbot.js +3 -1
- package/dist/src/explorer.js +2 -3
- package/dist/src/playwright-recorder.js +30 -0
- package/dist/src/remote.d.ts +54 -0
- package/dist/src/remote.js +229 -0
- package/dist/src/reporter.d.ts +1 -0
- package/dist/src/reporter.js +7 -1
- package/dist/src/state-manager.d.ts +2 -1
- package/dist/src/stats.d.ts +1 -0
- package/dist/src/stats.js +1 -0
- package/dist/src/test-plan.d.ts +2 -0
- package/dist/src/test-plan.js +7 -0
- package/dist/src/utils/aria.d.ts +2 -8
- package/dist/src/utils/aria.js +69 -40
- package/dist/src/utils/html.js +1 -0
- package/dist/src/utils/logger.d.ts +6 -0
- package/dist/src/utils/logger.js +24 -0
- package/dist/src/utils/page-readiness.js +18 -1
- package/dist/src/utils/url-matcher.js +3 -0
- package/dist/src/utils/web-element.d.ts +2 -0
- package/dist/src/utils/web-element.js +8 -0
- package/dist/src/utils/web-sandbox.d.ts +1 -1
- package/dist/src/utils/web-sandbox.js +2 -3
- package/docs/api-testing/basics.md +90 -0
- package/docs/api-testing/planning.md +57 -0
- package/docs/api-testing/running-tests.md +55 -0
- package/docs/assets/cloud-report.png +0 -0
- package/docs/assets/html-report.png +0 -0
- package/docs/assets/langfuse-trace.png +0 -0
- package/docs/assets/successful-explore-run.png +0 -0
- package/docs/basics/getting-started.md +140 -0
- package/docs/basics/prerequisites.md +63 -0
- package/docs/basics/providers.md +362 -0
- package/docs/basics/running.md +78 -0
- package/docs/contributing/ai-integration-tests.md +57 -0
- package/docs/contributing/contributing.md +90 -0
- package/docs/contributing/demo-videos.md +36 -0
- package/docs/contributing/npm-package.md +138 -0
- package/docs/contributing/observability.md +227 -0
- package/docs/contributing/regression-tests.md +103 -0
- package/docs/contributing/testing.md +95 -0
- package/docs/doc-collection/basics.md +128 -0
- package/docs/doc-collection/crawling.md +67 -0
- package/docs/doc-collection/interactive-mode.md +99 -0
- package/docs/index.json +86 -0
- package/docs/reference/commands.md +994 -0
- package/docs/reference/configuration.md +569 -0
- package/docs/reference/scripting.md +303 -0
- package/docs/superpowers/plans/2026-08-01-actor-boat.md +925 -0
- package/docs/superpowers/plans/2026-08-01-prima-boat.md +1120 -0
- package/docs/superpowers/reviews/2026-08-06-prima-vs-playwright-cli.md +268 -0
- package/docs/superpowers/specs/2026-08-01-actor-boat-design.md +204 -0
- package/docs/superpowers/specs/2026-08-01-prima-boat-design.md +242 -0
- package/docs/superpowers/specs/2026-08-03-global-config-design.md +138 -0
- package/docs/superpowers/specs/2026-08-07-prima-fixes-design.md +394 -0
- package/docs/web-testing/agents.md +158 -0
- package/docs/web-testing/automated-tests.md +134 -0
- package/docs/web-testing/basics.md +91 -0
- package/docs/web-testing/customization.md +131 -0
- package/docs/web-testing/hooks.md +238 -0
- package/docs/web-testing/page-interaction.md +84 -0
- package/docs/web-testing/planner.md +122 -0
- package/docs/web-testing/rerun.md +164 -0
- package/docs/web-testing/researcher.md +380 -0
- package/docs/workflow/agentic-usage.md +233 -0
- package/docs/workflow/application-spec.md +73 -0
- package/docs/workflow/ci.md +202 -0
- package/docs/workflow/knowledge.md +310 -0
- package/docs/workflow/planning-styles.md +67 -0
- package/docs/workflow/reporting.md +133 -0
- package/docs/workflow/test-plans.md +90 -0
- package/package.json +3 -2
- package/rules/navigator/verification-actions.md +20 -0
- package/src/action-result.ts +11 -0
- package/src/action.ts +38 -2
- package/src/ai/captain/web-mode.ts +6 -3
- package/src/ai/captain.ts +3 -0
- package/src/ai/navigator.ts +14 -8
- package/src/ai/pilot.ts +53 -2
- package/src/ai/provider.ts +2 -4
- package/src/ai/rerunner.ts +2 -1
- package/src/ai/researcher.ts +1 -1
- package/src/ai/rules.ts +17 -10
- package/src/ai/task-agent.ts +3 -1
- package/src/ai/tester.ts +32 -33
- package/src/ai/tools.ts +132 -36
- package/src/config.ts +15 -4
- package/src/execution-controller.ts +8 -0
- package/src/explorbot.ts +4 -2
- package/src/explorer.ts +2 -2
- package/src/playwright-recorder.ts +23 -0
- package/src/remote.ts +238 -0
- package/src/reporter.ts +7 -1
- package/src/state-manager.ts +2 -1
- package/src/stats.ts +1 -0
- package/src/test-plan.ts +9 -0
- package/src/utils/aria.ts +65 -45
- package/src/utils/html.ts +1 -0
- package/src/utils/logger.ts +24 -1
- package/src/utils/page-readiness.ts +24 -1
- package/src/utils/url-matcher.ts +3 -0
- package/src/utils/web-element.ts +9 -0
- package/src/utils/web-sandbox.ts +3 -4
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Automated Tests
|
|
2
|
+
|
|
3
|
+
When Explorbot runs a plan, it saves the executed scenarios to a runnable test file under `output/tests/`. Commit it, run it from CI, or edit it by hand.
|
|
4
|
+
|
|
5
|
+
Pick the framework you use:
|
|
6
|
+
|
|
7
|
+
- **Playwright** — set `ai.agents.historian.framework: 'playwright'` in your config. Output is a `.spec.ts` file.
|
|
8
|
+
- **CodeceptJS** — the default. Output is a `.js` file.
|
|
9
|
+
|
|
10
|
+
If you use neither, start with Playwright.
|
|
11
|
+
|
|
12
|
+
## Playwright
|
|
13
|
+
|
|
14
|
+
A file Explorbot produced from a plan called *Creating a plan*, trimmed for readability. See `example/output/tests/` for full examples.
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { test, expect } from '@playwright/test';
|
|
18
|
+
|
|
19
|
+
test.describe('Creating a plan', () => {
|
|
20
|
+
test.beforeEach(async ({ page }) => {
|
|
21
|
+
await page.goto('/projects/zyntra/plans/');
|
|
22
|
+
await page.waitForTimeout(1000);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('Create a new manual plan and verify it appears in the list', async ({ page }) => {
|
|
26
|
+
await test.step("Click the 'New plan' button in toolbar", async () => {
|
|
27
|
+
await page.getByRole('button', { name: 'New plan' }).first().click();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
await test.step('Select Manual plan type in modal', async () => {
|
|
31
|
+
await page.locator('#portal-container').getByRole('button', { name: 'Manual' }).click();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
await test.step('Click Save', async () => {
|
|
35
|
+
await page.getByRole('button', { name: 'Save' }).click();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
await test.step('Verification', async () => {
|
|
39
|
+
await expect(page).toContainText('Test Plan UI Creation 001');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// FAILED: Create a new automated plan and verify it appears under automated tab
|
|
44
|
+
test.skip('Create a new automated plan and verify it appears under automated tab', async ({ page }) => {
|
|
45
|
+
// ...
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test.fixme('Delete a plan from the list', async ({ page }) => {
|
|
49
|
+
// open the action menu
|
|
50
|
+
// click Delete
|
|
51
|
+
// confirm in dialog
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Three things to notice:
|
|
57
|
+
|
|
58
|
+
1. Every action is its own `test.step`. The label is the AI's description of that action, so the Playwright report tree reads like the plan it came from. Failures land on a single step.
|
|
59
|
+
2. The locators are real. `page.getByRole('button', { name: 'New plan' })` is what Playwright ran during the session, not a translation. If it worked then, it works now.
|
|
60
|
+
3. `test.beforeEach` reaches the starting state. It navigates to the plan's start URL and replays the `wait` / `waitForElement` knowledge you declared for that page. The closing `test.step('Verification', ...)` block holds whatever the Pilot verified.
|
|
61
|
+
|
|
62
|
+
Run it the normal way:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npx playwright test output/tests/runs_archive_feature_testing.spec.ts
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`npx explorbot rerun` does not run Playwright specs. It points you at `npx playwright test` instead.
|
|
69
|
+
|
|
70
|
+
### Scenarios that didn't pass
|
|
71
|
+
|
|
72
|
+
The file always runs, even when some scenarios failed:
|
|
73
|
+
|
|
74
|
+
- Passed scenarios become plain `test(...)`.
|
|
75
|
+
- Failed scenarios become `test.skip(...)` with a `// FAILED: <scenario>` comment above them, so you can see what broke and decide whether to fix or drop it.
|
|
76
|
+
- Scenarios Explorbot didn't reach become `test.fixme(...)`, with the planned steps preserved as comments.
|
|
77
|
+
|
|
78
|
+
Commit the file as-is. Passing scenarios run, broken ones are skipped and visible, planned ones wait for you.
|
|
79
|
+
|
|
80
|
+
## CodeceptJS
|
|
81
|
+
|
|
82
|
+
The default output is a `Feature` with one `Scenario` per plan entry, plus a `Before` block for setup:
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
import step, { Section } from 'codeceptjs/steps';
|
|
86
|
+
|
|
87
|
+
Feature('Runs Archive Feature Testing')
|
|
88
|
+
|
|
89
|
+
Before(({ I }) => {
|
|
90
|
+
I.amOnPage('/projects/zyntra/runs/archive');
|
|
91
|
+
I.wait(1);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
Scenario('Apply filters specific to archived runs and verify results', ({ I }) => {
|
|
95
|
+
Section('Open the filter panel');
|
|
96
|
+
I.click({ css: 'button.btn-only-icon.btn-lg:has(svg.md-icon-filter)' });
|
|
97
|
+
|
|
98
|
+
Section('Pick the Passed status');
|
|
99
|
+
I.click('Select status');
|
|
100
|
+
I.click('Passed');
|
|
101
|
+
I.click('Apply');
|
|
102
|
+
|
|
103
|
+
I.see('1 run found');
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Two things to notice:
|
|
108
|
+
|
|
109
|
+
1. `Before` reaches the starting state. It calls `I.amOnPage` for the plan's start URL and replays the `wait` / `waitForElement` knowledge you declared for that page.
|
|
110
|
+
2. Steps are grouped by `Section('...')`. Each label is the AI's description of that group, so the test reads top to bottom like the plan it came from.
|
|
111
|
+
|
|
112
|
+
Run it with:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
npx explorbot rerun output/tests/runs_archive_feature_testing.js
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
`npx explorbot rerun` heals broken steps automatically. See [Rerun](./rerun.md).
|
|
119
|
+
|
|
120
|
+
### Scenarios that didn't pass
|
|
121
|
+
|
|
122
|
+
The file always runs, even when some scenarios failed:
|
|
123
|
+
|
|
124
|
+
- Passed scenarios become plain `Scenario(...)`.
|
|
125
|
+
- Failed scenarios become `Scenario.skip(...)` with a `// FAILED: <scenario>` comment above them.
|
|
126
|
+
- Scenarios Explorbot didn't reach become `Scenario.todo(...)`, with the planned steps preserved as comments.
|
|
127
|
+
|
|
128
|
+
Commit the file as-is. Passing scenarios run, broken ones are skipped and visible, planned ones wait for you.
|
|
129
|
+
|
|
130
|
+
## See also
|
|
131
|
+
|
|
132
|
+
- [Test Plans](../workflow/test-plans.md) — the markdown plans that drive these test files
|
|
133
|
+
- [Rerun](./rerun.md) — re-run CodeceptJS tests with auto-healing
|
|
134
|
+
- [Configuration → Historian Agent Options](../reference/configuration.md#historian-agent-options) — the `framework` option
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Web Testing Basics
|
|
2
|
+
|
|
3
|
+
Explorbot tests a web app the way a curious QA engineer would: open a page, figure out what it does, invent test scenarios, run them, and remember what happened. You write no test scripts up front — the tests come from the app itself.
|
|
4
|
+
|
|
5
|
+
This page explains the concepts behind that loop and the minimum configuration to start. If you haven't installed Explorbot yet, do [Getting Started](../basics/getting-started.md) first.
|
|
6
|
+
|
|
7
|
+
## What it does
|
|
8
|
+
|
|
9
|
+
One exploration cycle has four parts:
|
|
10
|
+
|
|
11
|
+
1. **Research.** The Researcher agent reads the current page — HTML, ARIA snapshot, and optionally a screenshot — and builds a map of what's on it: forms, buttons, tables, navigation.
|
|
12
|
+
2. **Plan.** The Planner turns that map into test scenarios with priorities and expected outcomes, cycling through planning styles to broaden coverage.
|
|
13
|
+
3. **Test.** The Tester runs each scenario step by step in a real browser, adapting when a click misses or a modal appears. The Pilot supervises from above and steps in when the test gets stuck.
|
|
14
|
+
4. **Learn.** Outcomes are recorded — what worked, what failed, how failures were resolved — so the next run starts smarter.
|
|
15
|
+
|
|
16
|
+
When you run `/explore`, this cycle repeats. After the start page is covered, Explorbot picks promising sub-pages linked from it and continues there, until it runs out of pages or hits your test limit.
|
|
17
|
+
|
|
18
|
+
Two ideas hold this loop together, and you will meet them everywhere in these docs: states and learning.
|
|
19
|
+
|
|
20
|
+
### States
|
|
21
|
+
|
|
22
|
+
A page state is the URL plus the page's main headings (`h1` and `h2`). That's how Explorbot knows where it is. A URL alone isn't enough — a single-page app can show a list, an edit form, and a confirmation dialog all on one URL — so headings are part of the identity.
|
|
23
|
+
|
|
24
|
+
States are the anchor points for everything else. Navigation history is a chain of state transitions, knowledge and experience are matched to the current state, and loop detection compares recent state hashes: if the bot keeps cycling through the same one or two states, it knows it's stuck and changes strategy instead of burning iterations.
|
|
25
|
+
|
|
26
|
+
### Learning
|
|
27
|
+
|
|
28
|
+
Explorbot keeps two directories of markdown files next to your config:
|
|
29
|
+
|
|
30
|
+
- `knowledge/` — facts **you** teach it: credentials, quirks, hints, small automations. Each file targets pages by URL pattern, so knowledge for `/login` loads only on the login page and knowledge for `*` loads everywhere.
|
|
31
|
+
- `experience/` — what it **learned by doing**: failed attempts, working resolutions, session notes. Files are named after state hashes, so lessons from a page are re-read the next time that page appears.
|
|
32
|
+
|
|
33
|
+
Knowledge is the input you control; experience accumulates on its own. Both are plain markdown you can read and edit. See [Knowledge](../workflow/knowledge.md).
|
|
34
|
+
|
|
35
|
+
## Configure
|
|
36
|
+
|
|
37
|
+
Web testing needs one thing beyond the AI setup from Getting Started — the base URL of your app:
|
|
38
|
+
|
|
39
|
+
```javascript
|
|
40
|
+
export default {
|
|
41
|
+
web: {
|
|
42
|
+
url: 'http://localhost:3000',
|
|
43
|
+
},
|
|
44
|
+
ai: {
|
|
45
|
+
model: openrouter('openai/gpt-oss-20b:nitro'),
|
|
46
|
+
visionModel: openrouter('google/gemma-4-31b-it'),
|
|
47
|
+
agenticModel: openrouter('minimax/minimax-m2.5:nitro'),
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The three models split the work by cost: `model` does the heavy page reading on every step, `visionModel` analyzes screenshots, and `agenticModel` makes the high-level decisions on short inputs, so it can be smarter without costing much. The full breakdown is in [Getting Started](../basics/getting-started.md); provider setup is in [Providers](../basics/providers.md). Every other option — browser settings, directories, per-agent tuning — lives in the [Configuration reference](../reference/configuration.md).
|
|
53
|
+
|
|
54
|
+
## First run
|
|
55
|
+
|
|
56
|
+
One tip from Getting Started is worth repeating: don't start on your homepage. Point Explorbot at one focused page with a clear CRUD interface — a list-and-edit screen, a settings page. It gives the bot an obvious job and you an obvious way to judge the result.
|
|
57
|
+
|
|
58
|
+
The interactive route opens the TUI, where you watch the run and can step in:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npx explorbot start /admin/projects
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Then type `/explore` to run the full loop, or go one step at a time with `/research` (analyze the page), `/plan` (propose scenarios), and `/test` (run the next one).
|
|
65
|
+
|
|
66
|
+
The headless route runs the same loop without the TUI and exits when done — good for CI or overnight runs:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npx explorbot explore /admin/projects --max-tests 10 --focus "project management"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`--max-tests` caps how many tests run; `--focus` narrows planning to one feature. Both are optional.
|
|
73
|
+
|
|
74
|
+
## Output files
|
|
75
|
+
|
|
76
|
+
Every run leaves artifacts behind:
|
|
77
|
+
|
|
78
|
+
- **Test plans** in `output/plans/` — the scenarios as markdown, with priorities and results. You can re-run, edit, or extend them. See [Test Plans](../workflow/test-plans.md).
|
|
79
|
+
- **Runnable tests** in `output/tests/` — CodeceptJS/Playwright code generated from successful runs, ready to commit and run in CI. See [Automated Tests](./automated-tests.md).
|
|
80
|
+
- **A session report** in `output/reports/` — a human-readable summary that clusters defects, UX issues, and execution problems by root cause. See [Reporting](../workflow/reporting.md).
|
|
81
|
+
- **Experience files** in `experience/` — the lessons that make the next run faster and less error-prone.
|
|
82
|
+
|
|
83
|
+
## Where to go next
|
|
84
|
+
|
|
85
|
+
- [Customization](./customization.md) — make it work on *your* app: login, cookie banners, modals, test data.
|
|
86
|
+
- [Planner](./planner.md) — tune what gets tested: styles, priorities, custom rules.
|
|
87
|
+
- [Researcher](./researcher.md) — how pages are analyzed and what the UI map contains.
|
|
88
|
+
- [Page Interaction](./page-interaction.md) — how Explorbot reads pages and picks locators.
|
|
89
|
+
- [Automated Tests](./automated-tests.md) and [Rerun](./rerun.md) — the tests you keep, and re-running them with AI healing.
|
|
90
|
+
- [Agents](./agents.md) — the agents behind the loop, and per-agent model configuration.
|
|
91
|
+
- [Hooks](./hooks.md) — run your own code before and after agents.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Customization
|
|
2
|
+
|
|
3
|
+
Most real apps need a little setup before Explorbot can test them: a login, a cookie banner to dismiss, a slow page to wait for. This page shows the shortest recipe for each common case.
|
|
4
|
+
|
|
5
|
+
You have two tools:
|
|
6
|
+
|
|
7
|
+
- **Knowledge files** — markdown hints and small automations that run per URL. Start here.
|
|
8
|
+
- **Hooks** — code that runs for one agent only. Use these when knowledge isn't enough.
|
|
9
|
+
|
|
10
|
+
Each recipe below links to the full reference.
|
|
11
|
+
|
|
12
|
+
## Log in
|
|
13
|
+
|
|
14
|
+
Add a knowledge file for your login page and give Explorbot the credentials. Keep secrets in environment variables and reference them with `${env.NAME}`.
|
|
15
|
+
|
|
16
|
+
`knowledge/login.md`:
|
|
17
|
+
|
|
18
|
+
```markdown
|
|
19
|
+
---
|
|
20
|
+
url: /login
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
Log in with these credentials:
|
|
24
|
+
- email: ${env.APP_EMAIL}
|
|
25
|
+
- password: ${env.APP_PASSWORD}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Explorbot reads this when it opens the login page and signs in on its own. See [Knowledge](../workflow/knowledge.md).
|
|
29
|
+
|
|
30
|
+
## Stay logged in between runs
|
|
31
|
+
|
|
32
|
+
Logging in on every run is slow. Use `--session` to save cookies and local storage, then restore them next time:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx explorbot start /login --session # logs in, saves the session
|
|
36
|
+
npx explorbot start /dashboard --session # restores it, skips login
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Pass a filename to keep more than one session: `--session auth.json`.
|
|
40
|
+
|
|
41
|
+
## Dismiss a cookie banner
|
|
42
|
+
|
|
43
|
+
A cookie bar blocks the page until you accept it. Dismiss one on every page with a knowledge file on `*`. Wrap the click in `tryTo` so it does nothing when the bar is absent:
|
|
44
|
+
|
|
45
|
+
`knowledge/cookies.md`:
|
|
46
|
+
|
|
47
|
+
```markdown
|
|
48
|
+
---
|
|
49
|
+
url: *
|
|
50
|
+
code: |
|
|
51
|
+
await tryTo(() => I.click('Accept all'));
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
A cookie banner appears on first load. Accept it before interacting.
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Close modals and popups
|
|
58
|
+
|
|
59
|
+
A modal can cover the page right after it loads. Close it with a `code` block that runs only if the modal is there:
|
|
60
|
+
|
|
61
|
+
```markdown
|
|
62
|
+
---
|
|
63
|
+
url: /checkout
|
|
64
|
+
code: |
|
|
65
|
+
await tryTo(() => I.click('[aria-label="Close"]'));
|
|
66
|
+
---
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
To close a popup for one agent only — say, before research but not during a test — use a [hook](./hooks.md) instead.
|
|
70
|
+
|
|
71
|
+
## Wait for slow or single-page apps
|
|
72
|
+
|
|
73
|
+
Some pages show a spinner before the real content loads. Tell Explorbot to wait:
|
|
74
|
+
|
|
75
|
+
```markdown
|
|
76
|
+
---
|
|
77
|
+
url: /dashboard
|
|
78
|
+
wait: 2
|
|
79
|
+
waitForElement: '.dashboard-ready'
|
|
80
|
+
---
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`wait` pauses for the given seconds. `waitForElement` waits for a selector to appear. For single-page apps where a full reload breaks state, add `statePush: true` so Explorbot navigates without reloading.
|
|
84
|
+
|
|
85
|
+
## Set up and restore test data
|
|
86
|
+
|
|
87
|
+
To seed data before tests and clean it up after, use agent hooks. `tester.beforeHook` runs before the test loop; `afterHook` runs after it:
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
ai: {
|
|
91
|
+
agents: {
|
|
92
|
+
tester: {
|
|
93
|
+
beforeHook: {
|
|
94
|
+
type: 'codeceptjs',
|
|
95
|
+
hook: async ({ I }) => {
|
|
96
|
+
await I.executeScript(() => localStorage.setItem('cart', '[]'));
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
afterHook: {
|
|
100
|
+
type: 'playwright',
|
|
101
|
+
hook: async ({ page }) => {
|
|
102
|
+
await page.evaluate(() => localStorage.clear());
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
See [Hooks](./hooks.md) for every agent and hook type.
|
|
111
|
+
|
|
112
|
+
## Avoid fragile locators
|
|
113
|
+
|
|
114
|
+
Some frameworks generate random IDs that change on every load — for example Ember's `#ember123`. Tell Explorbot to ignore them, and it will prefer stable locators like ARIA labels and visible text:
|
|
115
|
+
|
|
116
|
+
```markdown
|
|
117
|
+
---
|
|
118
|
+
url: /projects/*
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Framework
|
|
122
|
+
|
|
123
|
+
This app is built with Ember. Do not use auto-generated IDs like #ember123 in locators.
|
|
124
|
+
Prefer ARIA labels and visible text.
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Knowledge or hooks?
|
|
128
|
+
|
|
129
|
+
Reach for a knowledge file first. It is markdown, lives beside your other knowledge, and applies to every agent on matching pages. Use a hook when you need code to run for one agent only, or different behavior for navigation versus testing. For a case-by-case comparison, see the decision table in [Hooks](./hooks.md#when-to-use-hooks-vs-knowledge).
|
|
130
|
+
|
|
131
|
+
Learn more in [Knowledge](../workflow/knowledge.md) and [Hooks](./hooks.md).
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# Agent Hooks
|
|
2
|
+
|
|
3
|
+
Hooks run custom code before or after a specific agent. Use them to prepare and clean up the page per agent.
|
|
4
|
+
|
|
5
|
+
> [!NOTE]
|
|
6
|
+
> For simple page automation such as waiting or clicking cookie banners, use [Knowledge Files](../workflow/knowledge.md) with the `wait`, `waitForElement`, or `code` fields. Reach for hooks when you need different behavior for different agents.
|
|
7
|
+
|
|
8
|
+
## When to Use Hooks vs Knowledge
|
|
9
|
+
|
|
10
|
+
| Use Case | Solution |
|
|
11
|
+
|----------|----------|
|
|
12
|
+
| Wait for element on all page visits | Knowledge: `waitForElement` |
|
|
13
|
+
| Dismiss cookie banner on page load | Knowledge: `code` |
|
|
14
|
+
| Wait for network idle only during research | Hook: `researcher.beforeHook` |
|
|
15
|
+
| Clean up test data after each test | Hook: `tester.afterHook` |
|
|
16
|
+
| Different waits for navigation vs testing | Hooks for each agent |
|
|
17
|
+
|
|
18
|
+
## Configuration
|
|
19
|
+
|
|
20
|
+
Hooks are configured per-agent in `explorbot.config.js`:
|
|
21
|
+
|
|
22
|
+
```javascript
|
|
23
|
+
export default {
|
|
24
|
+
ai: {
|
|
25
|
+
model: myProvider('gpt-4o'),
|
|
26
|
+
agents: {
|
|
27
|
+
navigator: {
|
|
28
|
+
beforeHook: {
|
|
29
|
+
type: 'playwright',
|
|
30
|
+
hook: async ({ page, url }) => {
|
|
31
|
+
await page.waitForLoadState('networkidle');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
tester: {
|
|
36
|
+
afterHook: {
|
|
37
|
+
type: 'codeceptjs',
|
|
38
|
+
hook: async ({ I, url }) => {
|
|
39
|
+
await I.executeScript(() => localStorage.clear());
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Hook Types
|
|
49
|
+
|
|
50
|
+
### Playwright Hooks
|
|
51
|
+
|
|
52
|
+
Get direct access to the Playwright page object:
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
beforeHook: {
|
|
56
|
+
type: 'playwright',
|
|
57
|
+
hook: async ({ page, url }) => {
|
|
58
|
+
await page.waitForLoadState('networkidle');
|
|
59
|
+
await page.locator('.loading').waitFor({ state: 'hidden' });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### CodeceptJS Hooks
|
|
65
|
+
|
|
66
|
+
Use the CodeceptJS `I` actor:
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
beforeHook: {
|
|
70
|
+
type: 'codeceptjs',
|
|
71
|
+
hook: async ({ I, url }) => {
|
|
72
|
+
await I.waitForElement('.page-ready');
|
|
73
|
+
await I.wait(1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## URL Pattern Matching
|
|
79
|
+
|
|
80
|
+
Run different hooks for different URL patterns:
|
|
81
|
+
|
|
82
|
+
```javascript
|
|
83
|
+
researcher: {
|
|
84
|
+
beforeHook: {
|
|
85
|
+
'/login': {
|
|
86
|
+
type: 'codeceptjs',
|
|
87
|
+
hook: async ({ I }) => await I.waitForElement('#login-form')
|
|
88
|
+
},
|
|
89
|
+
'/admin/*': {
|
|
90
|
+
type: 'playwright',
|
|
91
|
+
hook: async ({ page }) => await page.waitForLoadState('networkidle')
|
|
92
|
+
},
|
|
93
|
+
'/api/*': {
|
|
94
|
+
type: 'codeceptjs',
|
|
95
|
+
hook: async ({ I }) => await I.wait(2)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Pattern Syntax
|
|
102
|
+
|
|
103
|
+
| Pattern | Matches |
|
|
104
|
+
|---------|---------|
|
|
105
|
+
| `/login` | Exact path `/login` |
|
|
106
|
+
| `/admin/*` | `/admin` and any path starting with `/admin/` |
|
|
107
|
+
| `*` | All URLs (fallback) |
|
|
108
|
+
| `^/users/\d+$` | Regex: `/users/` followed by digits |
|
|
109
|
+
| `**/*.html` | Glob: any `.html` file |
|
|
110
|
+
|
|
111
|
+
## Supported Agents
|
|
112
|
+
|
|
113
|
+
| Agent | beforeHook | afterHook | Description |
|
|
114
|
+
|-------|------------|-----------|-------------|
|
|
115
|
+
| `navigator` | After navigation | After page capture | Browser navigation |
|
|
116
|
+
| `researcher` | After navigation | After research complete | Page analysis |
|
|
117
|
+
| `tester` | Before test loop | After test loop | Test execution |
|
|
118
|
+
| `driller` | Before drilling starts | After drilling completes | Component drilling |
|
|
119
|
+
| `captain` | Before handling command | After command complete | User commands |
|
|
120
|
+
|
|
121
|
+
> [!WARNING]
|
|
122
|
+
> The `planner` agent does not support hooks as it doesn't interact with the browser.
|
|
123
|
+
|
|
124
|
+
## Examples
|
|
125
|
+
|
|
126
|
+
### Wait for SPA to Load
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
navigator: {
|
|
130
|
+
beforeHook: {
|
|
131
|
+
type: 'playwright',
|
|
132
|
+
hook: async ({ page }) => {
|
|
133
|
+
await page.waitForFunction(() => {
|
|
134
|
+
return window.__APP_READY__ === true;
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Dismiss Modals Before Research
|
|
142
|
+
|
|
143
|
+
```javascript
|
|
144
|
+
researcher: {
|
|
145
|
+
beforeHook: {
|
|
146
|
+
type: 'codeceptjs',
|
|
147
|
+
hook: async ({ I }) => {
|
|
148
|
+
const modalVisible = await I.grabNumberOfVisibleElements('.modal-overlay');
|
|
149
|
+
if (modalVisible > 0) {
|
|
150
|
+
await I.click('.modal-close');
|
|
151
|
+
await I.wait(0.5);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Clean Up After Tests
|
|
159
|
+
|
|
160
|
+
```javascript
|
|
161
|
+
tester: {
|
|
162
|
+
afterHook: {
|
|
163
|
+
type: 'playwright',
|
|
164
|
+
hook: async ({ page }) => {
|
|
165
|
+
await page.evaluate(() => {
|
|
166
|
+
localStorage.clear();
|
|
167
|
+
sessionStorage.clear();
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Different Behavior per URL
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
tester: {
|
|
178
|
+
beforeHook: {
|
|
179
|
+
'/checkout': {
|
|
180
|
+
type: 'codeceptjs',
|
|
181
|
+
hook: async ({ I }) => {
|
|
182
|
+
// Ensure cart has items before checkout tests
|
|
183
|
+
await I.executeScript(() => {
|
|
184
|
+
if (!localStorage.getItem('cart')) {
|
|
185
|
+
localStorage.setItem('cart', JSON.stringify([{ id: 1, qty: 1 }]));
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
'/admin/*': {
|
|
191
|
+
type: 'codeceptjs',
|
|
192
|
+
hook: async ({ I }) => {
|
|
193
|
+
// Ensure admin session
|
|
194
|
+
await I.waitForElement('.admin-header', 5);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Error Handling
|
|
202
|
+
|
|
203
|
+
A hook error is logged but does not stop the agent:
|
|
204
|
+
|
|
205
|
+
```javascript
|
|
206
|
+
beforeHook: {
|
|
207
|
+
type: 'codeceptjs',
|
|
208
|
+
hook: async ({ I }) => {
|
|
209
|
+
try {
|
|
210
|
+
await I.waitForElement('.optional-banner', 2);
|
|
211
|
+
await I.click('.dismiss');
|
|
212
|
+
} catch {
|
|
213
|
+
// Banner not present, continue
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Execution Flow
|
|
220
|
+
|
|
221
|
+
```
|
|
222
|
+
┌─────────────────────────────────────────────────────────┐
|
|
223
|
+
│ Agent Execution │
|
|
224
|
+
├─────────────────────────────────────────────────────────┤
|
|
225
|
+
│ 1. Agent starts │
|
|
226
|
+
│ 2. Navigate to URL (if applicable) │
|
|
227
|
+
│ 3. ▶ beforeHook executes │
|
|
228
|
+
│ 4. Agent performs main work │
|
|
229
|
+
│ 5. ▶ afterHook executes │
|
|
230
|
+
│ 6. Agent completes │
|
|
231
|
+
└─────────────────────────────────────────────────────────┘
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## See Also
|
|
235
|
+
|
|
236
|
+
- [Knowledge Files](../workflow/knowledge.md) — page-level automation with `wait`, `waitForElement`, `code`
|
|
237
|
+
- [Configuration](../reference/configuration.md) — full configuration reference
|
|
238
|
+
- [Agents](./agents.md) — agent descriptions and workflows
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Page Interaction
|
|
2
|
+
|
|
3
|
+
This page explains how Explorbot agents read a web page and act on it — and the two things you can change to help them: filtering noisy HTML and marking custom components.
|
|
4
|
+
|
|
5
|
+
## How agents see a page
|
|
6
|
+
|
|
7
|
+
Agents read each page three ways at once:
|
|
8
|
+
|
|
9
|
+
| Source | What it gives | Used for |
|
|
10
|
+
|--------|---------------|----------|
|
|
11
|
+
| **ARIA snapshot** | Roles, labels, states, hierarchy | Understanding structure, building locators |
|
|
12
|
+
| **HTML** | Classes, IDs, data attributes, form fields | Precise locators, reading field values |
|
|
13
|
+
| **Screenshot** | Layout, colors, icons, coordinates | Visual checks, click fallbacks |
|
|
14
|
+
|
|
15
|
+
The accessibility tree is the primary source. HTML adds detail. The screenshot is a fallback when the first two aren't enough.
|
|
16
|
+
|
|
17
|
+
## Filter noisy HTML
|
|
18
|
+
|
|
19
|
+
Agents work from the `combined` HTML snapshot. Cookie banners, chat widgets, ads, and analytics tags add noise and burn tokens. Exclude them in your config:
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
// explorbot.config.js
|
|
23
|
+
html: {
|
|
24
|
+
combined: {
|
|
25
|
+
include: ['*'],
|
|
26
|
+
exclude: ['script', 'style', 'svg', '.cookie-banner', '.analytics-tracker'],
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Three snapshots exist, each configurable:
|
|
32
|
+
|
|
33
|
+
| Snapshot | Purpose | Config key |
|
|
34
|
+
|----------|---------|------------|
|
|
35
|
+
| `combined` | Main HTML for agents | `html.combined` |
|
|
36
|
+
| `minimal` | Interactive elements only | `html.minimal` |
|
|
37
|
+
| `text` | Text content only | `html.text` |
|
|
38
|
+
|
|
39
|
+
## Mark custom components
|
|
40
|
+
|
|
41
|
+
Some components are interactive but have no ARIA role or semantic HTML, so agents miss them. Mark them with a `data-explorbot-*` attribute:
|
|
42
|
+
|
|
43
|
+
```html
|
|
44
|
+
<div data-explorbot-role="button" data-explorbot-label="Save Draft">
|
|
45
|
+
<svg>...</svg>
|
|
46
|
+
Save
|
|
47
|
+
</div>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
A marked element is always kept in snapshots, treated as interactive, and shown to agents. During processing, `data-explorbot-role="button"` becomes `role="button"`, so you add a hint without changing how your component behaves.
|
|
51
|
+
|
|
52
|
+
Use this when standard locators fail to find an element, or when a custom control isn't detected as interactive.
|
|
53
|
+
|
|
54
|
+
## Locator priority
|
|
55
|
+
|
|
56
|
+
When an agent picks a locator, it prefers the most stable option first:
|
|
57
|
+
|
|
58
|
+
```mermaid
|
|
59
|
+
flowchart LR
|
|
60
|
+
A[ARIA, semantic text, and role] --> B[Scope with a container]
|
|
61
|
+
B --> C[HTML attributes, CSS, or XPath]
|
|
62
|
+
C --> D[Screenshot and visual coordinates]
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The agent starts with short semantic locators from ARIA or visible text. When a match is ambiguous, it scopes that locator to a container before moving to HTML-based selectors and, finally, visual coordinates.
|
|
66
|
+
|
|
67
|
+
1. Short ARIA or text — `I.click({ role: 'button', text: 'Save' })` or `I.click('Save')` when it is unique
|
|
68
|
+
2. Text with a container — `I.click('Save', '.modal')` — simplest and preferred when a container is known
|
|
69
|
+
3. ARIA with a container — `I.click({ role: 'button', text: 'Save' }, '.modal')` — for semantic disambiguation
|
|
70
|
+
4. CSS or XPath — `I.click('#save-btn')`
|
|
71
|
+
5. Coordinates — `I.clickXY(400, 300)` (last resort)
|
|
72
|
+
|
|
73
|
+
When a locator fails, the agent tries the next strategy, then a visual click. Locators that worked are saved to experience and preferred on the next run.
|
|
74
|
+
|
|
75
|
+
## What happens after each action
|
|
76
|
+
|
|
77
|
+
After every action, Explorbot captures the new page state and compares it with the previous one. The resulting diff tells the agent what changed — the URL, the accessibility tree, or the HTML — so it can confirm the action worked and decide what to do next. The Researcher turns a page into a structured UI map of sections and elements; see [Researcher](./researcher.md).
|
|
78
|
+
|
|
79
|
+
## See also
|
|
80
|
+
|
|
81
|
+
- [Knowledge files](../workflow/knowledge.md) — teach Explorbot about your app
|
|
82
|
+
- [Agent hooks](./hooks.md) — run code before or after an agent
|
|
83
|
+
- [Configuration](../reference/configuration.md) — full configuration reference
|
|
84
|
+
- [Researcher](./researcher.md) — how pages become UI maps
|