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
@@ -1,19 +1,24 @@
1
- import { Engine, start, end, withTitle, chainFlow } from "waygraph";
1
+ import { engine } from "../../config/waygraph.config.js";
2
+ import "../states/checkout.mem-stubs.js";
2
3
  import { loginFlow } from "./login.flow.js";
3
4
  import { AddAllToCartBlock } from "../blocks/saucedemo-web/inventory/methods/add-all-to-cart.method.block.js";
4
5
  import { RemoveAllFromCartBlock } from "../blocks/saucedemo-web/inventory/methods/remove-all-from-cart.method.block.js";
5
6
 
6
- const engine = new Engine();
7
+ /** Add every item, then remove them all (the bulk Methods). */
8
+ export const cartBulkEpisode = engine
9
+ .map()
10
+ .start()
11
+ .method(
12
+ AddAllToCartBlock.stubBefore((ctx) =>
13
+ ctx.title("Cart bulk add/remove all"),
14
+ ),
15
+ )
16
+ .method(RemoveAllFromCartBlock)
17
+ .end();
7
18
 
8
- /**
9
- * Episode after login: drain every Add button, then every Remove button.
10
- * Proves bulk Methods + round-trip (LoggedIn <-> ItemInCart) without
11
- * instanceOptions. Pair with loginFlow via chainFlow for `waygraph demo`.
12
- */
13
- export const cartBulkEpisode = withTitle(
14
- engine.defineFlow([start, AddAllToCartBlock, RemoveAllFromCartBlock, end]),
15
- "Cart bulk add/remove all",
16
- );
17
-
18
- /** Full demo: Sign In -> Add all -> Remove all. */
19
- export const cartBulkFlow = chainFlow(loginFlow, cartBulkEpisode);
19
+ export const cartBulkFlow = engine
20
+ .map({ memStub: true })
21
+ .start()
22
+ .flow(loginFlow)
23
+ .flow(cartBulkEpisode)
24
+ .end();
@@ -1,11 +1,13 @@
1
- import { Engine, start, end, withTitle } from "waygraph";
1
+ import { engine } from "../../config/waygraph.config.js";
2
+ import "../states/checkout.mem-stubs.js";
2
3
  import { NavCartBlock } from "../blocks/saucedemo-web/cart/nav-cart.block.js";
3
4
  import { NavContinueShoppingBlock } from "../blocks/saucedemo-web/inventory-item/nav-continue-shopping.block.js";
4
5
 
5
- const engine = new Engine();
6
-
7
- // Open cart and continue shopping - wires orphan nav-continue-shopping Block.
8
- export const cartContinueFlow = withTitle(
9
- engine.defineFlow([start, NavCartBlock, NavContinueShoppingBlock, end]),
10
- "Cart then continue shopping",
11
- );
6
+ export const cartContinueFlow = engine
7
+ .map()
8
+ .start()
9
+ .gotoPage(
10
+ NavCartBlock.stubBefore((ctx) => ctx.title("Cart then continue shopping")),
11
+ )
12
+ .gotoPage(NavContinueShoppingBlock)
13
+ .end();
@@ -1,9 +1,9 @@
1
- import { Engine, start, end } from "waygraph";
1
+ import { engine } from "../../config/waygraph.config.js";
2
+ import "../states/checkout.mem-stubs.js";
2
3
  import { RemoveFromCartBlock } from "../blocks/saucedemo-web/inventory/methods/remove-from-cart.effect.block.js";
3
4
 
4
- const engine = new Engine();
5
-
6
- // Registers remove-from-cart in the discoverable graph so waygraph auto can
7
- // offer live "Remove … from cart" rows. Not a product checkout path - Add /
8
- // Remove pairing for interactive explore.
9
- export const cartMemFlow = engine.defineFlow([start, RemoveFromCartBlock, end]);
5
+ export const cartMemFlow = engine
6
+ .map()
7
+ .start()
8
+ .method(RemoveFromCartBlock)
9
+ .end();
@@ -1,12 +1,17 @@
1
- import { Engine, start, end, withTitle } from "waygraph";
1
+ import { engine } from "../../config/waygraph.config.js";
2
+ import "../states/checkout.mem-stubs.js";
2
3
  import { NavItemDetailBlock } from "../blocks/saucedemo-web/inventory/nav-item-detail.block.js";
3
4
  import { NavBackToInventoryBlock } from "../blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.js";
