waygraph 0.13.7 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (358) hide show
  1. package/README.md +970 -232
  2. package/assets/stubs/stub.mp4 +0 -0
  3. package/assets/stubs/stub.pdf +32 -0
  4. package/assets/stubs/stub.png +0 -0
  5. package/dist/agent-dive.d.ts +9 -0
  6. package/dist/agent-dive.js +32 -0
  7. package/dist/auto-explore-run.d.ts +20 -2
  8. package/dist/auto-explore-run.js +9 -8
  9. package/dist/auto-explore.js +22 -2
  10. package/dist/auto-session-ipc.d.ts +123 -0
  11. package/dist/auto-session-ipc.js +381 -0
  12. package/dist/auto-session.d.ts +342 -0
  13. package/dist/auto-session.js +760 -0
  14. package/dist/cli.js +450 -51
  15. package/dist/engine.d.ts +201 -1
  16. package/dist/engine.js +312 -2
  17. package/dist/graph.d.ts +18 -0
  18. package/dist/graph.js +65 -2
  19. package/dist/highlights.d.ts +20 -1
  20. package/dist/highlights.js +60 -0
  21. package/dist/index.d.ts +8 -4
  22. package/dist/index.js +5 -3
  23. package/dist/map-check.d.ts +18 -0
  24. package/dist/map-check.js +140 -0
  25. package/dist/pilot-overlay.d.ts +88 -0
  26. package/dist/pilot-overlay.js +363 -0
  27. package/dist/pilot.d.ts +49 -0
  28. package/dist/pilot.js +53 -0
  29. package/dist/trait.d.ts +22 -0
  30. package/dist/trait.js +60 -3
  31. package/dist/types.d.ts +21 -1
  32. package/dist/types.js +17 -1
  33. package/examples/routed-demo/.waygraph-auto/4d4902b7.log +0 -0
  34. package/examples/routed-demo/.waygraph-auto/51ef462e.log +0 -0
  35. package/examples/routed-demo/.waygraph-auto/71527ad9.log +0 -0
  36. package/examples/routed-demo/.waygraph-auto/ca16778e.log +0 -0
  37. package/examples/routed-demo/package.json +26 -0
  38. package/examples/routed-demo/playwright.config.ts +20 -0
  39. package/examples/routed-demo/scripts/fixture-server.mjs +37 -0
  40. package/examples/routed-demo/scripts/with-fixture.mjs +70 -0
  41. package/examples/routed-demo/src/flows/routed-demo-map.flow.ts +39 -0
  42. package/examples/routed-demo/src/flows/routed-demo.flow.ts +12 -0
  43. package/examples/routed-demo/src/map/(app_base)/dashboard/_methods/click-widget.block.ts +23 -0
  44. package/examples/routed-demo/src/map/(app_base)/dashboard/_nav.block.ts +18 -0
  45. package/examples/routed-demo/src/map/(app_base)/dashboard/_page.block.ts +22 -0
  46. package/examples/routed-demo/src/map/(app_base)/dashboard/_sel.ts +10 -0
  47. package/examples/routed-demo/src/map/(external)/docs/_nav.block.ts +21 -0
  48. package/examples/routed-demo/src/map/(external)/docs/_page.block.ts +15 -0
  49. package/examples/routed-demo/src/map/(external)/docs/_sel.ts +7 -0
  50. package/examples/routed-demo/src/pages/dashboard.html +10 -0
  51. package/examples/routed-demo/src/pages/docs.html +8 -0
  52. package/examples/routed-demo/src/states/routed-demo.states.ts +10 -0
  53. package/examples/routed-demo/test-results/.last-run.json +4 -0
  54. package/examples/routed-demo/tests/routed-demo-map.spec.ts +17 -0
  55. package/examples/routed-demo/tests/routed-demo.spec.ts +75 -0
  56. package/examples/routed-demo/tsconfig.json +18 -0
  57. package/examples/routed-demo-consumer/package.json +18 -0
  58. package/examples/saucedemo/.waygraph-auto/00d5336e.log +0 -0
  59. package/examples/saucedemo/.waygraph-auto/010dd92b.log +0 -0
  60. package/examples/saucedemo/.waygraph-auto/011ad671.log +0 -0
  61. package/examples/saucedemo/.waygraph-auto/01b45645.log +0 -0
  62. package/examples/saucedemo/.waygraph-auto/03764153.log +0 -0
  63. package/examples/saucedemo/.waygraph-auto/0593587e.log +0 -0
  64. package/examples/saucedemo/.waygraph-auto/06d12823.log +0 -0
  65. package/examples/saucedemo/.waygraph-auto/083cc5b9.log +0 -0
  66. package/examples/saucedemo/.waygraph-auto/0b1f5b26.json +8 -0
  67. package/examples/saucedemo/.waygraph-auto/0c00f25f.log +0 -0
  68. package/examples/saucedemo/.waygraph-auto/0e480591.log +0 -0
  69. package/examples/saucedemo/.waygraph-auto/104751ef.log +0 -0
  70. package/examples/saucedemo/.waygraph-auto/110958b8.log +0 -0
  71. package/examples/saucedemo/.waygraph-auto/138107c1.log +0 -0
  72. package/examples/saucedemo/.waygraph-auto/159d541b.log +0 -0
  73. package/examples/saucedemo/.waygraph-auto/16aa2c01.log +0 -0
  74. package/examples/saucedemo/.waygraph-auto/16c35dd5.log +0 -0
  75. package/examples/saucedemo/.waygraph-auto/1706547d.log +0 -0
  76. package/examples/saucedemo/.waygraph-auto/17537e42.log +0 -0
  77. package/examples/saucedemo/.waygraph-auto/175655f7.log +0 -0
  78. package/examples/saucedemo/.waygraph-auto/17ede493.log +0 -0
  79. package/examples/saucedemo/.waygraph-auto/1fe2414f.log +0 -0
  80. package/examples/saucedemo/.waygraph-auto/1fe2e3b8.log +0 -0
  81. package/examples/saucedemo/.waygraph-auto/2219f00b.log +0 -0
  82. package/examples/saucedemo/.waygraph-auto/23e62571.log +0 -0
  83. package/examples/saucedemo/.waygraph-auto/25f68ada.log +0 -0
  84. package/examples/saucedemo/.waygraph-auto/26ca9cd8.log +0 -0
  85. package/examples/saucedemo/.waygraph-auto/2bb6c4e8.log +0 -0
  86. package/examples/saucedemo/.waygraph-auto/2d425004.log +0 -0
  87. package/examples/saucedemo/.waygraph-auto/2f5b3ea6.log +0 -0
  88. package/examples/saucedemo/.waygraph-auto/31bb303d.log +0 -0
  89. package/examples/saucedemo/.waygraph-auto/31f2042f.log +0 -0
  90. package/examples/saucedemo/.waygraph-auto/36551ec1.log +0 -0
  91. package/examples/saucedemo/.waygraph-auto/36a1c274.log +0 -0
  92. package/examples/saucedemo/.waygraph-auto/381aa338.log +0 -0
  93. package/examples/saucedemo/.waygraph-auto/3882bce1.log +0 -0
  94. package/examples/saucedemo/.waygraph-auto/38acd1dc.log +0 -0
  95. package/examples/saucedemo/.waygraph-auto/3b8b77b9.log +0 -0
  96. package/examples/saucedemo/.waygraph-auto/4028d2a2.log +0 -0
  97. package/examples/saucedemo/.waygraph-auto/4168b208.log +0 -0
  98. package/examples/saucedemo/.waygraph-auto/42cc9113.log +0 -0
  99. package/examples/saucedemo/.waygraph-auto/439d30aa.log +0 -0
  100. package/examples/saucedemo/.waygraph-auto/43ab66ce.log +0 -0
  101. package/examples/saucedemo/.waygraph-auto/43f66838.log +0 -0
  102. package/examples/saucedemo/.waygraph-auto/442171d4.log +0 -0
  103. package/examples/saucedemo/.waygraph-auto/453b1ce1.log +0 -0
  104. package/examples/saucedemo/.waygraph-auto/457322bd.log +0 -0
  105. package/examples/saucedemo/.waygraph-auto/46197027.log +0 -0
  106. package/examples/saucedemo/.waygraph-auto/46889468.log +0 -0
  107. package/examples/saucedemo/.waygraph-auto/4890da1c.log +0 -0
  108. package/examples/saucedemo/.waygraph-auto/4893a63b.log +0 -0
  109. package/examples/saucedemo/.waygraph-auto/4a85f496.log +0 -0
  110. package/examples/saucedemo/.waygraph-auto/4af71440.log +0 -0
  111. package/examples/saucedemo/.waygraph-auto/4f7496d1.log +0 -0
  112. package/examples/saucedemo/.waygraph-auto/50e8baaa.log +0 -0
  113. package/examples/saucedemo/.waygraph-auto/52b3a455.log +0 -0
  114. package/examples/saucedemo/.waygraph-auto/532dd9b8.log +0 -0
  115. package/examples/saucedemo/.waygraph-auto/5391ce40.log +0 -0
  116. package/examples/saucedemo/.waygraph-auto/57dbddb3.log +0 -0
  117. package/examples/saucedemo/.waygraph-auto/5897f501.log +0 -0
  118. package/examples/saucedemo/.waygraph-auto/59c0b57d.log +0 -0
  119. package/examples/saucedemo/.waygraph-auto/5b511794.log +0 -0
  120. package/examples/saucedemo/.waygraph-auto/5c0eef7f.log +0 -0
  121. package/examples/saucedemo/.waygraph-auto/5c47910f.log +0 -0
  122. package/examples/saucedemo/.waygraph-auto/5d60da77.log +0 -0
  123. package/examples/saucedemo/.waygraph-auto/5eda8273.log +0 -0
  124. package/examples/saucedemo/.waygraph-auto/5fc3a33b.log +0 -0
  125. package/examples/saucedemo/.waygraph-auto/61b6546d.log +0 -0
  126. package/examples/saucedemo/.waygraph-auto/621518ad.log +0 -0
  127. package/examples/saucedemo/.waygraph-auto/632b7118.log +0 -0
  128. package/examples/saucedemo/.waygraph-auto/64314c2b.log +0 -0
  129. package/examples/saucedemo/.waygraph-auto/650ed066.log +0 -0
  130. package/examples/saucedemo/.waygraph-auto/66516213.log +0 -0
  131. package/examples/saucedemo/.waygraph-auto/66c17079.log +0 -0
  132. package/examples/saucedemo/.waygraph-auto/69bf0b80.log +0 -0
  133. package/examples/saucedemo/.waygraph-auto/69c2347a.log +0 -0
  134. package/examples/saucedemo/.waygraph-auto/6d22bdb0.log +0 -0
  135. package/examples/saucedemo/.waygraph-auto/6d9aaad3.log +0 -0
  136. package/examples/saucedemo/.waygraph-auto/7103bebb.log +0 -0
  137. package/examples/saucedemo/.waygraph-auto/740c9faa.log +0 -0
  138. package/examples/saucedemo/.waygraph-auto/74872fc5.log +0 -0
  139. package/examples/saucedemo/.waygraph-auto/75846ca9.log +0 -0
  140. package/examples/saucedemo/.waygraph-auto/7626c85b.log +0 -0
  141. package/examples/saucedemo/.waygraph-auto/76308eec.log +0 -0
  142. package/examples/saucedemo/.waygraph-auto/76c1650e.log +0 -0
  143. package/examples/saucedemo/.waygraph-auto/7861f38f.log +0 -0
  144. package/examples/saucedemo/.waygraph-auto/78b21219.log +0 -0
  145. package/examples/saucedemo/.waygraph-auto/7af224ed.log +0 -0
  146. package/examples/saucedemo/.waygraph-auto/7c3be585.log +0 -0
  147. package/examples/saucedemo/.waygraph-auto/7ed55a2c.log +0 -0
  148. package/examples/saucedemo/.waygraph-auto/80086ba2.log +0 -0
  149. package/examples/saucedemo/.waygraph-auto/80206369.log +0 -0
  150. package/examples/saucedemo/.waygraph-auto/847f1092.log +0 -0
  151. package/examples/saucedemo/.waygraph-auto/84d6d293.log +0 -0
  152. package/examples/saucedemo/.waygraph-auto/8581abfa.log +0 -0
  153. package/examples/saucedemo/.waygraph-auto/87b7e0fd.log +0 -0
  154. package/examples/saucedemo/.waygraph-auto/87c79256.log +0 -0
  155. package/examples/saucedemo/.waygraph-auto/88af2495.log +0 -0
  156. package/examples/saucedemo/.waygraph-auto/8a3eb088.log +0 -0
  157. package/examples/saucedemo/.waygraph-auto/8c04a403.log +0 -0
  158. package/examples/saucedemo/.waygraph-auto/8c9ab09e.log +0 -0
  159. package/examples/saucedemo/.waygraph-auto/8cc5db51.log +0 -0
  160. package/examples/saucedemo/.waygraph-auto/8ea3a69c.log +0 -0
  161. package/examples/saucedemo/.waygraph-auto/9150f913.log +0 -0
  162. package/examples/saucedemo/.waygraph-auto/929a4313.log +0 -0
  163. package/examples/saucedemo/.waygraph-auto/95a599e4.log +0 -0
  164. package/examples/saucedemo/.waygraph-auto/96c45350.log +0 -0
  165. package/examples/saucedemo/.waygraph-auto/986030e6.log +0 -0
  166. package/examples/saucedemo/.waygraph-auto/99787abb.log +0 -0
  167. package/examples/saucedemo/.waygraph-auto/99ddb62c.log +0 -0
  168. package/examples/saucedemo/.waygraph-auto/a2dd30dd.log +0 -0
  169. package/examples/saucedemo/.waygraph-auto/a63a2d20.log +0 -0
  170. package/examples/saucedemo/.waygraph-auto/a78befb7.log +0 -0
  171. package/examples/saucedemo/.waygraph-auto/a84d9b79.log +0 -0
  172. package/examples/saucedemo/.waygraph-auto/a87bb3ee.log +0 -0
  173. package/examples/saucedemo/.waygraph-auto/a9270890.log +0 -0
  174. package/examples/saucedemo/.waygraph-auto/aa440153.log +0 -0
  175. package/examples/saucedemo/.waygraph-auto/ab7561e0.log +0 -0
  176. package/examples/saucedemo/.waygraph-auto/ac19ae60.log +0 -0
  177. package/examples/saucedemo/.waygraph-auto/ae21ad8e.log +0 -0
  178. package/examples/saucedemo/.waygraph-auto/af09042f.log +0 -0
  179. package/examples/saucedemo/.waygraph-auto/b1684126.log +0 -0
  180. package/examples/saucedemo/.waygraph-auto/b21e9d12.log +0 -0
  181. package/examples/saucedemo/.waygraph-auto/b5a838be.log +0 -0
  182. package/examples/saucedemo/.waygraph-auto/b603549d.log +0 -0
  183. package/examples/saucedemo/.waygraph-auto/b81e074f.log +0 -0
  184. package/examples/saucedemo/.waygraph-auto/b83e6259.log +0 -0
  185. package/examples/saucedemo/.waygraph-auto/b9cb2796.log +0 -0
  186. package/examples/saucedemo/.waygraph-auto/ba58abb7.log +0 -0
  187. package/examples/saucedemo/.waygraph-auto/bb0a0018.log +0 -0
  188. package/examples/saucedemo/.waygraph-auto/bb9fd384.log +0 -0
  189. package/examples/saucedemo/.waygraph-auto/bc0bdd0e.log +0 -0
  190. package/examples/saucedemo/.waygraph-auto/bc7d4a83.log +0 -0
  191. package/examples/saucedemo/.waygraph-auto/bd8e082a.log +0 -0
  192. package/examples/saucedemo/.waygraph-auto/bea0c93e.log +0 -0
  193. package/examples/saucedemo/.waygraph-auto/bf35201a.log +0 -0
  194. package/examples/saucedemo/.waygraph-auto/bffa3a7a.log +0 -0
  195. package/examples/saucedemo/.waygraph-auto/c02ea583.log +0 -0
  196. package/examples/saucedemo/.waygraph-auto/c2caf0a8.log +0 -0
  197. package/examples/saucedemo/.waygraph-auto/c3bdc714.log +0 -0
  198. package/examples/saucedemo/.waygraph-auto/c4afb8bc.log +0 -0
  199. package/examples/saucedemo/.waygraph-auto/c916a654.log +0 -0
  200. package/examples/saucedemo/.waygraph-auto/c9b8d69e.log +0 -0
  201. package/examples/saucedemo/.waygraph-auto/cd68bbc4.log +0 -0
  202. package/examples/saucedemo/.waygraph-auto/cdc6db50.log +0 -0
  203. package/examples/saucedemo/.waygraph-auto/d01906a7.log +0 -0
  204. package/examples/saucedemo/.waygraph-auto/d02e5e7e.log +0 -0
  205. package/examples/saucedemo/.waygraph-auto/d09aff71.log +0 -0
  206. package/examples/saucedemo/.waygraph-auto/d0e41396.log +0 -0
  207. package/examples/saucedemo/.waygraph-auto/d1370d76.log +0 -0
  208. package/examples/saucedemo/.waygraph-auto/d3714ae4.log +0 -0
  209. package/examples/saucedemo/.waygraph-auto/d9e5f8a4.log +0 -0
  210. package/examples/saucedemo/.waygraph-auto/da0685dc.log +0 -0
  211. package/examples/saucedemo/.waygraph-auto/da894ad8.log +0 -0
  212. package/examples/saucedemo/.waygraph-auto/daa2f922.log +0 -0
  213. package/examples/saucedemo/.waygraph-auto/daefb614.log +0 -0
  214. package/examples/saucedemo/.waygraph-auto/db97e833.log +0 -0
  215. package/examples/saucedemo/.waygraph-auto/dec3076e.log +0 -0
  216. package/examples/saucedemo/.waygraph-auto/e101d19a.log +0 -0
  217. package/examples/saucedemo/.waygraph-auto/e1973991.log +0 -0
  218. package/examples/saucedemo/.waygraph-auto/e207c989.log +0 -0
  219. package/examples/saucedemo/.waygraph-auto/e633e545.log +0 -0
  220. package/examples/saucedemo/.waygraph-auto/e69aec68.log +0 -0
  221. package/examples/saucedemo/.waygraph-auto/e70e2d06.log +0 -0
  222. package/examples/saucedemo/.waygraph-auto/e8306a4b.log +0 -0
  223. package/examples/saucedemo/.waygraph-auto/ebad3410.log +0 -0
  224. package/examples/saucedemo/.waygraph-auto/ec88b3ef.log +0 -0
  225. package/examples/saucedemo/.waygraph-auto/ecbb0966.log +0 -0
  226. package/examples/saucedemo/.waygraph-auto/ecdee753.log +0 -0
  227. package/examples/saucedemo/.waygraph-auto/ed888783.log +0 -0
  228. package/examples/saucedemo/.waygraph-auto/ed931dac.log +0 -0
  229. package/examples/saucedemo/.waygraph-auto/ef655a3f.log +0 -0
  230. package/examples/saucedemo/.waygraph-auto/f34c9a26.log +0 -0
  231. package/examples/saucedemo/.waygraph-auto/f3c29b21.log +0 -0
  232. package/examples/saucedemo/.waygraph-auto/f53f7cfc.log +0 -0
  233. package/examples/saucedemo/.waygraph-auto/f5525d53.log +0 -0
  234. package/examples/saucedemo/.waygraph-auto/f5ad5830.log +0 -0
  235. package/examples/saucedemo/.waygraph-auto/f90035b3.log +0 -0
  236. package/examples/saucedemo/.waygraph-auto/fa687bc2.log +0 -0
  237. package/examples/saucedemo/.waygraph-auto/faed36dd.log +0 -0
  238. package/examples/saucedemo/.waygraph-auto/fb66fba0.log +0 -0
  239. package/examples/saucedemo/.waygraph-auto/fc48fd76.log +0 -0
  240. package/examples/saucedemo/docs/CONVENTION.md +25 -5
  241. package/examples/saucedemo/docs/HELPERS.md +15 -4
  242. package/examples/saucedemo/scripts/capture-wrong-login.mjs +8 -2
  243. package/examples/saucedemo/scripts/prove-wrong-login-runtime.mjs +8 -2
  244. package/examples/saucedemo/src/blocks/SITE-MAP.md +14 -3
  245. package/examples/saucedemo/src/blocks/saucedemo-web/NAV.md +15 -1
  246. package/examples/saucedemo/src/blocks/saucedemo-web/cart/NAV.md +1 -0
  247. package/examples/saucedemo/src/blocks/saucedemo-web/cart/cart.sel.ts +9 -0
  248. package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-cart.block.ts +3 -2
  249. package/examples/saucedemo/src/blocks/saucedemo-web/cart/nav-checkout-info.block.ts +2 -1
  250. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/NAV.md +6 -1
  251. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/checkout-info.sel.ts +11 -0
  252. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-first-name.method.block.ts +22 -0
  253. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-last-name.method.block.ts +21 -0
  254. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/fill-postal-code.method.block.ts +21 -0
  255. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-one/methods/submit-checkout-info.method.block.ts +6 -7
  256. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/NAV.md +2 -0
  257. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/methods/checkout-overview.sel.ts +9 -0
  258. package/examples/saucedemo/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +7 -6
  259. package/examples/saucedemo/src/blocks/saucedemo-web/ff-owner-auth.block.ts +7 -2
  260. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/NAV.md +1 -0
  261. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/item-detail.sel.ts +9 -0
  262. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.ts +2 -1
  263. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-back-to-products.block.ts +2 -1
  264. package/examples/saucedemo/src/blocks/saucedemo-web/inventory-item/nav-continue-shopping.block.ts +2 -1
  265. package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +51 -0
  266. package/examples/saucedemo/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +69 -0
  267. package/examples/saucedemo/src/blocks/saucedemo-web/methods/login.sel.ts +13 -0
  268. package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login-for-flow.ts +4 -4
  269. package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +13 -51
  270. package/examples/saucedemo/src/blocks/saucedemo-web/methods/submit-logout.method.block.ts +4 -3
  271. package/examples/saucedemo/src/blocks/saucedemo-web/nav-login.block.ts +14 -6
  272. package/examples/saucedemo/src/flows/checkout-then-browse-again.flow.ts +15 -0
  273. package/examples/saucedemo/src/flows/checkout.flow.ts +20 -2
  274. package/examples/saucedemo/src/flows/device-showcase.flow.ts +4 -0
  275. package/examples/saucedemo/src/flows/login.flow.ts +3 -1
  276. package/examples/saucedemo/src/flows/shop.flow.ts +6 -0
  277. package/examples/saucedemo/src/flows/smoke.flow.ts +13 -7
  278. package/examples/saucedemo/src/flows/stub-on-error.flow.ts +4 -2
  279. package/examples/saucedemo/src/flows/viewer-blocked.flow.ts +6 -2
  280. package/examples/saucedemo/tests/flow-block-verify.spec.ts +3 -3
  281. package/examples/saucedemo/tests/submit-login-branch.spec.ts +5 -3
  282. package/package.json +2 -1
  283. package/templates/agents/waygraph-author.agent.md +43 -5
  284. package/templates/agents/waygraph-planner.agent.md +33 -2
  285. package/templates/quickstart/src/blocks/saucedemo-web/NAV.md +15 -1
  286. package/templates/quickstart/src/blocks/saucedemo-web/cart/NAV.md +1 -0
  287. package/templates/quickstart/src/blocks/saucedemo-web/cart/cart.sel.ts +9 -0
  288. package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-cart.block.ts +19 -15
  289. package/templates/quickstart/src/blocks/saucedemo-web/cart/nav-checkout-info.block.ts +2 -1
  290. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/NAV.md +6 -1
  291. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/checkout-info.sel.ts +11 -0
  292. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-first-name.method.block.ts +22 -0
  293. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-last-name.method.block.ts +21 -0
  294. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/fill-postal-code.method.block.ts +21 -0
  295. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-one/methods/submit-checkout-info.method.block.ts +6 -7
  296. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/NAV.md +2 -0
  297. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/methods/checkout-overview.sel.ts +9 -0
  298. package/templates/quickstart/src/blocks/saucedemo-web/checkout-step-two/methods/finish-order.method.block.ts +7 -6
  299. package/templates/quickstart/src/blocks/saucedemo-web/ff-owner-auth.block.ts +7 -2
  300. package/templates/quickstart/src/blocks/saucedemo-web/inventory/methods/add-to-cart.effect.block.ts +24 -16
  301. package/templates/quickstart/src/blocks/saucedemo-web/inventory/nav-item-detail.block.ts +3 -3
  302. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/NAV.md +1 -0
  303. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/item-detail.sel.ts +9 -0
  304. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-back-to-inventory.block.ts +2 -1
  305. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-back-to-products.block.ts +2 -1
  306. package/templates/quickstart/src/blocks/saucedemo-web/inventory-item/nav-continue-shopping.block.ts +2 -1
  307. package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-password.method.block.ts +51 -0
  308. package/templates/quickstart/src/blocks/saucedemo-web/methods/fill-username.method.block.ts +69 -0
  309. package/templates/quickstart/src/blocks/saucedemo-web/methods/login.sel.ts +13 -0
  310. package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login-for-flow.ts +4 -4
  311. package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-login.method.block.ts +35 -63
  312. package/templates/quickstart/src/blocks/saucedemo-web/methods/submit-logout.method.block.ts +4 -3
  313. package/templates/quickstart/src/blocks/saucedemo-web/nav-login.block.ts +14 -6
  314. package/templates/quickstart/src/flows/checkout-then-browse-again.flow.ts +15 -0
  315. package/templates/quickstart/src/flows/checkout.flow.ts +29 -2
  316. package/templates/quickstart/src/flows/device-showcase.flow.ts +4 -0
  317. package/templates/quickstart/src/flows/login.flow.ts +3 -1
  318. package/templates/quickstart/src/flows/shop.flow.ts +6 -0
  319. package/templates/quickstart/src/flows/smoke.flow.ts +13 -7
  320. package/templates/quickstart/src/flows/viewer-blocked.flow.ts +6 -2
  321. package/templates/quickstart/tests/chain-flow.spec.ts +8 -1
  322. package/templates/scaffold/STRUCTURE.md +23 -3
  323. package/templates/scaffold/scripts/fixture-server.mjs +11 -2
  324. package/templates/scaffold/src/flows/example.flow.ts +8 -6
  325. package/templates/scaffold/src/flows/mail-verify.flow.ts +85 -0
  326. package/templates/scaffold/src/flows/shop.flow.ts +23 -6
  327. package/templates/scaffold/src/map/(app_base)/docs/_nav.block.ts +20 -0
  328. package/templates/scaffold/src/map/(app_base)/docs/_page.block.ts +15 -0
  329. package/templates/scaffold/src/map/(app_base)/docs/_sel.ts +7 -0
  330. package/templates/scaffold/src/map/(app_base)/docs/docs.html +8 -0
  331. package/templates/scaffold/src/{blocks/demo-web/methods → map/(app_base)/home/_methods}/add-item.effect.block.ts +3 -3
  332. package/templates/scaffold/src/map/(app_base)/home/_methods/assert-hello.method.block.ts +46 -0
  333. package/templates/scaffold/src/map/(app_base)/home/_methods/assert-item-added.method.block.ts +38 -0
  334. package/templates/scaffold/src/{blocks/demo-web/methods → map/(app_base)/home/_methods}/clear-cart.method.block.ts +9 -3
  335. package/templates/scaffold/src/{blocks/demo-web/methods → map/(app_base)/home/_methods}/remove-item.effect.block.ts +3 -3
  336. package/templates/scaffold/src/{blocks/demo-web/nav-home.block.ts → map/(app_base)/home/_nav.block.ts} +2 -2
  337. package/templates/scaffold/src/{blocks/demo-web/home.page.block.ts → map/(app_base)/home/_page.block.ts} +7 -7
  338. package/templates/scaffold/src/{blocks/demo-web/demo-sel.ts → map/(app_base)/home/_sel.ts} +1 -0
  339. package/templates/scaffold/src/{blocks/demo-web → map/(app_base)/home}/home.html +4 -0
  340. package/templates/scaffold/src/map/(app_base)/home/nav-verification-link.block.ts +34 -0
  341. package/templates/scaffold/src/map/(external)/mailpit/_methods/assert-email-content.method.block.ts +48 -0
  342. package/templates/scaffold/src/map/(external)/mailpit/_methods/assert-email-received.method.block.ts +49 -0
  343. package/templates/scaffold/src/map/(external)/mailpit/_methods/extract-email-link.method.block.ts +41 -0
  344. package/templates/scaffold/src/map/(external)/mailpit/_methods/open-message.method.block.ts +39 -0
  345. package/templates/scaffold/src/map/(external)/mailpit/_nav.block.ts +20 -0
  346. package/templates/scaffold/src/map/(external)/mailpit/_page.block.ts +30 -0
  347. package/templates/scaffold/src/map/(external)/mailpit/_sel.ts +5 -0
  348. package/templates/scaffold/src/states/demo.mem-keys.ts +25 -1
  349. package/templates/scaffold/src/states/demo.states.ts +11 -0
  350. package/templates/scaffold/test-results/.last-run.json +4 -0
  351. package/templates/scaffold/tests/example.spec.ts +2 -2
  352. package/templates/scaffold/tests/mail-verify.spec.ts +191 -0
  353. package/templates/skills/waygraph-blind-pilot.skill.md +61 -0
  354. package/templates/skills/waygraph-pilot.skill.md +108 -0
  355. package/templates/quickstart/README-saucedemo-commands.md +0 -72
  356. package/templates/scaffold/src/blocks/SITE-MAP.md +0 -12
  357. package/templates/scaffold/src/blocks/demo-web/NAV.md +0 -29
  358. package/templates/scaffold/src/blocks/demo-web/methods/assert-hello.method.block.ts +0 -50
