waygraph 0.15.53 → 0.15.54

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.
Files changed (108) hide show
  1. package/dist/analysis/graph.d.ts +3 -0
  2. package/dist/auto-session/helpers.d.ts +10 -0
  3. package/dist/blocks-select.d.ts +3 -0
  4. package/dist/blocks-select.js +2 -0
  5. package/dist/config.d.ts +2 -0
  6. package/dist/core/blocks/api.d.ts +1 -0
  7. package/dist/core/blocks/method.d.ts +2 -0
  8. package/dist/core/blocks/method.js +1 -0
  9. package/dist/core/blocks/nav.d.ts +1 -0
  10. package/dist/core/blocks/page.d.ts +1 -0
  11. package/dist/core/branch-regression.d.ts +1 -0
  12. package/dist/core/compose.d.ts +1 -0
  13. package/dist/core/flow.d.ts +1 -0
  14. package/dist/core/map-builder.d.ts +8 -1
  15. package/dist/core/map-builder.js +1 -1
  16. package/dist/core/run-graph.d.ts +2 -0
  17. package/dist/core/run-graph.js +1 -0
  18. package/dist/errors.d.ts +1 -0
  19. package/dist/extensions.d.ts +1 -0
  20. package/dist/extensions.js +1 -0
  21. package/dist/highlights/demo-pace.d.ts +4 -0
  22. package/dist/highlights/demo-pace.js +4 -0
  23. package/dist/highlights/device.d.ts +2 -0
  24. package/dist/highlights/device.js +2 -0
  25. package/dist/highlights/types.d.ts +6 -0
  26. package/dist/session/auto-explore-run.js +6 -0
  27. package/dist/session/overlay-beacon.d.ts +7 -0
  28. package/dist/session/overlay-beacon.js +5 -0
  29. package/dist/session/pilot.d.ts +1 -0
  30. package/dist/traverse/coverage.d.ts +4 -0
  31. package/dist/traverse/coverage.js +3 -0
  32. package/dist/traverse/lease.d.ts +1 -0
  33. package/dist/traverse/lease.js +1 -0
  34. package/dist/traverse/run.d.ts +3 -0
  35. package/examples/routed-demo/src/flows/routed-demo-map.flow.ts +1 -1
  36. package/examples/routed-demo/src/flows/routed-demo.flow.ts +2 -2
  37. package/examples/saucedemo/README.md +11 -12
  38. package/examples/saucedemo/config/waygraph.config.ts +17 -0
  39. package/examples/saucedemo/docs/CONVENTION.md +1 -2
  40. package/examples/saucedemo/docs/HELPERS.md +1 -1
  41. package/examples/saucedemo/package-lock.json +10 -3
  42. package/examples/saucedemo/package.json +12 -29
  43. package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-cart.block.ts +0 -49
  44. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +22 -25
  45. package/examples/saucedemo/src/blocks/saucedemo-web/inventory/inventory.page.block.ts +0 -6
  46. package/examples/saucedemo/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +38 -96
  47. package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +1 -26
  48. package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +1 -45
  49. package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +14 -77
  50. package/examples/saucedemo/src/flows/api-demo.flow.ts +17 -11
  51. package/examples/saucedemo/src/flows/cart-bulk.flow.ts +19 -14
  52. package/examples/saucedemo/src/flows/cart-continue.flow.ts +10 -8
  53. package/examples/saucedemo/src/flows/cart-mem.flow.ts +7 -7
  54. package/examples/saucedemo/src/flows/catalog-logout.flow.ts +13 -8
  55. package/examples/saucedemo/src/flows/checkout-then-browse-again.flow.ts +26 -48
  56. package/examples/saucedemo/src/flows/checkout.flow.ts +70 -86
  57. package/examples/saucedemo/src/flows/device-showcase.flow.ts +24 -25
  58. package/examples/saucedemo/src/flows/login.flow.ts +11 -18
  59. package/examples/saucedemo/src/flows/mem-stub-demo.flow.ts +9 -20
  60. package/examples/saucedemo/src/flows/shop.flow.ts +15 -20
  61. package/examples/saucedemo/src/flows/smoke.flow.ts +12 -27
  62. package/examples/saucedemo/src/flows/stub-on-error.flow.ts +24 -43
  63. package/examples/saucedemo/src/flows/viewer-blocked.flow.ts +26 -34
  64. package/examples/saucedemo/src/states/checkout.mem-stubs.ts +11 -0
  65. package/examples/saucedemo/src/stubs/device-showcase.ts +193 -0
  66. package/examples/saucedemo/src/stubs/login.ts +37 -0
  67. package/examples/saucedemo/tests/chain-flow-episodes.spec.ts +7 -9
  68. package/examples/saucedemo/tests/submit-login-branch.spec.ts +18 -5
  69. package/package.json +3 -2
  70. package/templates/quickstart/README.md +4 -7
  71. package/templates/quickstart/config/waygraph.config.ts +17 -0
  72. package/templates/quickstart/docs/CONVENTION.md +1 -2
  73. package/templates/quickstart/docs/HELPERS.md +1 -1
  74. package/templates/quickstart/package.json +14 -14
  75. package/templates/quickstart/src/blocks/SITE-MAP.md +14 -3
  76. package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-cart.block.ts +0 -49
  77. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +22 -25
  78. package/templates/quickstart/src/blocks/saucedemo-web/inventory/inventory.page.block.ts +0 -6
  79. package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +38 -96
  80. package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +1 -26
  81. package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +1 -45
  82. package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +14 -77
  83. package/templates/quickstart/src/flows/api-demo.flow.ts +43 -0
  84. package/templates/quickstart/src/flows/cart-bulk.flow.ts +19 -14
  85. package/templates/quickstart/src/flows/cart-continue.flow.ts +10 -8
  86. package/templates/quickstart/src/flows/cart-mem.flow.ts +7 -7
  87. package/templates/quickstart/src/flows/catalog-logout.flow.ts +13 -8
  88. package/templates/quickstart/src/flows/checkout-then-browse-again.flow.ts +26 -48
  89. package/templates/quickstart/src/flows/checkout.flow.ts +70 -63
  90. package/templates/quickstart/src/flows/device-showcase.flow.ts +24 -25
  91. package/templates/quickstart/src/flows/login.flow.ts +11 -18
  92. package/templates/quickstart/src/flows/mem-stub-demo.flow.ts +12 -0
  93. package/templates/quickstart/src/flows/shop.flow.ts +15 -20
  94. package/templates/quickstart/src/flows/smoke.flow.ts +12 -27
  95. package/templates/quickstart/src/flows/stub-on-error.flow.ts +31 -0
  96. package/templates/quickstart/src/flows/viewer-blocked.flow.ts +26 -34
  97. package/templates/quickstart/src/states/checkout.mem-stubs.ts +11 -0
  98. package/templates/quickstart/src/stubs/device-showcase.ts +193 -0
  99. package/templates/quickstart/src/stubs/login.ts +37 -0
  100. package/templates/quickstart/tests/chain-flow.spec.ts +7 -10
  101. package/templates/skills/waygraph-convention.skill.md +1 -1
  102. package/examples/saucedemo/playwright.config.ts +0 -19
  103. package/examples/saucedemo/scripts/drive-auto-cli.mjs +0 -93
  104. package/examples/saucedemo/scripts/prove-add-to-cart-menu.mjs +0 -126
  105. package/examples/saucedemo/scripts/prove-auto-graph.mjs +0 -92
  106. package/examples/saucedemo/scripts/prove-wrong-login-runtime.mjs +0 -63
  107. package/templates/quickstart/playwright.config.ts +0 -14
  108. package/templates/quickstart/scripts/drive-auto-cli.mjs +0 -93
