waygraph 0.7.15 → 0.10.0
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 +90 -52
- package/dist/auto-explore-run.js +13 -7
- package/dist/auto-explore.js +47 -36
- package/dist/cli.d.ts +8 -12
- package/dist/cli.js +229 -249
- package/dist/engine.d.ts +77 -7
- package/dist/engine.js +108 -7
- package/dist/graph.d.ts +2 -1
- package/dist/graph.js +51 -11
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/examples/saucedemo/README.md +19 -5
- package/examples/saucedemo/docs/CONVENTION.md +22 -18
- package/examples/saucedemo/docs/HELPERS.md +186 -0
- package/examples/saucedemo/package-lock.json +1 -1
- package/examples/saucedemo/package.json +11 -5
- package/examples/saucedemo/scripts/capture-wrong-login.mjs +1 -1
- package/examples/saucedemo/scripts/drive-auto-cli.mjs +93 -0
- package/examples/saucedemo/scripts/prove-wrong-login-runtime.mjs +1 -1
- package/examples/saucedemo/scripts/show-auto-menu.mjs +72 -0
- package/examples/saucedemo/src/blocks/SITE-MAP.md +11 -8
- package/examples/saucedemo/src/blocks/saucedemo-web/NAV.md +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/cart/NAV.md +1 -1
- package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-cart.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-checkout-info.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/NAV.md +1 -1
- package/{templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/actions/submit-checkout-info.action.block.ts → examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/submit-checkout-info.method.block.ts} +5 -5
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/NAV.md +1 -1
- package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/{actions/finish-order.action.block.ts → methods/finish-order.method.block.ts} +5 -5
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/NAV.md +17 -5
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/inventory.page.block.ts +37 -0
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/add-all-to-cart.method.block.ts +55 -0
- package/{templates/quickstart/src/blocks/saucedemo-web/inventory/actions → examples/saucedemo/src/blocks/saucedemo-web/inventory/methods}/add-to-cart.effect.block.ts +6 -6
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/{actions → methods}/inventory-items.ts +40 -20
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/remove-all-from-cart.method.block.ts +55 -0
- package/{templates/quickstart/src/blocks/saucedemo-web/inventory/actions → examples/saucedemo/src/blocks/saucedemo-web/inventory/methods}/remove-from-cart.effect.block.ts +5 -5
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory/nav-item-detail.block.ts +4 -4
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-back-to-products.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-continue-shopping.block.ts +3 -3
- package/examples/saucedemo/src/blocks/saucedemo-web/{actions → methods}/submit-login-for-flow.ts +2 -2
- package/examples/saucedemo/src/blocks/saucedemo-web/{actions/submit-login.action.block.ts → methods/submit-login.method.block.ts} +5 -5
- package/{templates/quickstart/src/blocks/saucedemo-web/actions/submit-logout.action.block.ts → examples/saucedemo/src/blocks/saucedemo-web/methods/submit-logout.method.block.ts} +5 -5
- package/examples/saucedemo/src/flows/cart-bulk.flow.ts +19 -0
- package/examples/saucedemo/src/flows/cart-mem.flow.ts +1 -1
- package/examples/saucedemo/src/flows/catalog-logout.flow.ts +1 -1
- package/examples/saucedemo/src/flows/checkout-then-browse-again.flow.ts +4 -4
- package/examples/saucedemo/src/flows/checkout.flow.ts +4 -4
- package/examples/saucedemo/src/flows/login.flow.ts +1 -1
- package/examples/saucedemo/src/flows/shop.flow.ts +3 -3
- package/examples/saucedemo/src/flows/smoke.flow.ts +2 -2
- package/examples/saucedemo/src/flows/viewer-blocked.flow.ts +1 -1
- package/examples/saucedemo/tests/flow-block-verify.spec.ts +1 -1
- package/examples/saucedemo/tests/submit-login-branch.spec.ts +1 -1
- package/package.json +1 -1
- package/templates/quickstart/README-saucedemo-commands.md +72 -0
- package/templates/quickstart/docs/CONVENTION.md +5 -5
- package/templates/quickstart/docs/HELPERS.md +186 -0
- package/templates/quickstart/package.json +9 -5
- package/templates/quickstart/scripts/drive-auto-cli.mjs +93 -0
- package/templates/quickstart/src/blocks/SITE-MAP.md +11 -8
- package/templates/quickstart/src/blocks/saucedemo-web/NAV.md +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/cart/NAV.md +1 -1
- package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-cart.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-checkout-info.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/NAV.md +1 -1
- package/{examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/actions/submit-checkout-info.action.block.ts → templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/submit-checkout-info.method.block.ts} +5 -5
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/NAV.md +1 -1
- package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/{actions/finish-order.action.block.ts → methods/finish-order.method.block.ts} +5 -5
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/NAV.md +17 -5
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/inventory.page.block.ts +37 -0
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-all-to-cart.method.block.ts +55 -0
- package/{examples/saucedemo/src/blocks/saucedemo-web/inventory/actions → templates/quickstart/src/blocks/saucedemo-web/inventory/methods}/add-to-cart.effect.block.ts +6 -6
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/{actions → methods}/inventory-items.ts +40 -20
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/remove-all-from-cart.method.block.ts +55 -0
- package/{examples/saucedemo/src/blocks/saucedemo-web/inventory/actions → templates/quickstart/src/blocks/saucedemo-web/inventory/methods}/remove-from-cart.effect.block.ts +5 -5
- package/templates/quickstart/src/blocks/saucedemo-web/inventory/nav-item-detail.block.ts +1 -1
- package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-back-to-products.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-continue-shopping.block.ts +3 -3
- package/templates/quickstart/src/blocks/saucedemo-web/{actions → methods}/submit-login-for-flow.ts +2 -2
- package/templates/quickstart/src/blocks/saucedemo-web/{actions/submit-login.action.block.ts → methods/submit-login.method.block.ts} +5 -5
- package/{examples/saucedemo/src/blocks/saucedemo-web/actions/submit-logout.action.block.ts → templates/quickstart/src/blocks/saucedemo-web/methods/submit-logout.method.block.ts} +5 -5
- package/templates/quickstart/src/flows/cart-bulk.flow.ts +19 -0
- package/templates/quickstart/src/flows/cart-mem.flow.ts +1 -1
- package/templates/quickstart/src/flows/catalog-logout.flow.ts +1 -1
- package/templates/quickstart/src/flows/checkout-then-browse-again.flow.ts +4 -4
- package/templates/quickstart/src/flows/checkout.flow.ts +4 -4
- package/templates/quickstart/src/flows/login.flow.ts +1 -1
- package/templates/quickstart/src/flows/shop.flow.ts +3 -3
- package/templates/quickstart/src/flows/smoke.flow.ts +2 -2
- package/templates/quickstart/src/flows/viewer-blocked.flow.ts +1 -1
- package/templates/scaffold/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
A typed graph of reusable Blocks for driving a browser through E2E flows, in place of a
|
|
4
4
|
flat pile of ad hoc helper functions.
|
|
5
5
|
|
|
6
|
+
**Current:** `0.10.0` — CLI less-is-more (`auto` / `demo` / `run` + flags). Page hubs still as in 0.9.0.
|
|
7
|
+
|
|
6
8
|
This repo is the `waygraph` npm package itself. The full live **Sauce Demo** example
|
|
7
|
-
(Effect Add/Remove, MemNav Open details, `waygraph auto`) ships
|
|
8
|
-
[`examples/saucedemo`](./examples/saucedemo). `waygraph try demo` copies
|
|
9
|
+
(Page inventory hub, Effect Add/Remove, MemNav Open details, `waygraph auto`) ships
|
|
10
|
+
in-tree at [`examples/saucedemo`](./examples/saucedemo). `waygraph try demo` copies
|
|
9
11
|
[`templates/quickstart`](./templates/quickstart) (same Sauce Demo Blocks) into an OS
|
|
10
12
|
temp dir.
|
|
11
13
|
|
|
@@ -14,20 +16,72 @@ See [ROADMAP.md](./ROADMAP.md) for what's shipped, spec'd, and planned by versio
|
|
|
14
16
|
|
|
15
17
|
## Docs (GitHub Pages)
|
|
16
18
|
|
|
17
|
-
Browser docs (quick start, **demo /
|
|
19
|
+
Browser docs (quick start, **demo / run**, **auto explore**, engine handout, consumer layout, deploy):
|
|
18
20
|
|
|
19
21
|
- **Published:** https://deviate-dv8.github.io/waygraph/ (workflow auto-enables Pages via `enablement: true`; manual Settings only if org policy blocks it)
|
|
20
22
|
- **Source:** [`docs/`](./docs/) — static HTML, no build step
|
|
21
23
|
- **Local preview:** `npm run docs:preview` → http://127.0.0.1:4173/
|
|
22
24
|
- **Deploy:** push to `main` touching `docs/**` runs [`.github/workflows/pages.yml`](./.github/workflows/pages.yml) (`workflow_dispatch` also works)
|
|
23
|
-
- **Demo contract:** [`docs/demo.html`](./docs/demo.html) —
|
|
24
|
-
- **Auto explore:** [`docs/auto.html`](./docs/auto.html) —
|
|
25
|
+
- **Demo / run contract:** [`docs/demo.html`](./docs/demo.html) — `demo` / `run` / flags (`--auto-next`, `--auto-play-video`)
|
|
26
|
+
- **Auto explore:** [`docs/auto.html`](./docs/auto.html) — prefer `auto --cli` / `npm run auto:cli` (same menus as headed)
|
|
25
27
|
- **In-repo example:** [`examples/saucedemo`](./examples/saucedemo) — full Sauce Demo project
|
|
26
28
|
- **Convention showcase (Pages):** [`docs/saucedemo/`](./docs/saucedemo/) —
|
|
27
29
|
https://deviate-dv8.github.io/waygraph/saucedemo/
|
|
30
|
+
- **Helpers (consumer copy):** [`examples/saucedemo/docs/HELPERS.md`](./examples/saucedemo/docs/HELPERS.md)
|
|
28
31
|
|
|
29
32
|
This README stays the in-repo API narrative; Pages is the same material for eyeballing and cross-mesh handoff.
|
|
30
33
|
|
|
34
|
+
## 0.9.0 — Page, Method, Sel
|
|
35
|
+
|
|
36
|
+
Runtime is still one type: `Block`. Helpers are TypeScript salt.
|
|
37
|
+
|
|
38
|
+
| Helper | Role | Typical file |
|
|
39
|
+
|--------|------|----------------|
|
|
40
|
+
| `definePageBlock` | Screen hub (checkpoint + `verify` + registered methods) | `*.page.block.ts` |
|
|
41
|
+
| `defineMethodBlock` | One-shot non-nav step (submit, upload, logout) | `methods/*.method.block.ts` |
|
|
42
|
+
| `defineEffectBlock` | Instance mutate + `instanceOptions` auto menu | `methods/*.effect.block.ts` |
|
|
43
|
+
| `defineNavBlock` / `defineNavClickBlock` | `goto` / click-nav | `nav-*.block.ts` |
|
|
44
|
+
| `defineMemNavBlock` | Nav + per-row `instanceOptions` | `nav-*.block.ts` |
|
|
45
|
+
| `defineActionBlock` | **Deprecated** alias of `defineMethodBlock` | — |
|
|
46
|
+
|
|
47
|
+
**Page hub:** one Checkpoint = this screen. Methods hang off the page for readability /
|
|
48
|
+
auto grouping. Arrival-only hubs omit `url`/`click` (previous Block already landed here).
|
|
49
|
+
Deep-link hubs pass `url` or `click` like a Nav.
|
|
50
|
+
|
|
51
|
+
**`methods/` folder** (was `actions/`): on-page work lives next to the route, not free-floating.
|
|
52
|
+
|
|
53
|
+
**`*Sel`:** DOM selectors only (static strings + `(id) => …` for item-no-1 style). Mem keys
|
|
54
|
+
store values (which item / upload queue), not selectors. `instanceOptions` scrapes the live
|
|
55
|
+
DOM into menu rows and `mem.set`s on pick; predefined methods seed mem from the flow instead.
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { definePageBlock, Trait } from "waygraph";
|
|
59
|
+
|
|
60
|
+
export const InventorySel = {
|
|
61
|
+
list: ".inventory_list",
|
|
62
|
+
addBtn: (id: string) => `[data-test="add-to-cart-${id}"]`,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const InventoryPage = definePageBlock({
|
|
66
|
+
name: "page-inventory",
|
|
67
|
+
checkpoint: "LoggedIn",
|
|
68
|
+
verify: [
|
|
69
|
+
Trait.url({ pathname: "/inventory.html" }),
|
|
70
|
+
Trait.visible(InventorySel.list),
|
|
71
|
+
],
|
|
72
|
+
methods: {
|
|
73
|
+
addToCart: () => AddToCartBlock,
|
|
74
|
+
removeFromCart: () => RemoveFromCartBlock,
|
|
75
|
+
addAllToCart: () => AddAllToCartBlock,
|
|
76
|
+
removeAllFromCart: () => RemoveAllFromCartBlock,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Live reference: `examples/saucedemo/src/blocks/saucedemo-web/inventory/`
|
|
82
|
+
(`inventory.page.block.ts` + `methods/` + `InventorySel`). Bulk `add-all-to-cart` /
|
|
83
|
+
`remove-all-from-cart` are one menu row each (`from: "*"` — works after leave/return).
|
|
84
|
+
|
|
31
85
|
|
|
32
86
|
## Getting started (pick one)
|
|
33
87
|
|
|
@@ -172,24 +226,16 @@ a fresh tab (the run won't close a page you handed it unless you say so), and
|
|
|
172
226
|
so the caller can keep driving it - hands a run tab back instead of losing it. See
|
|
173
227
|
"Recipes" for capture-on-popup, which stays a documented pattern until a second real use
|
|
174
228
|
case promotes it to an engine API.
|
|
175
|
-
`defineNavBlock({ name, checkpoint, url })` or `
|
|
176
|
-
builds a Block whose only possible action is navigating
|
|
177
|
-
|
|
178
|
-
`(mem) =>
|
|
179
|
-
`page.goto(url)` or `page.locator(click).click()
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
regular `defineBlock`'s `act()` receives its `page` typed as `ActionPage` instead of raw
|
|
186
|
-
`Page` - structurally identical, every method still fully present and callable, except
|
|
187
|
-
`goto`/`reload`/`goBack`/`goForward` are re-declared `@deprecated`, so a TypeScript-aware
|
|
188
|
-
editor shows navigation struck through the instant it's typed in a regular Block, pointing
|
|
189
|
-
at `defineNavBlock` - nothing is blocked, no build ever fails, existing code that already
|
|
190
|
-
navigates from a regular Block keeps compiling and running unchanged. `waygraph check
|
|
191
|
-
[project]` is the complementary whole-project sweep for contexts with no editor watching
|
|
192
|
-
(CI, generated code) - same warning, on demand, across every `*.block.ts` file at once.
|
|
229
|
+
`defineNavBlock({ name, checkpoint, url })` or `defineNavClickBlock({ name, checkpoint, click })`
|
|
230
|
+
builds a Block whose only possible action is navigating. Prefer `defineNavClickBlock` for
|
|
231
|
+
click-nav in app code; `defineNavBlock` for `url` / `goto` deep links. Both accept a plain
|
|
232
|
+
string or `(mem) => string` / `(mem) => selector`. Generated `act()` is always exactly
|
|
233
|
+
`page.goto(url)` or `page.locator(click).click()`. For screen hubs that also register
|
|
234
|
+
methods, prefer `definePageBlock` (see **0.9.0 — Page, Method, Sel** above). A regular
|
|
235
|
+
`defineBlock` / `defineMethodBlock`'s `act()` receives `page` typed as `ActionPage` —
|
|
236
|
+
`goto`/`reload`/`goBack`/`goForward` are `@deprecated` there (editor strike-through pointing
|
|
237
|
+
at Nav/Page helpers). `waygraph check [project]` is the complementary whole-project sweep
|
|
238
|
+
for contexts with no editor watching (CI, generated code).
|
|
193
239
|
`new Engine({ browsers: { chromium, firefox, webkit } })` overrides which `BrowserType`
|
|
194
240
|
actually launches for a `mem`-only run, per browser name - waygraph is deliberately "just
|
|
195
241
|
an opinionated Playwright," so a stealth-patched or otherwise customized launcher (e.g.
|
|
@@ -216,33 +262,20 @@ Deliberately **not yet implemented** (tracked on the project board):
|
|
|
216
262
|
Mermaid) is `waygraph graph [project]` (`--mermaid`). Unattended JSON execution is
|
|
217
263
|
`chain` + `WAYGRAPH_JSON=1`.
|
|
218
264
|
|
|
219
|
-
**Friendly demo run
|
|
220
|
-
autoplay off** (manual "Run this step" / "Next"). Flags beat env:
|
|
265
|
+
**Friendly demo / run / auto (0.10.0 — less is more):**
|
|
221
266
|
|
|
222
267
|
| Want | Command |
|
|
223
268
|
|------|---------|
|
|
224
|
-
| Manual watch | `waygraph demo shopFlow` |
|
|
225
|
-
| Auto-advance | `waygraph demo shopFlow --
|
|
226
|
-
|
|
|
227
|
-
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
`
|
|
233
|
-
|
|
234
|
-
cursor travel + pulse before the real click; `url` NavBlocks still `goto`. Full page:
|
|
235
|
-
https://deviate-dv8.github.io/waygraph/demo.html
|
|
236
|
-
|
|
237
|
-
**Flow video (headless OK):** `waygraph chain "loginFlow({...}) then viewerBlockedFlow({...})" --video`
|
|
238
|
-
uses Playwright `recordVideo` and prints the `.webm` path when done (default dir:
|
|
239
|
-
`.waygraph-videos/`). Lighter than help-center-clip-engine (no overlay/ffmpeg pipeline).
|
|
240
|
-
Same flag works on `waygraph demo`. Programmatic: `Engine({ recordVideo: { dir: "./videos" } })`.
|
|
241
|
-
|
|
242
|
-
**Project hygiene:** `waygraph check` warns on nav outside NavBlocks **and** lists
|
|
243
|
-
**orphan Blocks** (a `*.block.ts` export not wired into any `.flow.ts` defineFlow array).
|
|
244
|
-
Zero orphans is required before `waygraph chain auto <fromCheckpoint> <toCheckpoint>`
|
|
245
|
-
builds a chain spec from the `waygraph auto` graph.
|
|
269
|
+
| Manual watch | `waygraph demo --blocks shopFlow` |
|
|
270
|
+
| Auto-advance | `waygraph demo --blocks shopFlow --auto-next` |
|
|
271
|
+
| QA watch + record | `waygraph demo --blocks shopFlow --auto-play-video` |
|
|
272
|
+
| Ad-hoc Blocks | `waygraph run --blocks "login then nav-cart" --data '{…}'` |
|
|
273
|
+
| Headed execute | `waygraph run --blocks shopFlow --non-headless --video` |
|
|
274
|
+
| Explore | `waygraph auto` / `waygraph auto --cli` |
|
|
275
|
+
| Path-find | `waygraph auto --blocks LoginPage OrderComplete` |
|
|
276
|
+
|
|
277
|
+
`--auto-next` (alias `--autoplay`) = panel Auto-advance. `--auto-play-video` is **demo only**.
|
|
278
|
+
`chain` remains a compat alias for `run --blocks` / `auto --blocks`.
|
|
246
279
|
|
|
247
280
|
## Example
|
|
248
281
|
|
|
@@ -361,17 +394,22 @@ npm run build # tsc -p tsconfig.build.json, emits dist/
|
|
|
361
394
|
## Layout
|
|
362
395
|
|
|
363
396
|
```
|
|
364
|
-
package.json the "waygraph" npm package itself
|
|
397
|
+
package.json the "waygraph" npm package itself (0.9.0+)
|
|
365
398
|
src/
|
|
366
399
|
types.ts Checkpoint, Instruction, Block, connect()
|
|
367
400
|
mem-page.ts MemKey, key(), MemPage
|
|
368
401
|
trait.ts Trait (type + discoverable Trait.url/.text/.visible), runVerify()
|
|
369
|
-
engine.ts runGraph(),
|
|
402
|
+
engine.ts runGraph(), definePageBlock, defineMethodBlock, Engine, …
|
|
403
|
+
graph.ts discoverGraph, orphans, paths
|
|
404
|
+
auto-explore.ts waygraph auto menu
|
|
370
405
|
index.ts public barrel
|
|
371
|
-
|
|
406
|
+
examples/saucedemo/ live Sauce Demo (Page + methods/ + Sel)
|
|
407
|
+
templates/quickstart/ try demo / init template (mirrors sauce)
|
|
408
|
+
docs/ GitHub Pages static HTML
|
|
409
|
+
typecheck/ compile-time-only fixtures
|
|
372
410
|
tests/ runtime unit + integration tests (@playwright/test)
|
|
373
|
-
tsconfig.json base config
|
|
374
|
-
tsconfig.build.json
|
|
411
|
+
tsconfig.json base config
|
|
412
|
+
tsconfig.build.json emits to dist/
|
|
375
413
|
```
|
|
376
414
|
|
|
377
415
|
In-package Sauce Demo: [`examples/saucedemo`](./examples/saucedemo). Other consumer
|
package/dist/auto-explore-run.js
CHANGED
|
@@ -84,7 +84,7 @@ function defaultMemValueForKey(keyName) {
|
|
|
84
84
|
return undefined;
|
|
85
85
|
}
|
|
86
86
|
function seedMemFromEnv(mem, entry) {
|
|
87
|
-
const raw = process.env.WAYGRAPH_AUTO_MEM;
|
|
87
|
+
const raw = process.env.WAYGRAPH_DATA ?? process.env.WAYGRAPH_AUTO_MEM;
|
|
88
88
|
if (!raw)
|
|
89
89
|
return false;
|
|
90
90
|
try {
|
|
@@ -99,9 +99,9 @@ function seedMemFromEnv(mem, entry) {
|
|
|
99
99
|
return false;
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
|
-
/** Pre-seed known demo keys (saucedemo creds) so headful
|
|
102
|
+
/** Pre-seed known demo keys (saucedemo creds) so headful/cli do not stop for mem forms. */
|
|
103
103
|
function seedDefaultMem(library, mem) {
|
|
104
|
-
const raw = process.env.WAYGRAPH_AUTO_MEM;
|
|
104
|
+
const raw = process.env.WAYGRAPH_DATA ?? process.env.WAYGRAPH_AUTO_MEM;
|
|
105
105
|
let envParsed = {};
|
|
106
106
|
if (raw) {
|
|
107
107
|
try {
|
|
@@ -151,7 +151,7 @@ async function ensureMem(entry, mem, cli) {
|
|
|
151
151
|
await promptMemCli(entry, mem);
|
|
152
152
|
return;
|
|
153
153
|
}
|
|
154
|
-
throw new Error(`Block "${entry.block.name}" needs MemPage keys -
|
|
154
|
+
throw new Error(`Block "${entry.block.name}" needs MemPage keys - pass --data '{...}' / WAYGRAPH_DATA (or WAYGRAPH_AUTO_MEM), or enter values in --cli`);
|
|
155
155
|
}
|
|
156
156
|
async function setAutoPanelRunning(page, label) {
|
|
157
157
|
await page
|
|
@@ -447,7 +447,7 @@ function printCliMenu(menu, library) {
|
|
|
447
447
|
}
|
|
448
448
|
else {
|
|
449
449
|
const desc = entry?.description ? ` - ${entry.description}` : "";
|
|
450
|
-
console.log(` [${n}] ${c.block} (${c.kind})
|
|
450
|
+
console.log(` [${n}] ${c.block} (${c.kind}) -> ${c.to}${desc}`);
|
|
451
451
|
}
|
|
452
452
|
}
|
|
453
453
|
}
|
|
@@ -532,7 +532,11 @@ export async function runAutoExplore(projectDir, options = {}) {
|
|
|
532
532
|
const pickWait = armPickWait();
|
|
533
533
|
pickSlot.resolve = pickWait.resolve;
|
|
534
534
|
const here = await detectHere(page, library.navBlocks);
|
|
535
|
+
if (cli)
|
|
536
|
+
console.error("waygraph auto: scanning page for moves ...");
|
|
535
537
|
const menu = await buildExploreMenu(page, graph, library, here);
|
|
538
|
+
if (cli)
|
|
539
|
+
console.error(`waygraph auto: ${menu.flat.length} move(s) available`);
|
|
536
540
|
if (menu.flat.length === 0) {
|
|
537
541
|
console.error(here
|
|
538
542
|
? `waygraph auto: no runnable Blocks on "${here}" - nothing on this page matches the graph.`
|
|
@@ -568,10 +572,12 @@ export async function runAutoExplore(projectDir, options = {}) {
|
|
|
568
572
|
else {
|
|
569
573
|
await ensureMem(entry, mem, cli);
|
|
570
574
|
}
|
|
575
|
+
const pickLabel = edge.label ?? entry.block.name;
|
|
576
|
+
console.error(`waygraph auto: running [${pick.index + 1}] ${pickLabel} ...`);
|
|
571
577
|
await runOneBlock(engine, entry, context, page, mem, !cli);
|
|
572
578
|
const landed = await detectHere(page, library.navBlocks);
|
|
573
|
-
lastRunNote = `${entry.block.name}
|
|
574
|
-
console.error(`waygraph auto: ran ${entry.block.name}
|
|
579
|
+
lastRunNote = `${entry.block.name} -> ${landed ?? edge.to}`;
|
|
580
|
+
console.error(`waygraph auto: ran ${entry.block.name} -> ${landed ?? edge.to}`);
|
|
575
581
|
}
|
|
576
582
|
catch (err) {
|
|
577
583
|
lastRunNote = `${entry.block.name} failed`;
|
package/dist/auto-explore.js
CHANGED
|
@@ -37,7 +37,8 @@ function isBlockLike(val) {
|
|
|
37
37
|
return instruction !== null && typeof instruction === "object" && typeof instruction?.act === "function";
|
|
38
38
|
}
|
|
39
39
|
function isNavBlockMarked(val) {
|
|
40
|
-
|
|
40
|
+
const kind = val.__waygraphKind;
|
|
41
|
+
return kind === "nav" || kind === "page";
|
|
41
42
|
}
|
|
42
43
|
function isUrlNav(entry) {
|
|
43
44
|
return entry.block.__waygraphNavClick === undefined;
|
|
@@ -52,7 +53,8 @@ async function navRunnable(page, entry) {
|
|
|
52
53
|
if (typeof click !== "string")
|
|
53
54
|
return false;
|
|
54
55
|
try {
|
|
55
|
-
|
|
56
|
+
// Short timeout: menu scan must stay snappy (many edges miss on this page).
|
|
57
|
+
return await page.locator(click).first().isVisible({ timeout: 150 });
|
|
56
58
|
}
|
|
57
59
|
catch {
|
|
58
60
|
return false;
|
|
@@ -61,14 +63,19 @@ async function navRunnable(page, entry) {
|
|
|
61
63
|
async function wildcardActionRunnable(page, entry, here) {
|
|
62
64
|
if (here === null)
|
|
63
65
|
return false;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
const name = entry.block.name;
|
|
67
|
+
// Bulk / non-instance * actions: show when matching live buttons exist.
|
|
68
|
+
try {
|
|
69
|
+
if (name === "add-all-to-cart" || name === "add-to-cart") {
|
|
70
|
+
return await page.locator('button[data-test^="add-to-cart-"]').first().isVisible({ timeout: 150 });
|
|
67
71
|
}
|
|
68
|
-
|
|
69
|
-
return
|
|
72
|
+
if (name === "remove-all-from-cart" || name === "remove-from-cart") {
|
|
73
|
+
return await page.locator('button[data-test^="remove-"]').first().isVisible({ timeout: 150 });
|
|
70
74
|
}
|
|
71
75
|
}
|
|
76
|
+
catch {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
72
79
|
return false;
|
|
73
80
|
}
|
|
74
81
|
/**
|
|
@@ -139,27 +146,40 @@ export async function buildExploreMenu(page, graph, library, here) {
|
|
|
139
146
|
const navigate = [];
|
|
140
147
|
const back = [];
|
|
141
148
|
const seen = new Set();
|
|
149
|
+
// Union Out tags create duplicate edges for the same Block - cache instanceOptions
|
|
150
|
+
// so we only scrape the DOM once per Block name per menu build.
|
|
151
|
+
const instanceOptionsCache = new Map();
|
|
142
152
|
const push = (bucket, edge) => {
|
|
143
153
|
if (seen.has(edge.block))
|
|
144
154
|
return;
|
|
145
155
|
seen.add(edge.block);
|
|
146
156
|
bucket.push(edge);
|
|
147
157
|
};
|
|
158
|
+
async function loadInstanceOptions(entry) {
|
|
159
|
+
const fn = entry.block.instanceOptions;
|
|
160
|
+
if (!fn)
|
|
161
|
+
return [];
|
|
162
|
+
const cached = instanceOptionsCache.get(entry.block.name);
|
|
163
|
+
if (cached)
|
|
164
|
+
return cached;
|
|
165
|
+
let options = [];
|
|
166
|
+
try {
|
|
167
|
+
options = await fn(page);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
options = [];
|
|
171
|
+
}
|
|
172
|
+
instanceOptionsCache.set(entry.block.name, options);
|
|
173
|
+
return options;
|
|
174
|
+
}
|
|
148
175
|
for (const edge of graph.edges) {
|
|
149
176
|
const entry = library.byName.get(edge.block);
|
|
150
177
|
if (!entry)
|
|
151
178
|
continue;
|
|
152
179
|
if (edge.kind === "action") {
|
|
153
180
|
if (here !== null && edge.from === here) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
let options = [];
|
|
157
|
-
try {
|
|
158
|
-
options = await instanceOptionsFn(page);
|
|
159
|
-
}
|
|
160
|
-
catch {
|
|
161
|
-
options = [];
|
|
162
|
-
}
|
|
181
|
+
if (entry.block.instanceOptions) {
|
|
182
|
+
const options = await loadInstanceOptions(entry);
|
|
163
183
|
for (const option of options) {
|
|
164
184
|
const seenKey = `${edge.block}::${option.id}`;
|
|
165
185
|
if (seen.has(seenKey))
|
|
@@ -177,15 +197,8 @@ export async function buildExploreMenu(page, graph, library, here) {
|
|
|
177
197
|
}
|
|
178
198
|
}
|
|
179
199
|
else if (here !== null && edge.from === "*") {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
let options = [];
|
|
183
|
-
try {
|
|
184
|
-
options = await instanceOptionsFn(page);
|
|
185
|
-
}
|
|
186
|
-
catch {
|
|
187
|
-
options = [];
|
|
188
|
-
}
|
|
200
|
+
if (entry.block.instanceOptions) {
|
|
201
|
+
const options = await loadInstanceOptions(entry);
|
|
189
202
|
for (const option of options) {
|
|
190
203
|
const seenKey = `${edge.block}::${option.id}`;
|
|
191
204
|
if (seen.has(seenKey))
|
|
@@ -195,7 +208,12 @@ export async function buildExploreMenu(page, graph, library, here) {
|
|
|
195
208
|
}
|
|
196
209
|
}
|
|
197
210
|
else if (await wildcardActionRunnable(page, entry, here)) {
|
|
198
|
-
|
|
211
|
+
const bulkLabel = {
|
|
212
|
+
"add-all-to-cart": "Add all to cart",
|
|
213
|
+
"remove-all-from-cart": "Remove all from cart",
|
|
214
|
+
};
|
|
215
|
+
const label = bulkLabel[entry.block.name] ?? (entry.description?.trim() || undefined);
|
|
216
|
+
push(anywhere, label ? { ...edge, label } : edge);
|
|
199
217
|
}
|
|
200
218
|
}
|
|
201
219
|
continue;
|
|
@@ -203,15 +221,8 @@ export async function buildExploreMenu(page, graph, library, here) {
|
|
|
203
221
|
// Nav: MemNavBlock (instanceOptions) expands one row per live target;
|
|
204
222
|
// plain NavBlock still uses click-visibility (navRunnable).
|
|
205
223
|
if (here !== null && (edge.from === here || edge.from === "*") && edge.to !== here) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
let options = [];
|
|
209
|
-
try {
|
|
210
|
-
options = await instanceOptionsFn(page);
|
|
211
|
-
}
|
|
212
|
-
catch {
|
|
213
|
-
options = [];
|
|
214
|
-
}
|
|
224
|
+
if (entry.block.instanceOptions) {
|
|
225
|
+
const options = await loadInstanceOptions(entry);
|
|
215
226
|
const bucket = isBackEdge(edge) ? back : navigate;
|
|
216
227
|
for (const option of options) {
|
|
217
228
|
const seenKey = `${edge.block}::${option.id}`;
|
|
@@ -249,7 +260,7 @@ export async function buildExploreMenu(page, graph, library, here) {
|
|
|
249
260
|
else {
|
|
250
261
|
if (forward.length > 0) {
|
|
251
262
|
sections.push({
|
|
252
|
-
title: `
|
|
263
|
+
title: `Methods from ${here}`,
|
|
253
264
|
edges: forward.sort((a, b) => a.block.localeCompare(b.block)),
|
|
254
265
|
});
|
|
255
266
|
}
|
package/dist/cli.d.ts
CHANGED
|
@@ -2,18 +2,14 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* waygraph CLI -- tooling around this same package's engine.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* run <flow> [project] Run a named flow (no overlay unless --step)
|
|
10
|
-
* list / nav / validate Discover and inspect flows
|
|
11
|
-
* check / auto / graph Hygiene + state graph
|
|
12
|
-
* init <name> Offline scaffold
|
|
5
|
+
* Primary verbs (less is more):
|
|
6
|
+
* auto Explore picker; `--blocks From To` = graph path-find + run
|
|
7
|
+
* demo Watch (step overlay); `--blocks` `--data` `--auto-next` `--auto-play-video`
|
|
8
|
+
* run Execute; `--blocks` `--data` `--non-headless` `--video`
|
|
13
9
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
10
|
+
* Also: list / nav / validate / check / graph / init / try
|
|
11
|
+
* Aliases (one release): `chain` -> run/demo --blocks; `--autoplay` -> `--auto-next`
|
|
12
|
+
*
|
|
13
|
+
* "project" defaults to cwd. Flags beat WAYGRAPH_* env.
|
|
18
14
|
*/
|
|
19
15
|
export {};
|