4
5
  import { SubmitLogoutBlock } from "../blocks/saucedemo-web/methods/submit-logout.method.block.js";
5
6
 
6
- const engine = new Engine();
7
-
8
- // Browse one product, return to inventory, log out - wires orphan catalog + logout Blocks.
9
- export const catalogLogoutFlow = withTitle(
10
- engine.defineFlow([start, NavItemDetailBlock, NavBackToInventoryBlock, SubmitLogoutBlock, end]),
11
- "Catalog browse then logout",
12
- );
7
+ export const catalogLogoutFlow = engine
8
+ .map()
9
+ .start()
10
+ .gotoPage(
11
+ NavItemDetailBlock.stubBefore((ctx) =>
12
+ ctx.title("Catalog browse then logout"),
13
+ ),
14
+ )
15
+ .gotoPage(NavBackToInventoryBlock)
16
+ .method(SubmitLogoutBlock)
17
+ .end();
@@ -1,13 +1,5 @@
1
- import { Engine, start, end, withTitle } from "waygraph";
2
- import type {
3
- LoginPage,
4
- LoggedIn,
5
- ItemInCart,
6
- CartPage,
7
- CheckoutInfoPage,
8
- CheckoutOverviewPage,
9
- OrderComplete,
10
- } from "../states/checkout.states.js";
1
+ import { engine } from "../../config/waygraph.config.js";
2
+ import "../states/checkout.mem-stubs.js";
11
3
  import { NavLoginBlock } from "../blocks/saucedemo-web/nav-login.block.js";
12
4
  import { FillUsernameBlock } from "../blocks/saucedemo-web/methods/fill-username.method.block.js";
13
5
  import { FillPasswordBlock } from "../blocks/saucedemo-web/methods/fill-password.method.block.js";
@@ -22,41 +14,27 @@ import { SubmitCheckoutInfoBlock } from "../blocks/saucedemo-web/checkout-step-o
22
14
  import { FinishOrderBlock } from "../blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.js";
23
15
  import { NavBackToProductsBlock } from "../blocks/saucedemo-web/inventory-item/nav-back-to-products.block.js";
24
16
 
25
- const engine = new Engine({ headless: false, slowMo: 250 });
26
-
27
- // Same atomic checkout chain, plus click-based nav-back-to-products
28
- // (proves OrderComplete -> LoggedIn without a goto teleport).
29
- export const checkoutThenBrowseAgainFlow = withTitle(
30
- engine.defineFlow<
31
- LoginPage,
32
- LoginPage,
33
- LoginPage,
34
- LoggedIn,
35
- ItemInCart,
36
- CartPage,
37
- CheckoutInfoPage,
38
- CheckoutInfoPage,
39
- CheckoutInfoPage,
40
- CheckoutInfoPage,
41
- CheckoutOverviewPage,
42
- OrderComplete,
43
- LoggedIn
44
- >([
45
- start,
46
- NavLoginBlock,
47
- FillUsernameBlock,
48
- FillPasswordBlock,
49
- SubmitLoginForFlow,
50
- AddToCartBlock,
51
- NavCartBlock,
52
- NavCheckoutInfoBlock,
53
- FillFirstNameBlock,
54
- FillLastNameBlock,
55
- FillPostalCodeBlock,
56
- SubmitCheckoutInfoBlock,
57
- FinishOrderBlock,
58
- NavBackToProductsBlock,
59
- end,
60
- ]),
61
- "Owner: Checkout, then click Back Home (click-based NavBlock demo)",
62
- );
17
+ /** Full checkout, then the "Back Home" click-based Nav Block returns to the catalogue. */
18
+ export const checkoutThenBrowseAgainFlow = engine
19
+ .map({ memStub: true })
20
+ .start()
21
+ .gotoPage(
22
+ NavLoginBlock.stubBefore((ctx) =>
23
+ ctx.title(
24
+ "Owner: Checkout, then click Back Home (click-based NavBlock demo)",
25
+ ),
26
+ ),
27
+ )
28
+ .method(FillUsernameBlock)
29
+ .method(FillPasswordBlock)
30
+ .method(SubmitLoginForFlow)
31
+ .method(AddToCartBlock)
32
+ .gotoPage(NavCartBlock)
33
+ .gotoPage(NavCheckoutInfoBlock)
34
+ .method(FillFirstNameBlock)
35
+ .method(FillLastNameBlock)
36
+ .method(FillPostalCodeBlock)
37
+ .method(SubmitCheckoutInfoBlock)
38
+ .method(FinishOrderBlock)
39
+ .gotoPage(NavBackToProductsBlock)
40
+ .end();
@@ -1,4 +1,5 @@
1
- import { Engine, withTitle } from "waygraph";
1
+ import { engine } from "../../config/waygraph.config.js";
2
+ import "../states/checkout.mem-stubs.js";
2
3
  import { NavLoginBlock } from "../blocks/saucedemo-web/nav-login.block.js";
