@sayer/agent-step 0.1.0 → 0.1.1
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 +120 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,2 +1,121 @@
|
|
|
1
1
|
# agent-step
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
A Playwright fixture for adding agentic actions to tests and combining them with other test steps.
|
|
4
|
+
|
|
5
|
+
You keep writing Playwright as usual. When a bit of the UI is annoying to locate, you hand that part to `agentStep` in plain English, then assert the result yourself.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
await agentStep({
|
|
9
|
+
action: 'Add the red medium shirt to the basket',
|
|
10
|
+
expect: ['The basket badge shows 1'],
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
await expect(page.locator('#badge')).toHaveText('1');
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
It drives the test's existing `page`. It does not spin up another browser or go through Playwright MCP.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -D @sayer/agent-step @playwright/test
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Needs Playwright 1.63+ and an OpenAI-compatible model that can do tool calling. OpenRouter works.
|
|
25
|
+
|
|
26
|
+
## Add it as a fixture
|
|
27
|
+
|
|
28
|
+
This is the bit you want. Put this in `tests/fixtures.ts` so it sits next to your other fixtures:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { test as base, expect } from '@playwright/test';
|
|
32
|
+
import {
|
|
33
|
+
agentStepFixture,
|
|
34
|
+
type AgentStepFixtures,
|
|
35
|
+
} from '@sayer/agent-step';
|
|
36
|
+
|
|
37
|
+
export const test = base.extend<AgentStepFixtures>(agentStepFixture);
|
|
38
|
+
export { expect };
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Then import `test` from there, not from `@playwright/test`:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { test, expect } from './fixtures';
|
|
45
|
+
|
|
46
|
+
test('checkout', async ({ page, agentStep }) => {
|
|
47
|
+
await page.goto('/shop');
|
|
48
|
+
|
|
49
|
+
await agentStep({
|
|
50
|
+
action: 'Add the red medium shirt to the basket',
|
|
51
|
+
expect: [
|
|
52
|
+
'The basket badge shows 1',
|
|
53
|
+
'The basket contains the red medium shirt',
|
|
54
|
+
],
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
await expect(page.locator('#badge')).toHaveText('1');
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`action` is what to do. `expect` is what should be true afterwards. Those are checked separately so the model that clicked around is not also marking its own homework.
|
|
62
|
+
|
|
63
|
+
## Or call it directly
|
|
64
|
+
|
|
65
|
+
If you do not want a fixture, keep the normal Playwright import and pass `page` in:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { test, expect } from '@playwright/test';
|
|
69
|
+
import { agentStep } from '@sayer/agent-step';
|
|
70
|
+
|
|
71
|
+
test('checkout', async ({ page }) => {
|
|
72
|
+
await page.goto('/shop');
|
|
73
|
+
|
|
74
|
+
await agentStep(page, {
|
|
75
|
+
action: 'Add the red medium shirt to the basket',
|
|
76
|
+
expect: ['The basket contains the red medium shirt'],
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Env
|
|
82
|
+
|
|
83
|
+
Set these where you run Playwright. The package reads `process.env` and does not load `.env` for you.
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
export AGENT_LLM_BASE_URL=https://openrouter.ai/api/v1
|
|
87
|
+
export AGENT_LLM_API_KEY=sk-or-...
|
|
88
|
+
export AGENT_LLM_MODEL=openai/gpt-4o-mini
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`AGENT_LLM_BASE_URL` is the API root. Do not put `/chat/completions` on the end.
|
|
92
|
+
|
|
93
|
+
Same shape works for OpenAI (`https://api.openai.com/v1`) or anything else that speaks Chat Completions with tools.
|
|
94
|
+
|
|
95
|
+
The model has to support tool calling. If you get "no choices" back, it is usually the model slug or tools not being supported.
|
|
96
|
+
|
|
97
|
+
## Secrets
|
|
98
|
+
|
|
99
|
+
Do not put passwords in the prompt. Use a placeholder and pass the real value in `secrets`:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
await agentStep({
|
|
103
|
+
action: 'Sign in with the test account email',
|
|
104
|
+
expect: ['Signed in as the test account email'],
|
|
105
|
+
secrets: { EMAIL: process.env.TEST_EMAIL! },
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
In the action, tell it to type `%EMAIL%`. The value is filled in the browser and redacted from reports.
|
|
110
|
+
|
|
111
|
+
## How it behaves
|
|
112
|
+
|
|
113
|
+
Each `agentStep` is a Playwright `test.step`. It snapshots the page, does a small allowlisted set of actions (`browser_click`, `browser_type`, etc), then asks the model again whether the `expect` lines hold. Transcripts and failures get attached to the report.
|
|
114
|
+
|
|
115
|
+
It will not run arbitrary JS or leave the current origin. Retries are off so it does not click pay twice.
|
|
116
|
+
|
|
117
|
+
This is not a replacement for Playwright assertions. Use `expect` for anything you actually care about. Pin the model in CI. It will cost tokens and it will flake more than a locator.
|
|
118
|
+
|
|
119
|
+
## Repo
|
|
120
|
+
|
|
121
|
+
Source is at [github.com/Sayer122/agent-step](https://github.com/Sayer122/agent-step).
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sayer/agent-step",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "A Playwright fixture for adding agentic actions to tests and combining them with other test steps",
|
|
5
5
|
"author": "Jack Sayer",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|