@mohasinac/appkit 4.34.0 → 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 (248) hide show
  1. package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +32 -2
  2. package/dist/_internal/server/features/seo/sitemap.js +2 -2
  3. package/dist/_internal/server/functions/scheduled.d.ts +1 -2
  4. package/dist/_internal/server/functions/scheduled.js +8 -9
  5. package/dist/_internal/server/jobs/core/testerSandboxCleanup.d.ts +15 -0
  6. package/dist/_internal/server/jobs/core/testerSandboxCleanup.js +15 -6
  7. package/dist/_internal/server/jobs/handlers/index.d.ts +0 -1
  8. package/dist/_internal/server/jobs/handlers/index.js +0 -1
  9. package/dist/features/auth/schemas/firestore.d.ts +1 -0
  10. package/dist/features/tester/components/TesterChecklistStepRow.d.ts +9 -1
  11. package/dist/features/tester/components/TesterChecklistStepRow.js +31 -2
  12. package/dist/features/tester/components/TesterHubView.js +8 -0
  13. package/dist/features/tester/repository/tester-checklist-item.repository.d.ts +16 -1
  14. package/dist/features/tester/repository/tester-checklist-item.repository.js +32 -6
  15. package/dist/features/tester/schemas/firestore.d.ts +109 -0
  16. package/dist/features/tester/schemas/firestore.js +14 -0
  17. package/dist/features/tester/seed-data/_money-flows.d.ts +23 -0
  18. package/dist/features/tester/seed-data/_money-flows.js +430 -0
  19. package/dist/features/tester/seed-data/authored/_types.d.ts +33 -0
  20. package/dist/features/tester/seed-data/authored/_types.js +35 -0
  21. package/dist/features/tester/seed-data/authored/account-auth__profile-settings.d.ts +2 -0
  22. package/dist/features/tester/seed-data/authored/account-auth__profile-settings.js +207 -0
  23. package/dist/features/tester/seed-data/authored/account-auth__signup-login.d.ts +2 -0
  24. package/dist/features/tester/seed-data/authored/account-auth__signup-login.js +298 -0
  25. package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.d.ts +2 -0
  26. package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.js +33 -0
  27. package/dist/features/tester/seed-data/authored/account-auth__testing-program.d.ts +2 -0
  28. package/dist/features/tester/seed-data/authored/account-auth__testing-program.js +138 -0
  29. package/dist/features/tester/seed-data/authored/addresses__address-filters.d.ts +2 -0
  30. package/dist/features/tester/seed-data/authored/addresses__address-filters.js +36 -0
  31. package/dist/features/tester/seed-data/authored/addresses__postal-lookup.d.ts +2 -0
  32. package/dist/features/tester/seed-data/authored/addresses__postal-lookup.js +75 -0
  33. package/dist/features/tester/seed-data/authored/addresses__postal-validation.d.ts +2 -0
  34. package/dist/features/tester/seed-data/authored/addresses__postal-validation.js +72 -0
  35. package/dist/features/tester/seed-data/authored/addresses__state-picker.d.ts +2 -0
  36. package/dist/features/tester/seed-data/authored/addresses__state-picker.js +54 -0
  37. package/dist/features/tester/seed-data/authored/addresses__unban-request.d.ts +2 -0
  38. package/dist/features/tester/seed-data/authored/addresses__unban-request.js +39 -0
  39. package/dist/features/tester/seed-data/authored/admin__bans-and-trust.d.ts +2 -0
  40. package/dist/features/tester/seed-data/authored/admin__bans-and-trust.js +226 -0
  41. package/dist/features/tester/seed-data/authored/admin__blog-faqs.d.ts +2 -0
  42. package/dist/features/tester/seed-data/authored/admin__blog-faqs.js +82 -0
  43. package/dist/features/tester/seed-data/authored/admin__bulk-actions.d.ts +2 -0
  44. package/dist/features/tester/seed-data/authored/admin__bulk-actions.js +177 -0
  45. package/dist/features/tester/seed-data/authored/admin__bundles.d.ts +2 -0
  46. package/dist/features/tester/seed-data/authored/admin__bundles.js +97 -0
  47. package/dist/features/tester/seed-data/authored/admin__buyer-data-admin.d.ts +2 -0
  48. package/dist/features/tester/seed-data/authored/admin__buyer-data-admin.js +232 -0
  49. package/dist/features/tester/seed-data/authored/admin__catalog-listings.d.ts +2 -0
  50. package/dist/features/tester/seed-data/authored/admin__catalog-listings.js +306 -0
  51. package/dist/features/tester/seed-data/authored/admin__category-brand-authoring.d.ts +2 -0
  52. package/dist/features/tester/seed-data/authored/admin__category-brand-authoring.js +158 -0
  53. package/dist/features/tester/seed-data/authored/admin__classifieds-digitalcodes-live.d.ts +2 -0
  54. package/dist/features/tester/seed-data/authored/admin__classifieds-digitalcodes-live.js +78 -0
  55. package/dist/features/tester/seed-data/authored/admin__content-deletes.d.ts +2 -0
  56. package/dist/features/tester/seed-data/authored/admin__content-deletes.js +261 -0
  57. package/dist/features/tester/seed-data/authored/admin__content-marketing.d.ts +2 -0
  58. package/dist/features/tester/seed-data/authored/admin__content-marketing.js +151 -0
  59. package/dist/features/tester/seed-data/authored/admin__coupons.d.ts +2 -0
  60. package/dist/features/tester/seed-data/authored/admin__coupons.js +214 -0
  61. package/dist/features/tester/seed-data/authored/admin__events-raffles-spin.d.ts +2 -0
  62. package/dist/features/tester/seed-data/authored/admin__events-raffles-spin.js +160 -0
  63. package/dist/features/tester/seed-data/authored/admin__media-watermark.d.ts +2 -0
  64. package/dist/features/tester/seed-data/authored/admin__media-watermark.js +104 -0
  65. package/dist/features/tester/seed-data/authored/admin__orders-fulfillment.d.ts +2 -0
  66. package/dist/features/tester/seed-data/authored/admin__orders-fulfillment.js +350 -0
  67. package/dist/features/tester/seed-data/authored/admin__prize-draws-lotteries.d.ts +2 -0
  68. package/dist/features/tester/seed-data/authored/admin__prize-draws-lotteries.js +105 -0
  69. package/dist/features/tester/seed-data/authored/admin__site-system.d.ts +2 -0
  70. package/dist/features/tester/seed-data/authored/admin__site-system.js +590 -0
  71. package/dist/features/tester/seed-data/authored/admin__uncovered-admin-pages.d.ts +2 -0
  72. package/dist/features/tester/seed-data/authored/admin__uncovered-admin-pages.js +235 -0
  73. package/dist/features/tester/seed-data/authored/admin__users-trust.d.ts +2 -0
  74. package/dist/features/tester/seed-data/authored/admin__users-trust.js +569 -0
  75. package/dist/features/tester/seed-data/authored/buying__bidding.d.ts +2 -0
  76. package/dist/features/tester/seed-data/authored/buying__bidding.js +417 -0
  77. package/dist/features/tester/seed-data/authored/buying__browsing-search.d.ts +2 -0
  78. package/dist/features/tester/seed-data/authored/buying__browsing-search.js +653 -0
  79. package/dist/features/tester/seed-data/authored/buying__buying-checkout.d.ts +2 -0
  80. package/dist/features/tester/seed-data/authored/buying__buying-checkout.js +533 -0
  81. package/dist/features/tester/seed-data/authored/buying__buying-coupons.d.ts +2 -0
  82. package/dist/features/tester/seed-data/authored/buying__buying-coupons.js +379 -0
  83. package/dist/features/tester/seed-data/authored/buying__cart.d.ts +2 -0
  84. package/dist/features/tester/seed-data/authored/buying__cart.js +1171 -0
  85. package/dist/features/tester/seed-data/authored/buying__image-tile-layout.d.ts +2 -0
  86. package/dist/features/tester/seed-data/authored/buying__image-tile-layout.js +140 -0
  87. package/dist/features/tester/seed-data/authored/buying__my-orders.d.ts +2 -0
  88. package/dist/features/tester/seed-data/authored/buying__my-orders.js +257 -0
  89. package/dist/features/tester/seed-data/authored/buying__offers.d.ts +2 -0
  90. package/dist/features/tester/seed-data/authored/buying__offers.js +1111 -0
  91. package/dist/features/tester/seed-data/authored/buying__order-status-lifecycle.d.ts +2 -0
  92. package/dist/features/tester/seed-data/authored/buying__order-status-lifecycle.js +252 -0
  93. package/dist/features/tester/seed-data/authored/buying__product-detail.d.ts +2 -0
  94. package/dist/features/tester/seed-data/authored/buying__product-detail.js +387 -0
  95. package/dist/features/tester/seed-data/authored/buying__return-request.d.ts +2 -0
  96. package/dist/features/tester/seed-data/authored/buying__return-request.js +152 -0
  97. package/dist/features/tester/seed-data/authored/buying__reviews-pagination.d.ts +2 -0
  98. package/dist/features/tester/seed-data/authored/buying__reviews-pagination.js +242 -0
  99. package/dist/features/tester/seed-data/authored/buying__reviews.d.ts +2 -0
  100. package/dist/features/tester/seed-data/authored/buying__reviews.js +113 -0
  101. package/dist/features/tester/seed-data/authored/buying__user-dashboard-extras.d.ts +2 -0
  102. package/dist/features/tester/seed-data/authored/buying__user-dashboard-extras.js +283 -0
  103. package/dist/features/tester/seed-data/authored/buying__user-dashboard-navigation.d.ts +2 -0
  104. package/dist/features/tester/seed-data/authored/buying__user-dashboard-navigation.js +167 -0
  105. package/dist/features/tester/seed-data/authored/buying__user-uncovered-pages.d.ts +2 -0
  106. package/dist/features/tester/seed-data/authored/buying__user-uncovered-pages.js +90 -0
  107. package/dist/features/tester/seed-data/authored/buying__wishlist-history.d.ts +2 -0
  108. package/dist/features/tester/seed-data/authored/buying__wishlist-history.js +344 -0
  109. package/dist/features/tester/seed-data/authored/community-support__public-profile.d.ts +2 -0
  110. package/dist/features/tester/seed-data/authored/community-support__public-profile.js +53 -0
  111. package/dist/features/tester/seed-data/authored/community-support__support-tickets.d.ts +2 -0
  112. package/dist/features/tester/seed-data/authored/community-support__support-tickets.js +76 -0
  113. package/dist/features/tester/seed-data/authored/content-discovery__blog.d.ts +2 -0
  114. package/dist/features/tester/seed-data/authored/content-discovery__blog.js +93 -0
  115. package/dist/features/tester/seed-data/authored/content-discovery__category-brand-relations.d.ts +2 -0
  116. package/dist/features/tester/seed-data/authored/content-discovery__category-brand-relations.js +149 -0
  117. package/dist/features/tester/seed-data/authored/content-discovery__coupons.d.ts +2 -0
  118. package/dist/features/tester/seed-data/authored/content-discovery__coupons.js +121 -0
  119. package/dist/features/tester/seed-data/authored/content-discovery__event-participation.d.ts +2 -0
  120. package/dist/features/tester/seed-data/authored/content-discovery__event-participation.js +207 -0
  121. package/dist/features/tester/seed-data/authored/content-discovery__events.d.ts +2 -0
  122. package/dist/features/tester/seed-data/authored/content-discovery__events.js +318 -0
  123. package/dist/features/tester/seed-data/authored/content-discovery__faq-help.d.ts +2 -0
  124. package/dist/features/tester/seed-data/authored/content-discovery__faq-help.js +65 -0
  125. package/dist/features/tester/seed-data/authored/content-discovery__notifications.d.ts +2 -0
  126. package/dist/features/tester/seed-data/authored/content-discovery__notifications.js +147 -0
  127. package/dist/features/tester/seed-data/authored/content-discovery__search.d.ts +2 -0
  128. package/dist/features/tester/seed-data/authored/content-discovery__search.js +332 -0
  129. package/dist/features/tester/seed-data/authored/cta-layout__checkout-bottom-bar.d.ts +2 -0
  130. package/dist/features/tester/seed-data/authored/cta-layout__checkout-bottom-bar.js +53 -0
  131. package/dist/features/tester/seed-data/authored/cta-layout__dialog-footers.d.ts +2 -0
  132. package/dist/features/tester/seed-data/authored/cta-layout__dialog-footers.js +52 -0
  133. package/dist/features/tester/seed-data/authored/cta-layout__editor-action-bar.d.ts +2 -0
  134. package/dist/features/tester/seed-data/authored/cta-layout__editor-action-bar.js +35 -0
  135. package/dist/features/tester/seed-data/authored/cta-layout__navbar-ctas.d.ts +2 -0
  136. package/dist/features/tester/seed-data/authored/cta-layout__navbar-ctas.js +141 -0
  137. package/dist/features/tester/seed-data/authored/cta-layout__product-bottom-bar.d.ts +2 -0
  138. package/dist/features/tester/seed-data/authored/cta-layout__product-bottom-bar.js +35 -0
  139. package/dist/features/tester/seed-data/authored/design-ux__back-to-top-button.d.ts +2 -0
  140. package/dist/features/tester/seed-data/authored/design-ux__back-to-top-button.js +95 -0
  141. package/dist/features/tester/seed-data/authored/design-ux__carousel-arrow-bounds.d.ts +2 -0
  142. package/dist/features/tester/seed-data/authored/design-ux__carousel-arrow-bounds.js +191 -0
  143. package/dist/features/tester/seed-data/authored/design-ux__dashboard-layout.d.ts +2 -0
  144. package/dist/features/tester/seed-data/authored/design-ux__dashboard-layout.js +158 -0
  145. package/dist/features/tester/seed-data/authored/design-ux__footer-theme.d.ts +2 -0
  146. package/dist/features/tester/seed-data/authored/design-ux__footer-theme.js +106 -0
  147. package/dist/features/tester/seed-data/authored/design-ux__form-validation-errors.d.ts +2 -0
  148. package/dist/features/tester/seed-data/authored/design-ux__form-validation-errors.js +88 -0
  149. package/dist/features/tester/seed-data/authored/design-ux__general-design.d.ts +2 -0
  150. package/dist/features/tester/seed-data/authored/design-ux__general-design.js +204 -0
  151. package/dist/features/tester/seed-data/authored/design-ux__hand-mode-layout.d.ts +2 -0
  152. package/dist/features/tester/seed-data/authored/design-ux__hand-mode-layout.js +301 -0
  153. package/dist/features/tester/seed-data/authored/design-ux__homepage-carousels.d.ts +2 -0
  154. package/dist/features/tester/seed-data/authored/design-ux__homepage-carousels.js +407 -0
  155. package/dist/features/tester/seed-data/authored/design-ux__status-badge-legibility.d.ts +2 -0
  156. package/dist/features/tester/seed-data/authored/design-ux__status-badge-legibility.js +214 -0
  157. package/dist/features/tester/seed-data/authored/design-ux__sticky-cta-bar.d.ts +2 -0
  158. package/dist/features/tester/seed-data/authored/design-ux__sticky-cta-bar.js +275 -0
  159. package/dist/features/tester/seed-data/authored/index.d.ts +2 -0
  160. package/dist/features/tester/seed-data/authored/index.js +237 -0
  161. package/dist/features/tester/seed-data/authored/page-wiring__data-loss.d.ts +2 -0
  162. package/dist/features/tester/seed-data/authored/page-wiring__data-loss.js +102 -0
  163. package/dist/features/tester/seed-data/authored/page-wiring__detail-pages.d.ts +2 -0
  164. package/dist/features/tester/seed-data/authored/page-wiring__detail-pages.js +50 -0
  165. package/dist/features/tester/seed-data/authored/page-wiring__drawer-pages.d.ts +2 -0
  166. package/dist/features/tester/seed-data/authored/page-wiring__drawer-pages.js +66 -0
  167. package/dist/features/tester/seed-data/authored/page-wiring__reachability.d.ts +2 -0
  168. package/dist/features/tester/seed-data/authored/page-wiring__reachability.js +115 -0
  169. package/dist/features/tester/seed-data/authored/public-pages__auth-error-pages.d.ts +2 -0
  170. package/dist/features/tester/seed-data/authored/public-pages__auth-error-pages.js +136 -0
  171. package/dist/features/tester/seed-data/authored/public-pages__bug-hunters.d.ts +2 -0
  172. package/dist/features/tester/seed-data/authored/public-pages__bug-hunters.js +69 -0
  173. package/dist/features/tester/seed-data/authored/public-pages__core-listing-pages.d.ts +2 -0
  174. package/dist/features/tester/seed-data/authored/public-pages__core-listing-pages.js +263 -0
  175. package/dist/features/tester/seed-data/authored/public-pages__help-how-it-works.d.ts +2 -0
  176. package/dist/features/tester/seed-data/authored/public-pages__help-how-it-works.js +102 -0
  177. package/dist/features/tester/seed-data/authored/public-pages__help-scams-guides-subpages.d.ts +2 -0
  178. package/dist/features/tester/seed-data/authored/public-pages__help-scams-guides-subpages.js +234 -0
  179. package/dist/features/tester/seed-data/authored/public-pages__legal-policy-pages.d.ts +2 -0
  180. package/dist/features/tester/seed-data/authored/public-pages__legal-policy-pages.js +126 -0
  181. package/dist/features/tester/seed-data/authored/public-pages__stores-sellers-directories.d.ts +2 -0
  182. package/dist/features/tester/seed-data/authored/public-pages__stores-sellers-directories.js +255 -0
  183. package/dist/features/tester/seed-data/authored/search-and-nav__employee-permissions.d.ts +2 -0
  184. package/dist/features/tester/seed-data/authored/search-and-nav__employee-permissions.js +59 -0
  185. package/dist/features/tester/seed-data/authored/search-and-nav__header-search.d.ts +2 -0
  186. package/dist/features/tester/seed-data/authored/search-and-nav__header-search.js +88 -0
  187. package/dist/features/tester/seed-data/authored/search-and-nav__settings-deep-links.d.ts +2 -0
  188. package/dist/features/tester/seed-data/authored/search-and-nav__settings-deep-links.js +51 -0
  189. package/dist/features/tester/seed-data/authored/search-and-nav__sidebar-search.d.ts +2 -0
  190. package/dist/features/tester/seed-data/authored/search-and-nav__sidebar-search.js +35 -0
  191. package/dist/features/tester/seed-data/authored/selling__become-seller.d.ts +2 -0
  192. package/dist/features/tester/seed-data/authored/selling__become-seller.js +94 -0
  193. package/dist/features/tester/seed-data/authored/selling__final-sale-authoring.d.ts +2 -0
  194. package/dist/features/tester/seed-data/authored/selling__final-sale-authoring.js +107 -0
  195. package/dist/features/tester/seed-data/authored/selling__listing-a-product.d.ts +2 -0
  196. package/dist/features/tester/seed-data/authored/selling__listing-a-product.js +285 -0
  197. package/dist/features/tester/seed-data/authored/selling__listing-lifecycle.d.ts +2 -0
  198. package/dist/features/tester/seed-data/authored/selling__listing-lifecycle.js +326 -0
  199. package/dist/features/tester/seed-data/authored/selling__listing-type-fields-roundtrip.d.ts +2 -0
  200. package/dist/features/tester/seed-data/authored/selling__listing-type-fields-roundtrip.js +136 -0
  201. package/dist/features/tester/seed-data/authored/selling__media-limits.d.ts +2 -0
  202. package/dist/features/tester/seed-data/authored/selling__media-limits.js +128 -0
  203. package/dist/features/tester/seed-data/authored/selling__sectionised-forms.d.ts +2 -0
  204. package/dist/features/tester/seed-data/authored/selling__sectionised-forms.js +167 -0
  205. package/dist/features/tester/seed-data/authored/selling__seller-analytics-payouts.d.ts +2 -0
  206. package/dist/features/tester/seed-data/authored/selling__seller-analytics-payouts.js +117 -0
  207. package/dist/features/tester/seed-data/authored/selling__seller-bids-bundles-filters.d.ts +2 -0
  208. package/dist/features/tester/seed-data/authored/selling__seller-bids-bundles-filters.js +88 -0
  209. package/dist/features/tester/seed-data/authored/selling__seller-catalog-org.d.ts +2 -0
  210. package/dist/features/tester/seed-data/authored/selling__seller-catalog-org.js +151 -0
  211. package/dist/features/tester/seed-data/authored/selling__seller-custom-brands.d.ts +2 -0
  212. package/dist/features/tester/seed-data/authored/selling__seller-custom-brands.js +105 -0
  213. package/dist/features/tester/seed-data/authored/selling__seller-guide.d.ts +2 -0
  214. package/dist/features/tester/seed-data/authored/selling__seller-guide.js +33 -0
  215. package/dist/features/tester/seed-data/authored/selling__seller-listing-types.d.ts +2 -0
  216. package/dist/features/tester/seed-data/authored/selling__seller-listing-types.js +347 -0
  217. package/dist/features/tester/seed-data/authored/selling__seller-marketing-extras.d.ts +2 -0
  218. package/dist/features/tester/seed-data/authored/selling__seller-marketing-extras.js +166 -0
  219. package/dist/features/tester/seed-data/authored/selling__seller-ops-comms.d.ts +2 -0
  220. package/dist/features/tester/seed-data/authored/selling__seller-ops-comms.js +89 -0
  221. package/dist/features/tester/seed-data/authored/selling__seller-orders.d.ts +2 -0
  222. package/dist/features/tester/seed-data/authored/selling__seller-orders.js +195 -0
  223. package/dist/features/tester/seed-data/authored/selling__seller-shipping-payouts-setup.d.ts +2 -0
  224. package/dist/features/tester/seed-data/authored/selling__seller-shipping-payouts-setup.js +180 -0
  225. package/dist/features/tester/seed-data/authored/selling__store-dashboard-navigation.d.ts +2 -0
  226. package/dist/features/tester/seed-data/authored/selling__store-dashboard-navigation.js +164 -0
  227. package/dist/features/tester/seed-data/authored/selling__store-uncovered-pages.d.ts +2 -0
  228. package/dist/features/tester/seed-data/authored/selling__store-uncovered-pages.js +116 -0
  229. package/dist/features/tester/seed-data/authored/seo__canonical-and-host.d.ts +2 -0
  230. package/dist/features/tester/seed-data/authored/seo__canonical-and-host.js +111 -0
  231. package/dist/features/tester/seed-data/authored/seo__og-images.d.ts +2 -0
  232. package/dist/features/tester/seed-data/authored/seo__og-images.js +91 -0
  233. package/dist/features/tester/seed-data/authored/seo__page-metadata.d.ts +2 -0
  234. package/dist/features/tester/seed-data/authored/seo__page-metadata.js +122 -0
  235. package/dist/features/tester/seed-data/authored/seo__sitemap-and-robots.d.ts +2 -0
  236. package/dist/features/tester/seed-data/authored/seo__sitemap-and-robots.js +105 -0
  237. package/dist/features/tester/seed-data/events-tester-seed-data.js +77 -5
  238. package/dist/features/tester/seed-data/offers-tester-seed-data.js +23 -9
  239. package/dist/features/tester/seed-data/products-tester-seed-data.js +65 -49
  240. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +744 -1
  241. package/dist/features/tester/seed-data/tester-window.d.ts +25 -0
  242. package/dist/features/tester/seed-data/tester-window.js +66 -0
  243. package/dist/seed/carousel-slides-seed-data.js +1 -1
  244. package/dist/seed/products-standard-seed-data.js +2 -2
  245. package/dist/seed/reviews-seed-data.js +6 -1
  246. package/dist/seed/users-seed-data.js +107 -4
  247. package/package.json +1 -1
  248. package/scripts/seed-cli.mjs +6 -0
