waygraph 0.7.11 → 0.7.13

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 (84) hide show
  1. package/README.md +2 -0
  2. package/dist/auto-explore-run.js +15 -1
  3. package/dist/cli.d.ts +1 -1
  4. package/dist/cli.js +61 -21
  5. package/dist/step-overlay.js +29 -20
  6. package/examples/saucedemo/README.md +35 -8
  7. package/examples/saucedemo/docs/CONVENTION.md +32 -14
  8. package/examples/saucedemo/package-lock.json +118 -0
  9. package/examples/saucedemo/scripts/capture-wrong-login.mjs +2 -2
  10. package/examples/saucedemo/scripts/prove-wrong-login-runtime.mjs +2 -2
  11. package/examples/saucedemo/src/blocks/SITE-MAP.md +43 -0
  12. package/examples/saucedemo/src/blocks/saucedemo-web/NAV.md +26 -0
  13. package/examples/saucedemo/src/blocks/saucedemo-web/actions/submit-login-for-flow.ts +13 -0
  14. package/examples/saucedemo/src/blocks/{actions → saucedemo-web/actions}/submit-login.action.block.ts +14 -10
  15. package/{templates/quickstart/src/blocks → examples/saucedemo/src/blocks/saucedemo-web}/actions/submit-logout.action.block.ts +8 -3
  16. package/examples/saucedemo/src/blocks/saucedemo-web/cart/NAV.md +22 -0
  17. package/{templates/quickstart/src/blocks → examples/saucedemo/src/blocks/saucedemo-web/cart}/nav-cart.block.ts +8 -3
  18. package/{templates/quickstart/src/blocks → examples/saucedemo/src/blocks/saucedemo-web/cart}/nav-checkout-info.block.ts +8 -1
  19. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/NAV.md +21 -0
  20. package/{templates/quickstart/src/blocks → examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one}/actions/submit-checkout-info.action.block.ts +9 -6
  21. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/NAV.md +21 -0
  22. package/{templates/quickstart/src/blocks → examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two}/actions/finish-order.action.block.ts +8 -1
  23. package/examples/saucedemo/src/blocks/saucedemo-web/inventory/NAV.md +26 -0
  24. package/examples/saucedemo/src/blocks/{actions → saucedemo-web/inventory/actions}/add-to-cart.effect.block.ts +10 -4
  25. package/{templates/quickstart/src/blocks → examples/saucedemo/src/blocks/saucedemo-web/inventory}/actions/inventory-items.ts +8 -0
  26. package/{templates/quickstart/src/blocks → examples/saucedemo/src/blocks/saucedemo-web/inventory}/actions/remove-from-cart.effect.block.ts +10 -4
  27. package/examples/saucedemo/src/blocks/{nav-item-detail.block.ts → saucedemo-web/inventory/nav-item-detail.block.ts} +10 -4
  28. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/NAV.md +25 -0
  29. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.ts +18 -0
  30. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-back-to-products.block.ts +18 -0
  31. package/examples/saucedemo/src/blocks/{nav-continue-shopping.block.ts → saucedemo-web/inventory-item/nav-continue-shopping.block.ts} +8 -2
  32. package/examples/saucedemo/src/blocks/{nav-login.block.ts → saucedemo-web/nav-login.block.ts} +8 -3
  33. package/examples/saucedemo/src/flows/cart-continue.flow.ts +2 -2
  34. package/examples/saucedemo/src/flows/cart-mem.flow.ts +1 -1
  35. package/examples/saucedemo/src/flows/catalog-logout.flow.ts +3 -3
  36. package/examples/saucedemo/src/flows/checkout-then-browse-again.flow.ts +8 -8
  37. package/examples/saucedemo/src/flows/checkout.flow.ts +7 -7
  38. package/examples/saucedemo/src/flows/login.flow.ts +2 -2
  39. package/examples/saucedemo/src/flows/shop.flow.ts +5 -5
  40. package/examples/saucedemo/src/flows/smoke.flow.ts +3 -3
  41. package/examples/saucedemo/src/flows/viewer-blocked.flow.ts +2 -2
  42. package/examples/saucedemo/tests/flow-block-verify.spec.ts +1 -1
  43. package/examples/saucedemo/tests/submit-login-branch.spec.ts +2 -2
  44. package/package.json +1 -1
  45. package/templates/quickstart/README.md +10 -0
  46. package/templates/quickstart/docs/CONVENTION.md +48 -26
  47. package/templates/quickstart/package.json +1 -1
  48. package/templates/quickstart/src/blocks/SITE-MAP.md +43 -0
  49. package/templates/quickstart/src/blocks/saucedemo-web/NAV.md +26 -0
  50. package/templates/quickstart/src/blocks/saucedemo-web/actions/submit-login-for-flow.ts +13 -0
  51. package/templates/quickstart/src/blocks/{actions → saucedemo-web/actions}/submit-login.action.block.ts +14 -10
  52. package/{examples/saucedemo/src/blocks → templates/quickstart/src/blocks/saucedemo-web}/actions/submit-logout.action.block.ts +8 -3
  53. package/templates/quickstart/src/blocks/saucedemo-web/cart/NAV.md +22 -0
  54. package/{examples/saucedemo/src/blocks → templates/quickstart/src/blocks/saucedemo-web/cart}/nav-cart.block.ts +8 -3
  55. package/{examples/saucedemo/src/blocks → templates/quickstart/src/blocks/saucedemo-web/cart}/nav-checkout-info.block.ts +8 -1
  56. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/NAV.md +21 -0
  57. package/{examples/saucedemo/src/blocks → templates/quickstart/src/blocks/saucedemo-web/checkout-step-one}/actions/submit-checkout-info.action.block.ts +9 -6
  58. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/NAV.md +21 -0
  59. package/{examples/saucedemo/src/blocks → templates/quickstart/src/blocks/saucedemo-web/checkout-step-two}/actions/finish-order.action.block.ts +8 -1
  60. package/templates/quickstart/src/blocks/saucedemo-web/inventory/NAV.md +26 -0
  61. package/templates/quickstart/src/blocks/{actions → saucedemo-web/inventory/actions}/add-to-cart.effect.block.ts +10 -4
  62. package/{examples/saucedemo/src/blocks → templates/quickstart/src/blocks/saucedemo-web/inventory}/actions/inventory-items.ts +8 -0
  63. package/{examples/saucedemo/src/blocks → templates/quickstart/src/blocks/saucedemo-web/inventory}/actions/remove-from-cart.effect.block.ts +10 -4
  64. package/templates/quickstart/src/blocks/{nav-item-detail.block.ts → saucedemo-web/inventory/nav-item-detail.block.ts} +10 -4
  65. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/NAV.md +25 -0
  66. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.ts +18 -0
  67. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-back-to-products.block.ts +18 -0
  68. package/templates/quickstart/src/blocks/{nav-continue-shopping.block.ts → saucedemo-web/inventory-item/nav-continue-shopping.block.ts} +8 -2
  69. package/templates/quickstart/src/blocks/{nav-login.block.ts → saucedemo-web/nav-login.block.ts} +8 -3
  70. package/templates/quickstart/src/flows/cart-continue.flow.ts +2 -2
  71. package/templates/quickstart/src/flows/cart-mem.flow.ts +1 -1
  72. package/templates/quickstart/src/flows/catalog-logout.flow.ts +3 -3
  73. package/templates/quickstart/src/flows/checkout-then-browse-again.flow.ts +8 -8
  74. package/templates/quickstart/src/flows/checkout.flow.ts +7 -7
  75. package/templates/quickstart/src/flows/login.flow.ts +2 -2
  76. package/templates/quickstart/src/flows/shop.flow.ts +5 -5
  77. package/templates/quickstart/src/flows/smoke.flow.ts +3 -3
  78. package/templates/quickstart/src/flows/viewer-blocked.flow.ts +2 -2
  79. package/examples/saucedemo/src/blocks/actions/submit-login-for-flow.ts +0 -10
  80. package/examples/saucedemo/src/blocks/nav-back-to-inventory.block.ts +0 -15
  81. package/examples/saucedemo/src/blocks/nav-back-to-products.block.ts +0 -14
  82. package/templates/quickstart/src/blocks/actions/submit-login-for-flow.ts +0 -10
  83. package/templates/quickstart/src/blocks/nav-back-to-inventory.block.ts +0 -15
  84. package/templates/quickstart/src/blocks/nav-back-to-products.block.ts +0 -14