@@ -7,7 +7,6 @@ the **reference** for waygraph consumer conventions:
7
7
  - **Nav** / **Effect** / **Action** file kinds (helpers are TypeScript salt;
8
8
  runtime is still `Block`)
9
9
  - `instanceOptions` menus for `waygraph auto` (Add/Remove + Open details)
10
- - Detailed Kind / Helper / Route comments on every Block file
11
10
  - Per-route `NAV.md` + root `src/blocks/SITE-MAP.md`
12
11
  - Inline `{ ff: true }` fast-forward, no `.ffStart()/.ffEnd()` bracket - see
13
12
  `checkoutFlow` (`src/flows/checkout.flow.ts`)
@@ -44,30 +43,30 @@ npx playwright install chromium
44
43
  | Graph crawl (Phase B-E) | `npm run traverse` |
45
44
  | Parallel crawl + leases | `npm run traverse:parallel` |
46
45
  | Coverage JSON + min gate (10%) | `npm run traverse:coverage` |
47
- | Shop demo stepper | `npm run demo:step` |
46
+ | Shop demo (login, then shop) | `npm run demo` |
48
47
  | Shop demo autoplay | `npm run demo:auto-next` |
49
- | **Device showcase** (mobile/tablet + portrait/landscape) | `npm run demo:device` |
50
- | Device showcase + `.webm` | `npm run demo:device:video` |
48
+ | **Device showcase** (mobile/tablet + portrait/landscape; narration in `src/stubs/device-showcase.ts`) | `npm run demo:device` |
49
+ | Device showcase + `.webm` | `npm run demo:video` |
51
50
  | **Cart bulk** demo (add-all → remove-all) | `npm run demo:bulk` |