@@ -2,6 +2,7 @@ import { defineNavClickBlock, Trait } from "waygraph";
2
2
  import type { StubCtx } from "waygraph";
3
3
  import type { CartPage } from "../../../states/checkout.states.js";
4
4
  import { InventorySel } from "../inventory/methods/inventory-items.js";
5
+ import { CartSel } from "./cart.sel.js";
5
6
 
6
7
  /**
7
8
  * Kind: Nav
@@ -14,7 +15,7 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
14
15
  name: "nav-cart",
15
16
  description: "Clicks the cart link in the header.",
16
17
  checkpoint: "CartPage",
17
- click: ".shopping_cart_link",
18
+ click: CartSel.cartLink,
18
19
  verify: [Trait.url({ pathname: "/cart.html" })],
19
20
  stubBefore: (ctx: StubCtx) => {
20
21
  ctx.title("Open cart · landscape");
@@ -35,7 +36,7 @@ export const NavCartBlock = defineNavClickBlock<CartPage>({
35
36
  ctx.zoomOut(false);
36
37
  ctx.highlights({
37
38
  cart: {
38
- selector: ".shopping_cart_link",
39
+ selector: CartSel.cartLink,
39
40
  label: "Cart",
40
41
  detail: "Open cart",
41
42
  focus: true,
@@ -1,5 +1,6 @@
1
1
  import { defineNavClickBlock, Trait } from "waygraph";
2
2
  import type { CheckoutInfoPage } from "../../../states/checkout.states.js";
3
+ import { CartSel } from "./cart.sel.js";
3
4
 
4
5
  /**
5
6
  * Kind: Nav
@@ -12,6 +13,6 @@ export const NavCheckoutInfoBlock = defineNavClickBlock<CheckoutInfoPage>({
12
13
  name: "nav-checkout-info",
13
14
  description: "Clicks 'Checkout' on the cart page.",
14
15
  checkpoint: "CheckoutInfoPage",
15
- click: "#checkout",
16
+ click: CartSel.checkoutBtn,
16
17
  verify: [Trait.url({ pathname: "/checkout-step-one.html" })],
17
18
  });
@@ -14,8 +14,13 @@ Shipping info form before order overview.
14
14
 
15
15
  | File | Kind | Notes |
16
16
  |------|------|-------|
17
- | `methods/submit-checkout-info.method.block.ts` | Method | Fill form + Continue -> overview |
17
+ | `methods/fill-first-name.method.block.ts` | Method | Fills first name only; self-loop on CheckoutInfoPage |
18
+ | `methods/fill-last-name.method.block.ts` | Method | Fills last name only; self-loop on CheckoutInfoPage |
19
+ | `methods/fill-postal-code.method.block.ts` | Method | Fills postal code only; self-loop on CheckoutInfoPage |
20
+ | `methods/submit-checkout-info.method.block.ts` | Method | Click Continue only -> overview |
21
+ | `methods/checkout-info.sel.ts` | helper | `CheckoutInfoSel` (not a Block) |
18
22
 
19
23
  ## Related mem keys / checkpoints
20
24
 
21
25
  - Checkpoints: `CheckoutInfoPage`, `CheckoutOverviewPage`
26
+ - Sel: `CheckoutInfoSel` (`methods/checkout-info.sel.ts`) - DOM only, not mem
@@ -0,0 +1,11 @@
1
+ /**
2
+ * DOM selectors for the shipping info form (`/checkout-step-one.html`).
3
+ * Convention: DOM strings live in `*Sel` next to the page, not inlined in
4
+ * each Block.
5
+ */
6
+ export const CheckoutInfoSel = {
7
+ firstName: "#first-name",
8
+ lastName: "#last-name",
9
+ postalCode: "#postal-code",
10
+ continueBtn: "#continue",
11
+ };
@@ -0,0 +1,22 @@
1
+ import { defineMethodBlock, checkpoint } from "waygraph";
2
+ import type { CheckoutInfoPage } from "../../../../states/checkout.states.js";
3
+ import { CheckoutInfoSel } from "./checkout-info.sel.js";
4
+
5
+ /**
6
+ * Kind: Method
7
+ * Helper: defineMethodBlock
8
+ * Route: saucedemo-web/checkout-step-one/methods/ (= /checkout-step-one.html)
9
+ *
10
+ * Fills the first name field only - self-loop on CheckoutInfoPage. Continue
11
+ * is its own Block (submit-checkout-info.method.block.ts).
12
+ */
13
+ export const FillFirstNameBlock = defineMethodBlock<CheckoutInfoPage, CheckoutInfoPage>({
14
+ name: "fill-first-name",
15
+ description: "Fills the first name field on the shipping info form.",
16
+ instruction: {
17
+ async act(page) {
18
+ await page.locator(CheckoutInfoSel.firstName).fill("Ada");
19
+ },
20
+ resolve: () => checkpoint("CheckoutInfoPage"),
21
+ },
22
+ });
@@ -0,0 +1,21 @@
1
+ import { defineMethodBlock, checkpoint } from "waygraph";
2
+ import type { CheckoutInfoPage } from "../../../../states/checkout.states.js";
3
+ import { CheckoutInfoSel } from "./checkout-info.sel.js";
4
+
5
+ /**
6
+ * Kind: Method
7
+ * Helper: defineMethodBlock
8
+ * Route: saucedemo-web/checkout-step-one/methods/ (= /checkout-step-one.html)
9
+ *
10
+ * Fills the last name field only - self-loop on CheckoutInfoPage.
11
+ */
12
+ export const FillLastNameBlock = defineMethodBlock<CheckoutInfoPage, CheckoutInfoPage>({
13
+ name: "fill-last-name",
14
+ description: "Fills the last name field on the shipping info form.",
15
+ instruction: {
16
+ async act(page) {
17
+ await page.locator(CheckoutInfoSel.lastName).fill("Lovelace");
18
+ },
19
+ resolve: () => checkpoint("CheckoutInfoPage"),
20
+ },
21
+ });
@@ -0,0 +1,21 @@
1
+ import { defineMethodBlock, checkpoint } from "waygraph";
2
+ import type { CheckoutInfoPage } from "../../../../states/checkout.states.js";
3
+ import { CheckoutInfoSel } from "./checkout-info.sel.js";
4
+
5
+ /**
6
+ * Kind: Method
7
+ * Helper: defineMethodBlock
8
+ * Route: saucedemo-web/checkout-step-one/methods/ (= /checkout-step-one.html)
9
+ *
10
+ * Fills the postal code field only - self-loop on CheckoutInfoPage.
11
+ */
12
+ export const FillPostalCodeBlock = defineMethodBlock<CheckoutInfoPage, CheckoutInfoPage>({
13
+ name: "fill-postal-code",
14
+ description: "Fills the postal code field on the shipping info form.",
15
+ instruction: {
16
+ async act(page) {
17
+ await page.locator(CheckoutInfoSel.postalCode).fill("1000");
18
+ },
19
+ resolve: () => checkpoint("CheckoutInfoPage"),
20
+ },
21
+ });
@@ -1,23 +1,22 @@
1
1
  import { defineMethodBlock, checkpoint, Trait } from "waygraph";
