@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.
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +32 -2
- package/dist/features/tester/components/TesterChecklistStepRow.d.ts +9 -1
- package/dist/features/tester/components/TesterChecklistStepRow.js +31 -2
- package/dist/features/tester/components/TesterHubView.js +8 -0
- package/dist/features/tester/schemas/firestore.d.ts +109 -0
- package/dist/features/tester/schemas/firestore.js +14 -0
- package/dist/features/tester/seed-data/_money-flows.d.ts +23 -0
- package/dist/features/tester/seed-data/_money-flows.js +430 -0
- package/dist/features/tester/seed-data/authored/_types.d.ts +33 -0
- package/dist/features/tester/seed-data/authored/_types.js +35 -0
- package/dist/features/tester/seed-data/authored/account-auth__profile-settings.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/account-auth__profile-settings.js +207 -0
- package/dist/features/tester/seed-data/authored/account-auth__signup-login.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/account-auth__signup-login.js +298 -0
- package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.js +33 -0
- package/dist/features/tester/seed-data/authored/account-auth__testing-program.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/account-auth__testing-program.js +138 -0
- package/dist/features/tester/seed-data/authored/addresses__address-filters.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/addresses__address-filters.js +36 -0
- package/dist/features/tester/seed-data/authored/addresses__postal-lookup.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/addresses__postal-lookup.js +75 -0
- package/dist/features/tester/seed-data/authored/addresses__postal-validation.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/addresses__postal-validation.js +72 -0
- package/dist/features/tester/seed-data/authored/addresses__state-picker.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/addresses__state-picker.js +54 -0
- package/dist/features/tester/seed-data/authored/addresses__unban-request.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/addresses__unban-request.js +39 -0
- package/dist/features/tester/seed-data/authored/admin__bans-and-trust.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__bans-and-trust.js +226 -0
- package/dist/features/tester/seed-data/authored/admin__blog-faqs.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__blog-faqs.js +82 -0
- package/dist/features/tester/seed-data/authored/admin__bulk-actions.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__bulk-actions.js +177 -0
- package/dist/features/tester/seed-data/authored/admin__bundles.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__bundles.js +97 -0
- package/dist/features/tester/seed-data/authored/admin__buyer-data-admin.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__buyer-data-admin.js +232 -0
- package/dist/features/tester/seed-data/authored/admin__catalog-listings.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__catalog-listings.js +306 -0
- package/dist/features/tester/seed-data/authored/admin__category-brand-authoring.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__category-brand-authoring.js +158 -0
- package/dist/features/tester/seed-data/authored/admin__classifieds-digitalcodes-live.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__classifieds-digitalcodes-live.js +78 -0
- package/dist/features/tester/seed-data/authored/admin__content-deletes.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__content-deletes.js +261 -0
- package/dist/features/tester/seed-data/authored/admin__content-marketing.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__content-marketing.js +151 -0
- package/dist/features/tester/seed-data/authored/admin__coupons.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__coupons.js +214 -0
- package/dist/features/tester/seed-data/authored/admin__events-raffles-spin.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__events-raffles-spin.js +160 -0
- package/dist/features/tester/seed-data/authored/admin__media-watermark.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__media-watermark.js +104 -0
- package/dist/features/tester/seed-data/authored/admin__orders-fulfillment.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__orders-fulfillment.js +350 -0
- package/dist/features/tester/seed-data/authored/admin__prize-draws-lotteries.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__prize-draws-lotteries.js +105 -0
- package/dist/features/tester/seed-data/authored/admin__site-system.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__site-system.js +590 -0
- package/dist/features/tester/seed-data/authored/admin__uncovered-admin-pages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__uncovered-admin-pages.js +235 -0
- package/dist/features/tester/seed-data/authored/admin__users-trust.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__users-trust.js +569 -0
- package/dist/features/tester/seed-data/authored/buying__bidding.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__bidding.js +417 -0
- package/dist/features/tester/seed-data/authored/buying__browsing-search.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__browsing-search.js +653 -0
- package/dist/features/tester/seed-data/authored/buying__buying-checkout.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__buying-checkout.js +533 -0
- package/dist/features/tester/seed-data/authored/buying__buying-coupons.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__buying-coupons.js +379 -0
- package/dist/features/tester/seed-data/authored/buying__cart.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__cart.js +1171 -0
- package/dist/features/tester/seed-data/authored/buying__image-tile-layout.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__image-tile-layout.js +140 -0
- package/dist/features/tester/seed-data/authored/buying__my-orders.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__my-orders.js +257 -0
- package/dist/features/tester/seed-data/authored/buying__offers.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__offers.js +1111 -0
- package/dist/features/tester/seed-data/authored/buying__order-status-lifecycle.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__order-status-lifecycle.js +252 -0
- package/dist/features/tester/seed-data/authored/buying__product-detail.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__product-detail.js +387 -0
- package/dist/features/tester/seed-data/authored/buying__return-request.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__return-request.js +152 -0
- package/dist/features/tester/seed-data/authored/buying__reviews-pagination.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__reviews-pagination.js +242 -0
- package/dist/features/tester/seed-data/authored/buying__reviews.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__reviews.js +113 -0
- package/dist/features/tester/seed-data/authored/buying__user-dashboard-extras.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__user-dashboard-extras.js +283 -0
- package/dist/features/tester/seed-data/authored/buying__user-dashboard-navigation.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__user-dashboard-navigation.js +167 -0
- package/dist/features/tester/seed-data/authored/buying__user-uncovered-pages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__user-uncovered-pages.js +90 -0
- package/dist/features/tester/seed-data/authored/buying__wishlist-history.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__wishlist-history.js +344 -0
- package/dist/features/tester/seed-data/authored/community-support__public-profile.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/community-support__public-profile.js +53 -0
- package/dist/features/tester/seed-data/authored/community-support__support-tickets.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/community-support__support-tickets.js +76 -0
- package/dist/features/tester/seed-data/authored/content-discovery__blog.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__blog.js +93 -0
- package/dist/features/tester/seed-data/authored/content-discovery__category-brand-relations.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__category-brand-relations.js +149 -0
- package/dist/features/tester/seed-data/authored/content-discovery__coupons.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__coupons.js +121 -0
- package/dist/features/tester/seed-data/authored/content-discovery__event-participation.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__event-participation.js +207 -0
- package/dist/features/tester/seed-data/authored/content-discovery__events.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__events.js +318 -0
- package/dist/features/tester/seed-data/authored/content-discovery__faq-help.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__faq-help.js +65 -0
- package/dist/features/tester/seed-data/authored/content-discovery__notifications.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__notifications.js +147 -0
- package/dist/features/tester/seed-data/authored/content-discovery__search.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__search.js +332 -0
- package/dist/features/tester/seed-data/authored/cta-layout__checkout-bottom-bar.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/cta-layout__checkout-bottom-bar.js +53 -0
- package/dist/features/tester/seed-data/authored/cta-layout__dialog-footers.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/cta-layout__dialog-footers.js +52 -0
- package/dist/features/tester/seed-data/authored/cta-layout__editor-action-bar.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/cta-layout__editor-action-bar.js +35 -0
- package/dist/features/tester/seed-data/authored/cta-layout__navbar-ctas.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/cta-layout__navbar-ctas.js +141 -0
- package/dist/features/tester/seed-data/authored/cta-layout__product-bottom-bar.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/cta-layout__product-bottom-bar.js +35 -0
- package/dist/features/tester/seed-data/authored/design-ux__back-to-top-button.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__back-to-top-button.js +95 -0
- package/dist/features/tester/seed-data/authored/design-ux__carousel-arrow-bounds.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__carousel-arrow-bounds.js +191 -0
- package/dist/features/tester/seed-data/authored/design-ux__dashboard-layout.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__dashboard-layout.js +158 -0
- package/dist/features/tester/seed-data/authored/design-ux__footer-theme.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__footer-theme.js +106 -0
- package/dist/features/tester/seed-data/authored/design-ux__form-validation-errors.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__form-validation-errors.js +88 -0
- package/dist/features/tester/seed-data/authored/design-ux__general-design.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__general-design.js +204 -0
- package/dist/features/tester/seed-data/authored/design-ux__hand-mode-layout.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__hand-mode-layout.js +301 -0
- package/dist/features/tester/seed-data/authored/design-ux__homepage-carousels.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__homepage-carousels.js +407 -0
- package/dist/features/tester/seed-data/authored/design-ux__status-badge-legibility.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__status-badge-legibility.js +214 -0
- package/dist/features/tester/seed-data/authored/design-ux__sticky-cta-bar.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__sticky-cta-bar.js +275 -0
- package/dist/features/tester/seed-data/authored/index.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/index.js +237 -0
- package/dist/features/tester/seed-data/authored/page-wiring__data-loss.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/page-wiring__data-loss.js +102 -0
- package/dist/features/tester/seed-data/authored/page-wiring__detail-pages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/page-wiring__detail-pages.js +50 -0
- package/dist/features/tester/seed-data/authored/page-wiring__drawer-pages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/page-wiring__drawer-pages.js +66 -0
- package/dist/features/tester/seed-data/authored/page-wiring__reachability.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/page-wiring__reachability.js +115 -0
- package/dist/features/tester/seed-data/authored/public-pages__auth-error-pages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/public-pages__auth-error-pages.js +136 -0
- package/dist/features/tester/seed-data/authored/public-pages__bug-hunters.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/public-pages__bug-hunters.js +69 -0
- package/dist/features/tester/seed-data/authored/public-pages__core-listing-pages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/public-pages__core-listing-pages.js +263 -0
- package/dist/features/tester/seed-data/authored/public-pages__help-how-it-works.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/public-pages__help-how-it-works.js +102 -0
- package/dist/features/tester/seed-data/authored/public-pages__help-scams-guides-subpages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/public-pages__help-scams-guides-subpages.js +234 -0
- package/dist/features/tester/seed-data/authored/public-pages__legal-policy-pages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/public-pages__legal-policy-pages.js +126 -0
- package/dist/features/tester/seed-data/authored/public-pages__stores-sellers-directories.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/public-pages__stores-sellers-directories.js +255 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__employee-permissions.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__employee-permissions.js +59 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__header-search.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__header-search.js +88 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__settings-deep-links.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__settings-deep-links.js +51 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__sidebar-search.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__sidebar-search.js +35 -0
- package/dist/features/tester/seed-data/authored/selling__become-seller.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__become-seller.js +94 -0
- package/dist/features/tester/seed-data/authored/selling__final-sale-authoring.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__final-sale-authoring.js +107 -0
- package/dist/features/tester/seed-data/authored/selling__listing-a-product.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__listing-a-product.js +285 -0
- package/dist/features/tester/seed-data/authored/selling__listing-lifecycle.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__listing-lifecycle.js +326 -0
- package/dist/features/tester/seed-data/authored/selling__listing-type-fields-roundtrip.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__listing-type-fields-roundtrip.js +136 -0
- package/dist/features/tester/seed-data/authored/selling__media-limits.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__media-limits.js +128 -0
- package/dist/features/tester/seed-data/authored/selling__sectionised-forms.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__sectionised-forms.js +167 -0
- package/dist/features/tester/seed-data/authored/selling__seller-analytics-payouts.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-analytics-payouts.js +117 -0
- package/dist/features/tester/seed-data/authored/selling__seller-bids-bundles-filters.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-bids-bundles-filters.js +88 -0
- package/dist/features/tester/seed-data/authored/selling__seller-catalog-org.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-catalog-org.js +151 -0
- package/dist/features/tester/seed-data/authored/selling__seller-custom-brands.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-custom-brands.js +105 -0
- package/dist/features/tester/seed-data/authored/selling__seller-guide.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-guide.js +33 -0
- package/dist/features/tester/seed-data/authored/selling__seller-listing-types.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-listing-types.js +347 -0
- package/dist/features/tester/seed-data/authored/selling__seller-marketing-extras.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-marketing-extras.js +166 -0
- package/dist/features/tester/seed-data/authored/selling__seller-ops-comms.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-ops-comms.js +89 -0
- package/dist/features/tester/seed-data/authored/selling__seller-orders.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-orders.js +195 -0
- package/dist/features/tester/seed-data/authored/selling__seller-shipping-payouts-setup.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-shipping-payouts-setup.js +180 -0
- package/dist/features/tester/seed-data/authored/selling__store-dashboard-navigation.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__store-dashboard-navigation.js +164 -0
- package/dist/features/tester/seed-data/authored/selling__store-uncovered-pages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__store-uncovered-pages.js +116 -0
- package/dist/features/tester/seed-data/authored/seo__canonical-and-host.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/seo__canonical-and-host.js +111 -0
- package/dist/features/tester/seed-data/authored/seo__og-images.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/seo__og-images.js +91 -0
- package/dist/features/tester/seed-data/authored/seo__page-metadata.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/seo__page-metadata.js +122 -0
- package/dist/features/tester/seed-data/authored/seo__sitemap-and-robots.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/seo__sitemap-and-robots.js +105 -0
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +744 -1
- package/dist/seed/carousel-slides-seed-data.js +1 -1
- package/dist/seed/products-standard-seed-data.js +2 -2
- package/dist/seed/reviews-seed-data.js +6 -1
- package/package.json +1 -1
- package/scripts/seed-cli.mjs +6 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: Authored six-part procedures for the content-discovery/events page.
|
|
3
|
+
* WHAT: 19 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
|
+
* 🛑 EVENTS ARE GLOBAL — the document carries no storeId, no categorySlugs and no
|
|
10
|
+
* brandSlug — which is why their facet counts are unscoped and why no case here
|
|
11
|
+
* filters an event by store. Time-bound event fixtures derive their windows from
|
|
12
|
+
* tester-window.ts, so a run can shorten them and actually watch one close.
|
|
13
|
+
*
|
|
14
|
+
* @tag domain:tester
|
|
15
|
+
* @tag layer:seed
|
|
16
|
+
* @tag pattern:none
|
|
17
|
+
* @tag access:server-only
|
|
18
|
+
* @tag consumers:seed-data/authored/index.ts
|
|
19
|
+
* @tag sideEffects:none
|
|
20
|
+
*/
|
|
21
|
+
export const authored = {
|
|
22
|
+
"checklist-content-discovery-events-view-event": {
|
|
23
|
+
roles: ["guest"],
|
|
24
|
+
startPage: "/events",
|
|
25
|
+
steps: [
|
|
26
|
+
"Open /events in a private window with no session.",
|
|
27
|
+
"Click event-favourite-blader-poll.",
|
|
28
|
+
"Read the title, dates, status and description.",
|
|
29
|
+
"Read the tab bar and open each tab in turn.",
|
|
30
|
+
"Read the address bar as each tab opens.",
|
|
31
|
+
],
|
|
32
|
+
inputs: { eventId: "event-favourite-blader-poll" },
|
|
33
|
+
expectedBehaviour: "An event detail page is split into routed child tabs — Overview, Participate and Leaderboard — so each is a real URL rather than local state. The description renders as HTML, which is where an event's extra images live since the document has no gallery field.",
|
|
34
|
+
expectedUiState: "Title, dates and status render. Each tab changes the URL and renders its own content. The description shows formatted prose and any inline images, not raw markup as visible text.",
|
|
35
|
+
endResult: "Read-only; nothing persists.",
|
|
36
|
+
},
|
|
37
|
+
"checklist-content-discovery-events-events-listing-cards-images": {
|
|
38
|
+
roles: ["guest"],
|
|
39
|
+
startPage: "/events",
|
|
40
|
+
steps: [
|
|
41
|
+
"Open /events in a private window with no session.",
|
|
42
|
+
"Look at every card's image.",
|
|
43
|
+
"Hard-reload with Ctrl+Shift+R and look again.",
|
|
44
|
+
"Read every status filter offered and select each in turn.",
|
|
45
|
+
"Read the results for each status.",
|
|
46
|
+
],
|
|
47
|
+
expectedBehaviour: "Every card renders its image, and every status chip corresponds to a real stored status. The seed carries a paused and a cancelled event specifically because those two chips previously had no rows at all and could never return anything.",
|
|
48
|
+
expectedUiState: "All cards show images on both loads, with no broken glyph or grey placeholder. Every status chip returns rows or a named empty state, and the paused and cancelled chips both return their fixtures.",
|
|
49
|
+
endResult: "Read-only; nothing persists beyond the URL.",
|
|
50
|
+
},
|
|
51
|
+
"checklist-content-discovery-events-lottery-cover-image": {
|
|
52
|
+
roles: ["guest"],
|
|
53
|
+
startPage: "/events",
|
|
54
|
+
steps: [
|
|
55
|
+
"Open /events in a private window and find event-tester-sandbox-lottery.",
|
|
56
|
+
"Look at its card image.",
|
|
57
|
+
"Open the lottery's detail page.",
|
|
58
|
+
"Look at the image at the top of that page.",
|
|
59
|
+
"Note whether either shows an emoji instead of a photograph.",
|
|
60
|
+
],
|
|
61
|
+
inputs: { eventId: "event-tester-sandbox-lottery" },
|
|
62
|
+
expectedBehaviour: "A lottery renders its stored cover image on both the card and the detail page. The 🎰 emoji is the fallback for an event with no image, and seeing it where one is set means the field is not reaching the renderer.",
|
|
63
|
+
expectedUiState: "Both the card and the detail hero show the cover photograph. Neither shows the 🎰 emoji placeholder.",
|
|
64
|
+
endResult: "Read-only; nothing persists.",
|
|
65
|
+
},
|
|
66
|
+
"checklist-content-discovery-events-lottery-prize-previews": {
|
|
67
|
+
roles: ["guest"],
|
|
68
|
+
startPage: "/events",
|
|
69
|
+
steps: [
|
|
70
|
+
"Open event-tester-sandbox-lottery's detail page in a private window.",
|
|
71
|
+
"Find the 'Prizes' collage above the numbered slot grid.",
|
|
72
|
+
"Count the tiles in the collage.",
|
|
73
|
+
"Count the slots in the numbered grid below it.",
|
|
74
|
+
"Compare the two numbers and read whether any collage tile is blank.",
|
|
75
|
+
"Read the page source for a slot price or weight value.",
|
|
76
|
+
],
|
|
77
|
+
expectedBehaviour: "Only slots carrying an image appear in the collage — a slot without one is omitted rather than rendered as an empty tile, so a 200-slot lottery with six photographed prizes shows six tiles. The client-facing slot shape is an allow-list: number, name, booked state and image reach the browser, price and weight never do.",
|
|
78
|
+
expectedUiState: "The collage holds one tile per photographed prize and no blank tiles. The numbered grid below still shows EVERY slot, photographed or not. No slot price or weight appears anywhere in the page or its source.",
|
|
79
|
+
expectedData: { blankCollageTiles: 0 },
|
|
80
|
+
endResult: "Read-only; nothing persists. A collage with as many tiles as the grid has slots means unphotographed slots are being rendered as empties.",
|
|
81
|
+
},
|
|
82
|
+
"checklist-content-discovery-events-related-events-section": {
|
|
83
|
+
roles: ["guest"],
|
|
84
|
+
startPage: "/events",
|
|
85
|
+
steps: [
|
|
86
|
+
"Open /events in a private window and open any active event.",
|
|
87
|
+
"Stay on the Overview tab and scroll to the 'Related Events' carousel.",
|
|
88
|
+
"Read the cards and their titles.",
|
|
89
|
+
"Check whether the event currently open appears among them.",
|
|
90
|
+
"Click one card and confirm it opens that event.",
|
|
91
|
+
],
|
|
92
|
+
expectedBehaviour: "Related events are other ACTIVE events sharing at least one tag, with the current event excluded. Ended and cancelled events must not be suggested — a suggestion the visitor cannot act on is worse than no carousel.",
|
|
93
|
+
expectedUiState: "The carousel holds real event cards with titles and images. The current event is not among them. No card is an ended or cancelled event. An empty rail beneath a heading is a fail — the section should not render at all.",
|
|
94
|
+
expectedData: { selfLinkCount: 0 },
|
|
95
|
+
endResult: "Read-only; nothing persists.",
|
|
96
|
+
},
|
|
97
|
+
"checklist-content-discovery-events-poll-vote-inline": {
|
|
98
|
+
roles: ["buyer"],
|
|
99
|
+
startPage: "/events",
|
|
100
|
+
steps: [
|
|
101
|
+
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
102
|
+
"Open event-favourite-blader-poll and click the Participate tab.",
|
|
103
|
+
"Read the options offered.",
|
|
104
|
+
"Select the first option and submit the vote.",
|
|
105
|
+
"Read what the page shows immediately afterwards, without reloading.",
|
|
106
|
+
"Reload the page and read the Participate tab again.",
|
|
107
|
+
"Try to vote a second time.",
|
|
108
|
+
],
|
|
109
|
+
inputs: { eventId: "event-favourite-blader-poll" },
|
|
110
|
+
expectedBehaviour: "A vote is recorded as an entry against this user and the tally updates in place. One vote per user is enforced server-side, so a second attempt is refused rather than silently counted again.",
|
|
111
|
+
expectedUiState: "The vote registers without a full page reload and the tally moves. After reloading, the same option is still shown as this user's choice. The second attempt is refused with a message rather than accepted.",
|
|
112
|
+
expectedData: { votesPerUser: 1 },
|
|
113
|
+
endResult: "The vote survives the reload.",
|
|
114
|
+
},
|
|
115
|
+
"checklist-content-discovery-events-poll-leaderboard-shows-tally": {
|
|
116
|
+
roles: ["guest"],
|
|
117
|
+
startPage: "/events",
|
|
118
|
+
steps: [
|
|
119
|
+
"Open event-favourite-blader-poll in a private window.",
|
|
120
|
+
"Click the Leaderboard tab.",
|
|
121
|
+
"Read every row — what it names and what number it carries.",
|
|
122
|
+
"Check whether the rows are option labels or people's names.",
|
|
123
|
+
"Check whether the counts descend down the list.",
|
|
124
|
+
],
|
|
125
|
+
expectedBehaviour: "A poll's leaderboard ranks OPTIONS by votes, not participants by who voted first. Reusing the generic entries-ranked-by-time view produces a list of voters, which answers a question nobody asked and publishes who voted.",
|
|
126
|
+
expectedUiState: "Each row names a poll option with its vote count or percentage, ordered highest first. No row names a person. A list of voter names is the failure even when it renders neatly.",
|
|
127
|
+
expectedData: { rowsAreOptions: true },
|
|
128
|
+
endResult: "Read-only; nothing persists.",
|
|
129
|
+
},
|
|
130
|
+
"checklist-content-discovery-events-admin-event-entries-export": {
|
|
131
|
+
roles: ["admin"],
|
|
132
|
+
startPage: "/admin/events",
|
|
133
|
+
steps: [
|
|
134
|
+
"Sign in as admin@letitrip.in / TempPass123!.",
|
|
135
|
+
"Open /admin/events and open the entries page for event-favourite-blader-poll.",
|
|
136
|
+
"Read the entries listed and expand one to read its response inline.",
|
|
137
|
+
"Click 'Download Report'.",
|
|
138
|
+
"Open the downloaded file and read it.",
|
|
139
|
+
"Compare the entries in the file against the ones shown on screen.",
|
|
140
|
+
],
|
|
141
|
+
expectedBehaviour: "Responses are readable inline, without downloading anything, and the download is a Markdown report of all entries. Both are needed: acting on an entry you cannot read is the dead-end shape this whole page family exists to close.",
|
|
142
|
+
expectedUiState: "Each entry can be expanded to show its response. 'Download Report' produces a Markdown file listing every entry with its response. The file's entries match what the page shows rather than being a shorter or differently-filtered set.",
|
|
143
|
+
endResult: "A report file exists on disk. Read-only against the data; nothing in the app changes.",
|
|
144
|
+
},
|
|
145
|
+
"checklist-content-discovery-events-survey-feedback-submit": {
|
|
146
|
+
roles: ["buyer"],
|
|
147
|
+
startPage: "/events",
|
|
148
|
+
steps: [
|
|
149
|
+
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
150
|
+
"Open event-metal-fight-era-feedback and click the Participate tab.",
|
|
151
|
+
"Submit the form with every field empty and read where the errors appear.",
|
|
152
|
+
"Type 'QA Feedback survey-feedback-submit' into the free-text field and answer any other required fields.",
|
|
153
|
+
"Submit the form.",
|
|
154
|
+
"Reload the page and read the Participate tab.",
|
|
155
|
+
],
|
|
156
|
+
inputs: { response: "QA Feedback survey-feedback-submit" },
|
|
157
|
+
expectedBehaviour: "The form validates against its schema and reports each problem on the field that caused it, then records an entry against this user.",
|
|
158
|
+
expectedUiState: "The empty submit marks individual fields rather than showing one banner. The filled submit produces a confirmation. After reloading, the tab shows the response as already submitted rather than offering a blank form again.",
|
|
159
|
+
endResult: "The entry survives the reload.",
|
|
160
|
+
},
|
|
161
|
+
"checklist-content-discovery-events-offer-coupon-display-copy": {
|
|
162
|
+
roles: ["buyer"],
|
|
163
|
+
startPage: "/events",
|
|
164
|
+
steps: [
|
|
165
|
+
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
166
|
+
"Open event-tester-sandbox-offer and read the coupon code displayed.",
|
|
167
|
+
"Click the copy control beside it.",
|
|
168
|
+
"Read any confirmation shown.",
|
|
169
|
+
"Open /checkout with an item in the cart and paste into the coupon field.",
|
|
170
|
+
"Read what was pasted and click 'Apply'.",
|
|
171
|
+
],
|
|
172
|
+
inputs: { eventId: "event-tester-sandbox-offer" },
|
|
173
|
+
expectedBehaviour: "The code is shown in full and the copy control puts exactly that string on the clipboard. A copy control that copies a truncated or differently-cased value produces a rejection the buyer cannot explain.",
|
|
174
|
+
expectedUiState: "The code is legible in full on the page. Copying shows a confirmation. The pasted value matches the displayed code character for character, and applying it is accepted.",
|
|
175
|
+
endResult: "Remove the coupon afterwards so later checkout cases start from an empty coupon list.",
|
|
176
|
+
},
|
|
177
|
+
"checklist-content-discovery-events-raffle-entry": {
|
|
178
|
+
roles: ["buyer"],
|
|
179
|
+
startPage: "/events",
|
|
180
|
+
steps: [
|
|
181
|
+
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
182
|
+
"Open event-won-original-set-raffle and click the Participate tab.",
|
|
183
|
+
"Read the entry conditions stated.",
|
|
184
|
+
"Enter the raffle.",
|
|
185
|
+
"Read what the page shows immediately, without reloading.",
|
|
186
|
+
"Reload and read the tab again.",
|
|
187
|
+
"Try to enter a second time.",
|
|
188
|
+
],
|
|
189
|
+
expectedBehaviour: "An open raffle records one entry per user. The entry is what makes the user eligible for the draw, so a second attempt must be refused rather than creating a duplicate that would double their odds.",
|
|
190
|
+
expectedUiState: "The entry is confirmed in place. After reloading the tab shows the user as already entered. The second attempt is refused with a message.",
|
|
191
|
+
expectedData: { entriesPerUser: 1 },
|
|
192
|
+
endResult: "The entry survives the reload.",
|
|
193
|
+
},
|
|
194
|
+
"checklist-content-discovery-events-raffle-entry-top-n-scorers": {
|
|
195
|
+
roles: ["buyer"],
|
|
196
|
+
startPage: "/events",
|
|
197
|
+
steps: [
|
|
198
|
+
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
199
|
+
"Open event-tester-sandbox-top-scorers and read the Overview tab's description of how winners are chosen.",
|
|
200
|
+
"Click the Participate tab and enter.",
|
|
201
|
+
"Click the Leaderboard tab and read how entries are ranked.",
|
|
202
|
+
"Read whether the ranking is by score and whether the eligible cut-off is stated.",
|
|
203
|
+
],
|
|
204
|
+
inputs: { eventId: "event-tester-sandbox-top-scorers" },
|
|
205
|
+
expectedBehaviour: "A top-N-scorers raffle draws from the highest-scoring entries, so the leaderboard must rank by score and the page must say how many qualify. Ranking by entry time instead would silently change who can win.",
|
|
206
|
+
expectedUiState: "The leaderboard is ordered by score, highest first, and the qualifying cut-off is stated. Entering is confirmed. A leaderboard ordered by entry time is the failure.",
|
|
207
|
+
endResult: "The entry survives a reload.",
|
|
208
|
+
},
|
|
209
|
+
"checklist-content-discovery-events-raffle-entry-top-n-participants": {
|
|
210
|
+
roles: ["buyer"],
|
|
211
|
+
startPage: "/events",
|
|
212
|
+
steps: [
|
|
213
|
+
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
214
|
+
"Open event-tester-sandbox-top-participants and read the Overview tab's description of how winners are chosen.",
|
|
215
|
+
"Click the Participate tab and enter.",
|
|
216
|
+
"Click the Leaderboard tab and read how entries are ranked.",
|
|
217
|
+
"Compare the ranking rule with the one on event-tester-sandbox-top-scorers.",
|
|
218
|
+
],
|
|
219
|
+
inputs: { eventId: "event-tester-sandbox-top-participants" },
|
|
220
|
+
expectedBehaviour: "A top-N-participants raffle draws from the earliest or most active participants rather than the highest scorers — a different rule from the scorers variant. The two fixtures exist side by side precisely so the difference is checkable.",
|
|
221
|
+
expectedUiState: "This event's leaderboard is ordered by its own rule and that rule is stated on the Overview tab. The two raffle types rank differently. Identical ranking on both means the raffle type is not reaching the leaderboard.",
|
|
222
|
+
endResult: "The entry survives a reload.",
|
|
223
|
+
},
|
|
224
|
+
"checklist-content-discovery-events-spin-wheel": {
|
|
225
|
+
roles: ["buyer"],
|
|
226
|
+
startPage: "/events",
|
|
227
|
+
steps: [
|
|
228
|
+
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
229
|
+
"Open event-tester-sandbox-spin and click the Participate tab.",
|
|
230
|
+
"Click the spin control ONCE and watch the wheel.",
|
|
231
|
+
"Read the prize shown and how long it took to appear.",
|
|
232
|
+
"Reload the page and read the Participate tab.",
|
|
233
|
+
],
|
|
234
|
+
inputs: { eventId: "event-tester-sandbox-spin" },
|
|
235
|
+
expectedBehaviour: "The very first spin succeeds and the prize is shown immediately over the realtime channel. A first attempt that fails and a second that works is the signature of a subscription established after the result was already written.",
|
|
236
|
+
expectedUiState: "The wheel spins and lands on a named prize within a few seconds. No 'Spin failed' error appears on the first attempt. After reloading, the result is still shown rather than the wheel offering another free spin.",
|
|
237
|
+
expectedData: { spinsUsed: 1 },
|
|
238
|
+
endResult: "The recorded spin and its prize survive the reload.",
|
|
239
|
+
},
|
|
240
|
+
"checklist-content-discovery-events-spin-wheel-max-per-user": {
|
|
241
|
+
roles: ["buyer"],
|
|
242
|
+
startPage: "/events",
|
|
243
|
+
steps: [
|
|
244
|
+
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
245
|
+
"Open event-tester-sandbox-spin and read the stated maximum spins per user.",
|
|
246
|
+
"Spin until that maximum is reached, reading the remaining count each time.",
|
|
247
|
+
"Attempt one more spin.",
|
|
248
|
+
"Read the refusal.",
|
|
249
|
+
"Reload the page and attempt another spin.",
|
|
250
|
+
],
|
|
251
|
+
expectedBehaviour: "The per-user spin cap is enforced server-side, so reloading does not restore a spin. A cap held only in the browser resets on refresh and the limit is no limit at all.",
|
|
252
|
+
expectedUiState: "The remaining count decreases with each spin. At zero the control is refused with a message naming the limit. After reloading it is still refused — a fresh spin available after a reload is the failure.",
|
|
253
|
+
expectedData: { spinsAfterReload: 0 },
|
|
254
|
+
endResult: "The exhausted state persists across reloads.",
|
|
255
|
+
},
|
|
256
|
+
"checklist-content-discovery-events-spin-wheel-window-blocked": {
|
|
257
|
+
roles: ["buyer"],
|
|
258
|
+
startPage: "/events",
|
|
259
|
+
steps: [
|
|
260
|
+
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
261
|
+
"Open event-tester-sandbox-spin and read the stated spin window.",
|
|
262
|
+
"If the window is currently closed, attempt a spin and read the refusal.",
|
|
263
|
+
"If it is open, wait for it to close — the window derives from the run's testing window, so shortening that shortens this — then attempt a spin.",
|
|
264
|
+
"Read the refusal and check it names the window rather than a generic failure.",
|
|
265
|
+
],
|
|
266
|
+
expectedBehaviour: "Spins outside the configured window are refused with a reason naming the window. The window is expressed as a fraction of the run's testing window rather than a baked duration, which is what makes 'wait for it to close' possible inside a session at all.",
|
|
267
|
+
expectedUiState: "Outside the window the spin control is refused and the message names the window or its times. It is not a generic 'Spin failed', which would be indistinguishable from the realtime failure above.",
|
|
268
|
+
endResult: "No spin is recorded outside the window. If the window cannot be reached within the session, answer null rather than guessing.",
|
|
269
|
+
},
|
|
270
|
+
"checklist-content-discovery-events-spin-results-tab": {
|
|
271
|
+
roles: ["guest"],
|
|
272
|
+
startPage: "/events",
|
|
273
|
+
steps: [
|
|
274
|
+
"Open event-tester-sandbox-spin in a private window with no session.",
|
|
275
|
+
"Find the 'Last 10 Spin Results' tab and open it.",
|
|
276
|
+
"Read every row — the name shown and the prize.",
|
|
277
|
+
"Count the rows.",
|
|
278
|
+
"Check whether any row shows a full real name.",
|
|
279
|
+
],
|
|
280
|
+
expectedBehaviour: "The results tab lists recent winners, capped at ten, with anonymous spins shown as 'Guest'. Named entries are shown masked — a public results list is exactly the surface where an unmasked display name leaks, and a masking helper that returns its input unchanged looks correct from every layer except this one.",
|
|
281
|
+
expectedUiState: "At most ten rows, each naming a prize. Anonymous spins read 'Guest'. Named entries are masked rather than showing a full real name.",
|
|
282
|
+
expectedData: { maxRows: 10 },
|
|
283
|
+
endResult: "Read-only; nothing persists.",
|
|
284
|
+
},
|
|
285
|
+
"checklist-content-discovery-events-event-guest-participation-toggle": {
|
|
286
|
+
roles: ["admin", "guest"],
|
|
287
|
+
startPage: "/admin/events",
|
|
288
|
+
steps: [
|
|
289
|
+
"Sign in as admin@letitrip.in / TempPass123!.",
|
|
290
|
+
"Open /admin/events/new and create an event titled 'QA Event guest-participation' with guest participation ENABLED, starting today and ending in a week.",
|
|
291
|
+
"Open its public page in a private window with no session.",
|
|
292
|
+
"Enter the event as a guest and read the confirmation.",
|
|
293
|
+
"Attempt to enter a second time from the same private window.",
|
|
294
|
+
"Read the refusal.",
|
|
295
|
+
"As admin, edit the event to disable guest participation and save.",
|
|
296
|
+
"Reload the public page in the private window and attempt to enter.",
|
|
297
|
+
],
|
|
298
|
+
inputs: { eventTitle: "QA Event guest-participation", guestParticipation: true },
|
|
299
|
+
expectedBehaviour: "With guest participation enabled an anonymous visitor may enter once per device, and a second attempt from the same device is blocked. With it disabled the entry control asks for sign-in instead of accepting anonymous entries.",
|
|
300
|
+
expectedUiState: "The first guest entry is confirmed. The second is refused with a message rather than silently accepted. After the toggle is disabled, the public page prompts for sign-in rather than offering entry.",
|
|
301
|
+
expectedData: { guestEntriesPerDevice: 1 },
|
|
302
|
+
endResult: "Delete the event afterwards so it does not accumulate across runs.",
|
|
303
|
+
},
|
|
304
|
+
"checklist-content-discovery-events-leaderboard-live-refresh": {
|
|
305
|
+
roles: ["buyer"],
|
|
306
|
+
startPage: "/events",
|
|
307
|
+
steps: [
|
|
308
|
+
"In window A, open event-favourite-blader-poll's Leaderboard tab signed out, and read the tallies.",
|
|
309
|
+
"Leave window A on that tab without reloading it.",
|
|
310
|
+
"In window B, sign in as vivaan.kapoor@gmail.com / TempPass123!.",
|
|
311
|
+
"In window B, open the same event's Participate tab and vote for an option.",
|
|
312
|
+
"Return to window A and watch the tallies for up to 15 seconds without reloading.",
|
|
313
|
+
],
|
|
314
|
+
expectedBehaviour: "The leaderboard updates from the live feed rather than only on load, so a viewer watching a poll sees it move. A tally that only changes on refresh makes a live event feel dead.",
|
|
315
|
+
expectedUiState: "Window A's tally for the voted option increases within about 15 seconds, with no reload and no interaction. A figure that only changes when the tester refreshes is the failure.",
|
|
316
|
+
endResult: "The vote persists. This requires vivaan.kapoor@gmail.com not to have voted on this poll already — if they have, use another buyer persona.",
|
|
317
|
+
},
|
|
318
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: Authored six-part procedures for the content-discovery/faq-help page.
|
|
3
|
+
* WHAT: 3 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
|
+
* @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-content-discovery-faq-help-faq-bottom-borders": {
|
|
18
|
+
roles: ["guest"],
|
|
19
|
+
startPage: "/faqs",
|
|
20
|
+
steps: [
|
|
21
|
+
"Open /faqs in a private window at a desktop width of 1280 pixels.",
|
|
22
|
+
"Look at the divider between each question row and the next.",
|
|
23
|
+
"Look specifically at the LAST row in a category, below its text.",
|
|
24
|
+
"Expand one question and look at the dividers again.",
|
|
25
|
+
"Switch the site to dark mode and look at every divider once more.",
|
|
26
|
+
],
|
|
27
|
+
inputs: { viewportWidth: 1280 },
|
|
28
|
+
expectedBehaviour: "Rows are separated by a divider between them, with none trailing after the last row — a stray border under the final item reads as a truncated list. Divider colour comes from a theme token that inverts, so it stays visible in both themes rather than being a fixed near-white line that vanishes on dark.",
|
|
29
|
+
expectedUiState: "A divider sits between consecutive rows and there is none below the last row of a category. Expanding a question does not double the divider or leave a hairline across the open panel. Every divider is visible in dark mode.",
|
|
30
|
+
endResult: "Read-only; nothing persists. Return the site to light mode afterwards.",
|
|
31
|
+
},
|
|
32
|
+
"checklist-content-discovery-faq-help-faq-mobile-count": {
|
|
33
|
+
roles: ["guest"],
|
|
34
|
+
startPage: "/faqs",
|
|
35
|
+
steps: [
|
|
36
|
+
"Resize the browser window to 390 pixels wide.",
|
|
37
|
+
"Open /faqs in a private window with no session.",
|
|
38
|
+
"Read the count shown against each category.",
|
|
39
|
+
"Open one category and count the questions it actually holds.",
|
|
40
|
+
"Compare the two numbers.",
|
|
41
|
+
"Try to scroll the page sideways.",
|
|
42
|
+
],
|
|
43
|
+
inputs: { viewportWidth: 390 },
|
|
44
|
+
expectedBehaviour: "The count beside a category matches what opening it reveals, at mobile width as at desktop. A count computed before an active-only filter is applied over-reports by every inactive entry.",
|
|
45
|
+
expectedUiState: "Each category's count matches its contents. Nothing is clipped at 390px and the page does not scroll sideways. Counts are not hidden entirely on mobile — they are the reason a visitor opens one category rather than another.",
|
|
46
|
+
expectedData: { mismatchedCountCount: 0 },
|
|
47
|
+
endResult: "Read-only; nothing persists. Restore the window width afterwards.",
|
|
48
|
+
},
|
|
49
|
+
"checklist-content-discovery-faq-help-tabs-mobile-dropdown": {
|
|
50
|
+
roles: ["guest"],
|
|
51
|
+
startPage: "/faqs",
|
|
52
|
+
steps: [
|
|
53
|
+
"Open /faqs at a desktop width of 1280 pixels and read how the categories are presented.",
|
|
54
|
+
"Resize the window to 390 pixels wide.",
|
|
55
|
+
"Read how the categories are presented now.",
|
|
56
|
+
"Open the mobile control and select a different category.",
|
|
57
|
+
"Read which category's questions are shown and check the control names the selected one.",
|
|
58
|
+
"Try to scroll the page sideways.",
|
|
59
|
+
],
|
|
60
|
+
inputs: { desktopWidth: 1280, mobileWidth: 390 },
|
|
61
|
+
expectedBehaviour: "A tab strip too wide for a phone becomes a dropdown rather than a sideways-scrolling row, so no category is hidden off the right edge where nobody looks for it.",
|
|
62
|
+
expectedUiState: "At 1280 the categories are a tab strip. At 390 they are a dropdown listing every category, and selecting one switches the questions AND updates the control's own label. The page does not scroll sideways at either width.",
|
|
63
|
+
endResult: "Read-only; nothing persists. Restore the window width afterwards.",
|
|
64
|
+
},
|
|
65
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: Authored six-part procedures for the content-discovery/notifications page.
|
|
3
|
+
* WHAT: 8 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
|
+
* 🛑 THE OPT-OUT CASE IS THE IMPORTANT ONE. The map from notification type to
|
|
10
|
+
* preference key must be COMPLETE: a missing entry left the key undefined, so the
|
|
11
|
+
* opt-out check never ran and the user's preference was silently ignored while the
|
|
12
|
+
* toggle sat there reading as honoured. Three types were missing.
|
|
13
|
+
*
|
|
14
|
+
* @tag domain:tester
|
|
15
|
+
* @tag layer:seed
|
|
16
|
+
* @tag pattern:none
|
|
17
|
+
* @tag access:server-only
|
|
18
|
+
* @tag consumers:seed-data/authored/index.ts
|
|
19
|
+
* @tag sideEffects:none
|
|
20
|
+
*/
|
|
21
|
+
export const authored = {
|
|
22
|
+
"checklist-content-discovery-notifications-receive-notification": {
|
|
23
|
+
roles: ["buyer"],
|
|
24
|
+
startPage: "/user/notifications",
|
|
25
|
+
steps: [
|
|
26
|
+
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
27
|
+
"Open /user/notifications and read the unread count on the header bell.",
|
|
28
|
+
"In a second window, sign in as vivaan.kapoor@gmail.com / TempPass123!.",
|
|
29
|
+
"As that second buyer, open /auctions/auction-tester-sandbox-cycle-1 and place a bid high enough to outbid the first buyer.",
|
|
30
|
+
"Return to the first window and open /user/notifications.",
|
|
31
|
+
"Read the newest entry and the bell's unread count.",
|
|
32
|
+
],
|
|
33
|
+
expectedBehaviour: "An event that concerns a user produces a notification addressed to them, carrying a title, a body and a destination. The destination is filled in from the record it relates to rather than hand-written per caller, which is why almost no call site used to set one.",
|
|
34
|
+
expectedUiState: "A new entry appears naming the auction, and the bell's unread count has increased. The entry has a readable title and body — not a raw type string like 'bid_outbid' shown as the whole message.",
|
|
35
|
+
endResult: "The notification survives a reload. This case requires the first buyer to hold the leading bid beforehand; place one first if they do not.",
|
|
36
|
+
},
|
|
37
|
+
"checklist-content-discovery-notifications-mark-read": {
|
|
38
|
+
roles: ["buyer"],
|
|
39
|
+
startPage: "/user/notifications",
|
|
40
|
+
steps: [
|
|
41
|
+
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
42
|
+
"Open /user/notifications and note the unread count on the bell.",
|
|
43
|
+
"Click one unread notification.",
|
|
44
|
+
"Read the bell's count and that row's unread styling.",
|
|
45
|
+
"Reload the page and read both again.",
|
|
46
|
+
"Use the mark-all-read control and read the count.",
|
|
47
|
+
"Reload once more.",
|
|
48
|
+
],
|
|
49
|
+
expectedBehaviour: "Read state is persisted per notification, so the count is the same before and after a reload. A count held only in component state resets to the original number on refresh and the user sees the same badge again.",
|
|
50
|
+
expectedUiState: "Opening one notification drops the count by exactly one and removes that row's unread styling. After the reload the count is still the reduced one. Mark-all-read takes it to zero and it is still zero after reloading.",
|
|
51
|
+
expectedData: { unreadCountAfterMarkAll: 0 },
|
|
52
|
+
endResult: "The count stays at zero across reloads.",
|
|
53
|
+
},
|
|
54
|
+
"checklist-content-discovery-notifications-notification-channel-prefs": {
|
|
55
|
+
roles: ["buyer"],
|
|
56
|
+
startPage: "/user/settings",
|
|
57
|
+
steps: [
|
|
58
|
+
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
59
|
+
"Open /user/settings and click the 'Notifications' tab.",
|
|
60
|
+
"Read every channel offered and every notification type listed.",
|
|
61
|
+
"Turn one channel off for one type and click 'Save preferences'.",
|
|
62
|
+
"Reload the page and open the tab again.",
|
|
63
|
+
"Read whether that one switch is still off and whether the others are unchanged.",
|
|
64
|
+
],
|
|
65
|
+
expectedBehaviour: "Preferences save per type and per channel, and saving one does not rewrite the others from a partly-populated form. The tab must also list every notification type — an incomplete list leaves whole categories with no way to opt out at all.",
|
|
66
|
+
expectedUiState: "The changed switch is off after the reload and every switch the tester did not touch holds its previous value. Types such as offer_received and payment_review are present in the list rather than missing.",
|
|
67
|
+
endResult: "Restore the switch afterwards, so later notification cases are not suppressed by a leftover opt-out.",
|
|
68
|
+
},
|
|
69
|
+
"checklist-content-discovery-notifications-notification-type-sample": {
|
|
70
|
+
roles: ["buyer"],
|
|
71
|
+
startPage: "/user/notifications",
|
|
72
|
+
steps: [
|
|
73
|
+
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
74
|
+
"Open /user/notifications.",
|
|
75
|
+
"Read every entry, noting its type icon or label, its title and its body.",
|
|
76
|
+
"Write down any entry whose body is empty, or reads as a raw type string, or repeats its own title verbatim.",
|
|
77
|
+
],
|
|
78
|
+
expectedBehaviour: "Each notification type renders its own title and body from a template keyed on the type. A type with no template falls back to something generic, which is visible as a body that simply restates the title or shows the type identifier.",
|
|
79
|
+
expectedUiState: "Every entry has a distinct, readable title and body. None shows a bare type identifier such as 'order_confirmed' as its message, and none has an empty body.",
|
|
80
|
+
expectedData: { untemplatedEntryCount: 0 },
|
|
81
|
+
endResult: "Read-only; nothing persists.",
|
|
82
|
+
},
|
|
83
|
+
"checklist-content-discovery-notifications-notification-tab-filters": {
|
|
84
|
+
roles: ["buyer"],
|
|
85
|
+
startPage: "/user/notifications",
|
|
86
|
+
steps: [
|
|
87
|
+
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
88
|
+
"Open /user/notifications and read every filter tab or chip offered.",
|
|
89
|
+
"Note the total number of entries with no filter applied.",
|
|
90
|
+
"Select each filter in turn and read the resulting count and rows.",
|
|
91
|
+
"Write down any filter that returns zero rows.",
|
|
92
|
+
"Clear the filter and check the original count returns.",
|
|
93
|
+
],
|
|
94
|
+
expectedBehaviour: "Every filter value offered corresponds to a type that notifications actually carry. A chip whose value is not a real stored type matches byte-exactly against nothing and stays empty forever, with no error to explain it.",
|
|
95
|
+
expectedUiState: "Each filter either returns rows or is genuinely empty for this account — and where it is empty, the same type is absent from the unfiltered list too. A chip that is empty while matching entries sit in the unfiltered list is the failure.",
|
|
96
|
+
endResult: "Read-only; nothing persists beyond the URL.",
|
|
97
|
+
},
|
|
98
|
+
"checklist-content-discovery-notifications-notification-email-actually-arrives": {
|
|
99
|
+
roles: ["buyer"],
|
|
100
|
+
startPage: "/user/settings",
|
|
101
|
+
steps: [
|
|
102
|
+
"Sign in as an account whose inbox you can open.",
|
|
103
|
+
"Open /user/settings, click the 'Notifications' tab, and make sure Email is on for order updates.",
|
|
104
|
+
"Place an order that will produce an order-confirmed notification.",
|
|
105
|
+
"Open /user/notifications and confirm the in-app entry is there.",
|
|
106
|
+
"Open the inbox, checking Spam as well, and wait up to five minutes.",
|
|
107
|
+
"Read the email's From name and address, its subject and its body.",
|
|
108
|
+
"Click the button or link inside it.",
|
|
109
|
+
],
|
|
110
|
+
expectedBehaviour: "The dispatcher fans out to in-app first and then email, rendering a per-type template rather than wrapping the one-line message in a paragraph — for a long time not one caller supplied email HTML, so every type shipped the same bare body.",
|
|
111
|
+
expectedUiState: "The email arrives in the inbox. Its From display name is spelled 'LetItRip' exactly. Its body is a real templated message rather than a single unstyled sentence. Its link opens the right page on the live site.",
|
|
112
|
+
endResult: "The in-app notification and the email both exist. An in-app entry with no email, while email is enabled for that type, is the failure this case separates from a delivery problem.",
|
|
113
|
+
},
|
|
114
|
+
"checklist-content-discovery-notifications-notification-email-opt-out-respected": {
|
|
115
|
+
roles: ["buyer"],
|
|
116
|
+
startPage: "/user/settings",
|
|
117
|
+
steps: [
|
|
118
|
+
"Sign in as an account whose inbox you can open.",
|
|
119
|
+
"Open /user/settings, click the 'Notifications' tab, and turn Email OFF for order updates.",
|
|
120
|
+
"Click 'Save preferences' and reload to confirm it stayed off.",
|
|
121
|
+
"Place an order that would produce an order-confirmed notification.",
|
|
122
|
+
"Open /user/notifications and read the entries.",
|
|
123
|
+
"Open the inbox and wait five minutes, checking Spam as well.",
|
|
124
|
+
"Turn Email back on for order updates and save.",
|
|
125
|
+
],
|
|
126
|
+
expectedBehaviour: "Turning a channel off suppresses that channel and nothing else — the in-app notification still appears. The suppression depends on a complete type-to-preference-key map: a type missing from it leaves the key undefined, the opt-out check never runs, and mail keeps arriving while the toggle reads as honoured.",
|
|
127
|
+
expectedUiState: "The in-app entry is present. NO email arrives for it. An email arriving with the toggle off is the exact failure, and it is invisible from the settings page — the switch looks the same either way.",
|
|
128
|
+
expectedData: { emailsReceived: 0 },
|
|
129
|
+
endResult: "The preference is turned back on by the final step. Waiting the full five minutes matters: concluding after thirty seconds proves nothing about a queue.",
|
|
130
|
+
},
|
|
131
|
+
"checklist-content-discovery-notifications-notification-links-to-right-entity": {
|
|
132
|
+
roles: ["buyer"],
|
|
133
|
+
startPage: "/user/notifications",
|
|
134
|
+
steps: [
|
|
135
|
+
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
136
|
+
"Open /user/notifications.",
|
|
137
|
+
"Click an order notification and read the address bar and the record shown.",
|
|
138
|
+
"Go back and click a bid notification, reading the address bar and what is shown.",
|
|
139
|
+
"Go back and click an offer notification, reading the address bar and what is shown.",
|
|
140
|
+
"Note any that land on a 404.",
|
|
141
|
+
],
|
|
142
|
+
expectedBehaviour: "The destination is resolved from the related record's type and id, so a caller cannot forget it. Bids, offers and reviews have no per-record page in any role, so those correctly resolve to their LIST — a real destination. Fabricating a per-record URL for them would 404, which is worse than a list.",
|
|
143
|
+
expectedUiState: "An order notification opens that specific order. A bid notification opens the bids list. An offer notification opens the offers list. None lands on a 404 and none lands on the dashboard root with no relation to what was clicked.",
|
|
144
|
+
expectedData: { notFoundCount: 0 },
|
|
145
|
+
endResult: "Read-only; nothing persists. A list is a pass for bids and offers; a 404 is a fail for anything.",
|
|
146
|
+
},
|
|
147
|
+
};
|