52
- | Cart bulk autoplay | `npm run demo:bulk:auto-next` |
53
51
  | **Owner checkout** (inline `{ ff: true }`, `ctx.caption()`, banner position) | `npm run demo:checkout` |
54
- | Owner checkout + `.webm` | `npm run demo:checkout:video` |
55
52
  | **FE + BE in one Flow** (`defineApiBlock`, live network panel) | `npm run demo:api` |
56
- | FE + BE demo + `.webm` | `npm run demo:api:video` |
53
+ | Record (headless `.webm`) | `npm run record` |
57
54
  | List flows | `npm run flows` |
58
55
 
56
+ Credentials and the selected item come from `registerMemStub` in `src/states/checkout.mem-stubs.ts` (`memStub: true` on the
57
+ flows), so no command needs `--data`. Settings, the base URL and the shared `engine` are in `config/waygraph.config.ts`.
58
+ Narration is chained on Blocks in the flows (`src/flows/`) or shared from `src/stubs/`; the Block files carry none.
59
+
59
60
  **Demo vs auto vs run for cart bulk**
60
61
 
61
62
  | | CLI | Needs `.flow.ts`? |
62
63
  |--|-----|-------------------|
63
- | **`run --blocks`** | `npm run run:bulk` — Block names + `--data` | No |
64
- | **`demo --blocks`** | `npm run demo:bulk` — named flow + `--data` | Optional (`cartBulkFlow`) |
64
+ | **`run --blocks`** | `waygraph run --blocks "loginFlow then add-all-to-cart"` | No |
65
+ | **`demo --blocks`** | `npm run demo:bulk` — named flow | Optional (`cartBulkFlow`) |
65
66
  | **`auto`** | `npm run auto` / `auto:cli` | No — live menu |
66
- | **`traverse`** | `npm run traverse` / `traverse:parallel` / `traverse:coverage` | No — graph crawl + `.waygraph-traverse/coverage.json` |
67
+ | **`traverse`** | `npm run traverse` | No — graph crawl + `.waygraph-traverse/coverage.json` |
67
68
  | **`auto --blocks From To`** | path-find on graph | No — checkpoints only |
68
69
 
69
- QA watch+record: `npm run demo:bulk:video` (`--auto-play-video`).
70
-
71
70
  ## Layout (short)
72
71
 
73
72
  ```text
@@ -0,0 +1,17 @@
1
+ import { Engine, defineConfig } from "waygraph";
2
+
3
+ const config = defineConfig({
4
+ baseUrl: "https://www.saucedemo.com",
5
+ playwright: {
6
+ workers: 1,
7
+ fullyParallel: false,
8
+ timeout: 30_000,
9
+ use: {
10
+ headless: true,
11
+ launchOptions: { args: ["--no-sandbox", "--disable-dev-shm-usage"] },
12
+ },
13
+ },
14
+ });
15
+
16
+ export default config;
17
+ export const engine = new Engine(config);
@@ -106,5 +106,4 @@ waygraph chain "loginFlow" --step --no-autoplay
106
106
 
107
107
  Flags beat env: `--step` / `--no-step`, `--autoplay` / `--no-autoplay`,
108
108
  `--base-url <url>`, `--title <text>`. Default BASE_URL resolution order for
109
- `demo`: `--base-url` > `WAYGRAPH_BASE_URL` > `package.json` `waygraph.baseUrl`
110
- > `playwright.config` `baseURL`.
109
+ `demo`: `--base-url` > `WAYGRAPH_BASE_URL` > `baseUrl` in `config/waygraph.config.ts`.
@@ -110,7 +110,7 @@ branch(SubmitLoginBlock, {
110
110
  });
111
111
  ```
112
112
 
113
- Linear `defineFlow([start, …, end])` usually skips `branch()` (one happy path).
113
+ A linear `map()` chain usually skips `branch()` (one happy path).
114
114
 
115
115
  ---
116
116
 
@@ -16,10 +16,12 @@
16
16
  }
17
17
  },
18
18
  "../..": {
19
- "version": "0.15.19",
19
+ "version": "0.15.53",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "tsx": "^4.0.0"
22
+ "open-props": "^1.7.23",
23
+ "tsx": "^4.0.0",
24
+ "urlpattern-polyfill": "^10.1.0"
23
25
  },