@@ -0,0 +1,91 @@
1
+ /*
2
+ * WHY: Authored six-part procedures for the seo/og-images checklist page.
3
+ * WHAT: 5 case(s), keyed by full checklist id.
4
+ *
5
+ * A social card is rendered server-side and never appears in the page a visitor
6
+ * sees, so every failure here is invisible until somebody shares a link. The brand
7
+ * card's image reader named a field the record does not have — always undefined,
8
+ * always omitted, and the card still rendered.
9
+ *
10
+ * @tag domain:tester
11
+ * @tag layer:seed
12
+ * @tag pattern:none
13
+ * @tag access:server-only
14
+ * @tag consumers:seed-data/authored/index.ts
15
+ * @tag sideEffects:none
16
+ */
17
+ export const authored = {
18
+ "checklist-seo-og-images-og-image-renders-homepage": {
19
+ roles: ["guest"],
20
+ startPage: "/",
21
+ steps: [
22
+ "Open the homepage and view the page source.",
23
+ "Find the og:image tag and copy its URL.",
24
+ "Open that URL in a fresh tab.",
25
+ "Read what renders — a real image, an error, or a blank frame.",
26
+ "Read the response status and content type in the network panel.",
27
+ ],
28
+ expectedBehaviour: "The social image URL serves a real image. It is generated rather than a static file, so a failure inside the generator returns an error or an empty frame that nothing on the site would ever reveal.",
29
+ expectedUiState: "The URL returns 200 with an image content type and renders a card carrying the site's branding. A blank frame or an error page is the finding.",
30
+ endResult: "Read-only.",
31
+ },
32
+ "checklist-seo-og-images-og-image-product": {
33
+ roles: ["guest"],
34
+ startPage: "/products/product-beyblade-burst-valkyrie",
35
+ steps: [
36
+ "Open /products/product-beyblade-burst-valkyrie and note the product's title and main photo.",
37
+ "View the source, find the og:image tag and copy its URL.",
38
+ "Open that URL in a fresh tab.",
39
+ "Read the title rendered on the card and compare it against the product's.",
40
+ "Check the product's own photo appears on the card rather than a generic placeholder.",
41
+ ],
42
+ inputs: { productId: "product-beyblade-burst-valkyrie" },
43
+ expectedBehaviour: "A product's card is built from that product. A card that renders correctly but with the site's default artwork is the more likely failure — it looks deliberate, and only comparing it against the product reveals that the record was never read.",
44
+ expectedUiState: "The card shows the product's own title and its own photo. A generic card is the finding.",
45
+ endResult: "Read-only.",
46
+ },
47
+ "checklist-seo-og-images-og-image-brand-logo-present": {
48
+ roles: ["guest"],
49
+ startPage: "/brands/brand-takara-tomy",
50
+ steps: [
51
+ "Open /brands/brand-takara-tomy and note the cover image shown in its hero.",
52
+ "View the source, find the og:image tag and copy its URL.",
53
+ "Open that URL in a fresh tab.",
54
+ "Read whether the brand's image is on the card or the slot is empty.",
55
+ "Repeat with /brands/brand-beyblade.",
56
+ ],
57
+ inputs: { brandId: "brand-takara-tomy" },
58
+ expectedBehaviour: "The card reads the same cover image the brand page's hero uses. It previously read a field that does not exist on a brand record at all, so the value was always undefined and the image was silently omitted — the card still rendered, just without it.",
59
+ expectedUiState: "The brand's cover image is on the card for both brands. An empty image slot with the rest of the card intact is exactly the failure this case exists for.",
60
+ endResult: "Read-only.",
61
+ },
62
+ "checklist-seo-og-images-og-tags-present-and-absolute": {
63
+ roles: ["guest"],
64
+ startPage: "/products/product-beyblade-burst-valkyrie",
65
+ steps: [
66
+ "Open /products/product-beyblade-burst-valkyrie and view the source.",
67
+ "List every og: and twitter: tag present.",
68
+ "Check og:title, og:description, og:image and og:url are all there.",
69
+ "Read og:image's and og:url's values and check both are absolute URLs.",
70
+ "Check their host matches the canonical's host.",
71
+ "Repeat on a store page and a blog post.",
72
+ ],
73
+ expectedBehaviour: "Social tags are present and their URLs are absolute on the canonical host. A relative social image URL is not fetchable by the service rendering the preview — it has no page context to resolve it against — so the card falls back to nothing.",
74
+ expectedUiState: "All four tags present on all three pages, with absolute URLs on the canonical host. A relative URL, or one on a different host, is the finding.",
75
+ endResult: "Read-only.",
76
+ },
77
+ "checklist-seo-og-images-og-image-missing-media-fallback": {
78
+ roles: ["guest"],
79
+ startPage: "/classified/classified-tester-sandbox-1",
80
+ steps: [
81
+ "Sign in as tester@letitrip.in / TempPass123!.",
82
+ "Find a listing with no photo of its own, or note that the sandbox classified has none.",
83
+ "Open its detail page and view the source.",
84
+ "Copy the og:image URL and open it in a fresh tab.",
85
+ "Read what renders.",
86
+ ],
87
+ expectedBehaviour: "A record with no image still produces a readable card, falling back to the site's own artwork rather than to a broken image. A card generator that assumes an image exists throws, and the shared link then has no preview at all.",
88
+ expectedUiState: "The card renders with the listing's title over the site's default artwork. A broken image, an error page or a 500 are all findings.",
89
+ endResult: "Read-only.",
90
+ },
91
+ };
@@ -0,0 +1,2 @@
1
+ import type { AuthoredCase } from "./_types";
2
+ export declare const authored: Record<string, AuthoredCase>;
@@ -0,0 +1,122 @@
1
+ /*
2
+ * WHY: Authored six-part procedures for the seo/page-metadata checklist page.
3
+ * WHAT: 7 case(s), keyed by full checklist id.
4
+ *
5
+ * Metadata failures are all silent by construction — a missing canonical, a title
6
+ * built from a slug and a 200 on a page that does not exist all render a page that
7
+ * looks entirely normal. The procedures read the source rather than the screen.
8
+ *
9
+ * @tag domain:tester
10
+ * @tag layer:seed
11
+ * @tag pattern:none
12
+ * @tag access:server-only
13
+ * @tag consumers:seed-data/authored/index.ts
14
+ * @tag sideEffects:none
15
+ */
16
+ export const authored = {
17
+ "checklist-seo-page-metadata-listing-pages-distinct-titles": {
18
+ roles: ["guest"],
19
+ startPage: "/products",
20
+ steps: [
21
+ "Open /products and read the browser tab's title and the page's meta description.",
22
+ "Open /auctions and read both.",
23
+ "Open /pre-orders, /bundles and /categories and read each.",
24
+ "Compare all five titles against one another.",
25
+ "Compare all five descriptions.",
26
+ ],
27
+ expectedBehaviour: "Each listing page states what it lists. Five pages sharing one site-wide default makes them indistinguishable in a result list, and a shared description is the more common half of the failure because nothing on screen shows it.",
28
+ expectedUiState: "Five distinct titles and five distinct descriptions, each naming its own section. Any repeat is a finding, named by the pages that share it.",
29
+ expectedData: { distinctTitles: 5 },
30
+ endResult: "Read-only.",
31
+ },
32
+ "checklist-seo-page-metadata-detail-page-title-from-record": {
33
+ roles: ["guest"],
34
+ startPage: "/products/product-beyblade-burst-valkyrie",
35
+ steps: [
36
+ "Open /products/product-beyblade-burst-valkyrie.",
37
+ "Read the product's name as shown on the page.",
38
+ "Read the browser tab's title.",
39
+ "Compare the two.",
40
+ "Read the meta description and check it draws on the product's own description.",
41
+ "Repeat on a prize-draw detail page and read its title.",
42
+ ],
43
+ inputs: { productId: "product-beyblade-burst-valkyrie" },
44
+ expectedBehaviour: "A detail page's title is the record's name. One listing type interpolated the raw slug instead, so its tab read a hyphenated identifier — which is legible enough to pass a glance and wrong in every search result.",
45
+ expectedUiState: "The tab title contains the product's readable name, not its hyphenated id. The prize-draw page is checked separately because that is where the slug leak was.",
46
+ endResult: "Read-only.",
47
+ },
48
+ "checklist-seo-page-metadata-detail-pages-have-canonical": {
49
+ roles: ["guest"],
50
+ startPage: "/classified/classified-tester-sandbox-1",
51
+ steps: [
52
+ "Sign in as tester@letitrip.in / TempPass123! so sandbox fixtures are visible.",
53
+ "Open /classified/classified-tester-sandbox-1 and view the page source.",
54
+ "Search the source for a canonical link element and read its href, or record that there is none.",
55
+ "Do the same on /digital-codes/digitalcode-tester-sandbox-1.",
56
+ "Do the same on /live/live-tester-sandbox-1.",
57
+ "Do the same on an ordinary product page as a control.",
58
+ ],
59
+ expectedBehaviour: "Every listing type declares a canonical. Three types had their metadata builder called without the site URL, so it returned nothing for them and those pages shipped with none at all — while the standard product page, the one anybody would spot-check, was fine.",
60
+ expectedUiState: "All four pages carry a canonical link element with an absolute URL. A page with none is the finding, named by listing type.",
61
+ expectedData: { pagesWithoutCanonical: 0 },
62
+ endResult: "Read-only.",
63
+ },
64
+ "checklist-seo-page-metadata-detail-canonical-uses-slug-not-id": {
65
+ roles: ["guest"],
66
+ startPage: "/classified/classified-tester-sandbox-1",
67
+ steps: [
68
+ "Sign in as tester@letitrip.in / TempPass123!.",
69
+ "Open /classified/classified-tester-sandbox-1 and note the exact path in the address bar.",
70
+ "View the source and read the canonical's path.",
71
+ "Compare the two paths character for character.",
72
+ "Copy the canonical's URL into a fresh tab and read what loads.",
73
+ ],
74
+ expectedBehaviour: "The canonical names the URL the route actually serves. A canonical built from the record's internal id while the route is keyed on its slug names an address that does not exist — so the page tells crawlers its real home is a 404.",
75
+ expectedUiState: "The canonical's path equals the address bar's path, and opening it loads the same page. A canonical that 404s is the failure.",
76
+ endResult: "Read-only.",
77
+ },
78
+ "checklist-seo-page-metadata-single-h1-per-page": {
79
+ roles: ["guest"],
80
+ startPage: "/products",
81
+ steps: [
82
+ "Open /products and use the browser's element inspector to count top-level headings.",
83
+ "Do the same on the homepage.",
84
+ "Do the same on a product detail page.",
85
+ "Do the same on a store page and on a blog post.",
86
+ "Record the count for each.",
87
+ ],
88
+ expectedBehaviour: "One top-level heading per page states what the page is. Several compete to be that statement, and none makes it clear which describes the page.",
89
+ expectedUiState: "Exactly one on each of the five pages. Any page with zero or with more than one is a finding, named with its count.",
90
+ expectedData: { headingsPerPage: 1 },
91
+ endResult: "Read-only.",
92
+ },
93
+ "checklist-seo-page-metadata-404-page-not-indexable": {
94
+ roles: ["guest"],
95
+ startPage: "/products",
96
+ steps: [
97
+ "Open the network panel and navigate to a product path whose trailing segment is a nonsense word no listing uses.",
98
+ "Read the status code of the document response.",
99
+ "Read what the page shows.",
100
+ "View the source and look for a robots meta tag.",
101
+ "Repeat with a nonsense store path and a nonsense category path.",
102
+ ],
103
+ expectedBehaviour: "A missing page returns 404 and marks itself not-indexable. A 200 carrying a 'not found' message is a soft 404 — the URL stays in the index indefinitely, and every mistyped link a crawler follows adds another.",
104
+ expectedUiState: "The document response is 404 on all three paths, the page shows a readable not-found state with a route onward, and it is marked not-indexable. A 200 status is the finding regardless of what the body says.",
105
+ expectedData: { statusCode: 404 },
106
+ endResult: "Read-only.",
107
+ },
108
+ "checklist-seo-page-metadata-title-length-reasonable": {
109
+ roles: ["guest"],
110
+ startPage: "/products",
111
+ steps: [
112
+ "Open a product with a long name and read the full tab title including any site-name suffix.",
113
+ "Count its characters.",
114
+ "Check the product's own name is not the part being cut off by the suffix.",
115
+ "Repeat on a blog post with a long headline.",
116
+ "Repeat on a category page.",
117
+ ],
118
+ expectedBehaviour: "A title stays short enough to be shown whole, and where it cannot, the record's own name survives and the brand suffix is what gives way. A title truncated mid-word in the record's name is worse than one with no suffix.",
119
+ expectedUiState: "Each title reads as a complete phrase with the record's name intact, roughly sixty characters or fewer. A title cut mid-word is the finding, quoted in full.",
120
+ endResult: "Read-only.",
121
+ },
122
+ };
@@ -0,0 +1,2 @@
1
+ import type { AuthoredCase } from "./_types";
2
+ export declare const authored: Record<string, AuthoredCase>;
@@ -0,0 +1,105 @@
1
+ /*
2
+ * WHY: Authored six-part procedures for the seo/sitemap-and-robots checklist page.
3
+ * WHAT: 6 case(s), keyed by full checklist id.
4
+ *
5
+ * Two of these are the ones that would have caught the de-indexing directly: a
6
+ * sitemap whose URLs all redirect, and a robots.txt naming a different host from
7
+ * the pages. Neither errors, neither is visible in a browser, and both are one
8
+ * request away from being provable.
9
+ *
10
+ * @tag domain:tester
11
+ * @tag layer:seed
12
+ * @tag pattern:none
13
+ * @tag access:server-only
14
+ * @tag consumers:seed-data/authored/index.ts
15
+ * @tag sideEffects:none
16
+ */
17
+ export const authored = {
18
+ "checklist-seo-sitemap-and-robots-sitemap-loads-and-parses": {
19
+ roles: ["guest"],
20
+ startPage: "/sitemap.xml",
21
+ steps: [
22
+ "Open /sitemap.xml directly in the browser.",
23
+ "Read the status shown in the network panel.",
24
+ "Read whether the browser rendered it as XML or as raw text with a parse error.",
25
+ "Count the URL entries, or read the count the browser reports.",
26
+ "Scan the entries for the main sections — products, categories, brands, stores, blog, events.",
27
+ ],
28
+ expectedBehaviour: "The sitemap is served as valid XML with a real inventory of public URLs. A sitemap that 404s or fails to parse is silently ignored by every crawler, and there is no report anywhere that says so.",
29
+ expectedUiState: "The document renders as XML with no parse error, returns 200, and holds well over a hundred entries covering each public section. A handful of entries, or only the homepage, is the finding.",
30
+ endResult: "Read-only.",
31
+ },
32
+ "checklist-seo-sitemap-and-robots-sitemap-urls-do-not-redirect": {
33
+ roles: ["guest"],
34
+ startPage: "/sitemap.xml",
35
+ steps: [
36
+ "Open /sitemap.xml and copy the first entry's URL exactly as written.",
37
+ "Paste it into a fresh tab with the network panel open.",
38
+ "Read the first response's status code before any redirect is followed.",
39
+ "Repeat with one entry from each section — a product, a category, a store, a blog post.",
40
+ "Note the host each entry uses and compare it against the host they land on.",
41
+ ],
42
+ expectedBehaviour: "A sitemap entry resolves directly. Every one of them redirecting means the sitemap names one host while the pages canonicalise to another — the exact shape that removed this site from search results, and it produces no error at any layer.",
43
+ expectedUiState: "Each sampled URL returns 200 on its first response, with no redirect step in the network panel. Any redirect is the finding, reported with the host it came from and the host it went to.",
44
+ expectedData: { redirectingSitemapUrls: 0 },
45
+ endResult: "Read-only.",
46
+ },
47
+ "checklist-seo-sitemap-and-robots-robots-loads-and-allows": {
48
+ roles: ["guest"],
49
+ startPage: "/robots.txt",
50
+ steps: [
51
+ "Open /robots.txt directly and read the whole file.",
52
+ "Read every Disallow line.",
53
+ "Check no rule disallows the site root for all user agents.",
54
+ "Read the Host line, if present, and note the hostname.",
55
+ "Compare that hostname against the address bar and against the sitemap's entries.",
56
+ ],
57
+ expectedBehaviour: "robots.txt loads, permits the public site and names the same host as everything else. A sustained failure on this file is worse than a wrong rule inside it — a crawler that cannot fetch robots.txt stops crawling the whole host, and the file was among the routes taken down by a past module-load failure.",
58
+ expectedUiState: "The file returns 200 with readable content, has no blanket disallow, and its host matches the sitemap's. A different host here is the same two-owners failure seen from another angle.",
59
+ endResult: "Read-only.",
60
+ },
61
+ "checklist-seo-sitemap-and-robots-robots-sitemap-line-correct": {
62
+ roles: ["guest"],
63
+ startPage: "/robots.txt",
64
+ steps: [
65
+ "Open /robots.txt and find the Sitemap: line.",
66
+ "Copy the URL it names exactly.",
67
+ "Open it in a fresh tab with the network panel open.",
68
+ "Read the status of the first response.",
69
+ "Check it is the same sitemap /sitemap.xml serves.",
70
+ ],
71
+ expectedBehaviour: "The Sitemap: line names a URL that loads on its first request. A line pointing at a redirecting or missing host means the sitemap is never read, while both files individually look fine.",
72
+ expectedUiState: "The named URL returns 200 directly and serves the sitemap. A redirect or a 404 is the finding.",
73
+ endResult: "Read-only.",
74
+ },
75
+ "checklist-seo-sitemap-and-robots-sitemap-excludes-private-routes": {
76
+ roles: ["guest"],
77
+ startPage: "/sitemap.xml",
78
+ steps: [
79
+ "Open /sitemap.xml and use the browser's find to search for '/admin'.",
80
+ "Search for '/store/' and for '/user/'.",
81
+ "Search for '/checkout' and for '/cart'.",
82
+ "Search for '/auth/'.",
83
+ "Record any match, with the full URL.",
84
+ ],
85
+ expectedBehaviour: "Only pages a signed-out visitor can actually read belong in the sitemap. A dashboard or checkout route there spends crawl budget on a redirect or an empty shell, and the shell is what gets indexed if anything is.",
86
+ expectedUiState: "None of those searches matches. Every match is a finding, listed with its URL.",
87
+ expectedData: { privateRoutesInSitemap: 0 },
88
+ endResult: "Read-only.",
89
+ },
90
+ "checklist-seo-sitemap-and-robots-sitemap-excludes-test-data": {
91
+ roles: ["guest"],
92
+ startPage: "/sitemap.xml",
93
+ steps: [
94
+ "Open /sitemap.xml and search for 'tester-sandbox'.",
95
+ "Search for 'tester-qa'.",
96
+ "Search for 'test-' as a looser check.",
97
+ "Record any match with its full URL.",
98
+ "Open one matched URL, if any, and read what it serves.",
99
+ ],
100
+ expectedBehaviour: "Sandbox fixtures are wiped and re-seeded on every tester run, so a sitemap entry for one is a URL that repeatedly disappears. Test data is filtered out of every public read for the same reason it must be filtered here.",
101
+ expectedUiState: "No sandbox id appears in the sitemap. A match is a finding, and if the URL currently loads that makes it worse rather than better — it means sandbox content is publicly indexable.",
102
+ expectedData: { sandboxUrlsInSitemap: 0 },
103
+ endResult: "Read-only.",
104
+ },
105
+ };
@@ -1,11 +1,17 @@
1
1
  /*
2
- * WHY: Shared tester sandbox — 1 disposable test event with both raffle and spin-wheel
3
- * fields populated, so testers can exercise the events/raffle/spin flow end to end.
4
- * Auto-expires after 7 days (testerSandboxCleanup).
5
- * WHAT: Exports eventsTesterSeedData — 1 Partial<EventDocument> tagged isTestData:true.
2
+ * WHY: Shared tester sandbox — disposable test events covering spin-wheel, both raffle
3
+ * variants, a coupon offer, and a lottery with a pre-booked slot, so testers can
4
+ * exercise each flow end to end.
5
+ * WHAT: Exports eventsTesterSeedData — 5 Partial<EventDocument> tagged isTestData:true.
6
+ *
7
+ * The lottery's draw window is expressed via tester-window.ts rather than a fixed
8
+ * duration, so an automated run can shorten it and still watch the window close.
9
+ * The other four stay long-lived on purpose: they are meant to read as ACTIVE
10
+ * events for a human tester who seeds today and returns tomorrow. A fixture that
11
+ * must expire mid-session should be added as its own row, not by re-timing these.
6
12
  *
7
13
  * EXPORTS:
8
- * eventsTesterSeedData — Array of 1 Partial<EventDocument> for the seed runner
14
+ * eventsTesterSeedData — Array of 5 Partial<EventDocument> for the seed runner
9
15
  *
10
16
  * @tag domain:events,tester
11
17
  * @tag layer:seed
@@ -17,6 +23,7 @@
17
23
  import { EVENT_FIELDS } from "../../../constants/field-names";
18
24
  import { seedPhoto } from "../../../seed/_helpers/media";
19
25
  import { testDataExpiresAt } from "./tester-ttl";
26
+ import { windowMinutes, windowOffset } from "./tester-window";
20
27
  const TEST_EVENT_COVER_ALT = "Test event cover";
21
28
  const TEST_RAFFLE_PRIZE = "Test prize — not a real reward";
22
29
  export const eventsTesterSeedData = [
@@ -118,4 +125,69 @@ export const eventsTesterSeedData = [
118
125
  createdAt: new Date(),
119
126
  updatedAt: new Date(),
120
127
  },
128
+ // ── Lottery, with one slot ALREADY BOOKED ───────────────────────────────────
129
+ // This fixture exists for exactly two checklist cases, both marked 🛑:
130
+ // page-wiring/data-loss/lottery-edit-preserves-bookings
131
+ // page-wiring/data-loss/lottery-booked-slot-cannot-be-deleted
132
+ // Neither could be tested before, because no lottery fixture existed anywhere —
133
+ // lottery events could previously only come from a hand-run seed.
134
+ //
135
+ // 🛑 Slot 3's booking IS the fixture. A booked slot carries a buyer id, a display
136
+ // name and a lottery number, and the bug being guarded silently cleared all three
137
+ // while returning a success message. Do not "tidy" this into an all-unbooked
138
+ // lottery — an unbooked slot cannot demonstrate the loss, and the case would then
139
+ // pass against the very bug it exists to catch.
140
+ //
141
+ // price/weight are server-only (toClientLotterySlot strips them). Uniform pricing
142
+ // means every slot is weight 50 by definition — see computeWeight().
143
+ {
144
+ id: "event-tester-sandbox-lottery",
145
+ slug: "tester-sandbox-lottery",
146
+ type: EVENT_FIELDS.TYPE_VALUES.LOTTERY,
147
+ title: "Tester Sandbox — Lottery",
148
+ description: "Disposable test lottery for the tester QA program. Slot 3 is pre-booked: edit an unrelated slot, save, reopen, and confirm slot 3 is STILL booked to the same buyer with the same lottery number.",
149
+ status: EVENT_FIELDS.STATUS_VALUES.ACTIVE,
150
+ startsAt: new Date(),
151
+ endsAt: windowOffset(1),
152
+ coverImage: {
153
+ type: "image",
154
+ url: seedPhoto("event-cover-tester-sandbox-lottery-20260101", 1200, 600),
155
+ alt: TEST_EVENT_COVER_ALT,
156
+ },
157
+ tags: ["test"],
158
+ lotteryConfig: {
159
+ totalSlots: 6,
160
+ pricingMode: "uniform",
161
+ uniformPrice: 100,
162
+ // Must outlast the run, or late batches meet a closed lottery. windowOffset(1)
163
+ // is the run's end, so the draw window is expressed in the same units.
164
+ drawWindowDurationMinutes: Math.ceil(windowMinutes()),
165
+ maxPullsPerTransaction: 1,
166
+ maxPullsPerUser: 1,
167
+ slots: [
168
+ { slotNumber: 1, name: "Test Prize — Dragoon Storm", price: 100, weight: 50, isBooked: false, image: seedPhoto("lottery-slot-tester-1-20260101", 600, 600) },
169
+ { slotNumber: 2, name: "Test Prize — Dranzer S", price: 100, weight: 50, isBooked: false, image: seedPhoto("lottery-slot-tester-2-20260101", 600, 600) },
170
+ {
171
+ slotNumber: 3,
172
+ name: "Test Prize — Draciel Shield",
173
+ price: 100,
174
+ weight: 50,
175
+ isBooked: true,
176
+ bookedByUserId: "user-ash-trainer",
177
+ bookedByDisplayName: "Mock User 4",
178
+ bookedByUserLotteryNumber: 1,
179
+ image: seedPhoto("lottery-slot-tester-3-20260101", 600, 600),
180
+ },
181
+ { slotNumber: 4, name: "Test Prize — Driger F", price: 100, weight: 50, isBooked: false },
182
+ { slotNumber: 5, name: "Test Prize — Wolborg", price: 100, weight: 50, isBooked: false },
183
+ { slotNumber: 6, name: "Test Prize — Trygle", price: 100, weight: 50, isBooked: false },
184
+ ],
185
+ },
186
+ stats: { totalEntries: 1, approvedEntries: 1, flaggedEntries: 0 },
187
+ createdBy: "user-admin-letitrip",
188
+ isTestData: true,
189
+ testDataExpiresAt: testDataExpiresAt(),
190
+ createdAt: new Date(),
191
+ updatedAt: new Date(),
192
+ },
121
193
  ];
@@ -11,7 +11,7 @@
11
11
  * drive it straight through the Offers checkout lane.
12
12
  *
13
13
  * Every date is Date.now()-relative (per CLAUDE.md's tester-fixture standards)
14
- * so the 4-hour testerSandboxRefresh re-arms it instead of letting it go stale.
14
+ * so each seed run re-arms it instead of letting it go stale.
15
15
  *
16
16
  * EXPORTS:
17
17
  * offersTesterSeedData — Array of 1 Partial<OfferDocument> for the seed runner
@@ -25,9 +25,23 @@
25
25
  */
