@mohasinac/appkit 4.34.1 → 4.35.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 (232) hide show
  1. package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +32 -2
  2. package/dist/features/tester/components/TesterChecklistStepRow.d.ts +9 -1
  3. package/dist/features/tester/components/TesterChecklistStepRow.js +31 -2
  4. package/dist/features/tester/components/TesterHubView.js +8 -0
  5. package/dist/features/tester/schemas/firestore.d.ts +109 -0
  6. package/dist/features/tester/schemas/firestore.js +14 -0
  7. package/dist/features/tester/seed-data/_money-flows.d.ts +23 -0
  8. package/dist/features/tester/seed-data/_money-flows.js +430 -0
  9. package/dist/features/tester/seed-data/authored/_types.d.ts +33 -0
  10. package/dist/features/tester/seed-data/authored/_types.js +35 -0
  11. package/dist/features/tester/seed-data/authored/account-auth__profile-settings.d.ts +2 -0
  12. package/dist/features/tester/seed-data/authored/account-auth__profile-settings.js +207 -0
  13. package/dist/features/tester/seed-data/authored/account-auth__signup-login.d.ts +2 -0
  14. package/dist/features/tester/seed-data/authored/account-auth__signup-login.js +298 -0
  15. package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.d.ts +2 -0
  16. package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.js +33 -0
  17. package/dist/features/tester/seed-data/authored/account-auth__testing-program.d.ts +2 -0
  18. package/dist/features/tester/seed-data/authored/account-auth__testing-program.js +138 -0
  19. package/dist/features/tester/seed-data/authored/addresses__address-filters.d.ts +2 -0
  20. package/dist/features/tester/seed-data/authored/addresses__address-filters.js +36 -0
  21. package/dist/features/tester/seed-data/authored/addresses__postal-lookup.d.ts +2 -0
  22. package/dist/features/tester/seed-data/authored/addresses__postal-lookup.js +75 -0
  23. package/dist/features/tester/seed-data/authored/addresses__postal-validation.d.ts +2 -0
  24. package/dist/features/tester/seed-data/authored/addresses__postal-validation.js +72 -0
  25. package/dist/features/tester/seed-data/authored/addresses__state-picker.d.ts +2 -0
  26. package/dist/features/tester/seed-data/authored/addresses__state-picker.js +54 -0
  27. package/dist/features/tester/seed-data/authored/addresses__unban-request.d.ts +2 -0
  28. package/dist/features/tester/seed-data/authored/addresses__unban-request.js +39 -0
  29. package/dist/features/tester/seed-data/authored/admin__bans-and-trust.d.ts +2 -0
  30. package/dist/features/tester/seed-data/authored/admin__bans-and-trust.js +226 -0
  31. package/dist/features/tester/seed-data/authored/admin__blog-faqs.d.ts +2 -0
  32. package/dist/features/tester/seed-data/authored/admin__blog-faqs.js +82 -0
  33. package/dist/features/tester/seed-data/authored/admin__bulk-actions.d.ts +2 -0
  34. package/dist/features/tester/seed-data/authored/admin__bulk-actions.js +177 -0
  35. package/dist/features/tester/seed-data/authored/admin__bundles.d.ts +2 -0
  36. package/dist/features/tester/seed-data/authored/admin__bundles.js +97 -0
  37. package/dist/features/tester/seed-data/authored/admin__buyer-data-admin.d.ts +2 -0
  38. package/dist/features/tester/seed-data/authored/admin__buyer-data-admin.js +232 -0
  39. package/dist/features/tester/seed-data/authored/admin__catalog-listings.d.ts +2 -0
  40. package/dist/features/tester/seed-data/authored/admin__catalog-listings.js +306 -0
  41. package/dist/features/tester/seed-data/authored/admin__category-brand-authoring.d.ts +2 -0
  42. package/dist/features/tester/seed-data/authored/admin__category-brand-authoring.js +158 -0
  43. package/dist/features/tester/seed-data/authored/admin__classifieds-digitalcodes-live.d.ts +2 -0
  44. package/dist/features/tester/seed-data/authored/admin__classifieds-digitalcodes-live.js +78 -0
  45. package/dist/features/tester/seed-data/authored/admin__content-deletes.d.ts +2 -0
  46. package/dist/features/tester/seed-data/authored/admin__content-deletes.js +261 -0
  47. package/dist/features/tester/seed-data/authored/admin__content-marketing.d.ts +2 -0
  48. package/dist/features/tester/seed-data/authored/admin__content-marketing.js +151 -0
  49. package/dist/features/tester/seed-data/authored/admin__coupons.d.ts +2 -0
  50. package/dist/features/tester/seed-data/authored/admin__coupons.js +214 -0
  51. package/dist/features/tester/seed-data/authored/admin__events-raffles-spin.d.ts +2 -0
  52. package/dist/features/tester/seed-data/authored/admin__events-raffles-spin.js +160 -0
  53. package/dist/features/tester/seed-data/authored/admin__media-watermark.d.ts +2 -0
  54. package/dist/features/tester/seed-data/authored/admin__media-watermark.js +104 -0
  55. package/dist/features/tester/seed-data/authored/admin__orders-fulfillment.d.ts +2 -0
  56. package/dist/features/tester/seed-data/authored/admin__orders-fulfillment.js +350 -0
  57. package/dist/features/tester/seed-data/authored/admin__prize-draws-lotteries.d.ts +2 -0
  58. package/dist/features/tester/seed-data/authored/admin__prize-draws-lotteries.js +105 -0
  59. package/dist/features/tester/seed-data/authored/admin__site-system.d.ts +2 -0
  60. package/dist/features/tester/seed-data/authored/admin__site-system.js +590 -0
  61. package/dist/features/tester/seed-data/authored/admin__uncovered-admin-pages.d.ts +2 -0
  62. package/dist/features/tester/seed-data/authored/admin__uncovered-admin-pages.js +235 -0
  63. package/dist/features/tester/seed-data/authored/admin__users-trust.d.ts +2 -0
  64. package/dist/features/tester/seed-data/authored/admin__users-trust.js +569 -0
  65. package/dist/features/tester/seed-data/authored/buying__bidding.d.ts +2 -0
  66. package/dist/features/tester/seed-data/authored/buying__bidding.js +417 -0
  67. package/dist/features/tester/seed-data/authored/buying__browsing-search.d.ts +2 -0
  68. package/dist/features/tester/seed-data/authored/buying__browsing-search.js +653 -0
  69. package/dist/features/tester/seed-data/authored/buying__buying-checkout.d.ts +2 -0
  70. package/dist/features/tester/seed-data/authored/buying__buying-checkout.js +533 -0
  71. package/dist/features/tester/seed-data/authored/buying__buying-coupons.d.ts +2 -0
  72. package/dist/features/tester/seed-data/authored/buying__buying-coupons.js +379 -0
  73. package/dist/features/tester/seed-data/authored/buying__cart.d.ts +2 -0
  74. package/dist/features/tester/seed-data/authored/buying__cart.js +1171 -0
  75. package/dist/features/tester/seed-data/authored/buying__image-tile-layout.d.ts +2 -0
  76. package/dist/features/tester/seed-data/authored/buying__image-tile-layout.js +140 -0
  77. package/dist/features/tester/seed-data/authored/buying__my-orders.d.ts +2 -0
  78. package/dist/features/tester/seed-data/authored/buying__my-orders.js +257 -0
  79. package/dist/features/tester/seed-data/authored/buying__offers.d.ts +2 -0
  80. package/dist/features/tester/seed-data/authored/buying__offers.js +1111 -0
  81. package/dist/features/tester/seed-data/authored/buying__order-status-lifecycle.d.ts +2 -0
  82. package/dist/features/tester/seed-data/authored/buying__order-status-lifecycle.js +252 -0
  83. package/dist/features/tester/seed-data/authored/buying__product-detail.d.ts +2 -0
  84. package/dist/features/tester/seed-data/authored/buying__product-detail.js +387 -0
  85. package/dist/features/tester/seed-data/authored/buying__return-request.d.ts +2 -0
  86. package/dist/features/tester/seed-data/authored/buying__return-request.js +152 -0
  87. package/dist/features/tester/seed-data/authored/buying__reviews-pagination.d.ts +2 -0
  88. package/dist/features/tester/seed-data/authored/buying__reviews-pagination.js +242 -0
  89. package/dist/features/tester/seed-data/authored/buying__reviews.d.ts +2 -0
  90. package/dist/features/tester/seed-data/authored/buying__reviews.js +113 -0
  91. package/dist/features/tester/seed-data/authored/buying__user-dashboard-extras.d.ts +2 -0
  92. package/dist/features/tester/seed-data/authored/buying__user-dashboard-extras.js +283 -0
  93. package/dist/features/tester/seed-data/authored/buying__user-dashboard-navigation.d.ts +2 -0
  94. package/dist/features/tester/seed-data/authored/buying__user-dashboard-navigation.js +167 -0
  95. package/dist/features/tester/seed-data/authored/buying__user-uncovered-pages.d.ts +2 -0
  96. package/dist/features/tester/seed-data/authored/buying__user-uncovered-pages.js +90 -0
  97. package/dist/features/tester/seed-data/authored/buying__wishlist-history.d.ts +2 -0
  98. package/dist/features/tester/seed-data/authored/buying__wishlist-history.js +344 -0
  99. package/dist/features/tester/seed-data/authored/community-support__public-profile.d.ts +2 -0
  100. package/dist/features/tester/seed-data/authored/community-support__public-profile.js +53 -0
  101. package/dist/features/tester/seed-data/authored/community-support__support-tickets.d.ts +2 -0
  102. package/dist/features/tester/seed-data/authored/community-support__support-tickets.js +76 -0
  103. package/dist/features/tester/seed-data/authored/content-discovery__blog.d.ts +2 -0
  104. package/dist/features/tester/seed-data/authored/content-discovery__blog.js +93 -0
  105. package/dist/features/tester/seed-data/authored/content-discovery__category-brand-relations.d.ts +2 -0
  106. package/dist/features/tester/seed-data/authored/content-discovery__category-brand-relations.js +149 -0
  107. package/dist/features/tester/seed-data/authored/content-discovery__coupons.d.ts +2 -0
  108. package/dist/features/tester/seed-data/authored/content-discovery__coupons.js +121 -0
  109. package/dist/features/tester/seed-data/authored/content-discovery__event-participation.d.ts +2 -0
  110. package/dist/features/tester/seed-data/authored/content-discovery__event-participation.js +207 -0
  111. package/dist/features/tester/seed-data/authored/content-discovery__events.d.ts +2 -0
  112. package/dist/features/tester/seed-data/authored/content-discovery__events.js +318 -0
  113. package/dist/features/tester/seed-data/authored/content-discovery__faq-help.d.ts +2 -0
  114. package/dist/features/tester/seed-data/authored/content-discovery__faq-help.js +65 -0
  115. package/dist/features/tester/seed-data/authored/content-discovery__notifications.d.ts +2 -0
  116. package/dist/features/tester/seed-data/authored/content-discovery__notifications.js +147 -0
  117. package/dist/features/tester/seed-data/authored/content-discovery__search.d.ts +2 -0
  118. package/dist/features/tester/seed-data/authored/content-discovery__search.js +332 -0
  119. package/dist/features/tester/seed-data/authored/cta-layout__checkout-bottom-bar.d.ts +2 -0
  120. package/dist/features/tester/seed-data/authored/cta-layout__checkout-bottom-bar.js +53 -0
  121. package/dist/features/tester/seed-data/authored/cta-layout__dialog-footers.d.ts +2 -0
  122. package/dist/features/tester/seed-data/authored/cta-layout__dialog-footers.js +52 -0
  123. package/dist/features/tester/seed-data/authored/cta-layout__editor-action-bar.d.ts +2 -0
  124. package/dist/features/tester/seed-data/authored/cta-layout__editor-action-bar.js +35 -0
  125. package/dist/features/tester/seed-data/authored/cta-layout__navbar-ctas.d.ts +2 -0
  126. package/dist/features/tester/seed-data/authored/cta-layout__navbar-ctas.js +141 -0
  127. package/dist/features/tester/seed-data/authored/cta-layout__product-bottom-bar.d.ts +2 -0
  128. package/dist/features/tester/seed-data/authored/cta-layout__product-bottom-bar.js +35 -0
  129. package/dist/features/tester/seed-data/authored/design-ux__back-to-top-button.d.ts +2 -0
  130. package/dist/features/tester/seed-data/authored/design-ux__back-to-top-button.js +95 -0
  131. package/dist/features/tester/seed-data/authored/design-ux__carousel-arrow-bounds.d.ts +2 -0
  132. package/dist/features/tester/seed-data/authored/design-ux__carousel-arrow-bounds.js +191 -0
  133. package/dist/features/tester/seed-data/authored/design-ux__dashboard-layout.d.ts +2 -0
  134. package/dist/features/tester/seed-data/authored/design-ux__dashboard-layout.js +158 -0
  135. package/dist/features/tester/seed-data/authored/design-ux__footer-theme.d.ts +2 -0
  136. package/dist/features/tester/seed-data/authored/design-ux__footer-theme.js +106 -0
  137. package/dist/features/tester/seed-data/authored/design-ux__form-validation-errors.d.ts +2 -0
  138. package/dist/features/tester/seed-data/authored/design-ux__form-validation-errors.js +88 -0
  139. package/dist/features/tester/seed-data/authored/design-ux__general-design.d.ts +2 -0
  140. package/dist/features/tester/seed-data/authored/design-ux__general-design.js +204 -0
  141. package/dist/features/tester/seed-data/authored/design-ux__hand-mode-layout.d.ts +2 -0
  142. package/dist/features/tester/seed-data/authored/design-ux__hand-mode-layout.js +301 -0
  143. package/dist/features/tester/seed-data/authored/design-ux__homepage-carousels.d.ts +2 -0
  144. package/dist/features/tester/seed-data/authored/design-ux__homepage-carousels.js +407 -0
  145. package/dist/features/tester/seed-data/authored/design-ux__status-badge-legibility.d.ts +2 -0
  146. package/dist/features/tester/seed-data/authored/design-ux__status-badge-legibility.js +214 -0
  147. package/dist/features/tester/seed-data/authored/design-ux__sticky-cta-bar.d.ts +2 -0
  148. package/dist/features/tester/seed-data/authored/design-ux__sticky-cta-bar.js +275 -0
  149. package/dist/features/tester/seed-data/authored/index.d.ts +2 -0
  150. package/dist/features/tester/seed-data/authored/index.js +237 -0
  151. package/dist/features/tester/seed-data/authored/page-wiring__data-loss.d.ts +2 -0
  152. package/dist/features/tester/seed-data/authored/page-wiring__data-loss.js +102 -0
  153. package/dist/features/tester/seed-data/authored/page-wiring__detail-pages.d.ts +2 -0
  154. package/dist/features/tester/seed-data/authored/page-wiring__detail-pages.js +50 -0
  155. package/dist/features/tester/seed-data/authored/page-wiring__drawer-pages.d.ts +2 -0
  156. package/dist/features/tester/seed-data/authored/page-wiring__drawer-pages.js +66 -0
  157. package/dist/features/tester/seed-data/authored/page-wiring__reachability.d.ts +2 -0
  158. package/dist/features/tester/seed-data/authored/page-wiring__reachability.js +115 -0
  159. package/dist/features/tester/seed-data/authored/public-pages__auth-error-pages.d.ts +2 -0
  160. package/dist/features/tester/seed-data/authored/public-pages__auth-error-pages.js +136 -0
  161. package/dist/features/tester/seed-data/authored/public-pages__bug-hunters.d.ts +2 -0
  162. package/dist/features/tester/seed-data/authored/public-pages__bug-hunters.js +69 -0
  163. package/dist/features/tester/seed-data/authored/public-pages__core-listing-pages.d.ts +2 -0
  164. package/dist/features/tester/seed-data/authored/public-pages__core-listing-pages.js +263 -0
  165. package/dist/features/tester/seed-data/authored/public-pages__help-how-it-works.d.ts +2 -0
  166. package/dist/features/tester/seed-data/authored/public-pages__help-how-it-works.js +102 -0
  167. package/dist/features/tester/seed-data/authored/public-pages__help-scams-guides-subpages.d.ts +2 -0
  168. package/dist/features/tester/seed-data/authored/public-pages__help-scams-guides-subpages.js +234 -0
  169. package/dist/features/tester/seed-data/authored/public-pages__legal-policy-pages.d.ts +2 -0
  170. package/dist/features/tester/seed-data/authored/public-pages__legal-policy-pages.js +126 -0
  171. package/dist/features/tester/seed-data/authored/public-pages__stores-sellers-directories.d.ts +2 -0
  172. package/dist/features/tester/seed-data/authored/public-pages__stores-sellers-directories.js +255 -0
  173. package/dist/features/tester/seed-data/authored/search-and-nav__employee-permissions.d.ts +2 -0
  174. package/dist/features/tester/seed-data/authored/search-and-nav__employee-permissions.js +59 -0
  175. package/dist/features/tester/seed-data/authored/search-and-nav__header-search.d.ts +2 -0
  176. package/dist/features/tester/seed-data/authored/search-and-nav__header-search.js +88 -0
  177. package/dist/features/tester/seed-data/authored/search-and-nav__settings-deep-links.d.ts +2 -0
  178. package/dist/features/tester/seed-data/authored/search-and-nav__settings-deep-links.js +51 -0
  179. package/dist/features/tester/seed-data/authored/search-and-nav__sidebar-search.d.ts +2 -0
  180. package/dist/features/tester/seed-data/authored/search-and-nav__sidebar-search.js +35 -0
  181. package/dist/features/tester/seed-data/authored/selling__become-seller.d.ts +2 -0
  182. package/dist/features/tester/seed-data/authored/selling__become-seller.js +94 -0
  183. package/dist/features/tester/seed-data/authored/selling__final-sale-authoring.d.ts +2 -0
  184. package/dist/features/tester/seed-data/authored/selling__final-sale-authoring.js +107 -0
  185. package/dist/features/tester/seed-data/authored/selling__listing-a-product.d.ts +2 -0
  186. package/dist/features/tester/seed-data/authored/selling__listing-a-product.js +285 -0
  187. package/dist/features/tester/seed-data/authored/selling__listing-lifecycle.d.ts +2 -0
  188. package/dist/features/tester/seed-data/authored/selling__listing-lifecycle.js +326 -0
  189. package/dist/features/tester/seed-data/authored/selling__listing-type-fields-roundtrip.d.ts +2 -0
  190. package/dist/features/tester/seed-data/authored/selling__listing-type-fields-roundtrip.js +136 -0
  191. package/dist/features/tester/seed-data/authored/selling__media-limits.d.ts +2 -0
  192. package/dist/features/tester/seed-data/authored/selling__media-limits.js +128 -0
  193. package/dist/features/tester/seed-data/authored/selling__sectionised-forms.d.ts +2 -0
  194. package/dist/features/tester/seed-data/authored/selling__sectionised-forms.js +167 -0
  195. package/dist/features/tester/seed-data/authored/selling__seller-analytics-payouts.d.ts +2 -0
  196. package/dist/features/tester/seed-data/authored/selling__seller-analytics-payouts.js +117 -0
  197. package/dist/features/tester/seed-data/authored/selling__seller-bids-bundles-filters.d.ts +2 -0
  198. package/dist/features/tester/seed-data/authored/selling__seller-bids-bundles-filters.js +88 -0
  199. package/dist/features/tester/seed-data/authored/selling__seller-catalog-org.d.ts +2 -0
  200. package/dist/features/tester/seed-data/authored/selling__seller-catalog-org.js +151 -0
  201. package/dist/features/tester/seed-data/authored/selling__seller-custom-brands.d.ts +2 -0
  202. package/dist/features/tester/seed-data/authored/selling__seller-custom-brands.js +105 -0
  203. package/dist/features/tester/seed-data/authored/selling__seller-guide.d.ts +2 -0
  204. package/dist/features/tester/seed-data/authored/selling__seller-guide.js +33 -0
  205. package/dist/features/tester/seed-data/authored/selling__seller-listing-types.d.ts +2 -0
  206. package/dist/features/tester/seed-data/authored/selling__seller-listing-types.js +347 -0
  207. package/dist/features/tester/seed-data/authored/selling__seller-marketing-extras.d.ts +2 -0
  208. package/dist/features/tester/seed-data/authored/selling__seller-marketing-extras.js +166 -0
  209. package/dist/features/tester/seed-data/authored/selling__seller-ops-comms.d.ts +2 -0
  210. package/dist/features/tester/seed-data/authored/selling__seller-ops-comms.js +89 -0
  211. package/dist/features/tester/seed-data/authored/selling__seller-orders.d.ts +2 -0
  212. package/dist/features/tester/seed-data/authored/selling__seller-orders.js +195 -0
  213. package/dist/features/tester/seed-data/authored/selling__seller-shipping-payouts-setup.d.ts +2 -0
  214. package/dist/features/tester/seed-data/authored/selling__seller-shipping-payouts-setup.js +180 -0
  215. package/dist/features/tester/seed-data/authored/selling__store-dashboard-navigation.d.ts +2 -0
  216. package/dist/features/tester/seed-data/authored/selling__store-dashboard-navigation.js +164 -0
  217. package/dist/features/tester/seed-data/authored/selling__store-uncovered-pages.d.ts +2 -0
  218. package/dist/features/tester/seed-data/authored/selling__store-uncovered-pages.js +116 -0
  219. package/dist/features/tester/seed-data/authored/seo__canonical-and-host.d.ts +2 -0
  220. package/dist/features/tester/seed-data/authored/seo__canonical-and-host.js +111 -0
  221. package/dist/features/tester/seed-data/authored/seo__og-images.d.ts +2 -0
  222. package/dist/features/tester/seed-data/authored/seo__og-images.js +91 -0
  223. package/dist/features/tester/seed-data/authored/seo__page-metadata.d.ts +2 -0
  224. package/dist/features/tester/seed-data/authored/seo__page-metadata.js +122 -0
  225. package/dist/features/tester/seed-data/authored/seo__sitemap-and-robots.d.ts +2 -0
  226. package/dist/features/tester/seed-data/authored/seo__sitemap-and-robots.js +105 -0
  227. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +744 -1
  228. package/dist/seed/carousel-slides-seed-data.js +1 -1
  229. package/dist/seed/products-standard-seed-data.js +2 -2
  230. package/dist/seed/reviews-seed-data.js +6 -1
  231. package/package.json +1 -1
  232. package/scripts/seed-cli.mjs +6 -0