3
4
  import { FillUsernameBlock } from "../blocks/saucedemo-web/methods/fill-username.method.block.js";
4
5
  import { FillPasswordBlock } from "../blocks/saucedemo-web/methods/fill-password.method.block.js";
@@ -13,65 +14,71 @@ import { SubmitCheckoutInfoBlock } from "../blocks/saucedemo-web/checkout-step-o
13
14
  import { FinishOrderBlock } from "../blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.js";
14
15
  import { LoginSel } from "../blocks/saucedemo-web/methods/login.sel.js";
15
16
 
16
- const engine = new Engine({ headless: false, slowMo: 250 });
17
-
18
- /**
19
- * Owner checkout via map() + .ffStart/.ffEnd (no separate FfOwnerAuthBlock,
20
- * no HighlightFixtureMap). Auth collapses to one blitz step; post-login
21
- * blocks keep their own ctx stubBefore/stubAfter. Call-site decorate example
22
- * on fill-username when --ff-expand shows inners again.
23
- */
24
- export const checkoutFlow = withTitle(
25
- engine
26
- .map()
27
- .start()
28
- .ffStart("ff-owner-auth")
29
- .gotoPage(NavLoginBlock)
30
- .method(
31
- FillUsernameBlock.stubBefore((ctx) => {
32
- ctx.ring("username", {
33
- selector: LoginSel.username,
34
- label: "Demo user",
35
- detail: "standard_user from Mem - library block stays neutral underneath",
36
- tag: "AC",
37
- duration: true,
38
- focus: true,
39
- });
40
- }),
41
- )
42
- .method(
43
- FillPasswordBlock.stubBefore((ctx) => {
44
- ctx.ring("password", {
45
- selector: LoginSel.password,
46
- label: "Password",
47
- detail: "Filled from Mem credentials.",
48
- duration: 1500,
49
- focus: true,
50
- });
51
- }),
52
- )
53
- .method(
54
- SubmitLoginForFlow.stubBefore((ctx) => {
55
- ctx.ring("submit", {
56
- selector: LoginSel.loginButton,
57
- label: "Sign in",
58
- tag: "GATE",
59
- duration: true,
60
- fastMode: 500,
61
- focus: true,
62
- weight: "bold",
63
- });
64
- }),
65
- )
66
- .ffEnd()
67
- .method(AddToCartBlock)
68
- .gotoPage(NavCartBlock)
69
- .gotoPage(NavCheckoutInfoBlock)
70
- .method(FillFirstNameBlock)
71
- .method(FillLastNameBlock)
72
- .method(FillPostalCodeBlock)
73
- .method(SubmitCheckoutInfoBlock)
74
- .method(FinishOrderBlock)
75
- .end(),
76
- "Owner: Full Checkout",
77
- );
17
+ export const checkoutFlow = engine
18
+ .map({ memStub: true })
19
+ .start()
20
+ .gotoPage(NavLoginBlock, { ff: true })
21
+ .method(
22
+ FillUsernameBlock.stubBefore((ctx) => {
23
+ ctx.ring("username", {
24
+ selector: LoginSel.username,
25
+ label: "Demo user",
26
+ detail:
27
+ "standard_user from Mem - library block stays neutral underneath",
28
+ tag: "AC",
29
+ duration: true,
30
+ focus: true,
31
+ });
32
+ }),
33
+ { ff: true },
34
+ )
35
+ .method(
36
+ FillPasswordBlock.stubBefore((ctx) => {
37
+ ctx.ring("password", {
38
+ selector: LoginSel.password,
39
+ label: "Password",
40
+ detail: "Filled from Mem credentials.",
41
+ duration: 1500,
42
+ focus: true,
43
+ });
44
+ }),
45
+ { ff: true },
46
+ )
47
+ .method(
48
+ SubmitLoginForFlow.stubBefore((ctx) => {
49
+ ctx.ring("submit", {
50
+ selector: LoginSel.loginButton,
51
+ label: "Sign in",
52
+ tag: "GATE",
53
+ duration: true,
54
+ fastMode: 500,
55
+ focus: true,
56
+ weight: "bold",
57
+ });
58
+ }),
59
+ { ff: true },
60
+ )
61
+ .method(AddToCartBlock.stubBefore((ctx) => ctx.title("Owner: Full Checkout")))
62
+ .gotoPage(NavCartBlock)
63
+ .gotoPage(NavCheckoutInfoBlock)
64
+ .method(
65
+ FillFirstNameBlock.stubBefore((ctx) => {
66
+ ctx.caption("Enter the first name on the order");
67
+ ctx.titlePos("left");
68
+ }),
69
+ )
70
+ .method(
71
+ FillLastNameBlock.stubBefore((ctx) => {
72
+ ctx.caption("Enter the last name on the order");
73
+ ctx.titlePos("center");
74
+ }),
75
+ )
76
+ .method(
77
+ FillPostalCodeBlock.stubBefore((ctx) => {
78
+ ctx.caption("Enter a postal code to calculate shipping");
79
+ ctx.titlePos("right");
80
+ }),
81
+ )
82
+ .method(SubmitCheckoutInfoBlock.stubBefore((ctx) => ctx.hideCaption()))
83
+ .method(FinishOrderBlock)
84
+ .end();
@@ -1,32 +1,31 @@
1
- import { Engine, start, end, withTitle } from "waygraph";
1
+ import { engine } from "../../config/waygraph.config.js";
2
+ import "../states/checkout.mem-stubs.js";
2
3
  import { NavLoginBlock } from "../blocks/saucedemo-web/nav-login.block.js";
