@beryl-so/cli 0.67.0 → 0.77.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 +26 -14
- package/dist/adapters/mcp.js +6 -4
- package/dist/beryl-test-skill.js +129 -107
- package/dist/commands/accounts.js +92 -10
- package/dist/commands/config-vars.js +87 -16
- package/dist/commands/environments.js +18 -1
- package/dist/commands/init.js +42 -108
- package/dist/commands/jobs.js +129 -0
- package/dist/commands/projects.js +68 -45
- package/dist/commands/runs.js +5 -432
- package/dist/commands/tests.js +34 -409
- package/dist/commands/third-party-integrations.js +26 -3
- package/dist/commands/watch.js +36 -0
- package/dist/lint.js +120 -6
- package/dist/registry/index.js +2 -0
- package/dist/schema.generated.js +152 -27
- package/dist/skill-tables.js +3 -0
- package/package.json +2 -3
- package/dist/email-pump.js +0 -138
- package/dist/local-exec.js +0 -239
- package/dist/local-run.js +0 -340
- package/dist/playwright-install.js +0 -220
- package/dist/progress.js +0 -44
package/README.md
CHANGED
|
@@ -13,10 +13,9 @@ npx @beryl-so/cli@latest init
|
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Signs you in (browser approval by default, emailed one-time code as fallback; new
|
|
16
|
-
emails are signed up on the spot), wires the beryl
|
|
16
|
+
emails are signed up on the spot), wires the beryl MCP server into the
|
|
17
17
|
agent you pick with --claude, --cursor, --vscode or --opencode (it asks when you pass
|
|
18
|
-
none), installs the beryl-test authoring skill
|
|
19
|
-
Safe to re-run.
|
|
18
|
+
none), and installs the beryl-test authoring skill. Safe to re-run.
|
|
20
19
|
|
|
21
20
|
## Install
|
|
22
21
|
|
|
@@ -78,11 +77,11 @@ Set up Beryl in this repo: sign in and wire up your coding agent
|
|
|
78
77
|
|
|
79
78
|
### guide
|
|
80
79
|
|
|
81
|
-
Print the Beryl test
|
|
80
|
+
Print the Beryl test guide
|
|
82
81
|
|
|
83
82
|
| Command | Summary | MCP tool |
|
|
84
83
|
| --- | --- | --- |
|
|
85
|
-
| `beryl guide` | Print the Beryl test
|
|
84
|
+
| `beryl guide` | Print the Beryl test guide | `guide` |
|
|
86
85
|
|
|
87
86
|
### login
|
|
88
87
|
|
|
@@ -177,9 +176,11 @@ Create and manage projects: a site you author tests for and run.
|
|
|
177
176
|
| `beryl projects create [url]` | Create a project for a URL, or an empty one with just --name | `projects_create` |
|
|
178
177
|
| `beryl projects rename <name>` | Rename a project | `projects_rename` |
|
|
179
178
|
| `beryl projects quarantine [state]` | Turn auto quarantine on or off and tune when it mutes and releases a test | `projects_quarantine` |
|
|
179
|
+
| `beryl projects surfaces <surfaces...>` | Set which surfaces are enabled for this project | `projects_surfaces` |
|
|
180
|
+
| `beryl projects findings-gate <mode>` | Turn the findings gate on each run on or off | `projects_findings_gate` |
|
|
180
181
|
| `beryl projects delete` | Delete a project and all its tests and runs | `projects_delete` |
|
|
181
182
|
| `beryl projects re-explore` | Send the agent back in to run/heal existing tests and discover new flows | none |
|
|
182
|
-
| `beryl projects report` | Aggregate quality report across recent runs (pass rates,
|
|
183
|
+
| `beryl projects report` | Aggregate quality report across recent runs (pass rates, per-test history, trend) | `projects_report` |
|
|
183
184
|
| `beryl projects reusable-auth <url>` | Check whether a saved login can be reused for a URL before creating a project | `projects_reusable_auth` |
|
|
184
185
|
|
|
185
186
|
### envs
|
|
@@ -191,7 +192,7 @@ Manage a project's environments: the URLs and auth Beryl runs tests against.
|
|
|
191
192
|
| `beryl envs list` | List a project's environments | `envs_list` |
|
|
192
193
|
| `beryl envs get <env-id>` | Show one environment | `envs_get` |
|
|
193
194
|
| `beryl envs create <name> <url>` | Add an environment (e.g. staging) to a project | `envs_create` |
|
|
194
|
-
| `beryl envs update <env-id>` | Update an environment's name, URL, auth settings, Site Health screen sizes, schedule, CI and pages, or issue tracker settings | `envs_update` |
|
|
195
|
+
| `beryl envs update <env-id>` | Update an environment's name, URL, app ids, auth settings, Site Health screen sizes, schedule, CI and pages, or issue tracker settings | `envs_update` |
|
|
195
196
|
| `beryl envs delete <env-id>` | Delete an environment | `envs_delete` |
|
|
196
197
|
|
|
197
198
|
### schedule
|
|
@@ -213,13 +214,12 @@ Author, inspect, version, and heal a project's tests: the checks Beryl runs on e
|
|
|
213
214
|
|
|
214
215
|
| Command | Summary | MCP tool |
|
|
215
216
|
| --- | --- | --- |
|
|
216
|
-
| `beryl tests lint` | Validate a plan JSON file offline, before sending it to the server | `tests_lint` |
|
|
217
217
|
| `beryl tests list` | List the project's tests with their latest result | `tests_list` |
|
|
218
218
|
| `beryl tests get <test-id>` | Show one test | `tests_get` |
|
|
219
219
|
| `beryl tests plan <test-id>` | Print a test's current step plan (JSON) | `tests_plan` |
|
|
220
|
-
| `beryl tests create` | Create a test case from a JSON action plan (for tests authored locally, e.g. by your coding agent) | `tests_create` |
|
|
221
220
|
| `beryl tests set-plan <test-id>` | Replace a test's step plan from a JSON file (creates a new version) | `tests_set_plan` |
|
|
222
221
|
| `beryl tests rename <test-id> <title>` | Rename a test | `tests_rename` |
|
|
222
|
+
| `beryl tests set-intent <test-id> <intent>` | Edit what a test proves, the target heal judges against | `tests_set_intent` |
|
|
223
223
|
| `beryl tests set-groups <test-id>` | Replace the groups a test belongs to | `tests_set_groups` |
|
|
224
224
|
| `beryl tests set-access <test-id> <access>` | Mark a test read or write | `tests_set_access` |
|
|
225
225
|
| `beryl tests add-groups <test-ids...>` | Add groups to one or more tests, keeping the groups they already have | `tests_add_groups` |
|
|
@@ -234,7 +234,7 @@ Author, inspect, version, and heal a project's tests: the checks Beryl runs on e
|
|
|
234
234
|
| `beryl tests reset <test-id>` | Discard user edits and return the test to its latest system-authored version | `tests_reset` |
|
|
235
235
|
| `beryl tests heal <test-id> <state>` | Turn self-healing on or off for a test | `tests_heal` |
|
|
236
236
|
| `beryl tests history <test-id>` | Pass/fail history, streak, and stability for a test | `tests_history` |
|
|
237
|
-
| `beryl tests script
|
|
237
|
+
| `beryl tests script <test-id>` | Print the rendered Playwright spec for a test | `tests_script` |
|
|
238
238
|
| `beryl tests export <test-ids...>` | Export tests as Playwright .spec.ts files in a ZIP | `tests_export` |
|
|
239
239
|
|
|
240
240
|
### groups
|
|
@@ -259,7 +259,6 @@ Trigger a run of a project's tests (e.g. in CI), then watch, inspect, and downlo
|
|
|
259
259
|
| Command | Summary | MCP tool |
|
|
260
260
|
| --- | --- | --- |
|
|
261
261
|
| `beryl runs trigger` | Trigger a test run (whole suite, a subset, or one environment) | `runs_trigger` |
|
|
262
|
-
| `beryl runs local [test-ids...]` | Run tests on your machine with Playwright; results sync to Beryl | `runs_local` |
|
|
263
262
|
| `beryl runs list` | List recent runs | `runs_list` |
|
|
264
263
|
| `beryl runs get <run-id>` | Show one run with its per-test results | `runs_get` |
|
|
265
264
|
| `beryl runs watch <run-id>` | Follow a run until it finishes | `runs_watch` |
|
|
@@ -286,6 +285,18 @@ Site Health, or how your site reads to search engines and visitors: content, spe
|
|
|
286
285
|
| `beryl health tracker teams` | List the teams of the connected issue tracker | `health_tracker_teams` |
|
|
287
286
|
| `beryl health tracker projects` | List a tracker team's projects | `health_tracker_projects` |
|
|
288
287
|
|
|
288
|
+
### jobs
|
|
289
|
+
|
|
290
|
+
Test-creation jobs: the cloud agent reads a document and authors tests from it.
|
|
291
|
+
|
|
292
|
+
| Command | Summary | MCP tool |
|
|
293
|
+
| --- | --- | --- |
|
|
294
|
+
| `beryl jobs create [file]` | Create tests from a document (PRD, release notes) on Beryl's cloud | `jobs_create` |
|
|
295
|
+
| `beryl jobs list` | List the project's test-creation jobs | `jobs_list` |
|
|
296
|
+
| `beryl jobs get <job-id>` | Show a job's status and the tests it created | `jobs_get` |
|
|
297
|
+
| `beryl jobs clone <job-id>` | Run a job again: queue a new job with the same document and environment | `jobs_clone` |
|
|
298
|
+
| `beryl jobs delete <job-id>` | Delete a job; the flows and tests it created stay | `jobs_delete` |
|
|
299
|
+
|
|
289
300
|
### explorations
|
|
290
301
|
|
|
291
302
|
Inspect the agent's exploration runs: how it crawled a site and authored its tests.
|
|
@@ -308,13 +319,13 @@ Manage the variables, secrets, and files the agent can use while exploring and r
|
|
|
308
319
|
| `beryl config vars set <key> <value>` | Create or update a config variable | `config_vars_set` |
|
|
309
320
|
| `beryl config vars get <key>` | Show one config variable | `config_vars_get` |
|
|
310
321
|
| `beryl config vars delete <key>` | Delete a config variable | `config_vars_delete` |
|
|
311
|
-
| `beryl config secrets list` | List the project's secrets (values are never returned) | `config_secrets_list` |
|
|
322
|
+
| `beryl config secrets list` | List the project's secrets (values are never returned); a test account's password is managed on the account, not here | `config_secrets_list` |
|
|
312
323
|
| `beryl config secrets set <key> <value>` | Create a secret (write-only; re-setting a key replaces it) | `config_secrets_set` |
|
|
313
324
|
| `beryl config secrets get <key>` | Show one secret's metadata, or reveal its value with --reveal | `config_secrets_get` |
|
|
314
325
|
| `beryl config secrets delete <key>` | Delete a secret | `config_secrets_delete` |
|
|
315
|
-
| `beryl config files list` | List files
|
|
326
|
+
| `beryl config files list` | List uploaded files: fixtures tests attach and Android and iOS app builds | `config_files_list` |
|
|
316
327
|
| `beryl config files get <file>` | Show one uploaded file's metadata | `config_files_get` |
|
|
317
|
-
| `beryl config files upload <file>` | Upload a file | `config_files_upload` |
|
|
328
|
+
| `beryl config files upload <file>` | Upload a file: a fixture an upload step attaches, or an Android or iOS app build | `config_files_upload` |
|
|
318
329
|
| `beryl config files download <file-id>` | Get a short-lived download URL for a file | `config_files_download` |
|
|
319
330
|
| `beryl config files delete <file-id>` | Delete an uploaded file | `config_files_delete` |
|
|
320
331
|
|
|
@@ -356,6 +367,7 @@ Durable identities on the site under test: what an authenticated test signs in a
|
|
|
356
367
|
| `beryl accounts list` | List the test accounts an environment's tests sign in as | `accounts_list` |
|
|
357
368
|
| `beryl accounts get <account-id>` | Show one test account: origin, lifetime, sign-in state | `accounts_get` |
|
|
358
369
|
| `beryl accounts create` | Add a test account: the customer's own, or one Beryl signs up | `accounts_create` |
|
|
370
|
+
| `beryl accounts capture` | Store a signed-in session as a captured test account | `accounts_capture` |
|
|
359
371
|
| `beryl accounts signup <account-id>` | Store a test account's signup plan and sign it up on its environment | `accounts_signup` |
|
|
360
372
|
| `beryl accounts set-login <account-id>` | Store the sign-in plan a run replays once, plus the probe that proves it | `accounts_set_login` |
|
|
361
373
|
| `beryl accounts get-login <account-id>` | Read the stored sign-in plan, its probe, and the hash a safe write must cite | `accounts_get_login` |
|
package/dist/adapters/mcp.js
CHANGED
|
@@ -278,13 +278,15 @@ export function mcpInstructions() {
|
|
|
278
278
|
"version, and whether this build is behind npm's latest). " +
|
|
279
279
|
"Beryl authors, runs, and heals end-to-end tests for any web app: tests are JSON " +
|
|
280
280
|
"action plans replayed in real cloud browsers, signing in as a durable test " +
|
|
281
|
-
"account whose mail arrives at the project's own mailbox
|
|
281
|
+
"account whose mail arrives at the project's own mailbox, so signup/OTP/" +
|
|
282
282
|
"magic-link flows are self-contained, with no human login needed. " +
|
|
283
|
-
"
|
|
284
|
-
"
|
|
283
|
+
"New tests are authored only by Beryl's cloud agent: give it a document describing " +
|
|
284
|
+
"the flows with `jobs_create`; there is no local authoring. " +
|
|
285
|
+
"The guide (plan shape, outcome assertions, accounts, email/OTP wiring, the " +
|
|
286
|
+
"run-fix loop) ships as both the beryl-test skill and the `guide` tool, same " +
|
|
285
287
|
`content. If a beryl-test skill stating v${version} is already loaded, do not ` +
|
|
286
288
|
"call `guide`; if no beryl-test skill is available or it states another version, " +
|
|
287
|
-
"call `guide` before
|
|
289
|
+
"call `guide` before editing a test plan or a sign-in plan. " +
|
|
288
290
|
"An account can hold several workspaces and projects: call `projects_list` first " +
|
|
289
291
|
"and pass `project` (an id is enough) on every project-scoped tool, or the call fails.");
|
|
290
292
|
}
|
package/dist/beryl-test-skill.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// The `beryl-test`
|
|
1
|
+
// The `beryl-test` skill, installed by `beryl init` into
|
|
2
2
|
// `.agents/skills/beryl-test/SKILL.md` (vendor-neutral, editor-agnostic) — and, when
|
|
3
3
|
// claude-code is a selected editor, ALSO into the `.claude/skills/beryl-test/SKILL.md`
|
|
4
4
|
// that Claude Code actually indexes (see `writeSkills` in `commands/init.ts`). Kept as an
|
|
@@ -17,23 +17,24 @@ export const BERYL_TEST_SKILL_DIR = "beryl-test";
|
|
|
17
17
|
// nor `.claude/skills/`, so `init` writes them their own pointer instead. Thin on purpose:
|
|
18
18
|
// it sends the agent to the `guide` MCP tool rather than inlining the 500-line skill, and
|
|
19
19
|
// `guide` ships with the CLI so the real guidance never drifts from the installed version.
|
|
20
|
-
const BERYL_GUIDE_POINTER = `When
|
|
21
|
-
MCP tool first. It returns the full
|
|
22
|
-
assertions, test accounts and the project mailbox, and the
|
|
20
|
+
const BERYL_GUIDE_POINTER = `When creating, running, editing, or debugging Beryl tests in this repo, call the
|
|
21
|
+
\`guide\` MCP tool first. It returns the full guide: where new tests come from, the
|
|
22
|
+
ActionPlan shape, outcome assertions, test accounts and the project mailbox, and the
|
|
23
|
+
local run-fix loop.
|
|
23
24
|
|
|
24
|
-
Then use the Beryl MCP tools: \`projects_list\` to find the project,
|
|
25
|
-
|
|
25
|
+
Then use the Beryl MCP tools: \`projects_list\` to find the project, \`jobs_create\` to
|
|
26
|
+
have Beryl's cloud agent author tests from a document, and \`runs_trigger\` to run them.
|
|
26
27
|
|
|
27
28
|
The \`guide\` tool ships with the CLI and always matches the installed version, so treat
|
|
28
29
|
it as the source of truth over anything cached here.`;
|
|
29
30
|
// Cursor reads its own `.cursor/rules/*.mdc`, auto-loaded when alwaysApply is set.
|
|
30
31
|
export const BERYL_CURSOR_RULE_FILENAME = "beryl.mdc";
|
|
31
32
|
export const BERYL_CURSOR_RULE = `---
|
|
32
|
-
description:
|
|
33
|
+
description: Creating, running and editing Beryl end-to-end tests
|
|
33
34
|
alwaysApply: true
|
|
34
35
|
---
|
|
35
36
|
|
|
36
|
-
# Beryl
|
|
37
|
+
# Beryl tests
|
|
37
38
|
|
|
38
39
|
${BERYL_GUIDE_POINTER}
|
|
39
40
|
`;
|
|
@@ -43,7 +44,7 @@ ${BERYL_GUIDE_POINTER}
|
|
|
43
44
|
export const BERYL_COPILOT_MARK_BEGIN = "<!-- BEGIN beryl (managed by beryl init) -->";
|
|
44
45
|
export const BERYL_COPILOT_MARK_END = "<!-- END beryl -->";
|
|
45
46
|
export const BERYL_COPILOT_SECTION = `${BERYL_COPILOT_MARK_BEGIN}
|
|
46
|
-
## Beryl
|
|
47
|
+
## Beryl tests
|
|
47
48
|
|
|
48
49
|
${BERYL_GUIDE_POINTER}
|
|
49
50
|
${BERYL_COPILOT_MARK_END}`;
|
|
@@ -89,60 +90,64 @@ export const BERYL_TEST_SKILL_OTP_EXAMPLE_PLAN = {
|
|
|
89
90
|
};
|
|
90
91
|
export const BERYL_TEST_SKILL = `---
|
|
91
92
|
name: beryl-test
|
|
92
|
-
description:
|
|
93
|
+
description: Create, run, and fix durable, healable end-to-end tests for a web app with Beryl. Use when asking Beryl's cloud agent to create tests from a document (\`jobs_create\`), running them in Beryl's cloud with \`runs_trigger\`, setting up test accounts, or fixing a banked test's plan with your own coding agent.
|
|
93
94
|
---
|
|
94
95
|
|
|
95
|
-
#
|
|
96
|
+
# Beryl tests
|
|
96
97
|
|
|
97
|
-
beryl-test v${cliVersion()}
|
|
98
|
+
beryl-test v${cliVersion()}, installed by \`beryl init\`; the \`guide\` tool always returns the current version of this guide.
|
|
98
99
|
|
|
99
100
|
A Beryl test drives a real browser through a flow and asserts the flow reached its
|
|
100
|
-
meaningful outcome. \`beryl init\` wired
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
tests as the app's markup drifts, but only when
|
|
104
|
-
|
|
105
|
-
**
|
|
101
|
+
meaningful outcome. \`beryl init\` wired the **beryl** MCP server (\`jobs_create\`,
|
|
102
|
+
\`accounts_list\`, \`runs_trigger\`, and the rest). You do everything below by
|
|
103
|
+
calling those tools; tests are authored and run in Beryl's cloud. Beryl **heals**
|
|
104
|
+
tests as the app's markup drifts, but only when a test has the three things that make
|
|
105
|
+
it durable: a real **outcome assertion**, a strong **natural-language intent**, and a
|
|
106
|
+
**verified plan** (every save is proven by a replay).
|
|
106
107
|
|
|
107
108
|
## 0. Start here
|
|
108
109
|
|
|
109
|
-
**
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
**New tests are authored only by Beryl's cloud agent.** There is no local authoring: you
|
|
111
|
+
do not draft a new plan here. A human writes a document (a PRD, release notes, a list of
|
|
112
|
+
flows) and \`jobs_create\` hands it to the agent, which explores the environment and
|
|
113
|
+
authors one test per scenario and surface. \`jobs_get\` shows the job's status, the tests
|
|
114
|
+
it produced and any scenario it skipped. The document is sent to the LLM that drives the
|
|
115
|
+
agent, so it must not hold anything the user would not share with it.
|
|
113
116
|
|
|
114
|
-
|
|
115
|
-
|
|
117
|
+
What you do here: set up the accounts tests sign in as (§1), trigger and read runs
|
|
118
|
+
(§4), and fix a banked test's plan when it needs it (§2).
|
|
119
|
+
|
|
120
|
+
Set up (once): if you cannot call the Beryl tools yet, run \`beryl init\` in a terminal
|
|
121
|
+
to wire them. Then, before the first job:
|
|
116
122
|
|
|
117
123
|
- \`envs_list\`: the root URL gotos resolve against (§2). If it is empty, set it with
|
|
118
124
|
\`envs_update\` to a URL Beryl's cloud can reach, never \`localhost\`, \`127.0.0.1\`
|
|
119
|
-
or a private IP (refused).
|
|
120
|
-
|
|
125
|
+
or a private IP (refused). A local dev server is not testable until it is reachable
|
|
126
|
+
from the cloud (deploy a preview, or tunnel it).
|
|
121
127
|
- \`accounts_list\`: who do authenticated tests sign in as (§1)? Store its sign-in with
|
|
122
128
|
\`accounts_set_login\`, prove it with \`accounts_check\`.
|
|
123
129
|
- \`mailbox_get\`: the address the account receives mail at (§5).
|
|
124
130
|
|
|
125
|
-
\`accounts_list\` comes FIRST:
|
|
126
|
-
|
|
127
|
-
created until its account's login plan is stored.
|
|
131
|
+
\`accounts_list\` comes FIRST: an authenticated test cannot be saved until its account's
|
|
132
|
+
login plan is stored.
|
|
128
133
|
|
|
129
|
-
Then
|
|
134
|
+
Then:
|
|
130
135
|
|
|
131
|
-
1. **
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
136
|
+
1. **Create tests** with \`jobs_create\` (the document, and the environment to
|
|
137
|
+
explore). \`jobs_get\` shows progress, the tests it banked (each one already
|
|
138
|
+
proven by a clean replay), and every scenario it skipped, with why.
|
|
139
|
+
2. A job can pause as \`awaiting_input\` when the app's login wall blocks it (no
|
|
140
|
+
self-serve signup). Its \`needs\` field says what to do: capture a signed-in
|
|
141
|
+
session with the Beryl browser extension from the webapp. The job resumes by
|
|
142
|
+
itself and keeps everything it already banked.
|
|
143
|
+
3. When the job is done, run the new ids together ONCE with \`runs_trigger\` so they
|
|
144
|
+
land as one run with real first results.
|
|
145
|
+
4. **A test is red or wrong?** Fix its plan with the run-fix loop (§4).
|
|
141
146
|
|
|
142
147
|
## 1. First: who do your tests sign in as?
|
|
143
148
|
|
|
144
149
|
An authenticated test **signs in as an account that already exists** — it does not sign
|
|
145
|
-
one up. Start every
|
|
150
|
+
one up. Start every session with \`accounts_list\`:
|
|
146
151
|
|
|
147
152
|
\`\`\`
|
|
148
153
|
label email type login status
|
|
@@ -152,17 +157,17 @@ admin qa+admin@x7k2p9.email.beryl.so provisioned (permanent) otp rea
|
|
|
152
157
|
|
|
153
158
|
Author the sign-in as ordinary opening steps citing the reserved handles — fill
|
|
154
159
|
\`{{login_email}}\`, fill \`{{login_password}}\`, submit, assert the logged-in shell.
|
|
155
|
-
Set \`requires_auth: true\` AND \`auth_mode
|
|
156
|
-
default and
|
|
160
|
+
Set \`requires_auth: true\` AND \`auth_mode\`, both, always; \`auth_mode\` has NO
|
|
161
|
+
default and a save rejects a \`requires_auth\` plan without it. \`"inline"\` = the plan
|
|
157
162
|
signs itself in like this; \`"session"\` = no sign-in steps, rides the account's
|
|
158
163
|
once-per-run session (§ Session mode). \`auth_label\` picks a non-default identity
|
|
159
164
|
(the \`*\` row is the default). Handles resolve at run time to the named account, so
|
|
160
165
|
one plan stays correct across environments.
|
|
161
166
|
|
|
162
|
-
**The account needs a stored login plan before any authenticated test can be
|
|
167
|
+
**The account needs a stored login plan before any authenticated test can be saved.**
|
|
163
168
|
A run replays that plan to produce the session its tests ride, and replays it again
|
|
164
|
-
when the session expires, so
|
|
165
|
-
|
|
169
|
+
when the session expires, so Beryl rejects a \`requires_auth\` plan whose account has
|
|
170
|
+
none, naming the fix. Store it once per account with
|
|
166
171
|
\`accounts_set_login\` (§ Session mode).
|
|
167
172
|
|
|
168
173
|
**NEVER paste a real email or password into a plan.** Handles resolve at run time —
|
|
@@ -239,9 +244,9 @@ An empty \`accounts_list\` means nothing is set up. In order of preference:
|
|
|
239
244
|
let the plan \`await_email\` through; later sign-ins read the same mailbox.
|
|
240
245
|
4. **Neither** → the flow is not testable authenticated. Say so rather than guessing.
|
|
241
246
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
247
|
+
Every saved login is a test account: \`{{login_email}}\` and \`{{login_password}}\` resolve
|
|
248
|
+
only from the environment's account, and a login password is never set with
|
|
249
|
+
\`config secrets set\`. The webapp's Test accounts tab edits the same accounts.
|
|
245
250
|
|
|
246
251
|
### Session mode: sign in once per run, not once per test
|
|
247
252
|
|
|
@@ -264,26 +269,21 @@ descriptions.
|
|
|
264
269
|
Then write the tests with \`requires_auth: true\`, \`auth_mode: "session"\`, and NO
|
|
265
270
|
sign-in steps.
|
|
266
271
|
|
|
267
|
-
**Creates share the sign-in.** \`tests_create\` replays session-mode plans against the
|
|
268
|
-
account's established session (reused while it stays live), so a batch of creates costs
|
|
269
|
-
at most one sign-in — but still create one at a time: racing creates race the same
|
|
270
|
-
mailbox for mail.
|
|
271
|
-
|
|
272
272
|
An expired session is never your problem: every run proves the stored session and, on a
|
|
273
273
|
miss, signs in again from the login plan. A "reconnect" message only appears when there
|
|
274
274
|
is no stored login plan to refresh from.
|
|
275
275
|
|
|
276
276
|
When \`accounts_check\` fails, its description explains which half broke and each
|
|
277
|
-
\`SESSION_*\` reason. The one that changes your
|
|
277
|
+
\`SESSION_*\` reason. The one that changes your plans: an account marked
|
|
278
278
|
unsupported (its session cannot survive a fresh browser) is not your bug, but it IS
|
|
279
|
-
your move
|
|
279
|
+
your move: switch its session-mode tests to \`auth_mode: "inline"\` and their own
|
|
280
280
|
sign-in steps.
|
|
281
281
|
|
|
282
282
|
### Two identities in one test
|
|
283
283
|
|
|
284
|
-
Invite-a-teammate-and-accept-as-them needs two identities mid-flow
|
|
285
|
-
one test. Bank the half the app shows to account A ("the invitation is listed as
|
|
286
|
-
pending", "the share link is issued")
|
|
284
|
+
Invite-a-teammate-and-accept-as-them needs two identities mid-flow, so it is not bankable
|
|
285
|
+
as one test. Bank the half the app shows to account A ("the invitation is listed as
|
|
286
|
+
pending", "the share link is issued"): a real, strong outcome. While fixing a plan you can
|
|
287
287
|
drive the full handshake live: a second account (\`accounts_create\`, labelled), or a
|
|
288
288
|
second mailbox (\`mailbox_create\`, read with \`mailbox_read\`).
|
|
289
289
|
|
|
@@ -291,15 +291,18 @@ SSO-only sites are not a dead end: with a dedicated Google test account they fol
|
|
|
291
291
|
item 2 like any password account. The captured session is the FALLBACK — no test account
|
|
292
292
|
can be provided, or Google challenges the scripted sign-in: a human signs in once
|
|
293
293
|
through a live browser view in the Beryl webapp, Beryl stores the session encrypted
|
|
294
|
-
server-side and injects it into cloud runs
|
|
295
|
-
|
|
296
|
-
|
|
294
|
+
server-side and injects it into cloud runs; the session never leaves Beryl's cloud.
|
|
295
|
+
|
|
296
|
+
## 2. Fixing a test's plan
|
|
297
297
|
|
|
298
|
-
|
|
298
|
+
New tests come from \`jobs_create\` (§0). You write plan JSON only to fix a banked test
|
|
299
|
+
(\`tests_plan\` returns its current plan) or to store an account's sign-in or signup
|
|
300
|
+
plan (§1). Either way, the rules below hold.
|
|
299
301
|
|
|
300
|
-
1. **
|
|
301
|
-
|
|
302
|
-
|
|
302
|
+
1. **Start from evidence, not memory.** Pull the failed run first: \`runs_get\` for
|
|
303
|
+
the failing step and error, \`runs_explain\` for the run's own diagnosis,
|
|
304
|
+
\`tests_events\` for how the test behaved over time. Fix what the evidence shows,
|
|
305
|
+
never what you assume the page looks like.
|
|
303
306
|
2. **Write it as an ActionPlan** — a JSON object whose \`steps\` are
|
|
304
307
|
\`{action, selector, url, value, ...}\`. Two structural rules:
|
|
305
308
|
- the **first executed step is a \`goto\`**, and
|
|
@@ -357,17 +360,13 @@ ${JSON.stringify(BERYL_TEST_SKILL_EXAMPLE_PLAN, null, 2)
|
|
|
357
360
|
.map((line) => ` ${line}`)
|
|
358
361
|
.join("\n")}
|
|
359
362
|
\`\`\`
|
|
360
|
-
3. **
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
the
|
|
364
|
-
|
|
365
|
-
own description. Inspect the exact spec with \`tests_script\`.
|
|
363
|
+
3. **Save through the replay gate.** \`tests_recompile\` replays the edited plan
|
|
364
|
+
against the live site first and rejects it on a red replay; prefer it always.
|
|
365
|
+
\`tests_set_plan\` saves with no replay (the next run proves it); reserve it for
|
|
366
|
+
when the flow cannot replay right now (for example a third-party step). Pass a new
|
|
367
|
+
\`description\` only when the edit changes what the test proves (§3).
|
|
366
368
|
Full ActionPlan JSON Schema:
|
|
367
369
|
https://api.beryl.so/api/v1/schemas/action-plan.schema.json.
|
|
368
|
-
Groups are optional and never block: after the test is banked, if \`groups_list\`
|
|
369
|
-
shows any, offer them once (\`tests_set_groups\`); no answer = leave it ungrouped and
|
|
370
|
-
move on. Never create a group yourself, that is the user's call.
|
|
371
370
|
|
|
372
371
|
### Testing a mobile or tablet viewport
|
|
373
372
|
A test runs at a desktop viewport unless you say otherwise. To cover a responsive layout,
|
|
@@ -376,9 +375,32 @@ full Chromium device emulation, not a resize: the viewport, a mobile Chrome user
|
|
|
376
375
|
touch and the device pixel ratio all change together, so a hamburger or a nav that only
|
|
377
376
|
exists on small screens actually renders and is testable. \`mobile\` emulates a Pixel-class
|
|
378
377
|
phone, \`tablet\` a Galaxy-class tablet; both keep a Chrome user-agent so the emulated UA
|
|
379
|
-
matches the engine.
|
|
380
|
-
|
|
381
|
-
|
|
378
|
+
matches the engine. A test's surface is fixed when it is created, so when fixing a plan
|
|
379
|
+
keep \`device\` as it is: a small-screen test's selectors must come from what the
|
|
380
|
+
small-screen layout renders (a hamburger, not the desktop nav). The account, session and
|
|
381
|
+
teardown rules are unchanged; \`device\` only sets the frame it runs in.
|
|
382
|
+
|
|
383
|
+
### App tests (Android and iOS)
|
|
384
|
+
\`device: "android"\` and \`device: "ios"\` are not browsers: the plan drives the environment's
|
|
385
|
+
app (its \`app_ids.android\` from the newest APK, or \`app_ids.ios\` from the newest simulator
|
|
386
|
+
build, uploaded to Files) on an emulator or simulator in Beryl's cloud. App tests are written
|
|
387
|
+
and verified by a test-creation job (\`jobs_create\`), never run locally. When you edit one,
|
|
388
|
+
its rules differ from a web plan's:
|
|
389
|
+
|
|
390
|
+
- The first step is \`launch\` (open the app), not \`goto\`. A later \`launch\` relaunches
|
|
391
|
+
with the app's data kept, which is how a plan proves something persisted.
|
|
392
|
+
- Steps: launch, back (Android only; iOS has no back button), fill, click, press, scroll,
|
|
393
|
+
wait_for, expect, await_email.
|
|
394
|
+
- Selectors are \`id=<resource id>\` (Android) or \`id=<accessibility identifier>\` (iOS), or
|
|
395
|
+
\`text=<visible text or accessibility label>\`; no CSS. React Native's \`testID\` shows up as
|
|
396
|
+
the id on both; a Flutter icon button needs a \`Semantics\` label to have text.
|
|
397
|
+
- \`have_text\` needs an \`id=\` selector; to check text is on screen, use \`visible\` with
|
|
398
|
+
\`text=\`. No URL or title expects: an app has no URL.
|
|
399
|
+
- Keys: Enter and Backspace, plus Tab on Android. Never put \`\${\` in plan text.
|
|
400
|
+
- A signed-in app test sets \`requires_auth\` and \`auth_mode: "session"\` and rides the
|
|
401
|
+
account's sign-in on that surface. The test-creation job saves that sign-in itself when
|
|
402
|
+
the app has a login screen; \`accounts_set_login\` with \`surface: "android"\` or
|
|
403
|
+
\`surface: "ios"\` only replaces it.
|
|
382
404
|
|
|
383
405
|
### The outcome assertion is the whole game
|
|
384
406
|
|
|
@@ -408,17 +430,16 @@ observable proof the flow worked.
|
|
|
408
430
|
- **Don't work around a real app failure to make a test go green.** A genuinely broken
|
|
409
431
|
flow is a finding to report, not something to paper over with a weaker assertion.
|
|
410
432
|
|
|
411
|
-
### Traps when
|
|
433
|
+
### Traps when writing a plan against a real app
|
|
412
434
|
|
|
413
|
-
Every one of these has produced a wrong plan or a red
|
|
435
|
+
Every one of these has produced a wrong plan or a red run. Check them.
|
|
414
436
|
|
|
415
|
-
1. **
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
the login.
|
|
437
|
+
1. **A gated page can look public in signed-in evidence.** Run artifacts captured
|
|
438
|
+
while a session was live never show the login wall, so do not mark a flow public
|
|
439
|
+
(no \`requires_auth\`) from them; check how the page behaves logged out.
|
|
419
440
|
2. **The sign-UP flow is not the sign-IN flow.** A brand-new address often gets an
|
|
420
441
|
extra "create your account" step a returning address skips. A stored login plan must
|
|
421
|
-
be the **returning** path
|
|
442
|
+
be the **returning** path: what the app shows the SECOND time that account arrives.
|
|
422
443
|
3. **Read the DOM, not just the accessibility tree, before picking a selector.** Two
|
|
423
444
|
buttons can share a label ("Continue" / "Continue with Google"), and Beryl relaxes
|
|
424
445
|
\`text=X\` to a case-insensitive SUBSTRING — \`text=Continue\` is ambiguous. Use
|
|
@@ -442,8 +463,9 @@ Every one of these has produced a wrong plan or a red \`tests_create\`. Check th
|
|
|
442
463
|
|
|
443
464
|
## 3. Writing the natural-language intent
|
|
444
465
|
|
|
445
|
-
|
|
446
|
-
|
|
466
|
+
The cloud agent drafts each new test's intent. When a fix changes what a test proves,
|
|
467
|
+
pass the new intent as the \`description\` of \`tests_set_plan\`. 1-3 sentences. This is
|
|
468
|
+
the immutable anchor from §6.
|
|
447
469
|
|
|
448
470
|
- **State the purpose, not the steps.** Not "clicks Sign in, types email and password,
|
|
449
471
|
clicks submit" — the trajectory will change. Instead: *what does a green run prove is
|
|
@@ -459,19 +481,18 @@ Good:
|
|
|
459
481
|
Weak (describes steps + asserts nothing meaningful):
|
|
460
482
|
> "Goes to /login, fills the form, and checks the page loaded."
|
|
461
483
|
|
|
462
|
-
## 4. The
|
|
484
|
+
## 4. The run-fix loop
|
|
463
485
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
no id to run the whole suite and record the results in Beryl.
|
|
486
|
+
Every run happens in Beryl's cloud. \`runs_trigger\` against one test id (or a list)
|
|
487
|
+
starts a run; \`runs_watch\` follows it live; \`runs_get\` returns each result's
|
|
488
|
+
failing step, error and artifacts; \`runs_explain\` turns a red run into a diagnosis.
|
|
468
489
|
|
|
469
|
-
The loop:
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
490
|
+
The loop: \`runs_trigger\` against the test id, read the failure with \`runs_get\` /
|
|
491
|
+
\`runs_explain\`, fix the plan (§2), save with \`tests_recompile\` (which already
|
|
492
|
+
replays it against the live site, so a green recompile IS the fix proven), then one
|
|
493
|
+
final \`runs_trigger\` so the suite records a clean run. If recompile keeps rejecting
|
|
494
|
+
an edit, the evidence disagrees with your theory: pull more of it rather than trying
|
|
495
|
+
variations.
|
|
475
496
|
|
|
476
497
|
## 5. Testing an OTP / signup flow (\`await_email\`)
|
|
477
498
|
|
|
@@ -527,12 +548,8 @@ For a magic-link flow, replace the code steps with
|
|
|
527
548
|
|
|
528
549
|
Two caveats:
|
|
529
550
|
|
|
530
|
-
-
|
|
531
|
-
|
|
532
|
-
app's mail really is received and extracted before the test is accepted. The replay
|
|
533
|
-
signs up / sends mail FOR REAL, so turn \`tests_create\`'s verify off only if that side
|
|
534
|
-
effect is unwanted. \`runs_local\` serves \`await_email\` the same way, so the local loop
|
|
535
|
-
covers OTP/signup flows end to end.
|
|
551
|
+
- Every run serves \`await_email\` from the project mailbox. It signs up / sends
|
|
552
|
+
mail FOR REAL, like every run.
|
|
536
553
|
- §2's outcome discipline still applies: the green signal is the post-verification
|
|
537
554
|
state (the welcome screen, the dashboard), not "an email arrived".
|
|
538
555
|
|
|
@@ -571,14 +588,19 @@ Two shapes:
|
|
|
571
588
|
\`third_party_integrations_target\` names, trigger the app's message, then
|
|
572
589
|
\`{ "action": "await_third_party", "provider": "slack", "expect_text": "..." }\`.
|
|
573
590
|
- **Integration intact**: no declaration. Trigger the app's message, then
|
|
574
|
-
\`await_third_party\`.
|
|
591
|
+
\`await_third_party\`. When the app only answers its bot, ping the bot instead:
|
|
592
|
+
\`{ "action": "send_third_party", "provider": "slack", "value": "hello" }\` mentions it in
|
|
593
|
+
the project's channel, then \`await_third_party\` waits for its reply (in the channel or
|
|
594
|
+
in the thread). The bot's app must be recorded for the environment first:
|
|
595
|
+
\`third_party_integrations_target\` with \`env\` and \`app\`. A reply only the sender can
|
|
596
|
+
see never reaches Beryl, so such a bot can't be tested this way.
|
|
575
597
|
|
|
576
598
|
Rules:
|
|
577
599
|
|
|
578
600
|
- Always tear down what the test connected in \`after\`: disconnect the integration in
|
|
579
601
|
the app.
|
|
580
|
-
- These steps
|
|
581
|
-
|
|
602
|
+
- These steps need Beryl's provider accounts, which live in Beryl's cloud; they run
|
|
603
|
+
like any other cloud test.
|
|
582
604
|
- A setup error saying Beryl's access "is being restored" is on Beryl's side: do not
|
|
583
605
|
edit the test.
|
|
584
606
|
- Never add steps that browse Slack itself; the actions above do all of it.
|