@@ -0,0 +1,149 @@
1
+ /*
2
+ * WHY: Authored six-part procedures for the content-discovery/category-brand-relations page.
3
+ * WHAT: 8 case(s), keyed by full checklist id.
4
+ *
5
+ * 🛑 THE TWO SIDES OF THE TREE ARE ASYMMETRIC AND THAT ASYMMETRY IS THE POINT.
6
+ *
7
+ * A PRODUCT carries its full ancestor chain, so a category page matches on its own
8
+ * id alone. A STORE carries a single category with no chain, so the store side
9
+ * genuinely needs the descendant list. Reversing either is a real defect that
10
+ * renders as an empty grid: expanding a root into every descendant blows the
11
+ * query's value cap and the throw is swallowed, while NOT expanding the store side
12
+ * hides every store filed below the top tier.
13
+ *
14
+ * Brands are rows in the same collection as categories, discriminated by a type
15
+ * field, and they match products by DISPLAY NAME rather than by id — so renaming a
16
+ * brand silently orphans its catalogue while the page keeps rendering.
17
+ *
18
+ * @tag domain:tester
19
+ * @tag layer:seed
20
+ * @tag pattern:none
21
+ * @tag access:server-only
22
+ * @tag consumers:seed-data/authored/index.ts
23
+ * @tag sideEffects:none
24
+ */
25
+ export const authored = {
26
+ "checklist-content-discovery-category-brand-relations-tier-depth-reachable": {
27
+ roles: ["guest"],
28
+ startPage: "/categories",
29
+ steps: [
30
+ "Open /categories and find Spinning Tops.",
31
+ "Click into it and read the child categories listed.",
32
+ "Click Beyblade Burst and read its children.",
33
+ "Click Burst Parts and read its children.",
34
+ "Click one of those and note there are no further children.",
35
+ "Count how many clicks it took to reach the leaf.",
36
+ ],
37
+ expectedBehaviour: "Every tier is reachable by clicking, with no typed URLs. A tier that renders but offers no way down is unreachable in practice, which is the same as not existing for anyone browsing.",
38
+ expectedUiState: "Four levels: Spinning Tops, then Beyblade Burst, then Burst Parts, then a leaf such as Layers or Drivers. Each page lists its own children until the leaf, which lists none.",
39
+ expectedData: { tiersReached: 4 },
40
+ endResult: "Read-only.",
41
+ },
42
+ "checklist-content-discovery-category-brand-relations-second-root-reachable": {
43
+ roles: ["guest"],
44
+ startPage: "/categories",
45
+ steps: [
46
+ "Open /categories and read every top-level category shown.",
47
+ "Check both Spinning Tops and Living Collectibles are present.",
48
+ "Click Living Collectibles and read its children.",
49
+ "Click down to a leaf under it.",
50
+ "Check the leaf lists at least one live-item listing.",
51
+ ],
52
+ inputs: { rootA: "category-spinning-tops", rootB: "category-living-collectibles" },
53
+ expectedBehaviour: "Both roots are on the index. The tree had one root and two tiers before it was rebuilt, so the live-item listings carried no category at all and were unreachable from every category and brand page — a whole listing type invisible to browsing while its detail pages worked fine.",
54
+ expectedUiState: "Two roots on the index, and the Living Collectibles branch walks down to a leaf holding a live listing. One root, or a second root that leads nowhere, is the finding.",
55
+ endResult: "Read-only.",
56
+ },
57
+ "checklist-content-discovery-category-brand-relations-root-page-shows-descendant-products": {
58
+ roles: ["guest"],
59
+ startPage: "/categories/category-spinning-tops",
60
+ steps: [
61
+ "Open /categories/category-beyblade-burst and note the title of one product listed there.",
62
+ "Open /categories/category-spinning-tops.",
63
+ "Search the listing for that same product.",
64
+ "Read the product count shown on the root page.",
65
+ "Compare it against the counts on its four generation children.",
66
+ ],
67
+ inputs: { rootId: "category-spinning-tops", childId: "category-beyblade-burst" },
68
+ expectedBehaviour: "A product carries its FULL ancestor chain, so a root page matches on its own id and needs no descendant expansion. A product visible on a leaf but missing from its root means the chain was not written on the product side — and nothing appends ancestors on write today, so a listing created through the seller form has a single-element chain and is invisible on every ancestor page.",
69
+ expectedUiState: "The product from the child page also appears on the root page, and the root's count is at least the sum of its children's. A root showing only its own directly-tagged products — normally none — is the finding.",
70
+ endResult: "Read-only.",
71
+ },
72
+ "checklist-content-discovery-category-brand-relations-root-page-not-blank-on-large-tree": {
73
+ roles: ["guest"],
74
+ startPage: "/categories/category-spinning-tops",
75
+ steps: [
76
+ "Open /categories/category-spinning-tops with the browser console open.",
77
+ "Read whether the product grid renders rows or is empty.",
78
+ "Read the console for any error.",
79
+ "Read the network panel for any failed request.",
80
+ "Change the sort and read the grid again.",
81
+ "Page forward once and read it again.",
82
+ ],
83
+ inputs: { rootId: "category-spinning-tops" },
84
+ expectedBehaviour: "The root page renders products. Expanding a root into itself plus every descendant on a fifty-node tree exceeds the query's value cap, the query throws, and every caller wraps that fetch so the failure resolves to nothing — a blank grid with no error in the console, no failed request, and nothing to point at.",
85
+ expectedUiState: "Rows render on the default view and after a sort change and a page forward, with a clean console. A blank grid is the finding precisely BECAUSE nothing else signals it.",
86
+ expectedData: { consoleErrors: 0 },
87
+ endResult: "Read-only.",
88
+ },
89
+ "checklist-content-discovery-category-brand-relations-mid-tier-scopes-to-own-subtree": {
90
+ roles: ["guest"],
91
+ startPage: "/categories/category-beyblade-burst",
92
+ steps: [
93
+ "Open /categories/category-spinning-tops and note its product count.",
94
+ "Open /categories/category-beyblade-burst and note its count.",
95
+ "Compare the two.",
96
+ "Open /categories/category-beyblade-metal and note the title of a product listed there.",
97
+ "Search for it on the Beyblade Burst page.",
98
+ ],
99
+ inputs: { parentId: "category-spinning-tops", childId: "category-beyblade-burst" },
100
+ expectedBehaviour: "A mid-tier category shows its own subtree only. Equal counts on parent and child mean the scoping is not being applied at all — which reads as a working page right up until somebody notices a Metal Fight product on the Burst page.",
101
+ expectedUiState: "The child's count is strictly smaller than the parent's, and no Metal Fight product appears on the Burst page. Equal counts, or a sibling's product appearing, are both findings.",
102
+ endResult: "Read-only.",
103
+ },
104
+ "checklist-content-discovery-category-brand-relations-store-under-deep-category-visible-at-root": {
105
+ roles: ["guest"],
106
+ startPage: "/categories/category-spinning-tops",
107
+ steps: [
108
+ "Open /categories/category-spinning-tops and open its Stores tab.",
109
+ "Read every store listed.",
110
+ "Open a deeper category under the same root and open its Stores tab.",
111
+ "Read the stores listed there.",
112
+ "Check every store from the deeper page also appears on the root's tab.",
113
+ ],
114
+ inputs: { rootId: "category-spinning-tops" },
115
+ expectedBehaviour: "A store carries a SINGLE category with no ancestor chain, so the store side genuinely does need the descendant list — the opposite of the product side. It expanded direct children only, so a store filed three tiers down was invisible on its root while its products were not, which is why the two sides look inconsistent when this breaks.",
116
+ expectedUiState: "Every store on a descendant category's Stores tab also appears on the root's. A store visible deep and absent at the root is the finding, named.",
117
+ endResult: "Read-only.",
118
+ },
119
+ "checklist-content-discovery-category-brand-relations-brand-page-lists-its-products": {
120
+ roles: ["guest"],
121
+ startPage: "/brands/brand-takara-tomy",
122
+ steps: [
123
+ "Open /brands/brand-takara-tomy and read the brand name in the hero.",
124
+ "Read the products listed and count them.",
125
+ "Open one of those products and read the brand named on its detail page.",
126
+ "Compare that string against the brand page's name, character for character.",
127
+ "Repeat on /brands/brand-beyblade.",
128
+ ],
129
+ inputs: { brandId: "brand-takara-tomy" },
130
+ expectedBehaviour: "Products are matched to a brand by its DISPLAY NAME, not its id. The two strings must agree exactly, so renaming a brand orphans its entire catalogue — and the page still renders its hero, its editorial panels and an empty grid, with nothing anywhere reporting that a rename caused it.",
131
+ expectedUiState: "Both brand pages list products, and each listed product's own detail page names the same brand string as the page's title. An empty grid on a brand with known products is the finding.",
132
+ endResult: "Read-only.",
133
+ },
134
+ "checklist-content-discovery-category-brand-relations-brand-and-category-are-one-collection": {
135
+ roles: ["guest"],
136
+ startPage: "/brands/brand-takara-tomy",
137
+ steps: [
138
+ "Open /brands/brand-takara-tomy and read every panel on the page.",
139
+ "Note whether an About-this-brand panel with website, country and founding year is present.",
140
+ "Open /categories/category-beyblade-burst and read every panel there.",
141
+ "Check no About-this-brand panel appears on the category page.",
142
+ "Check both pages render their highlights and questions sections, or neither if both are unset.",
143
+ ],
144
+ inputs: { brandId: "brand-takara-tomy", categoryId: "category-beyblade-burst" },
145
+ expectedBehaviour: "A brand and a category are rows in ONE collection distinguished by a type field, so the only thing keeping their pages apart is that each renders the fields belonging to its own kind. Brand-only fields were seeded and accepted by the interface for a long time while nothing rendered them anywhere.",
146
+ expectedUiState: "The brand page shows website, country and founding year; the category page shows none of them and shows no empty labelled slots for them either.",
147
+ endResult: "Read-only.",
148
+ },
149
+ };
@@ -0,0 +1,2 @@
1
+ import type { AuthoredCase } from "./_types";
2
+ export declare const authored: Record<string, AuthoredCase>;
@@ -0,0 +1,121 @@
1
+ /*
2
+ * WHY: Authored six-part procedures for the content-discovery/coupons page.
3
+ * WHAT: 6 case(s), keyed by full checklist id.
4
+ *
5
+ * Written by hand, case by case, against the label each one states. There is no
6
+ * generator: the authoring scripts were deleted once it was clear they were
7
+ * scaffolding around work that is simply writing.
8
+ *
9
+ * These are the buyer-facing DISCOVERY cases — browsing, claiming, and the
10
+ * rejection messages. The stacking arithmetic lives on buying/buying-coupons and
11
+ * is not repeated here; a rule tested in two places drifts in one of them.
12
+ *
13
+ * @tag domain:tester
14
+ * @tag layer:seed
15
+ * @tag pattern:none
16
+ * @tag access:server-only
17
+ * @tag consumers:seed-data/authored/index.ts
18
+ * @tag sideEffects:none
19
+ */
20
+ export const authored = {
21
+ "checklist-content-discovery-coupons-view-claimed-coupons": {
22
+ roles: ["buyer"],
23
+ startPage: "/user/coupons",
24
+ steps: [
25
+ "Sign in as vivaan.kapoor@gmail.com / TempPass123!.",
26
+ "Open /user/coupons and read what is listed.",
27
+ "Open /promotions, click the 'Coupons' tab, and claim NEWBLADER.",
28
+ "Open /user/coupons again.",
29
+ "Read the NEWBLADER row — its code, discount, minimum spend and expiry.",
30
+ "Reload the page.",
31
+ ],
32
+ inputs: { coupon: "NEWBLADER" },
33
+ expectedBehaviour: "The wallet lists coupons this buyer has claimed, with enough detail to decide whether to use one. An unclaimed coupon has no row here at all, which is why claiming is part of the procedure rather than an assumption.",
34
+ expectedUiState: "Before claiming, the page either lists previously-claimed coupons or shows a named empty state — not a blank panel. After claiming, a NEWBLADER row appears carrying its code, its discount, any minimum spend and an expiry date. Values reading 'undefined' or 'NaN%' are the shape failure to watch for, since the card reads both a flat and a nested coupon shape.",
35
+ endResult: "The NEWBLADER row survives the reload.",
36
+ },
37
+ "checklist-content-discovery-coupons-coupon-discount-applied": {
38
+ roles: ["buyer"],
39
+ startPage: "/promotions",
40
+ steps: [
41
+ "Sign in as vivaan.kapoor@gmail.com / TempPass123!.",
42
+ "Open /promotions, click the 'Coupons' tab, and read the ARENA25 card's stated discount and minimum spend.",
43
+ "Add product-beyblade-burst-regalia-genesis (₹1,399, Beyblade Arena) to the cart.",
44
+ "Open /checkout and complete the address and add-ons steps.",
45
+ "Type ARENA25 in the coupon field and click 'Apply'.",
46
+ "Read the discount amount applied and compare it with what the card promised.",
47
+ ],
48
+ inputs: { coupon: "ARENA25", itemPrice: 1399 },
49
+ expectedBehaviour: "The discount a public card advertises is the discount checkout applies. A card that states a percentage while checkout applies a cap the card never mentioned is a promise the corpus cannot keep.",
50
+ expectedUiState: "The applied amount matches the card's stated terms, including any maximum-discount cap the card should also be stating. ARENA25 appears in the applied list with no error.",
51
+ endResult: "Reloading /checkout shows the same coupon and amount. A discrepancy between the card and the applied amount is a copy bug at minimum and a pricing bug at worst.",
52
+ },
53
+ "checklist-content-discovery-coupons-coupon-expired-rejected": {
54
+ roles: ["buyer"],
55
+ startPage: "/checkout",
56
+ steps: [
57
+ "Sign in as vivaan.kapoor@gmail.com / TempPass123!.",
58
+ "Add product-beyblade-burst-regalia-genesis (₹1,399) to the cart.",
59
+ "Open /checkout and complete the address and add-ons steps.",
60
+ "Type TESTEREXPIRED in the coupon field and click 'Apply'.",
61
+ "Read the exact wording of the rejection.",
62
+ ],
63
+ inputs: { coupon: "TESTEREXPIRED" },
64
+ expectedBehaviour: "An expired coupon is refused with a reason that names expiry specifically. TESTEREXPIRED is seeded with an end date a day in the past and isActive still true, so this exercises the date check rather than the active flag — the two are separate reasons and a single generic message cannot tell a buyer which applies.",
65
+ expectedUiState: "The rejection names expiry, in the shape 'This coupon has expired'. It does not read 'Invalid coupon', which would leave the buyer retyping a code that will never work. TESTEREXPIRED does not enter the applied list.",
66
+ expectedData: { couponApplied: false },
67
+ endResult: "Reloading /checkout shows TESTEREXPIRED absent.",
68
+ },
69
+ "checklist-content-discovery-coupons-coupon-below-min-purchase": {
70
+ roles: ["buyer"],
71
+ startPage: "/checkout",
72
+ steps: [
73
+ "Sign in as vivaan.kapoor@gmail.com / TempPass123!.",
74
+ "Add product-tester-standard-3 (₹99) to the cart and nothing else.",
75
+ "Open /checkout and complete the address and add-ons steps.",
76
+ "Type ARENA25 in the coupon field and click 'Apply'.",
77
+ "Read the exact wording of the rejection and whether it names the required amount.",
78
+ ],
79
+ inputs: { coupon: "ARENA25", cartSubtotal: 99, minPurchase: 1000 },
80
+ expectedBehaviour: "A coupon below its minimum spend is refused with a message that names the threshold, so the buyer knows how much more to add. The minimum is measured against the items the coupon could actually discount, not the whole cart.",
81
+ expectedUiState: "The rejection names a minimum purchase and states the amount. It is not a bare 'Invalid coupon'. ARENA25 does not enter the applied list.",
82
+ expectedData: { couponApplied: false },
83
+ endResult: "Reloading /checkout shows ARENA25 absent.",
84
+ },
85
+ "checklist-content-discovery-coupons-coupon-not-combinable": {
86
+ roles: ["buyer"],
87
+ startPage: "/checkout",
88
+ steps: [
89
+ "Sign in as vivaan.kapoor@gmail.com / TempPass123!.",
90
+ "Add product-beyblade-burst-regalia-genesis (₹1,399, Beyblade Arena) to the cart.",
91
+ "Open /checkout and complete the address and add-ons steps.",
92
+ "Type ARENA25 in the coupon field and click 'Apply'.",
93
+ "Type ARENAVIP in the coupon field and click 'Apply'.",
94
+ "Read the rejection and check whether it names the coupon already holding the slot.",
95
+ "Open the 'How coupons work' panel and read whether its rules match what just happened.",
96
+ ],
97
+ inputs: { coupon1: "ARENA25", coupon2: "ARENAVIP" },
98
+ expectedBehaviour: "Both are seller coupons on the same store, and the rule is one per store — so the second is refused. The refusal must name the coupon occupying the slot, otherwise the buyer cannot tell which one to remove.",
99
+ expectedUiState: "ARENA25 stays applied with its amount unchanged. The rejection names ARENA25 as the blocker. The help panel's stated rules match the behaviour just observed — a panel describing rules the code does not enforce is worse than no panel.",
100
+ expectedData: { storeCouponCount: 1 },
101
+ endResult: "Reloading /checkout shows ARENA25 applied and ARENAVIP absent.",
102
+ },
103
+ "checklist-content-discovery-coupons-coupon-per-user-limit": {
104
+ roles: ["buyer"],
105
+ startPage: "/checkout",
106
+ steps: [
107
+ "Sign in as vivaan.kapoor@gmail.com / TempPass123!.",
108
+ "Add product-beyblade-burst-regalia-genesis (₹1,399) to the cart.",
109
+ "Open /checkout, complete the address and add-ons steps, apply TESTERLIMITED, and place the order with Cash on Delivery.",
110
+ "Add product-beyblade-metal-storm-pegasus (₹1,299) to the cart.",
111
+ "Open /checkout, complete the address and add-ons steps, and type TESTERLIMITED in the coupon field.",
112
+ "Read the rejection.",
113
+ "Sign out, sign in as rehan.sheikh@gmail.com / TempPass123!, add the same item, and apply TESTERLIMITED at checkout.",
114
+ ],
115
+ inputs: { coupon: "TESTERLIMITED", perUserLimit: 1 },
116
+ expectedBehaviour: "TESTERLIMITED allows one use per user and has no global limit, so exhausting it for one buyer must leave it fully usable for the next. Enforcing a per-user limit as if it were global would withdraw the coupon from everybody after a single redemption.",
117
+ expectedUiState: "The second attempt by the same buyer is refused with a limit-reached message. The DIFFERENT buyer's attempt is accepted and the coupon appears in their applied list. A refusal for the second buyer means the limit is being read as global.",
118
+ expectedData: { perUserLimit: 1 },
119
+ endResult: "One order carries the discount and a second buyer can still use the code. The cross-account half is the case — the same-account half alone passes under either reading.",
120
+ },
121
+ };
@@ -0,0 +1,2 @@
1
+ import type { AuthoredCase } from "./_types";
2
+ export declare const authored: Record<string, AuthoredCase>;
@@ -0,0 +1,207 @@
1
+ /*
2
+ * WHY: Authored six-part procedures for the content-discovery/event-participation page.
3
+ * WHAT: 12 case(s), keyed by full checklist id.
4
+ *
5
+ * Events were covered from the ADMIN side — creating them, configuring raffles and
6
+ * spin wheels, drawing winners. What nobody had written was the participant's own
7
+ * experience: joining, seeing their own entry, finding themselves on a leaderboard,
8
+ * and learning that they won.
9
+ *
10
+ * That asymmetry is worth naming. An admin surface can look complete while the
11
+ * participant sees nothing at all, because the two are different pages reading
12
+ * different projections of the same record — and the admin one is the one that
13
+ * gets built first and looked at most.
14
+ *
15
+ * @tag domain:tester
16
+ * @tag layer:seed
17
+ * @tag pattern:none
18
+ * @tag access:server-only
19
+ * @tag consumers:seed-data/authored/index.ts
20
+ * @tag sideEffects:none
21
+ */
22
+ const SIGN_IN_BUYER = "Sign in as rehan.sheikh@gmail.com / TempPass123!.";
23
+ export const authored = {
24
+ "checklist-content-discovery-event-participation-join-event-as-participant": {
25
+ roles: ["buyer"],
26
+ startPage: "/events",
27
+ steps: [
28
+ SIGN_IN_BUYER,
29
+ "Open /events and pick an event whose status is active.",
30
+ "Open it and find the control for joining.",
31
+ "Use it.",
32
+ "Read the outcome shown.",
33
+ "Check it states whether the entry was confirmed or waitlisted, and why if waitlisted.",
34
+ ],
35
+ expectedBehaviour: "Joining produces an entry with an explicit status. Waitlisted and confirmed are different outcomes with different consequences, so reporting only 'joined' leaves the participant believing they have a place they may not have.",
36
+ expectedUiState: "The result names the entry's status, and a waitlisted entry says why. A bare success message is the finding.",
37
+ endResult: "One entry exists for this account.",
38
+ },
39
+ "checklist-content-discovery-event-participation-own-entry-visible-after-join": {
40
+ roles: ["buyer"],
41
+ startPage: "/events",
42
+ steps: [
43
+ SIGN_IN_BUYER,
44
+ "Join an active event.",
45
+ "Return to the event page and look for the participant's own entry.",
46
+ "Read its status there.",
47
+ "Check the page shows the participant is already in rather than offering to join again.",
48
+ "Look for the entry anywhere else the buyer's own account lists it.",
49
+ ],
50
+ expectedBehaviour: "A participant can see their own entry without asking anyone. An entry that exists only on an admin screen is a record about somebody that they cannot read — and the join control still offering itself is what makes them try again.",
51
+ expectedUiState: "The event page shows the participant's own entry with its status, and the join control reflects that they are already in.",
52
+ endResult: "The entry is visible to its owner.",
53
+ },
54
+ "checklist-content-discovery-event-participation-entry-survives-reload-and-relogin": {
55
+ roles: ["buyer"],
56
+ startPage: "/events",
57
+ steps: [
58
+ SIGN_IN_BUYER,
59
+ "Join an active event and note the entry's status.",
60
+ "Reload the event page and read the entry again.",
61
+ "Sign out and sign back in as the same account.",
62
+ "Open the event page and read the entry.",
63
+ "Open the event in a different browser signed in as the same account.",
64
+ ],
65
+ expectedBehaviour: "The entry is a stored record keyed to the account, so it survives a reload, a sign-out and a different device. An entry held only in the browser disappears the moment the participant switches devices, which is exactly when they check whether they got in.",
66
+ expectedUiState: "The entry and its status are present after the reload, after signing back in, and in the second browser.",
67
+ endResult: "The entry persists.",
68
+ },
69
+ "checklist-content-discovery-event-participation-cannot-join-twice": {
70
+ roles: ["buyer"],
71
+ startPage: "/events",
72
+ steps: [
73
+ SIGN_IN_BUYER,
74
+ "Join an active event.",
75
+ "Attempt to join the same event again from the page.",
76
+ "Read what happens.",
77
+ "Open the event in a second tab and attempt to join from there as well.",
78
+ "Check the account has exactly one entry.",
79
+ ],
80
+ expectedBehaviour: "A second join is refused rather than creating a duplicate. Two entries for one account inflate the entry count, double the account's odds in any draw, and are indistinguishable from two different people once the names are masked.",
81
+ expectedUiState: "The second attempt is refused with a message saying the account is already entered, and only one entry exists. Two entries is the finding.",
82
+ expectedData: { entriesForAccount: 1 },
83
+ endResult: "Exactly one entry exists.",
84
+ },
85
+ "checklist-content-discovery-event-participation-leave-or-cancel-entry": {
86
+ roles: ["buyer"],
87
+ startPage: "/events",
88
+ steps: [
89
+ SIGN_IN_BUYER,
90
+ "Join an active event.",
91
+ "Find the control for withdrawing and use it.",
92
+ "Read the confirmation, if one is shown.",
93
+ "Read the entry's state afterwards.",
94
+ "Reload and read it again.",
95
+ "Check the event's entry count fell.",
96
+ ],
97
+ expectedBehaviour: "Withdrawing is possible and is reflected in both the entry and the event's counts. An entry that cannot be withdrawn leaves a participant permanently counted in something they left — and if the counts do not follow, a waitlisted person is never promoted into the freed place.",
98
+ expectedUiState: "The entry reads as cancelled or is gone, the state survives a reload, and the event's entry count is one lower.",
99
+ endResult: "The entry is withdrawn.",
100
+ },
101
+ "checklist-content-discovery-event-participation-closed-event-cannot-be-joined": {
102
+ roles: ["buyer"],
103
+ startPage: "/events",
104
+ steps: [
105
+ SIGN_IN_BUYER,
106
+ "Open /events and find an event whose status is ended.",
107
+ "Open it and read whether a join control is offered.",
108
+ "If one is offered, use it and read what happens.",
109
+ "Repeat with an event whose status is cancelled.",
110
+ "Repeat with one whose status is paused.",
111
+ ],
112
+ expectedBehaviour: "An event that cannot be joined says so on the page rather than accepting a click and failing at submit. The status set includes paused and cancelled alongside ended, and each has to be handled — a page that only knows about ended lets the other two through.",
113
+ expectedUiState: "None of the three offers a working join control, and each states its own status. A control that fails only on submit is the finding, named by status.",
114
+ endResult: "No entry is created.",
115
+ },
116
+ "checklist-content-discovery-event-participation-leaderboard-shows-real-participants": {
117
+ roles: ["buyer"],
118
+ startPage: "/events",
119
+ steps: [
120
+ SIGN_IN_BUYER,
121
+ "Open an event that has a leaderboard and open that tab.",
122
+ "Read the rows — the names and the scores.",
123
+ "Check the names are masked rather than showing full identities.",
124
+ "Check the scores are real numbers rather than zeros or placeholders.",
125
+ "Cross-check one row against the event's entry list if it is visible.",
126
+ ],
127
+ expectedBehaviour: "The leaderboard lists real entrants with real scores, and their names are masked. A masking helper that only copies its input instead of masking is invisible everywhere except to a human who recognises a real name — one shipped in exactly that shape and sat, because the field it should have masked was not being displayed at all.",
128
+ expectedUiState: "Real participants with real scores, each name partially hidden. A full name is a finding and a leak; all-zero scores is a separate finding.",
129
+ endResult: "Read-only.",
130
+ },
131
+ "checklist-content-discovery-event-participation-leaderboard-own-row-findable": {
132
+ roles: ["buyer"],
133
+ startPage: "/events",
134
+ steps: [
135
+ SIGN_IN_BUYER,
136
+ "Join an event that has a leaderboard and take part enough to appear on it.",
137
+ "Open the leaderboard.",
138
+ "Look for the participant's own row without scrolling the whole list.",
139
+ "Check it is highlighted, pinned, or otherwise findable.",
140
+ "Read the position shown for it.",
141
+ ],
142
+ expectedBehaviour: "A participant can find themselves. A leaderboard is read almost entirely to answer one question — where am I — and on a long list without a marker that answer requires scrolling past everyone else.",
143
+ expectedUiState: "The participant's own row is marked or surfaced, with their position. Having to scroll a long list to find it is the finding.",
144
+ endResult: "Read-only.",
145
+ },
146
+ "checklist-content-discovery-event-participation-leaderboard-ordering-correct": {
147
+ roles: ["buyer"],
148
+ startPage: "/events",
149
+ steps: [
150
+ SIGN_IN_BUYER,
151
+ "Open an event leaderboard and write down the first ten rows in order with their scores.",
152
+ "Check each score is not greater than the one above it.",
153
+ "Find two rows with equal scores and note their order.",
154
+ "Reload the page and read the first ten again.",
155
+ "Check the order is identical, including the tied pair.",
156
+ ],
157
+ expectedBehaviour: "The ordering is by score and is stable across reloads, ties included. An unstable tie break swaps positions between two visits — so a participant sees themselves at rank 6 and then rank 7 with nothing having changed, which reads as the site losing their score.",
158
+ expectedUiState: "Scores are non-increasing down the list, and the whole order including the tied pair is identical after the reload.",
159
+ endResult: "Read-only.",
160
+ },
161
+ "checklist-content-discovery-event-participation-leaderboard-empty-state": {
162
+ roles: ["buyer"],
163
+ startPage: "/events",
164
+ steps: [
165
+ SIGN_IN_BUYER,
166
+ "Open /events and find an event with no entries yet, such as a draft or a newly-started one.",
167
+ "Open its leaderboard.",
168
+ "Read what is shown.",
169
+ "Check it states there are no entries rather than showing a blank panel.",
170
+ "Check whatever chrome the leaderboard has — headings, columns — either renders sensibly or is omitted.",
171
+ ],
172
+ expectedBehaviour: "An empty leaderboard says it is empty. A blank panel is indistinguishable from a leaderboard that failed to load, and the participant's reasonable conclusion is that their entry was lost.",
173
+ expectedUiState: "An explicit empty state. A blank area, or column headings over nothing, are both findings.",
174
+ endResult: "Read-only.",
175
+ },
176
+ "checklist-content-discovery-event-participation-raffle-winner-announced-to-participants": {
177
+ roles: ["admin", "buyer"],
178
+ startPage: "/events",
179
+ steps: [
180
+ "Sign in as admin@letitrip.in / TempPass123! and open an event with a raffle configured.",
181
+ "Draw the raffle and note who won.",
182
+ "Sign in as the winning participant.",
183
+ "Open the event page and read whether the result is announced.",
184
+ "Open the account's notifications and look for one about the win.",
185
+ "Sign in as a non-winning participant and check the result is visible to them too.",
186
+ ],
187
+ expectedBehaviour: "A drawn raffle is announced on the event page and the winner is notified. A result that exists only in the admin screen means the winner never learns they won — and the notification's link has to land somewhere real, which for entries means the list rather than a fabricated per-entry page that would 404.",
188
+ expectedUiState: "The event page names the winner, the winner has a notification, and other participants can see the result. A win visible only to an admin is the finding.",
189
+ endResult: "One raffle is drawn.",
190
+ },
191
+ "checklist-content-discovery-event-participation-spin-wheel-one-use-enforced": {
192
+ roles: ["buyer"],
193
+ startPage: "/events",
194
+ steps: [
195
+ SIGN_IN_BUYER,
196
+ "Open /events and find a spin-wheel event that is currently open.",
197
+ "Take a spin and read the result.",
198
+ "Attempt to spin again immediately.",
199
+ "Read what happens.",
200
+ "Reload the page and attempt once more.",
201
+ "If a prize was won, follow whatever the interface offers for claiming it.",
202
+ ],
203
+ expectedBehaviour: "The per-user spin limit is enforced server-side and survives a reload, and a won prize is claimable. A limit held only in the browser is defeated by refreshing — which is the first thing anyone does after a disappointing spin.",
204
+ expectedUiState: "The second spin is refused before and after the reload, with a message naming the limit, and a won prize can actually be claimed. A spin that works again after a reload is the finding.",
205
+ endResult: "One spin is used; claim the prize if one was won.",
206
+ },
207
+ };
@@ -0,0 +1,2 @@
1
+ import type { AuthoredCase } from "./_types";
2
+ export declare const authored: Record<string, AuthoredCase>;