3
4
  import { FillUsernameBlock } from "../blocks/saucedemo-web/methods/fill-username.method.block.js";
4
5
  import { FillPasswordBlock } from "../blocks/saucedemo-web/methods/fill-password.method.block.js";
5
6
  import { SubmitLoginForFlow } from "../blocks/saucedemo-web/methods/submit-login-for-flow.js";
6
7
  import { AddToCartBlock } from "../blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.js";
7
8
  import { NavCartBlock } from "../blocks/saucedemo-web/cart/nav-cart.block.js";
9
+ import { deviceShowcase as d } from "../stubs/device-showcase.js";
8
10
 
9
- const engine = new Engine();
10
-
11
- /**
12
- * Short device/orientation showcase (0.13.3+):
13
- * login mobile portrait -> land on inventory landscape ->
14
- * add-to-cart tablet portrait -> open cart tablet landscape -> desktop
15
- *
16
- * Run:
17
- * npm run demo:device
18
- * npm run demo:device:video
19
- */
20
- export const deviceShowcaseFlow = withTitle(
21
- engine.defineFlow([
22
- start,
23
- NavLoginBlock,
24
- FillUsernameBlock,
25
- FillPasswordBlock,
26
- SubmitLoginForFlow,
27
- AddToCartBlock,
28
- NavCartBlock,
29
- end,
30
- ]),
31
- "Device showcase",
32
- );
11
+ /** Sign in on a phone, shop on a tablet, open the cart in landscape: the device and zoom narration in src/stubs/device-showcase.ts. */
12
+ export const deviceShowcaseFlow = engine
13
+ .map({ memStub: true })
14
+ .start()
15
+ .gotoPage(NavLoginBlock)
16
+ .method(
17
+ FillUsernameBlock.stubBefore(d.username.before).stubAfter(d.username.after),
18
+ )
19
+ .method(
20
+ FillPasswordBlock.stubBefore(d.password.before).stubAfter(d.password.after),
21
+ )
22
+ .method(
23
+ SubmitLoginForFlow.stubBefore(d.submit.before).stubAfter(d.submit.after),
24
+ )
25
+ .method(
26
+ AddToCartBlock.stubBefore(d.addToCart.before).stubAfter(d.addToCart.after),
27
+ )
28
+ .gotoPage(
29
+ NavCartBlock.stubBefore(d.openCart.before).stubAfter(d.openCart.after),
30
+ )
31
+ .end();
@@ -1,23 +1,16 @@
1
- import { Engine, withTitle } from "waygraph";
1
+ import { engine } from "../../config/waygraph.config.js";
2
+ import "../states/checkout.mem-stubs.js";
2
3
  import { NavLoginBlock } from "../blocks/saucedemo-web/nav-login.block.js";