@@ -1,15 +1,17 @@
1
1
  import { defineBlock, checkpoint, Trait } from "waygraph";
2
- import type { LoginPage, LoginSubmitOutcome } from "../../states/checkout.states.js";
3
- import { LoginCreds } from "../../states/checkout.mem-keys.js";
2
+ import type { LoginPage, LoginSubmitOutcome } from "../../../states/checkout.states.js";
3
+ import { LoginCreds } from "../../../states/checkout.mem-keys.js";
4
4
 
5
5
  type LoginObserve = "success" | "failure";
6
6
 
7
- // Fills credentials on the login page and submits - never navigates (nav-login.block.ts
8
- // does that). Port of the old login.block.ts with the goto split out.
9
- //
10
- // Branches on real auth outcome: good creds -> LoggedIn; bad creds / locked user ->
11
- // LoginPage (error banner visible). waygraph auto stays on LoginPage instead of
12
- // pretending the run reached inventory.
7
+ /**
8
+ * Kind: Action
9
+ * Helper: defineBlock
10
+ * Route: saucedemo-web/actions/ (page URL /)
11
+ *
12
+ * Fills credentials and submits - never page.goto (nav-login owns that).
13
+ * Branches: good creds -> LoggedIn; bad/locked -> LoginPage with error banner.
14
+ */
13
15
  export const SubmitLoginActionBlock = defineBlock<LoginPage, LoginSubmitOutcome>({
14
16
  name: "submit-login",
15
17
  description: "Logs a user in when credentials are valid; stays on LoginPage when auth fails.",
@@ -19,11 +21,13 @@ export const SubmitLoginActionBlock = defineBlock<LoginPage, LoginSubmitOutcome>
19
21
  const { username, password } = mem.get(LoginCreds.key);
20
22
  await page.locator("#user-name").fill(username);
21
23
  await page.locator("#password").fill(password);
22
- await page.locator("#login-button").click();
24
+ // noWaitAfter: observe owns the inventory URL wait. Default click
25
+ // navigation-wait can hang under waygraph auto's demo cursor patch.
26
+ await page.locator("#login-button").click({ noWaitAfter: true });
23
27
  },
24
28
  async observe(page): Promise<LoginObserve> {
25
29
  try {
26
- await page.waitForURL(/\/inventory\.html/, { timeout: 5_000 });
30
+ await page.waitForURL(/\/inventory\.html/, { timeout: 8_000 });
27
31
  return "success";
28
32
  } catch {
29
33
  return "failure";
@@ -1,8 +1,13 @@
1
1
  import { defineBlock, checkpoint, Trait } from "waygraph";
2
- import type { LoggedIn, LoginPage } from "../../states/checkout.states.js";
2
+ import type { LoggedIn, LoginPage } from "../../../states/checkout.states.js";
3
3
 
4
- // Opens the burger menu and clicks Logout - completes the graph's own real
5
- // cycle back to LoginPage, the same Checkpoint nav-login.block.ts lands on.
4
+ /**
5
+ * Kind: Action
6
+ * Helper: defineBlock
7
+ * Route: saucedemo-web/actions/ (page URL / after logout)
8
+ *
9
+ * Burger menu Logout - real cycle back to LoginPage (same Checkpoint nav-login lands on).
10
+ */
6
11
  export const SubmitLogoutBlock = defineBlock<LoggedIn, LoginPage>({
7
12
  name: "submit-logout",
8
13
  description: "Opens the burger menu and logs out.",
@@ -0,0 +1,22 @@
1
+ # cart/ - URL `/cart.html`
2
+
3
+ Shopping cart page and checkout entry.
4
+
5
+ ## URL
6
+
7
+ - `/cart.html`
8
+
9
+ ## Nav blocks
10
+
11
+ | File | Helper | Notes |
12
+ |------|--------|-------|
13
+ | `nav-cart.block.ts` | `defineNavBlock` | Header cart link (`click`, not url) |
14
+ | `nav-checkout-info.block.ts` | `defineNavBlock` | "Checkout" button -> step one |
15
+
16
+ ## Effects / actions
17
+
18
+ (none on this route; cart mutations live under `inventory/actions/`)
19
+
20
+ ## Related mem keys / checkpoints
21
+
22
+ - Checkpoints: `CartPage`, `CheckoutInfoPage`, `ItemInCart` / `LoggedIn` (cart contents)
@@ -1,8 +1,13 @@
1
1
  import { defineNavBlock, Trait } from "waygraph";
2
- import type { CartPage } from "../states/checkout.states.js";
2
+ import type { CartPage } from "../../../states/checkout.states.js";
3
3
 
4
- // click, not url - the real "Cart" link in the page header, clickable from
5
- // any inventory-adjacent page (with or without an item already added).
4
+ /**
5
+ * Kind: Nav
6
+ * Helper: defineNavBlock
7
+ * Route: saucedemo-web/cart/ (= /cart.html)
8
+ *
9
+ * click, not url - header cart link from inventory-adjacent pages.
10
+ */
6
11
  export const NavCartBlock = defineNavBlock<CartPage>({
7
12
  name: "nav-cart",
8
13
  description: "Clicks the cart link in the header.",
@@ -1,6 +1,13 @@
1
1
  import { defineNavBlock, Trait } from "waygraph";
2
- import type { CheckoutInfoPage } from "../states/checkout.states.js";
2
+ import type { CheckoutInfoPage } from "../../../states/checkout.states.js";
3
3
 
4
+ /**
5
+ * Kind: Nav
6
+ * Helper: defineNavBlock
7
+ * Route: saucedemo-web/cart/ (click leaves /cart.html -> /checkout-step-one.html)
8
+ *
9
+ * Cart page "Checkout" button - owns the nav into step one.
10
+ */
4
11
  export const NavCheckoutInfoBlock = defineNavBlock<CheckoutInfoPage>({
5
12
  name: "nav-checkout-info",
6
13
  description: "Clicks 'Checkout' on the cart page.",
@@ -0,0 +1,21 @@
1
+ # checkout-step-one/ - URL `/checkout-step-one.html`
2
+
3
+ Shipping info form before order overview.
4
+
5
+ ## URL
6
+
7
+ - `/checkout-step-one.html`
8
+
9
+ ## Nav blocks
10
+
11
+ (none - arrival is via `cart/nav-checkout-info.block.ts`)
12
+
13
+ ## Effects / actions
14
+
15
+ | File | Kind | Notes |
16
+ |------|------|-------|
17
+ | `actions/submit-checkout-info.action.block.ts` | Action | Fill form + Continue -> overview |
18
+
19
+ ## Related mem keys / checkpoints
20
+
21
+ - Checkpoints: `CheckoutInfoPage`, `CheckoutOverviewPage`
@@ -1,11 +1,14 @@
1
1
  import { defineBlock, checkpoint, Trait } from "waygraph";
2
- import type { CheckoutInfoPage, CheckoutOverviewPage } from "../../states/checkout.states.js";
2
+ import type { CheckoutInfoPage, CheckoutOverviewPage } from "../../../../states/checkout.states.js";
3
3
 
4
- // Fills the shipping info form and continues - never navigates
5
- // (nav-checkout-info.block.ts already got here). Replaces the old
6
- // checkout-info.action.block.ts, which used to also click the cart link and
7
- // the checkout button itself - three real page transitions bundled into one
8
- // non-atomic Block.
4
+ /**
5
+ * Kind: Action
6
+ * Helper: defineBlock
7
+ * Route: saucedemo-web/checkout-step-one/actions/ (= /checkout-step-one.html)
8
+ *
9
+ * Fills shipping form and continues - never navigates itself
10
+ * (nav-checkout-info already got here).
11
+ */
9
12
  export const SubmitCheckoutInfoBlock = defineBlock<CheckoutInfoPage, CheckoutOverviewPage>({
10
13
  name: "submit-checkout-info",
11
14
  description: "Fills in the shipping info form and continues to the order overview.",
@@ -0,0 +1,21 @@
1
+ # checkout-step-two/ - URL `/checkout-step-two.html`
2
+
3
+ Order overview / finish page.
4
+
5
+ ## URL
6
+
7
+ - `/checkout-step-two.html`
8
+
9
+ ## Nav blocks
10
+
11
+ (none - arrival is via submit-checkout-info Action)
12
+
13
+ ## Effects / actions
14
+
15
+ | File | Kind | Notes |
16
+ |------|------|-------|
17
+ | `actions/finish-order.action.block.ts` | Action | Finish -> thank-you / OrderComplete |
18
+
19
+ ## Related mem keys / checkpoints
20
+
21
+ - Checkpoints: `CheckoutOverviewPage`, `OrderComplete`
@@ -1,6 +1,13 @@
1
1
  import { defineBlock, checkpoint, Trait, narrate } from "waygraph";
2
- import type { CheckoutOverviewPage, OrderComplete } from "../../states/checkout.states.js";
2
+ import type { CheckoutOverviewPage, OrderComplete } from "../../../../states/checkout.states.js";
3
3
 
4
+ /**
5
+ * Kind: Action
6
+ * Helper: defineBlock
7
+ * Route: saucedemo-web/checkout-step-two/actions/ (= /checkout-step-two.html)
8
+ *
9
+ * Places the order on the overview page - form/finish click, not a NavBlock.
10
+ */
4
11
  export const FinishOrderBlock = defineBlock<CheckoutOverviewPage, OrderComplete>({
5
12
  name: "finish-order",
6
13
  description: "Places the order and confirms the 'Thank you for your order!' completion page.",
@@ -0,0 +1,26 @@
1
+ # inventory/ - URL `/inventory.html`
2
+
3
+ Product catalog after a successful login.
4
+
5
+ ## URL
6
+
7
+ - `/inventory.html`
8
+
9
+ ## Nav blocks
10
+
11
+ | File | Helper | Notes |
12
+ |------|--------|-------|
13
+ | `nav-item-detail.block.ts` | `defineMemNavBlock` | Opens mem-picked product detail; instance rows per card |
14
+
15
+ ## Effects / actions
16
+
17
+ | File | Kind | Notes |
18
+ |------|------|-------|
19
+ | `actions/add-to-cart.effect.block.ts` | Effect | Add mem-picked item; instance menu |
20
+ | `actions/remove-from-cart.effect.block.ts` | Effect | Remove mem-picked item; may empty cart |
21
+ | `actions/inventory-items.ts` | helper | DOM collectors (not a Block) |
22
+
23
+ ## Related mem keys / checkpoints
24
+
25
+ - Mem: `saucedemo.selectedItem` (`SelectedItem`)
26
+ - Checkpoints: `LoggedIn`, `ItemInCart`, `ItemDetailPage` (via MemNav)
@@ -1,10 +1,16 @@
1
1
  import { defineEffectBlock, checkpoint, type Checkpoint, type WaygraphInstanceOption } from "waygraph";
2
- import type { ItemInCart } from "../../states/checkout.states.js";
3
- import { SelectedItem } from "../../states/checkout.mem-keys.js";
2
+ import type { ItemInCart } from "../../../../states/checkout.states.js";
3
+ import { SelectedItem } from "../../../../states/checkout.mem-keys.js";
4
4
  import { collectAddableItems } from "./inventory-items.js";
5
5
 
6
- // EffectBlock: mutates cart for the mem-picked product. waygraph auto lists
7
- // one "Add …" row per live Add button via instanceOptions.
6
+ /**
7
+ * Kind: Effect
8
+ * Helper: defineEffectBlock
9
+ * Route: saucedemo-web/inventory/actions/ (= /inventory.html)
10
+ *
11
+ * Mutates cart for the mem-picked product. waygraph auto lists one
12
+ * "Add ..." row per live Add button via instanceOptions.
13
+ */
8
14
  export const AddToCartBlock = defineEffectBlock<Checkpoint<string>, ItemInCart>({
9
15
  name: "add-to-cart",
10
16
  description: "Adds the item named by mem (saucedemo.selectedItem) to the cart.",
@@ -1,5 +1,13 @@
1
1
  import type { Page, Locator } from "@playwright/test";
2
2
 
3
+ /**
4
+ * Kind: helper (not a Block)
5
+ * Route: saucedemo-web/inventory/actions/ (= /inventory.html)
6
+ *
7
+ * DOM collectors for Effect / MemNav instanceOptions. Discovery ignores this
8
+ * file (no *.block.ts suffix). Keep selectors here so add/remove/detail stay thin.
9
+ */
10
+
3
11
  /** Product slug + display name (saucedemo inventory / detail / cart). */
4
12
  export type InventoryItem = { id: string; name: string };
5
13
 
@@ -1,12 +1,18 @@
1
1
  import { defineEffectBlock, checkpoint, type Checkpoint, type WaygraphInstanceOption } from "waygraph";
2
- import type { RemoveFromCartOutcome } from "../../states/checkout.states.js";
3
- import { SelectedItem } from "../../states/checkout.mem-keys.js";
2
+ import type { RemoveFromCartOutcome } from "../../../../states/checkout.states.js";
3
+ import { SelectedItem } from "../../../../states/checkout.mem-keys.js";
4
4
  import { collectRemovableItems } from "./inventory-items.js";
5
5
 
6
6
  type RemoveObserve = "still-has-items" | "cart-empty";
7
7
 
8
- // EffectBlock: removes the mem-picked product. After Add, waygraph auto
9
- // shows matching "Remove …" rows from the live Remove buttons.
8
+ /**
9
+ * Kind: Effect
10
+ * Helper: defineEffectBlock
11
+ * Route: saucedemo-web/inventory/actions/ (= /inventory.html)
12
+ *
13
+ * Removes the mem-picked product. After Add, waygraph auto shows matching
14
+ * "Remove ..." rows from live Remove buttons.
15
+ */
10
16
  export const RemoveFromCartBlock = defineEffectBlock<Checkpoint<string>, RemoveFromCartOutcome>({
11
17
  name: "remove-from-cart",
12
18
  description: "Removes the item named by mem (saucedemo.selectedItem) from the cart.",
@@ -1,13 +1,19 @@
1
1
  import { defineMemNavBlock, Trait, type WaygraphInstanceOption } from "waygraph";
2
- import type { ItemDetailPage } from "../states/checkout.states.js";
3
- import { SelectedItem } from "../states/checkout.mem-keys.js";
2
+ import type { ItemDetailPage } from "../../../states/checkout.states.js";
3
+ import { SelectedItem } from "../../../states/checkout.mem-keys.js";
4
4
  import {
5
5
  collectInventoryItems,
6
6
  inventoryItemTitleSelector,
7
7
  } from "./actions/inventory-items.js";
8
8
 
9
- // MemNavBlock: opens the mem-picked product's detail page. waygraph auto
10
- // lists one "Open … details" row per inventory card (not only the first item).
9
+ /**
10
+ * Kind: Nav
11
+ * Helper: defineMemNavBlock
12
+ * Route: saucedemo-web/inventory/ (= /inventory.html)
13
+ *
14
+ * Opens the mem-picked product detail page. waygraph auto lists one
15
+ * "Open ... details" row per inventory card via instanceOptions.
16
+ */
11
17
  export const NavItemDetailBlock = defineMemNavBlock<ItemDetailPage>({
12
18
  name: "nav-item-detail",
13
19
  description: "Opens the product named by mem (saucedemo.selectedItem) on its detail page.",
@@ -0,0 +1,25 @@
1
+ # inventory-item/ - URL `/inventory-item.html`
2
+
3
+ Single product detail page, plus nav edges that return to catalog
4
+ (continue shopping / back home / back to products).
5
+
6
+ ## URL
7
+
8
+ - `/inventory-item.html` (detail)
9
+ - Related landings: `/inventory.html` (via back / continue-shopping clicks)
10
+
11
+ ## Nav blocks
12
+
13
+ | File | Helper | Notes |
14
+ |------|--------|-------|
15
+ | `nav-continue-shopping.block.ts` | `defineNavBlock` | Cart "Continue Shopping" -> inventory |
16
+ | `nav-back-to-products.block.ts` | `defineNavBlock` | Order-complete "Back Home" -> inventory |
17
+ | `nav-back-to-inventory.block.ts` | `defineNavBlock` | Detail "Back to products" -> inventory |
18
+
19
+ ## Effects / actions
20
+
21
+ (none on this route)
22
+
23
+ ## Related mem keys / checkpoints
24
+
25
+ - Checkpoints: `ItemDetailPage`, `LoggedIn` (after back / continue), `OrderComplete` (from for back-to-products)
@@ -0,0 +1,18 @@
1
+ import { defineNavBlock, Trait } from "waygraph";
2
+ import type { LoggedIn } from "../../../states/checkout.states.js";
3
+
4
+ /**
5
+ * Kind: Nav
6
+ * Helper: defineNavBlock
7
+ * Route: saucedemo-web/inventory-item/ (= /inventory-item.html From)
8
+ *
9
+ * click, not url - detail page "Back to products". Separate Block from
10
+ * nav-back-to-products (different From Checkpoint; atomic convention).
11
+ */
12
+ export const NavBackToInventoryBlock = defineNavBlock<LoggedIn>({
13
+ name: "nav-back-to-inventory",
14
+ description: "Clicks 'Back to products' on the item detail page.",
15
+ checkpoint: "LoggedIn",
16
+ click: "#back-to-products",
17
+ verify: [Trait.url({ pathname: "/inventory.html" })],
18
+ });
@@ -0,0 +1,18 @@
1
+ import { defineNavBlock, Trait } from "waygraph";
2
+ import type { LoggedIn } from "../../../states/checkout.states.js";
3
+
4
+ /**
5
+ * Kind: Nav
6
+ * Helper: defineNavBlock
7
+ * Route: saucedemo-web/inventory-item/ (lands on /inventory.html)
8
+ *
9
+ * click, not url - order-complete "Back Home" proves the button path
10
+ * (a url NavBlock would teleport without exercising the control).
11
+ */
12
+ export const NavBackToProductsBlock = defineNavBlock<LoggedIn>({
13
+ name: "nav-back-to-products",
14
+ description: "Clicks 'Back Home' on the order confirmation page.",
15
+ checkpoint: "LoggedIn",
16
+ click: "#back-to-products",
17
+ verify: [Trait.url({ pathname: "/inventory.html" })],
18
+ });
@@ -1,7 +1,13 @@
1
1
  import { defineNavBlock, Trait } from "waygraph";
2
- import type { LoggedIn } from "../states/checkout.states.js";
2
+ import type { LoggedIn } from "../../../states/checkout.states.js";
3
3
 
4
- // click, not url - the cart page's own real "Continue Shopping" button.
4
+ /**
5
+ * Kind: Nav
6
+ * Helper: defineNavBlock
7
+ * Route: saucedemo-web/inventory-item/ (lands on /inventory.html)
8
+ *
9
+ * click, not url - cart page "Continue Shopping" proves the app's own path.
10
+ */
5
11
  export const NavContinueShoppingBlock = defineNavBlock<LoggedIn>({
6
12
  name: "nav-continue-shopping",
7
13
  description: "Clicks 'Continue Shopping' on the cart page.",
@@ -1,8 +1,13 @@
1
1
  import { defineNavBlock, Trait } from "waygraph";
2
- import type { LoginPage } from "../states/checkout.states.js";
2
+ import type { LoginPage } from "../../states/checkout.states.js";
3
3
 
4
- // Nav to the login page (/). page.goto lives here, generated by defineNavBlock -
5
- // actions/submit-login.action.block.ts never navigates.
4
+ /**
5
+ * Kind: Nav
6
+ * Helper: defineNavBlock
7
+ * Route: saucedemo-web/ (= /)
8
+ *
9
+ * page.goto to the login form lives here only. submit-login Action never navigates.
10
+ */
6
11
  export const NavLoginBlock = defineNavBlock<LoginPage>({
7
12
  name: "nav-login",
8
13
  description: "Goes to the Swag Labs login page.",
@@ -1,6 +1,6 @@
1
1
  import { Engine, start, end, withTitle } from "waygraph";
2
- import { NavCartBlock } from "../blocks/nav-cart.block.js";
3
- import { NavContinueShoppingBlock } from "../blocks/nav-continue-shopping.block.js";
2
+ import { NavCartBlock } from "../blocks/saucedemo-web/cart/nav-cart.block.js";
3
+ import { NavContinueShoppingBlock } from "../blocks/saucedemo-web/inventory-item/nav-continue-shopping.block.js";
4
4
 
5
5
  const engine = new Engine();
6
6
 
@@ -1,5 +1,5 @@
1
1
  import { Engine, start, end } from "waygraph";
2
- import { RemoveFromCartBlock } from "../blocks/actions/remove-from-cart.effect.block.js";
2
+ import { RemoveFromCartBlock } from "../blocks/saucedemo-web/inventory/actions/remove-from-cart.effect.block.js";
3
3
 
4
4
  const engine = new Engine();
5
5
 
@@ -1,7 +1,7 @@
1
1
  import { Engine, start, end, withTitle } from "waygraph";
2
- import { NavItemDetailBlock } from "../blocks/nav-item-detail.block.js";
3
- import { NavBackToInventoryBlock } from "../blocks/nav-back-to-inventory.block.js";
4
- import { SubmitLogoutBlock } from "../blocks/actions/submit-logout.action.block.js";
2
+ import { NavItemDetailBlock } from "../blocks/saucedemo-web/inventory/nav-item-detail.block.js";
3
+ import { NavBackToInventoryBlock } from "../blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.js";
4
+ import { SubmitLogoutBlock } from "../blocks/saucedemo-web/actions/submit-logout.action.block.js";
5
5
 
6
6
  const engine = new Engine();
7
7
 
@@ -8,14 +8,14 @@ import type {
8
8
  CheckoutOverviewPage,
9
9
  OrderComplete,
10
10
  } from "../states/checkout.states.js";
11
- import { NavLoginBlock } from "../blocks/nav-login.block.js";
12
- import { SubmitLoginForFlow } from "../blocks/actions/submit-login-for-flow.js";
13
- import { AddToCartBlock } from "../blocks/actions/add-to-cart.effect.block.js";
14
- import { NavCartBlock } from "../blocks/nav-cart.block.js";
15
- import { NavCheckoutInfoBlock } from "../blocks/nav-checkout-info.block.js";
16
- import { SubmitCheckoutInfoBlock } from "../blocks/actions/submit-checkout-info.action.block.js";
17
- import { FinishOrderBlock } from "../blocks/actions/finish-order.action.block.js";
18
- import { NavBackToProductsBlock } from "../blocks/nav-back-to-products.block.js";
11
+ import { NavLoginBlock } from "../blocks/saucedemo-web/nav-login.block.js";
12
+ import { SubmitLoginForFlow } from "../blocks/saucedemo-web/actions/submit-login-for-flow.js";
13
+ import { AddToCartBlock } from "../blocks/saucedemo-web/inventory/actions/add-to-cart.effect.block.js";
14
+ import { NavCartBlock } from "../blocks/saucedemo-web/cart/nav-cart.block.js";
15
+ import { NavCheckoutInfoBlock } from "../blocks/saucedemo-web/cart/nav-checkout-info.block.js";
16
+ import { SubmitCheckoutInfoBlock } from "../blocks/saucedemo-web/checkout-step-one/actions/submit-checkout-info.action.block.js";
17
+ import { FinishOrderBlock } from "../blocks/saucedemo-web/checkout-step-two/actions/finish-order.action.block.js";
18
+ import { NavBackToProductsBlock } from "../blocks/saucedemo-web/inventory-item/nav-back-to-products.block.js";
19
19
 
20
20
  const engine = new Engine({ headless: false, slowMo: 250 });
21
21
 
@@ -8,13 +8,13 @@ import type {
8
8
  CheckoutOverviewPage,
9
9
  OrderComplete,
10
10
  } from "../states/checkout.states.js";
11
- import { NavLoginBlock } from "../blocks/nav-login.block.js";
12
- import { SubmitLoginForFlow } from "../blocks/actions/submit-login-for-flow.js";
13
- import { AddToCartBlock } from "../blocks/actions/add-to-cart.effect.block.js";
14
- import { NavCartBlock } from "../blocks/nav-cart.block.js";
15
- import { NavCheckoutInfoBlock } from "../blocks/nav-checkout-info.block.js";
16
- import { SubmitCheckoutInfoBlock } from "../blocks/actions/submit-checkout-info.action.block.js";
17
- import { FinishOrderBlock } from "../blocks/actions/finish-order.action.block.js";
11
+ import { NavLoginBlock } from "../blocks/saucedemo-web/nav-login.block.js";
12
+ import { SubmitLoginForFlow } from "../blocks/saucedemo-web/actions/submit-login-for-flow.js";
13
+ import { AddToCartBlock } from "../blocks/saucedemo-web/inventory/actions/add-to-cart.effect.block.js";
14
+ import { NavCartBlock } from "../blocks/saucedemo-web/cart/nav-cart.block.js";
15
+ import { NavCheckoutInfoBlock } from "../blocks/saucedemo-web/cart/nav-checkout-info.block.js";
16
+ import { SubmitCheckoutInfoBlock } from "../blocks/saucedemo-web/checkout-step-one/actions/submit-checkout-info.action.block.js";
17
+ import { FinishOrderBlock } from "../blocks/saucedemo-web/checkout-step-two/actions/finish-order.action.block.js";
18
18
 
19
19
  const engine = new Engine({ headless: false, slowMo: 250 });
20
20
 
@@ -1,6 +1,6 @@
1
1
  import { Engine, start, end, withTitle } from "waygraph";
2
- import { NavLoginBlock } from "../blocks/nav-login.block.js";
3
- import { SubmitLoginForFlow } from "../blocks/actions/submit-login-for-flow.js";
2
+ import { NavLoginBlock } from "../blocks/saucedemo-web/nav-login.block.js";
3
+ import { SubmitLoginForFlow } from "../blocks/saucedemo-web/actions/submit-login-for-flow.js";
4
4
 
5
5
  const engine = new Engine();
6
6
 
@@ -1,9 +1,9 @@
1
1
  import { Engine, start, end, withTitle } from "waygraph";
2
- import { AddToCartBlock } from "../blocks/actions/add-to-cart.effect.block.js";
3
- import { NavCartBlock } from "../blocks/nav-cart.block.js";
4
- import { NavCheckoutInfoBlock } from "../blocks/nav-checkout-info.block.js";
5
- import { SubmitCheckoutInfoBlock } from "../blocks/actions/submit-checkout-info.action.block.js";
6
- import { FinishOrderBlock } from "../blocks/actions/finish-order.action.block.js";
2
+ import { AddToCartBlock } from "../blocks/saucedemo-web/inventory/actions/add-to-cart.effect.block.js";
3
+ import { NavCartBlock } from "../blocks/saucedemo-web/cart/nav-cart.block.js";
4
+ import { NavCheckoutInfoBlock } from "../blocks/saucedemo-web/cart/nav-checkout-info.block.js";
5
+ import { SubmitCheckoutInfoBlock } from "../blocks/saucedemo-web/checkout-step-one/actions/submit-checkout-info.action.block.js";
6
+ import { FinishOrderBlock } from "../blocks/saucedemo-web/checkout-step-two/actions/finish-order.action.block.js";
7
7
 
8
8
  const engine = new Engine();
9
9
 
@@ -1,8 +1,8 @@
1
1
  import { Engine, start, end } from "waygraph";
2
2
  import type { LoginPage, LoggedIn, ItemInCart } from "../states/checkout.states.js";
3
- import { NavLoginBlock } from "../blocks/nav-login.block.js";
4
- import { SubmitLoginForFlow } from "../blocks/actions/submit-login-for-flow.js";
5
- import { AddToCartBlock } from "../blocks/actions/add-to-cart.effect.block.js";
3
+ import { NavLoginBlock } from "../blocks/saucedemo-web/nav-login.block.js";
4
+ import { SubmitLoginForFlow } from "../blocks/saucedemo-web/actions/submit-login-for-flow.js";
5
+ import { AddToCartBlock } from "../blocks/saucedemo-web/inventory/actions/add-to-cart.effect.block.js";
6
6
 
7
7
  const engine = new Engine();
8
8
 
@@ -1,6 +1,6 @@
1
1
  import { Engine, start, end, withTitle, withSessionReset } from "waygraph";
2
- import { NavLoginBlock } from "../blocks/nav-login.block.js";
3
- import { SubmitLoginActionBlock } from "../blocks/actions/submit-login.action.block.js";
2
+ import { NavLoginBlock } from "../blocks/saucedemo-web/nav-login.block.js";
3
+ import { SubmitLoginActionBlock } from "../blocks/saucedemo-web/actions/submit-login.action.block.js";
4
4
 
5
5
  const engine = new Engine();
6
6
 
@@ -1,7 +1,7 @@
1
1
  import { test, expect } from "@playwright/test";
2
2
  import { MemPage, checkpoint, Trait } from "waygraph";
3
3
  import { checkoutFlow } from "../src/flows/checkout.flow.js";
4
- import { SubmitLoginActionBlock } from "../src/blocks/actions/submit-login.action.block.js";
4
+ import { SubmitLoginActionBlock } from "../src/blocks/saucedemo-web/actions/submit-login.action.block.js";
5
5
  import { LoginCreds, SelectedItem } from "../src/states/checkout.mem-keys.js";
6
6
 
7
7
  // checkoutFlow.withBlockVerify/modBlockVerify - a spec that only imports the
@@ -1,7 +1,7 @@
1
1
  import { test, expect } from "@playwright/test";
2
2
  import { MemPage, Engine, start, end } from "waygraph";
3
- import { NavLoginBlock } from "../src/blocks/nav-login.block.js";
4
- import { SubmitLoginActionBlock } from "../src/blocks/actions/submit-login.action.block.js";
3
+ import { NavLoginBlock } from "../src/blocks/saucedemo-web/nav-login.block.js";
4
+ import { SubmitLoginActionBlock } from "../src/blocks/saucedemo-web/actions/submit-login.action.block.js";
5
5
  import { LoginCreds } from "../src/states/checkout.mem-keys.js";
6
6
 
7
7
  test("submit-login: wrong password branches to LoginPage with error banner", async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waygraph",
3
- "version": "0.7.11",
3
+ "version": "0.7.13",
4
4
  "type": "module",
5
5
  "description": "A typed graph of reusable Blocks for driving a browser through E2E flows.",
6
6
  "license": "MIT",
@@ -0,0 +1,10 @@
1
+ # waygraph quickstart (Sauce Demo)
2
+
3
+ Temp-dir template for `npx waygraph try demo`. Same Blocks as
4
+ `examples/saucedemo` (route-folder convention under `src/blocks/saucedemo-web/`).
5
+
6
+ Convention walkthrough on Pages:
7
+ https://deviate-dv8.github.io/waygraph/saucedemo/
8
+
9
+ Do not edit this tree as the long-lived showcase - edit `examples/saucedemo`,
10
+ then re-copy Blocks here when shipping a release that bumps `try demo`.