26
26
  import { OfferStatusValues } from "../../seller/schemas/firestore";
27
27
  import { testDataExpiresAt } from "./tester-ttl";
28
+ import { windowOffset } from "./tester-window";
28
29
  const NOW = new Date();
29
30
  const hoursAgo = (n) => new Date(NOW.getTime() - n * 3600000);
30
- const hoursFromNow = (n) => new Date(NOW.getTime() + n * 3600000);
31
+ /*
32
+ * Deadlines expressed as fractions of the testing window rather than fixed hours.
33
+ *
34
+ * "An accepted offer past its checkoutDeadline cannot be checked out" is a real
35
+ * checklist case, and a fixed 36-hour deadline makes it untestable in any session
36
+ * shorter than a day and a half. Fractions scale with TESTER_WINDOW_MINUTES, so the
37
+ * lapse actually happens while someone is watching.
38
+ *
39
+ * OUTLASTS_RUN is deliberately greater than 1: the "still live" offers must NOT
40
+ * lapse mid-run, or every other offer case starts failing for the wrong reason.
41
+ */
42
+ const OUTLASTS_RUN = 2;
43
+ const LAPSES_MID_RUN = 1 / 3;
44
+ const CHECKOUT_LAPSES_MID_RUN = 1 / 6;
31
45
  export const offersTesterSeedData = [
32
46
  {
33
47
  id: "offer-tester-sandbox-accepted",
@@ -52,11 +66,11 @@ export const offersTesterSeedData = [
52
66
  status: OfferStatusValues.ACCEPTED,
53
67
  buyerNote: "Sandbox offer — already accepted so testers can drive checkout.",
54
68
  sellerNote: "Accepted for QA sandbox testing.",
55
- expiresAt: hoursFromNow(24),
69
+ expiresAt: windowOffset(OUTLASTS_RUN),
56
70
  acceptedAt: hoursAgo(1),
57
71
  respondedAt: hoursAgo(1),
58
72
  // Well inside the 48h window so the lane is live for a whole test session.
59
- checkoutDeadline: hoursFromNow(36),
73
+ checkoutDeadline: windowOffset(OUTLASTS_RUN),
60
74
  createdAt: hoursAgo(2),
61
75
  updatedAt: hoursAgo(1),
62
76
  isTestData: true,
@@ -83,7 +97,7 @@ export const offersTesterSeedData = [
83
97
  status: OfferStatusValues.COUNTERED,
84
98
  buyerNote: "Sandbox offer — seller has countered, accept it to test the counter path.",
85
99
  sellerNote: "Counter: ₹1,150.",
86
- expiresAt: hoursFromNow(24),
100
+ expiresAt: windowOffset(OUTLASTS_RUN),
87
101
  respondedAt: hoursAgo(1),
88
102
  createdAt: hoursAgo(2),
89
103
  updatedAt: hoursAgo(1),
@@ -112,10 +126,10 @@ export const offersTesterSeedData = [
112
126
  status: OfferStatusValues.ACCEPTED,
113
127
  buyerNote: "Sandbox offer — accepted with a short checkout window.",
114
128
  sellerNote: "Accepted. Pay soon!",
115
- expiresAt: hoursFromNow(1),
129
+ expiresAt: windowOffset(LAPSES_MID_RUN),
116
130
  acceptedAt: hoursAgo(0),
117
131
  respondedAt: hoursAgo(0),
118
- checkoutDeadline: new Date(NOW.getTime() + 30 * 60000),
132
+ checkoutDeadline: windowOffset(CHECKOUT_LAPSES_MID_RUN),
119
133
  createdAt: hoursAgo(1),
120
134
  updatedAt: hoursAgo(0),
121
135
  isTestData: true,
@@ -141,7 +155,7 @@ export const offersTesterSeedData = [
141
155
  currency: "INR",
142
156
  status: OfferStatusValues.PENDING,
143
157
  buyerNote: "Sandbox offer — still pending, withdraw it to test that path.",
144
- expiresAt: hoursFromNow(24),
158
+ expiresAt: windowOffset(OUTLASTS_RUN),
145
159
  createdAt: hoursAgo(1),
146
160
  updatedAt: hoursAgo(1),
147
161
  isTestData: true,
@@ -168,7 +182,7 @@ export const offersTesterSeedData = [
168
182
  currency: "INR",
169
183
  status: OfferStatusValues.PENDING,
170
184
  buyerNote: "Sandbox inbound offer — accept, counter, or decline it from your store dashboard.",
171
- expiresAt: hoursFromNow(24),
185
+ expiresAt: windowOffset(OUTLASTS_RUN),
172
186
  createdAt: hoursAgo(2),
173
187
  updatedAt: hoursAgo(2),
174
188
  isTestData: true,