3
4
  import { FillUsernameBlock } from "../blocks/saucedemo-web/methods/fill-username.method.block.js";
4
5
  import { FillPasswordBlock } from "../blocks/saucedemo-web/methods/fill-password.method.block.js";
5
6
  import { SubmitLoginForFlow } from "../blocks/saucedemo-web/methods/submit-login-for-flow.js";
6
7
 
7
- const engine = new Engine();
8
-
9
- // The step-mode overlay prepends "Episode N: " itself - the title here is
10
- // just the label, not the full heading.
11
- // map() + ctx stubs on the Method blocks (see fill-username / fill-password /
12
- // submit-login) - no HighlightFixtureMap.
13
- export const loginFlow = withTitle(
14
- engine
15
- .map()
16
- .start()
17
- .gotoPage(NavLoginBlock)
18
- .method(FillUsernameBlock)
19
- .method(FillPasswordBlock)
20
- .method(SubmitLoginForFlow)
21
- .end(),
22
- "Sign In",
23
- );
8
+ /** Standard user signs in. Credentials come from the memStub in src/states/checkout.mem-stubs.ts unless --data / mem set them. */
9
+ export const loginFlow = engine
10
+ .map({ memStub: true })
11
+ .start()
12
+ .gotoPage(NavLoginBlock.stubBefore((ctx) => ctx.title("Sign In")))
13
+ .method(FillUsernameBlock)
14
+ .method(FillPasswordBlock)
15
+ .method(SubmitLoginForFlow)
16
+ .end();
@@ -0,0 +1,12 @@
1
+ import { engine } from "../../config/waygraph.config.js";
2
+ import "../states/checkout.mem-stubs.js";
3
+ import { NavLoginBlock } from "../blocks/saucedemo-web/nav-login.block.js";
4
+ import { FillUsernameBlock } from "../blocks/saucedemo-web/methods/fill-username.method.block.js";
5
+
6
+ /** memStub: the credentials are never supplied; src/states/checkout.mem-stubs.ts fills them. */
7
+ export const memStubDemoFlow = engine
8
+ .map({ memStub: true })
9
+ .start()
10
+ .gotoPage(NavLoginBlock)
11
+ .method(FillUsernameBlock)
12
+ .end();
@@ -1,4 +1,5 @@
1
- import { Engine, withTitle } from "waygraph";
1
+ import { engine } from "../../config/waygraph.config.js";
2
+ import "../states/checkout.mem-stubs.js";
2
3
  import { AddToCartBlock } from "../blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.js";
3
4
  import { NavCartBlock } from "../blocks/saucedemo-web/cart/nav-cart.block.js";
4
5
  import { NavCheckoutInfoBlock } from "../blocks/saucedemo-web/cart/nav-checkout-info.block.js";
@@ -8,22 +9,16 @@ import { FillPostalCodeBlock } from "../blocks/saucedemo-web/checkout-step-one/m
8
9
  import { SubmitCheckoutInfoBlock } from "../blocks/saucedemo-web/checkout-step-one/methods/submit-checkout-info.method.block.js";
9
10
  import { FinishOrderBlock } from "../blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.js";
10
11
 
11
- const engine = new Engine();
12
-
13
- // Episode-2 half of chainFlow(loginFlow, shopFlow) - assumes already LoggedIn
14
- // (AddToCartBlock's In is the Checkpoint<string> wildcard).
15
- export const shopFlow = withTitle(
16
- engine
17
- .map()
18
- .start()
19
- .method(AddToCartBlock)
20
- .gotoPage(NavCartBlock)
21
- .gotoPage(NavCheckoutInfoBlock)
22
- .method(FillFirstNameBlock)
23
- .method(FillLastNameBlock)
24
- .method(FillPostalCodeBlock)
25
- .method(SubmitCheckoutInfoBlock)
26
- .method(FinishOrderBlock)
27
- .end(),
28
- "Shop & Checkout",
29
- );
12
+ /** Add the selected item, check out and place the order. Starts signed in (run it after loginFlow). */
13
+ export const shopFlow = engine
14
+ .map({ memStub: true })
15
+ .start()
16
+ .method(AddToCartBlock.stubBefore((ctx) => ctx.title("Shop & Checkout")))
17
+ .gotoPage(NavCartBlock)
18
+ .gotoPage(NavCheckoutInfoBlock)
19
+ .method(FillFirstNameBlock)
20
+ .method(FillLastNameBlock)
21
+ .method(FillPostalCodeBlock)
22
+ .method(SubmitCheckoutInfoBlock)
23
+ .method(FinishOrderBlock)
24
+ .end();
@@ -1,33 +1,18 @@
1
- import { Engine, start, end } from "waygraph";
2
- import type { LoginPage, LoggedIn, ItemInCart } from "../states/checkout.states.js";
1
+ import { engine } from "../../config/waygraph.config.js";
2
+ import "../states/checkout.mem-stubs.js";
3
3
  import { NavLoginBlock } from "../blocks/saucedemo-web/nav-login.block.js";