24
26
  "bin": {
25
27
  "waygraph": "bin/waygraph"
@@ -27,7 +29,12 @@
27
29
  "devDependencies": {
28
30
  "@playwright/test": "^1.63.0",
29
31
  "@types/node": "^26.0.0",
30
- "typescript": "^5.6.0"
32
+ "knip": "^6.42.1",
33
+ "typedoc": "^0.28.20",
34
+ "typedoc-plugin-markdown": "^4.14.1",
35
+ "typedoc-vitepress-theme": "^1.1.4",
36
+ "typescript": "^5.6.0",
37
+ "vitepress": "^1.6.4"
31
38
  },
32
39
  "peerDependencies": {
33
40
  "@playwright/test": "^1.40.0"
@@ -9,37 +9,20 @@
9
9
  "test": "waygraph test",
10
10
  "test:ui": "waygraph test ui",
11
11
  "flows": "waygraph list",
12
- "demo": "waygraph demo --blocks \"loginFlow then shopFlow\" --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"},\\\"saucedemo.selectedItem\\\":{\\\"id\\\":\\\"sauce-labs-backpack\\\",\\\"name\\\":\\\"Sauce Labs Backpack\\\"}}\"",
13
- "demo:step": "waygraph demo --blocks \"loginFlow then shopFlow\" --title \"Shop demo\" --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"},\\\"saucedemo.selectedItem\\\":{\\\"id\\\":\\\"sauce-labs-backpack\\\",\\\"name\\\":\\\"Sauce Labs Backpack\\\"}}\"",
14
- "demo:auto-next": "waygraph demo --blocks \"loginFlow then shopFlow\" --auto-next --title \"Product then cart\" --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"},\\\"saucedemo.selectedItem\\\":{\\\"id\\\":\\\"sauce-labs-backpack\\\",\\\"name\\\":\\\"Sauce Labs Backpack\\\"}}\"",
15
- "auto": "waygraph auto",
16
- "auto:cli": "waygraph auto --cli --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"}}\"",
17
- "prove:auto-cli": "node scripts/drive-auto-cli.mjs",
18
- "traverse": "waygraph traverse --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"}}\" --max-steps 40",
19
- "traverse:parallel": "waygraph traverse --parallel 2 --session clone --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"}}\" --max-steps 30",
20
- "traverse:coverage": "waygraph traverse --min-edge-coverage 10% --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"}}\" --max-steps 40",
12
+ "check": "waygraph check",
21
13
  "graph": "waygraph graph",
22
14
  "graph:mermaid": "waygraph graph --mermaid",
23
- "demo:stub-on-error": "waygraph demo --blocks stubOnErrorFlow --auto-next --fast --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"locked_out_user\\\",\\\"password\\\":\\\"secret_sauce\\\"}}\" --title \"stubOnError prove\"",
24
- "prove:login-branch": "node scripts/prove-wrong-login-runtime.mjs",
25
- "prove:graph": "node scripts/prove-auto-graph.mjs",
26
- "prove:add-to-cart-menu": "node scripts/prove-add-to-cart-menu.mjs",
27
- "prove": "npm run prove:login-branch && npm run prove:graph && npm run prove:add-to-cart-menu && npm test",
28
- "record": "waygraph run --blocks \"loginFlow then shopFlow({\\\"saucedemo.selectedItem\\\":{\\\"id\\\":\\\"sauce-labs-backpack\\\",\\\"name\\\":\\\"Sauce Labs Backpack\\\"}})\" --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"}}\" --video --no-step",
29
- "demo:device": "waygraph demo --blocks deviceShowcaseFlow --auto-next --title \"Device showcase\" --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"},\\\"saucedemo.selectedItem\\\":{\\\"id\\\":\\\"sauce-labs-backpack\\\",\\\"name\\\":\\\"Sauce Labs Backpack\\\"}}\"",
30
- "demo:device:video": "waygraph demo --blocks deviceShowcaseFlow --auto-play-video --title \"Device showcase\" --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"},\\\"saucedemo.selectedItem\\\":{\\\"id\\\":\\\"sauce-labs-backpack\\\",\\\"name\\\":\\\"Sauce Labs Backpack\\\"}}\" --video ./.tmp/device-showcase",
31
- "demo:bulk": "waygraph demo --blocks cartBulkFlow --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"}}\"",
32
- "demo:bulk:auto-next": "waygraph demo --blocks cartBulkFlow --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"}}\" --auto-next --title \"Cart bulk demo\"",
33
- "demo:bulk:video": "waygraph demo --blocks cartBulkFlow --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"}}\" --auto-play-video --title \"Cart bulk demo\"",
34
- "demo:checkout": "waygraph demo --blocks checkoutFlow --auto-next --title \"Owner: Full Checkout\" --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"},\\\"saucedemo.selectedItem\\\":{\\\"id\\\":\\\"sauce-labs-backpack\\\",\\\"name\\\":\\\"Sauce Labs Backpack\\\"}}\"",
35
- "demo:checkout:video": "waygraph demo --blocks checkoutFlow --auto-play-video --title \"Owner: Full Checkout\" --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"},\\\"saucedemo.selectedItem\\\":{\\\"id\\\":\\\"sauce-labs-backpack\\\",\\\"name\\\":\\\"Sauce Labs Backpack\\\"}}\"",
36
- "demo:api": "waygraph demo --blocks apiDemoFlow --auto-next --title \"FE + BE in one Flow\" --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"}}\"",
37
- "demo:api:video": "waygraph demo --blocks apiDemoFlow --auto-play-video --title \"FE + BE in one Flow\" --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"}}\"",
38
- "run:bulk": "waygraph run --blocks \"loginFlow then add-all-to-cart then remove-all-from-cart\" --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"}}\"",
39
- "chain:bulk": "waygraph run --blocks \"loginFlow then add-all-to-cart then remove-all-from-cart\" --data \"{\\\"saucedemo.credentials\\\":{\\\"username\\\":\\\"standard_user\\\",\\\"password\\\":\\\"secret_sauce\\\"}}\" --non-headless"
40
- },
41
- "waygraph": {
42
- "baseUrl": "https://www.saucedemo.com"
15
+ "auto": "waygraph auto",
16
+ "auto:cli": "waygraph auto --cli",
17
+ "demo": "waygraph demo --blocks \"loginFlow then shopFlow\"",
18
+ "demo:auto-next": "waygraph demo --blocks \"loginFlow then shopFlow\" --auto-next",
19
+ "demo:checkout": "waygraph demo --blocks checkoutFlow --auto-next",
20
+ "demo:device": "waygraph demo --blocks deviceShowcaseFlow --auto-next",
21
+ "demo:bulk": "waygraph demo --blocks cartBulkFlow --auto-next",
22
+ "demo:api": "waygraph demo --blocks apiDemoFlow --auto-next",
23
+ "demo:video": "waygraph demo --blocks deviceShowcaseFlow --auto-play-video",
24
+ "record": "waygraph run --blocks \"loginFlow then shopFlow\" --video --no-step",
25
+ "traverse": "waygraph traverse --max-steps 40"
43
26
  },