2
2
  import type { CheckoutInfoPage, CheckoutOverviewPage } from "../../../../states/checkout.states.js";
3
+ import { CheckoutInfoSel } from "./checkout-info.sel.js";
3
4
 
4
5
  /**
5
6
  * Kind: Method
6
7
  * Helper: defineMethodBlock
7
8
  * Route: saucedemo-web/checkout-step-one/methods/ (= /checkout-step-one.html)
8
9
  *
9
- * Fills shipping form and continues - never navigates itself
10
- * (nav-checkout-info already got here).
10
+ * Clicks Continue only - fields are filled by fill-first-name /
11
+ * fill-last-name / fill-postal-code (each its own Block). One Block, one
12
+ * action: submit.
11
13
  */
12
14
  export const SubmitCheckoutInfoBlock = defineMethodBlock<CheckoutInfoPage, CheckoutOverviewPage>({
13
15
  name: "submit-checkout-info",
14
- description: "Fills in the shipping info form and continues to the order overview.",
16
+ description: "Continues from the shipping info form to the order overview.",
15
17
  instruction: {
16
18
  async act(page) {
17
- await page.locator("#first-name").fill("Ada");
18
- await page.locator("#last-name").fill("Lovelace");
19
- await page.locator("#postal-code").fill("1000");
20
- await page.locator("#continue").click();
19
+ await page.locator(CheckoutInfoSel.continueBtn).click();
21
20
  },
22
21
  resolve: () => checkpoint("CheckoutOverviewPage"),
23
22
  verify: [Trait.url({ pathname: "/checkout-step-two.html" })],
@@ -15,7 +15,9 @@ Order overview / finish page.
15
15
  | File | Kind | Notes |
16
16
  |------|------|-------|
17
17
  | `methods/finish-order.method.block.ts` | Method | Finish -> thank-you / OrderComplete |
18
+ | `methods/checkout-overview.sel.ts` | helper | `CheckoutOverviewSel` (not a Block) |
18
19
 
19
20
  ## Related mem keys / checkpoints
20
21
 
21
22
  - Checkpoints: `CheckoutOverviewPage`, `OrderComplete`
23
+ - Sel: `CheckoutOverviewSel` (`methods/checkout-overview.sel.ts`) - DOM only, not mem
@@ -0,0 +1,9 @@
1
+ /**
2
+ * DOM selectors for the order overview / completion page
3
+ * (`/checkout-step-two.html`). Convention: DOM strings live in `*Sel` next
4
+ * to the page, not inlined in each Block.
5
+ */
6
+ export const CheckoutOverviewSel = {
7
+ finishBtn: "#finish",
8
+ completeHeader: ".complete-header",
9
+ };
@@ -1,5 +1,6 @@
1
1
  import { defineMethodBlock, checkpoint, Trait, narrate } from "waygraph";
2
2
  import type { CheckoutOverviewPage, OrderComplete } from "../../../../states/checkout.states.js";
3
+ import { CheckoutOverviewSel } from "./checkout-overview.sel.js";
3
4
 
4
5
  /**
5
6
  * Kind: Method
@@ -13,17 +14,17 @@ export const FinishOrderBlock = defineMethodBlock<CheckoutOverviewPage, OrderCom
13
14
  description: "Places the order and confirms the 'Thank you for your order!' completion page.",
14
15
  instruction: {
15
16
  async act(page) {
16
- const finishButton = page.locator("#finish");
17
+ const finishButton = page.locator(CheckoutOverviewSel.finishBtn);
17
18
  await narrate(finishButton, "Placing the order", () => finishButton.click());
18
19
  },
19
20
  resolve: () => checkpoint("OrderComplete"),
20
- verify: [Trait.text(".complete-header", "Thank you for your order!")],
21
+ verify: [Trait.text(CheckoutOverviewSel.completeHeader, "Thank you for your order!")],
21
22
  stubBefore: {
22
- finish: { selector: "#finish", label: "Finish" },
23
+ finish: { selector: CheckoutOverviewSel.finishBtn, label: "Finish" },
23
24
  },
24
25
  stubAfter: {
25
26
  thanks: {
26
- selector: ".complete-header",
27
+ selector: CheckoutOverviewSel.completeHeader,
27
28
  label: "Order confirmed",
28
29
  detail: "Thank you for your order!",
29
30
  duration: true,
@@ -42,7 +43,7 @@ export const FinishOrderBlock = defineMethodBlock<CheckoutOverviewPage, OrderCom
42
43
  caption: "Completion page is the durable proof",
43
44
  detail: "The thank-you header is what verify asserts on.",
44
45
  tag: "YAP",
45
- selector: ".complete-header",
46
+ selector: CheckoutOverviewSel.completeHeader,
46
47
  duration: 2500,
47
48
  fastMode: 700,
48
49
  },
@@ -50,7 +51,7 @@ export const FinishOrderBlock = defineMethodBlock<CheckoutOverviewPage, OrderCom
50
51
  caption: "Episode continues after this yap",
51
52
  detail: "Next step rings the same banner, then you move on.",
52
53
  tag: "YAP",
53
- selector: ".complete-header",
54
+ selector: CheckoutOverviewSel.completeHeader,
54
55
  duration: true,
55
56
  fastMode: 500,
56
57
  },
@@ -1,5 +1,7 @@
1
1
  import { fastForwardComposeBlock } from "waygraph";
2
2
  import { NavLoginBlock } from "./nav-login.block.js";
3
+ import { FillUsernameBlock } from "./methods/fill-username.method.block.js";
4
+ import { FillPasswordBlock } from "./methods/fill-password.method.block.js";
3
5
  import { SubmitLoginForFlow } from "./methods/submit-login-for-flow.js";
4
6
 
5
7
  /**
@@ -7,11 +9,14 @@ import { SubmitLoginForFlow } from "./methods/submit-login-for-flow.js";
7
9
  * Helper: fastForwardComposeBlock
8
10
  * Route: saucedemo-web/ (auth prefix)
9
11
  *
10
- * Collapses nav-login + submit-login into one opaque demo/run step so
11
- * checkout demos skip watching auth. Use --ff-expand to gate inners again.
12
+ * Collapses nav-login + fill-username + fill-password + submit-login into
13
+ * one opaque demo/run step so checkout demos skip watching auth. Use
14
+ * --ff-expand to gate inners again (they show as 4 separate steps).
12
15
  * loginFlow stays expanded for Sign In episode narration.
13
16
  */
14
17
  export const FfOwnerAuthBlock = fastForwardComposeBlock("ff-owner-auth", [
15
18
  NavLoginBlock,
19
+ FillUsernameBlock,
20
+ FillPasswordBlock,
16
21
  SubmitLoginForFlow,
17
22
  ]);
@@ -23,3 +23,4 @@ Single product detail page, plus nav edges that return to catalog
23
23
  ## Related mem keys / checkpoints
24
24
 
25
25
  - Checkpoints: `ItemDetailPage`, `LoggedIn` (after back / continue), `OrderComplete` (from for back-to-products)
26
+ - Sel: `ItemDetailSel` (`item-detail.sel.ts`) - DOM only, not mem
@@ -0,0 +1,9 @@
1
+ /**
2
+ * DOM selectors for the item detail page (`/inventory-item.html`) and the
3
+ * order-complete page's equivalent nav control. Convention: DOM strings
4
+ * live in `*Sel` next to the page, not inlined in each Block.
5
+ */
6
+ export const ItemDetailSel = {
7
+ continueShoppingBtn: "#continue-shopping",
8
+ backToProductsBtn: "#back-to-products",
9
+ };
@@ -1,5 +1,6 @@
1
1
  import { defineNavClickBlock, Trait } from "waygraph";
2
2
  import type { LoggedIn } from "../../../states/checkout.states.js";
3
+ import { ItemDetailSel } from "./item-detail.sel.js";
3
4
 
4
5
  /**
5
6
  * Kind: Nav
@@ -13,6 +14,6 @@ export const NavBackToInventoryBlock = defineNavClickBlock<LoggedIn>({
13
14
  name: "nav-back-to-inventory",
14
15
  description: "Clicks 'Back to products' on the item detail page.",
15
16
  checkpoint: "LoggedIn",
16
- click: "#back-to-products",
17
+ click: ItemDetailSel.backToProductsBtn,
17
18
  verify: [Trait.url({ pathname: "/inventory.html" })],
18
19
  });
@@ -1,5 +1,6 @@
1
1
  import { defineNavClickBlock, Trait } from "waygraph";
2
2
  import type { LoggedIn } from "../../../states/checkout.states.js";
3
+ import { ItemDetailSel } from "./item-detail.sel.js";
3
4
 
4
5
  /**
5
6
  * Kind: Nav
@@ -13,6 +14,6 @@ export const NavBackToProductsBlock = defineNavClickBlock<LoggedIn>({
13
14
  name: "nav-back-to-products",
14
15
  description: "Clicks 'Back Home' on the order confirmation page.",
15
16
  checkpoint: "LoggedIn",
16
- click: "#back-to-products",
17
+ click: ItemDetailSel.backToProductsBtn,
17
18
  verify: [Trait.url({ pathname: "/inventory.html" })],
18
19
  });
@@ -1,5 +1,6 @@
1
1
  import { defineNavClickBlock, Trait } from "waygraph";
2
2
  import type { LoggedIn } from "../../../states/checkout.states.js";
3
+ import { ItemDetailSel } from "./item-detail.sel.js";
3
4
 
4
5
  /**
5
6
  * Kind: Nav
@@ -12,6 +13,6 @@ export const NavContinueShoppingBlock = defineNavClickBlock<LoggedIn>({
12
13
  name: "nav-continue-shopping",
13
14
  description: "Clicks 'Continue Shopping' on the cart page.",
14
15
  checkpoint: "LoggedIn",
15
- click: "#continue-shopping",
16
+ click: ItemDetailSel.continueShoppingBtn,
16
17
  verify: [Trait.url({ pathname: "/inventory.html" })],
17
18
  });
@@ -0,0 +1,51 @@
1
+ import { defineMethodBlock, checkpoint, type StubCtx } from "waygraph";
2
+ import type { LoginPage } from "../../../states/checkout.states.js";
3
+ import { LoginCreds } from "../../../states/checkout.mem-keys.js";
4
+ import { LoginSel } from "./login.sel.js";
5
+
6
+ /**
7
+ * Kind: Method
8
+ * Helper: defineMethodBlock
9
+ * Route: saucedemo-web/methods/ (page URL /)
10
+ *
11
+ * Fills the password field only - self-loop on LoginPage. See
12
+ * fill-username.method.block.ts for why this is split from submit.
13
+ */
14
+ export const FillPasswordBlock = defineMethodBlock<LoginPage, LoginPage>({
15
+ name: "fill-password",
16
+ description: "Fills the password field on the login form.",
17
+ requires: [LoginCreds.key],
18
+ instruction: {
19
+ async act(page, _input, mem) {
20
+ const { password } = mem.get(LoginCreds.key);
21
+ await page.locator(LoginSel.password).fill(password);
22
+ },
23
+ resolve: () => checkpoint("LoginPage"),
24
+ stubBefore: (ctx: StubCtx) => {
25
+ ctx.highlights({
26
+ password: {
27
+ selector: LoginSel.password,
28
+ label: "Password",
29
+ todo: "login-pass",
30
+ focus: true,
31
+ color: "#c9a6ff",
32
+ zoom: 1.4,
33
+ },
34
+ });
35
+ },
36
+ stubAfter: (ctx: StubCtx) => {
37
+ ctx.todos(
38
+ "saucedemo",
39
+ [
40
+ { id: "login-user", text: "Enter username", done: true },
41
+ { id: "login-pass", text: "Enter password", done: true },
42
+ { id: "login-submit", text: "Tap Login" },
43
+ { id: "cart-find", text: "Find the product" },
44
+ { id: "cart-add", text: "Add to cart" },
45
+ { id: "cart-open", text: "Open cart" },
46
+ ],
47
+ { title: "Device showcase", index: 2 },
48
+ );
49
+ },
50
+ },
51
+ });
@@ -0,0 +1,69 @@
1
+ import { defineMethodBlock, checkpoint, type StubCtx } from "waygraph";
2
+ import type { LoginPage } from "../../../states/checkout.states.js";
3
+ import { LoginCreds } from "../../../states/checkout.mem-keys.js";
4
+ import { LoginSel } from "./login.sel.js";
5
+
6
+ /**
7
+ * Kind: Method
8
+ * Helper: defineMethodBlock
9
+ * Route: saucedemo-web/methods/ (page URL /)
10
+ *
11
+ * Fills the username field only - self-loop on LoginPage, no submit, no
12
+ * page.goto. Submit is its own Block (submit-login.method.block.ts) so the
13
+ * graph/demo show fill vs submit as real, distinct steps instead of one
14
+ * Block doing "input username and password and login at the same time".
15
+ */
16
+ export const FillUsernameBlock = defineMethodBlock<LoginPage, LoginPage>({
17
+ name: "fill-username",
18
+ description: "Fills the username field on the login form.",
19
+ requires: [LoginCreds.key],
20
+ instruction: {
21
+ async act(page, _input, mem) {
22
+ const { username } = mem.get(LoginCreds.key);
23
+ await page.locator(LoginSel.username).fill(username);
24
+ },
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
+ ctx.highlights({
44
+ username: {
45
+ selector: LoginSel.username,
46
+ label: "Username",
47
+ todo: "login-user",
48
+ focus: true,
49
+ color: "#c9a6ff",
50
+ zoom: 1.4,
51
+ },
52
+ });
53
+ },
54
+ stubAfter: (ctx: StubCtx) => {
55
+ ctx.todos(
56
+ "saucedemo",
57
+ [
58
+ { id: "login-user", text: "Enter username", done: true },
59
+ { id: "login-pass", text: "Enter password" },
60
+ { id: "login-submit", text: "Tap Login" },
61
+ { id: "cart-find", text: "Find the product" },
62
+ { id: "cart-add", text: "Add to cart" },
63
+ { id: "cart-open", text: "Open cart" },
64
+ ],
65
+ { title: "Device showcase", index: 1 },
66
+ );
67
+ },
68
+ },
69
+ });
@@ -0,0 +1,13 @@
1
+ /**
2
+ * DOM selectors for the login route (`/`) and its logout burger menu.
3
+ * Convention: DOM strings live in `*Sel` next to the page, not inlined in
4
+ * each Block.
5
+ */
6
+ export const LoginSel = {
7
+ username: "#user-name",
8
+ password: "#password",
9
+ loginButton: "#login-button",
10
+ errorBanner: '[data-test="error"]',
11
+ burgerMenuButton: "#react-burger-menu-btn",
12
+ logoutLink: "#logout_sidebar_link",
13
+ };
@@ -1,13 +1,13 @@
1
1
  import type { DefinedBlock } from "waygraph";
2
2
  import type { LoginPage, LoggedIn } from "../../../states/checkout.states.js";
3
- import { SubmitLoginActionBlock } from "./submit-login.method.block.js";
3
+ import { SubmitLoginBlock } from "./submit-login.method.block.js";
4
4
 
5
5
  /**
6
6
  * Kind: helper (not a discoverable Block file)
7
- * Helper: typed alias over SubmitLoginActionBlock
7
+ * Helper: typed alias over SubmitLoginBlock
8
8
  * Route: saucedemo-web/methods/ (page URL /)
9
9
  *
10
10
  * DefinedBlock cast so linear Flows can chain .withVerify on Out=LoggedIn;
11
- * runtime still branches on bad credentials via SubmitLoginActionBlock.
11
+ * runtime still branches on bad credentials via SubmitLoginBlock.
12
12
  */
13
- export const SubmitLoginForFlow = SubmitLoginActionBlock as unknown as DefinedBlock<LoginPage, LoggedIn>;
13
+ export const SubmitLoginForFlow = SubmitLoginBlock as unknown as DefinedBlock<LoginPage, LoggedIn>;
@@ -1,6 +1,6 @@
1
1
  import { defineMethodBlock, checkpoint, Trait, type StubCtx } from "waygraph";
2
2
  import type { LoginPage, LoginSubmitOutcome } from "../../../states/checkout.states.js";
3
- import { LoginCreds } from "../../../states/checkout.mem-keys.js";
3
+ import { LoginSel } from "./login.sel.js";
4
4
 
5
5
  type LoginObserve = "success" | "failure";
6
6
 
@@ -9,30 +9,26 @@ type LoginObserve = "success" | "failure";
9
9
  * Helper: defineMethodBlock
10
10
  * Route: saucedemo-web/methods/ (page URL /)
11
11
  *
12
- * Fills credentials and submits - never page.goto (nav-login Page hub owns that).
12
+ * Clicks Login only - never page.goto (nav-login Page hub owns that), never
13
+ * fills fields (fill-username.method.block.ts / fill-password.method.block.ts
14
+ * already did that). One Block, one action: submit.
13
15
  * Branches: good creds -> LoggedIn; bad/locked -> LoginPage with error banner.
14
- * stubBefore/stubAfter drive the floating todo dock (Method fill/click advances
15
- * todoIndex mid-act; stubAfter marks complete / fail).
16
16
  */
17
- export const SubmitLoginActionBlock = defineMethodBlock<LoginPage, LoginSubmitOutcome>({
17
+ export const SubmitLoginBlock = defineMethodBlock<LoginPage, LoginSubmitOutcome>({
18
18
  name: "submit-login",
19
- description: "Logs a user in when credentials are valid; stays on LoginPage when auth fails.",
20
- requires: [LoginCreds.key],
19
+ description: "Submits the login form; stays on LoginPage when auth fails.",
21
20
  instruction: {
22
- async act(page, _input, mem) {
23
- const { username, password } = mem.get(LoginCreds.key);
24
- await page.locator("#user-name").fill(username);
25
- await page.locator("#password").fill(password);
21
+ async act(page) {
26
22
  // noWaitAfter: observe owns the inventory URL wait. Default click
27
23
  // navigation-wait can hang under waygraph auto's demo cursor patch.
28
- await page.locator("#login-button").click({ noWaitAfter: true });
24
+ await page.locator(LoginSel.loginButton).click({ noWaitAfter: true });
29
25
  },
30
26
  async observe(page): Promise<LoginObserve> {
31
27
  // Race inventory nav vs error banner - locked_out / wrong password show
32
28
  // Epic sadface immediately; do not burn the full inventory timeout.
33
29
  const inventory = page.waitForURL(/\/inventory\.html/, { timeout: 8_000 }).then(() => "success" as const);
34
30
  const errorBanner = page
35
- .locator('[data-test="error"]')
31
+ .locator(LoginSel.errorBanner)
36
32
  .first()
37
33
  .waitFor({ state: "visible", timeout: 8_000 })
38
34
  .then(() => "failure" as const);
@@ -46,45 +42,11 @@ export const SubmitLoginActionBlock = defineMethodBlock<LoginPage, LoginSubmitOu
46
42
  verify: (out) =>
47
43
  out.__state === "LoggedIn"
48
44
  ? [Trait.url({ pathname: "/inventory.html" })]
49
- : [Trait.visible('[data-test="error"]')],
50
- // Open lifecycle: banner title, todos, Screen Studio camera zoom,
51
- // sequential highlight queue (appear / dwell / fade), focus + color.
45
+ : [Trait.visible(LoginSel.errorBanner)],
52
46
  stubBefore: (ctx: StubCtx) => {
53
- ctx.title("Signing in · mobile");
54
- ctx.device("mobile");
55
- ctx.portrait();
56
- ctx.todos(
57
- "saucedemo",
58
- [
59
- { id: "login-user", text: "Enter username" },
60
- { id: "login-pass", text: "Enter password" },
61
- { id: "login-submit", text: "Tap Login" },
62
- { id: "cart-find", text: "Find the product" },
63
- { id: "cart-add", text: "Add to cart" },
64
- { id: "cart-open", text: "Open cart" },
65
- ],
66
- { title: "Device showcase", index: 0 },
67
- );
68
- ctx.zoom(1.35);
69
47
  ctx.highlights({
70
- username: {
71
- selector: "#user-name",
72
- label: "Username",
73
- todo: "login-user",
74
- focus: true,
75
- color: "#c9a6ff",
76
- zoom: 1.4,
77
- },
78
- password: {
79
- selector: "#password",
80
- label: "Password",
81
- todo: "login-pass",
82
- focus: true,
83
- color: "#c9a6ff",
84
- zoom: 1.4,
85
- },
86
48
  submit: {
87
- selector: "#login-button",
49
+ selector: LoginSel.loginButton,
88
50
  label: "Login",
89
51
  todo: "login-submit",
90
52
  focus: true,
@@ -108,7 +70,7 @@ export const SubmitLoginActionBlock = defineMethodBlock<LoginPage, LoginSubmitOu
108
70
  { title: "Sign in", style: "checklist" },
109
71
  );
110
72
  ctx.ring("error", {
111
- selector: '[data-test="error"]',
73
+ selector: LoginSel.errorBanner,
112
74
  label: "Login error banner",
113
75
  tone: "danger",
114
76
  focus: true,
@@ -144,7 +106,7 @@ export const SubmitLoginActionBlock = defineMethodBlock<LoginPage, LoginSubmitOu
144
106
  stubOnError: (ctx: StubCtx) => {
145
107
  ctx.title("Login failed");
146
108
  ctx.ring("error", {
147
- selector: '[data-test="error"]',
109
+ selector: LoginSel.errorBanner,
148
110
  label: "Login error banner",
149
111
  tone: "danger",
150
112
  focus: true,
@@ -1,5 +1,6 @@
1
1
  import { defineMethodBlock, checkpoint, Trait } from "waygraph";
2
2
  import type { LoggedIn, LoginPage } from "../../../states/checkout.states.js";
3
+ import { LoginSel } from "./login.sel.js";
3
4
 
4
5
  /**
5
6
  * Kind: Method
@@ -13,10 +14,10 @@ export const SubmitLogoutBlock = defineMethodBlock<LoggedIn, LoginPage>({
13
14
  description: "Opens the burger menu and logs out.",
14
15
  instruction: {
15
16
  async act(page) {
16
- await page.locator("#react-burger-menu-btn").click();
17
- await page.locator("#logout_sidebar_link").click();
17
+ await page.locator(LoginSel.burgerMenuButton).click();
18
+ await page.locator(LoginSel.logoutLink).click();
18
19
  },
19
20
  resolve: () => checkpoint("LoginPage"),
20
- verify: [Trait.visible("#login-button")],
21
+ verify: [Trait.visible(LoginSel.loginButton)],
21
22
  },
22
23
  });