4
4
  import { FillUsernameBlock } from "../blocks/saucedemo-web/methods/fill-username.method.block.js";
5
5
  import { FillPasswordBlock } from "../blocks/saucedemo-web/methods/fill-password.method.block.js";
6
6
  import { SubmitLoginForFlow } from "../blocks/saucedemo-web/methods/submit-login-for-flow.js";
7
7
  import { AddToCartBlock } from "../blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.js";
8
8
 
9
- const engine = new Engine();
10
-
11
- // The QA case: a smoke test only cares that it was able to navigate this far -
12
- // it doesn't need the same DOM confirmation the real checkout.flow.ts wants.
13
- // Same Blocks, same act/resolve, zero duplication - only verify differs.
14
- // .withVerify([]) reads from the Block itself, discoverable by typing
15
- // "NavLoginBlock."/"SubmitLoginForFlow." in an editor - not a free function
16
- // you have to already know exists.
17
- //
18
- // Explicit <LoginPage, LoginPage, LoginPage, LoggedIn, ItemInCart> here -
19
- // AddToCartBlock's In is now the wildcard Checkpoint<string> (it's reused as
20
- // shopFlow's own entry block too), and inferring the chain purely from
21
- // several chained .withVerify([]) calls in one array trips TS's overload
22
- // resolution into unifying the wrong Out type partway through; pinning the
23
- // type args sidesteps it rather than fighting it. The two middle `LoginPage`
24
- // entries are fill-username / fill-password (self-loop Methods).
25
- export const smokeFlow = engine.defineFlow<LoginPage, LoginPage, LoginPage, LoggedIn, ItemInCart>([
26
- start,
27
- NavLoginBlock.withVerify([]),
28
- FillUsernameBlock,
29
- FillPasswordBlock,
30
- SubmitLoginForFlow.withVerify([]),
31
- AddToCartBlock.withVerify([]),
32
- end,
33
- ]);
9
+ /** Smoke: the happy path with the Blocks' own verify lists switched off where a later step already proves the outcome. */
10
+ export const smokeFlow = engine
11
+ .map()
12
+ .start()
13
+ .gotoPage(NavLoginBlock.withVerify([]))
14
+ .method(FillUsernameBlock)
15
+ .method(FillPasswordBlock)
16
+ .method(SubmitLoginForFlow.withVerify([]))
17
+ .method(AddToCartBlock.withVerify([]))
18
+ .end();
@@ -0,0 +1,31 @@
1
+ import { engine } from "../../config/waygraph.config.js";
2
+ import "../states/checkout.mem-stubs.js";
3
+ import { Trait } from "waygraph";
4
+ import { NavLoginBlock } from "../blocks/saucedemo-web/nav-login.block.js";
5
+ import { FillUsernameBlock } from "../blocks/saucedemo-web/methods/fill-username.method.block.js";
6
+ import { FillPasswordBlock } from "../blocks/saucedemo-web/methods/fill-password.method.block.js";
7
+ import { SubmitLoginBlock } from "../blocks/saucedemo-web/methods/submit-login.method.block.js";
8
+ import { loginFailed } from "../stubs/login.js";
9
+
10
+ /**
11
+ * Forces a verify failure (locked_out_user is refused, but the verify demands the inventory page) to show `stubOnError` ringing
12
+ * the error banner before the failure panel. Needs locked_out_user credentials: `--data` or mem.
13
+ */
14
+ export const stubOnErrorFlow = engine
15
+ .map({
16
+ expectedFailure:
17
+ "Intentional verify fail - stubOnError rings the error banner before the panel",
18
+ })
19
+ .start()
20
+ .gotoPage(
21
+ NavLoginBlock.stubBefore((ctx) =>
22
+ ctx.title("stubOnError: locked_out fail rings"),
23
+ ),
24
+ )
25
+ .method(FillUsernameBlock)
26
+ .method(FillPasswordBlock)
27
+ .method(SubmitLoginBlock.stubOnError(loginFailed))
28
+ .end()
29
+ .withBlockVerify("submit-login", [
30
+ Trait.url({ pathname: "/inventory.html" }),
31
+ ]);
@@ -1,40 +1,32 @@
1
- import { Engine, withTitle, withSessionReset, withExpectedFailure } from "waygraph";
1
+ import { engine } from "../../config/waygraph.config.js";
2
+ import "../states/checkout.mem-stubs.js";
2
3
  import { NavLoginBlock } from "../blocks/saucedemo-web/nav-login.block.js";