44
27
  "dependencies": {
45
28
  "waygraph": "file:../.."
@@ -1,7 +1,5 @@
1
1
  import { defineNavClickBlock, Trait } from "waygraph";
2
- import type { StubCtx } from "waygraph";
3
2
  import type { CartPage } from "../../../states/checkout.states.js";
4
- import { InventorySel } from "../inventory/methods/inventory-items.js";
5
3
  import { CartSel } from "./cart.sel.js";
6
4
 
7
5
  /**
@@ -17,51 +15,4 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
17
15
  checkpoint: "CartPage",
18
16
  click: CartSel.cartLink,
19
17
  verify: [Trait.url({ pathname: "/cart.html" })],
20
- stubBefore: (ctx: StubCtx) => {
21
- ctx.title("Open cart · landscape");
22
- ctx.landscape();
23
- ctx.todos(
24
- "saucedemo",
25
- [
26
- { id: "login-user", text: "Enter username", done: true },
27
- { id: "login-pass", text: "Enter password", done: true },
28
- { id: "login-submit", text: "Tap Login", done: true },
29
- { id: "cart-find", text: "Find the product", done: true },
30
- { id: "cart-add", text: "Add to cart", done: true },
31
- { id: "cart-open", text: "Open cart" },
32
- ],
33
- { title: "Device showcase", index: 5 },
34
- );
35
- ctx.zoom(1.4);
36
- ctx.zoomOut(false);
37
- ctx.highlights({
38
- cart: {
39
- selector: CartSel.cartLink,
40
- label: "Cart",
41
- detail: "tone: planned (purple) - open cart",
42
- tone: "planned",
43
- focus: true,
44
- zoomOut: false,
45
- followMouse: false,
46
- weight: "bold",
47
- gesture: "tap",
48
- },
49
- });
50
- },
51
- stubAfter: (ctx: StubCtx) => {
52
- ctx.banner("Your cart · desktop");
53
- ctx.clearDevice();
54
- ctx.hideTodos();
55
- ctx.zoomOut(true);
56
- ctx.ring("items", {
57
- selector: InventorySel.cartItem,
58
- label: "Cart items",
59
- detail: "tone: success (green) - product in cart",
60
- tone: "success",
61
- focus: true,
62
- zoomOut: true,
63
- followMouse: false,
64
- duration: true,
65
- });
66
- },
67
18
  });
@@ -1,5 +1,8 @@
1
- import { defineMethodBlock, checkpoint, Trait, narrate, type StubCtx } from "waygraph";
2
- import type { CheckoutOverviewPage, OrderComplete } from "../../../../states/checkout.states.js";
1
+ import { defineMethodBlock, checkpoint, Trait, narrate } from "waygraph";
2
+ import type {
3
+ CheckoutOverviewPage,
4
+ OrderComplete,
5
+ } from "../../../../states/checkout.states.js";
3
6
  import { CheckoutOverviewSel } from "./checkout-overview.sel.js";
4
7
 
5
8
  /**
@@ -10,34 +13,27 @@ import { CheckoutOverviewSel } from "./checkout-overview.sel.js";
10
13
  * Places the order on the overview page - form/finish click, not a NavBlock.
11
14
  * Stubs use open ctx lifecycles (preferred) - not static slot maps.
12
15
  */
13
- export const FinishOrderBlock = defineMethodBlock<CheckoutOverviewPage, OrderComplete>({
16
+ export const FinishOrderBlock = defineMethodBlock<
17
+ CheckoutOverviewPage,
18
+ OrderComplete
19
+ >({
14
20
  name: "finish-order",
15
- description: "Places the order and confirms the 'Thank you for your order!' completion page.",
21
+ description:
22
+ "Places the order and confirms the 'Thank you for your order!' completion page.",
16
23
  instruction: {
17
24
  async act(page) {
18
25
  const finishButton = page.locator(CheckoutOverviewSel.finishBtn);
19
- await narrate(finishButton, "Placing the order", () => finishButton.click());
26
+ await narrate(finishButton, "Placing the order", () =>
27
+ finishButton.click(),
28
+ );
20
29
  },
21
30
  resolve: () => checkpoint("OrderComplete"),
22
- verify: [Trait.text(CheckoutOverviewSel.completeHeader, "Thank you for your order!")],
23
- stubBefore: (ctx: StubCtx) => {
24
- ctx.ring("finish", {
25
- selector: CheckoutOverviewSel.finishBtn,
26
- label: "Finish",
27
- detail: "tone: warning (yellow) - place order",
28
- tone: "warning",
29
- weight: "bold",
30
- });
31
- },
32
- stubAfter: (ctx: StubCtx) => {
33
- ctx.ring("thanks", {
34
- selector: CheckoutOverviewSel.completeHeader,
35
- label: "Order confirmed",
36
- detail: "tone: success (green) - thank you!",
37
- tone: "success",
38
- duration: true,
39
- });
40
- },
31
+ verify: [
32
+ Trait.text(
33
+ CheckoutOverviewSel.completeHeader,
34
+ "Thank you for your order!",
35
+ ),
36
+ ],
41
37
  // Shown AFTER act (order already placed) - selectors must match the
42
38
  // completion page, not #finish on the overview.
43
39
  slides: [
@@ -50,7 +46,8 @@ export const FinishOrderBlock = defineMethodBlock<CheckoutOverviewPage, OrderCom
50
46
  },
51
47
  {
52
48
  caption: "Completion page is the durable proof",
53
- detail: "tone: success - the thank-you header is what verify asserts on.",
49
+ detail:
50
+ "tone: success - the thank-you header is what verify asserts on.",
54
51
  tag: "YAP",
55
52
  tone: "success",
56
53
  selector: CheckoutOverviewSel.completeHeader,
@@ -1,5 +1,4 @@
1
1
  import { definePageBlock, Trait } from "waygraph";
2
- import type { StubCtx } from "waygraph";
3
2
  import type { LoggedIn } from "../../../states/checkout.states.js";
4
3
  import { AddToCartBlock } from "./methods/add-to-cart.effect.block.js";
5
4
  import { RemoveFromCartBlock } from "./methods/remove-from-cart.effect.block.js";
@@ -28,11 +27,6 @@ export const InventoryPageBlock = definePageBlock<LoggedIn>({
28
27
  Trait.url({ pathname: "/inventory.html" }),
29
28
  Trait.visible(InventorySel.list),
30
29
  ],
31
- // Showcase responsive dashboard: tablet after mobile login (toast + lerp).
32
- stubBefore: (ctx: StubCtx) => {
33
- ctx.title("Inventory · tablet");
34
- ctx.device("tablet");
35
- },
36
30
  methods: {
37
31
  addToCart: () => AddToCartBlock,
38
32
  removeFromCart: () => RemoveFromCartBlock,
@@ -1,11 +1,13 @@
1
- import { defineEffectBlock, checkpoint, type Checkpoint, type WaygraphInstanceOption } from "waygraph";
2
- import type { StubCtx } from "waygraph";
1
+ import {
2
+ defineEffectBlock,
3
+ checkpoint,
4
+ type Checkpoint,
5
+ type WaygraphInstanceOption,
6
+ } from "waygraph";
3
7
  import type { ItemInCart } from "../../../../states/checkout.states.js";
4
8
  import { SelectedItem } from "../../../../states/checkout.mem-keys.js";
5
9
  import { collectAddableItems, InventorySel } from "./inventory-items.js";
6
10
 
7
- /** Showcase product for headed demos (matches shopFlow --data selectedItem). */
8
- const DEMO_PRODUCT_ID = "sauce-labs-backpack";
9
11
 
10
12
  /**
11
13
  * Kind: Effect
@@ -15,100 +17,40 @@ const DEMO_PRODUCT_ID = "sauce-labs-backpack";
15
17
  * Mutates cart for the mem-picked product. waygraph auto lists one
16
18
  * "Add ..." row per live Add button via instanceOptions.
17
19
  */
18
- export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>({
19
- name: "add-to-cart",
20
- description: "Adds the item named by mem (saucedemo.selectedItem) to the cart.",
21
- requires: [SelectedItem.key],
22
- instruction: {
23
- async act(page, _input, mem) {
24
- const { id } = mem.get(SelectedItem.key);
25
- await page.locator(InventorySel.addBtn(id)).click();
26
- },
27
- resolve: () => checkpoint("ItemInCart"),
28
- verify: [
29
- {
30
- name: "item-added-to-cart",
31
- async check(page, mem) {
32
- const { id } = mem.get(SelectedItem.key);
33
- return await page.locator(InventorySel.removeBtn(id)).first().isVisible();
34
- },
20
+ export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>(
21
+ {
22
+ name: "add-to-cart",
23
+ description:
24
+ "Adds the item named by mem (saucedemo.selectedItem) to the cart.",
25
+ requires: [SelectedItem.key],
26
+ instruction: {
27
+ async act(page, _input, mem) {
28
+ const { id } = mem.get(SelectedItem.key);
29
+ await page.locator(InventorySel.addBtn(id)).click();
35
30
  },
36
- ],
37
- // Demo: zoom product -> add (stay zoomed), then badge after act.
38
- stubBefore: (ctx: StubCtx) => {
39
- ctx.title("Pick a product · tablet");
40
- ctx.device("tablet");
41
- ctx.portrait();
42
- ctx.todos(
43
- "saucedemo",
44
- [
45
- { id: "login-user", text: "Enter username", done: true },
46
- { id: "login-pass", text: "Enter password", done: true },
47
- { id: "login-submit", text: "Tap Login", done: true },
48
- { id: "cart-find", text: "Find the product" },
49
- { id: "cart-add", text: "Add to cart" },
50
- { id: "cart-open", text: "Open cart" },
51
- ],
52
- { title: "Device showcase", index: 3 },
53
- );
54
- ctx.zoom(1.35);
55
- ctx.zoomOut(false);
56
- ctx.highlights({
57
- product: {
58
- selector: InventorySel.title(DEMO_PRODUCT_ID),
59
- label: "Sauce Labs Backpack",
60
- detail: "tone: info (blue)",
61
- tone: "info",
62
- focus: true,
63
- zoom: 1.45,
64
- zoomOut: false,
31
+ resolve: () => checkpoint("ItemInCart"),
32
+ verify: [
33
+ {
34
+ name: "item-added-to-cart",
35
+ async check(page, mem) {
36
+ const { id } = mem.get(SelectedItem.key);
37
+ return await page
38
+ .locator(InventorySel.removeBtn(id))
39
+ .first()
40
+ .isVisible();
41
+ },
65
42
  },
66
- add: {
67
- selector: InventorySel.addBtn(DEMO_PRODUCT_ID),
68
- label: "Add to cart",
69
- detail: "tone: success (green)",
70
- tone: "success",
71
- focus: true,
72
- zoom: 1.5,
73
- zoomOut: false,
74
- weight: "bold",
75
- },
76
- });
43
+ ],
77
44
  },
78
- stubAfter: (ctx: StubCtx) => {
79
- ctx.banner("In the cart");
80
- ctx.todos(
81
- "saucedemo",
82
- [
83
- { id: "login-user", text: "Enter username", done: true },
84
- { id: "login-pass", text: "Enter password", done: true },
85
- { id: "login-submit", text: "Tap Login", done: true },
86
- { id: "cart-find", text: "Find the product", done: true },
87
- { id: "cart-add", text: "Add to cart" },
88
- { id: "cart-open", text: "Open cart" },
89
- ],
90
- { title: "Device showcase", index: 4 },
91
- );
92
- ctx.zoomOut(false);
93
- ctx.ring("badge", {
94
- selector: InventorySel.cartBadge,
95
- label: "Cart badge",
96
- detail: "tone: success (green) - count updated",
97
- tone: "success",
98
- focus: true,
99
- zoomOut: false,
100
- duration: true,
101
- });
45
+ async instanceOptions(page): Promise<readonly WaygraphInstanceOption[]> {
46
+ const items = await collectAddableItems(page);
47
+ return items.map((item) => ({
48
+ id: item.id,
49
+ label: `Add "${item.name}" to cart`,
50
+ key: SelectedItem.key,
51
+ value: item,
52
+ highlight: InventorySel.addBtn(item.id),
53
+ }));
102
54
  },
103
55
  },
104
- async instanceOptions(page): Promise<readonly WaygraphInstanceOption[]> {
105
- const items = await collectAddableItems(page);
106
- return items.map((item) => ({
107
- id: item.id,
108
- label: `Add "${item.name}" to cart`,
109
- key: SelectedItem.key,
110
- value: item,
111
- highlight: InventorySel.addBtn(item.id),
112
- }));
113
- },
114
- });
56
+ );
@@ -1,4 +1,4 @@
1
- import { defineMethodBlock, checkpoint, type StubCtx } from "waygraph";
1
+ import { defineMethodBlock, checkpoint } from "waygraph";
2
2
  import type { LoginPage } from "../../../states/checkout.states.js";
3
3
  import { LoginCreds } from "../../../states/checkout.mem-keys.js";
4
4
  import { LoginSel } from "./login.sel.js";
@@ -21,30 +21,5 @@ export const FillPasswordBlock = defineMethodBlock<LoginPage, LoginPage>({
21
21
  await page.locator(LoginSel.password).fill(password);
22
22
  },
23
23
  resolve: () => checkpoint("LoginPage"),
24
- stubBefore: (ctx: StubCtx) => {
25
- ctx.ring("password", {
26
- selector: LoginSel.password,
27
- label: "Password",
28
- detail: "tone: planned (purple)",
29
- todo: "login-pass",
30
- tone: "planned",
31
- focus: true,
32
- zoom: 1.4,
33
- });
34
- },
35
- stubAfter: (ctx: StubCtx) => {
36
- ctx.todos(
37
- "saucedemo",
38
- [
39
- { id: "login-user", text: "Enter username", done: true },
40
- { id: "login-pass", text: "Enter password", done: true },
41
- { id: "login-submit", text: "Tap Login" },
42
- { id: "cart-find", text: "Find the product" },
43
- { id: "cart-add", text: "Add to cart" },
44
- { id: "cart-open", text: "Open cart" },
45
- ],
46
- { title: "Device showcase", index: 2 },
47
- );
48
- },
49
24
  },
50
25
  });
@@ -1,4 +1,4 @@
1
- import { defineMethodBlock, checkpoint, type StubCtx } from "waygraph";
1
+ import { defineMethodBlock, checkpoint } from "waygraph";
2
2
  import type { LoginPage } from "../../../states/checkout.states.js";
3
3
  import { LoginCreds } from "../../../states/checkout.mem-keys.js";
4
4
  import { LoginSel } from "./login.sel.js";
@@ -23,49 +23,5 @@ export const FillUsernameBlock = defineMethodBlock<LoginPage, LoginPage>({
23
23
  await page.locator(LoginSel.username).fill(username);
24
24
  },
25
25
  resolve: () => checkpoint("LoginPage"),
26
- stubBefore: (ctx: StubCtx) => {
27
- ctx.title("Signing in · mobile");
28
- ctx.device("mobile");
29
- ctx.portrait();
30
- ctx.todos(
31
- "saucedemo",
32
- [
33
- { id: "login-user", text: "Enter username" },
34
- { id: "login-pass", text: "Enter password" },
35
- { id: "login-submit", text: "Tap Login" },
36
- { id: "cart-find", text: "Find the product" },
37
- { id: "cart-add", text: "Add to cart" },
38
- { id: "cart-open", text: "Open cart" },
39
- ],
40
- { title: "Device showcase", index: 0 },
41
- );
42
- ctx.zoom(1.35);
43
- const fromMem = ctx.mem?.get(LoginCreds.key)?.username;
44
- ctx.ring("username", {
45
- selector: LoginSel.username,
46
- label: "Username",
47
- detail: fromMem
48
- ? `tone: info (blue) - mem ${fromMem}`
49
- : "tone: info (blue)",
50
- tone: "info",
51
- todo: "login-user",
52
- focus: true,
53
- zoom: 1.4,
54
- });
55
- },
56
- stubAfter: (ctx: StubCtx) => {
57
- ctx.todos(
58
- "saucedemo",
59
- [
60
- { id: "login-user", text: "Enter username", done: true },
61
- { id: "login-pass", text: "Enter password" },
62
- { id: "login-submit", text: "Tap Login" },
63
- { id: "cart-find", text: "Find the product" },
64
- { id: "cart-add", text: "Add to cart" },
65
- { id: "cart-open", text: "Open cart" },
66
- ],
67
- { title: "Device showcase", index: 1 },
68
- );
69
- },
70
26
  },
71
27
  });