3
4
  import { FillUsernameBlock } from "../blocks/saucedemo-web/methods/fill-username.method.block.js";
4
5
  import { FillPasswordBlock } from "../blocks/saucedemo-web/methods/fill-password.method.block.js";
5
6
  import { SubmitLoginBlock } from "../blocks/saucedemo-web/methods/submit-login.method.block.js";
7
+ import { loginRefused } from "../stubs/login.js";
6
8
 
7
- const engine = new Engine();
8
-
9
- // A genuinely DIFFERENT scenario from checkoutFlow - not the same steps
10
- // split in half. Same login blocks, different user, different outcome:
11
- // locked_out_user attempts the exact same login an Owner (standard_user,
12
- // checkoutFlow) just completed successfully, and is blocked -
13
- // saucedemo.com's real response, verified live: stays on "/", shows
14
- // "Epic sadface: Sorry, this user has been locked out."
15
- //
16
- // withSessionReset matters here for real, not cosmetically - entered right
17
- // after checkoutFlow's already-authenticated session, this needs its own
18
- // genuinely fresh cookies/storage, or the previous user's session would
19
- // still be live and this login attempt wouldn't mean anything.
20
- //
21
- // submit-login branches: observe sees no /inventory.html navigation,
22
- // resolve -> LoginPage, verify confirms the error banner. Demo still wraps
23
- // withExpectedFailure so step 9/9 shows stubOnError rings + amber
24
- // "expected outcome" panel (branching no longer throws).
25
- export const viewerBlockedFlow = withExpectedFailure(
26
- withTitle(
27
- withSessionReset(
28
- engine
29
- .map()
30
- .start()
31
- .gotoPage(NavLoginBlock)
32
- .method(FillUsernameBlock)
33
- .method(FillPasswordBlock)
34
- .method(SubmitLoginBlock)
35
- .end(),
9
+ /**
10
+ * locked_out_user attempts the login a standard user just completed and is refused: the app stays on the login page and
11
+ * shows the error banner. Run it after another flow to see it needs a reset: `.flow(viewerBlockedFlow, { reset: true })`.
12
+ */
13
+ export const viewerBlockedFlow = engine
14
+ .map({
15
+ sessionReset: true,
16
+ expectedFailure:
17
+ "locked_out_user stays on LoginPage with the error banner - this is the product working as intended.",
18
+ })
19
+ .start()
20
+ .gotoPage(
21
+ NavLoginBlock.stubBefore((ctx) =>
22
+ ctx.title("Viewer: Blocked Login Attempt"),
36
23
  ),
37
- "Viewer: Blocked Login Attempt",
38
- ),
39
- "locked_out_user stays on LoginPage with the error banner - this is the product working as intended.",
40
- );
24
+ )
25
+ .method(FillUsernameBlock)
26
+ .method(FillPasswordBlock)
27
+ .method(
28
+ SubmitLoginBlock.stubAfter((ctx) => {
29
+ if (ctx.out?.__state === "LoginPage") loginRefused(ctx);
30
+ }),
31
+ )
32
+ .end();
@@ -0,0 +1,11 @@
1
+ import { registerMemStub } from "waygraph";
2
+ import { LoginCreds, SelectedItem } from "./checkout.mem-keys.js";
3
+
4
+ registerMemStub(LoginCreds.key, () => ({
5
+ username: "standard_user",
6
+ password: "secret_sauce",
7
+ }));
8
+ registerMemStub(SelectedItem.key, () => ({
9
+ id: "sauce-labs-backpack",
10
+ name: "Sauce Labs Backpack",
11
+ }));