@mohasinac/appkit 4.42.0 → 4.42.2
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/layout/DashboardLayoutClient.js +2 -30
- package/dist/_internal/server/features/offers/adapters.d.ts +29 -7
- package/dist/_internal/server/features/offers/adapters.js +14 -3
- package/dist/_internal/server/features/orders/adapters.js +54 -1
- package/dist/client.d.ts +1 -0
- package/dist/client.js +1 -0
- package/dist/features/account/components/UserOrdersView.js +30 -2
- package/dist/features/account/hooks/useAddresses.d.ts +21 -6
- package/dist/features/account/hooks/useAddresses.js +1 -1
- package/dist/features/addresses/hooks/usePostalLookup.js +84 -12
- package/dist/features/admin/components/AdminCategoriesView.js +37 -2
- package/dist/features/admin/components/AdminOffersView.js +2 -2
- package/dist/features/admin/constants/filter-tabs.d.ts +25 -0
- package/dist/features/admin/constants/filter-tabs.js +30 -0
- package/dist/features/admin/hooks/useAdminListingData.d.ts +35 -0
- package/dist/features/admin/hooks/useAdminListingData.js +45 -9
- package/dist/features/cart/schemas/index.d.ts +15 -0
- package/dist/features/cart/schemas/index.js +2 -0
- package/dist/features/cart/types/index.d.ts +22 -0
- package/dist/features/categories/components/CategoriesIndexListing.js +19 -1
- package/dist/features/categories/components/CategoriesIndexPageView.js +14 -1
- package/dist/features/classified/components/ClassifiedDetailPageView.d.ts +8 -0
- package/dist/features/classified/components/ClassifiedDetailPageView.js +1 -0
- package/dist/features/events/actions/event-actions.d.ts +13 -0
- package/dist/features/events/actions/event-actions.js +75 -1
- package/dist/features/events/repository/event-entry.repository.d.ts +17 -0
- package/dist/features/events/repository/event-entry.repository.js +36 -0
- package/dist/features/homepage/components/BrandsSection.js +1 -1
- package/dist/features/homepage/components/CustomerReviewsSection.js +1 -1
- package/dist/features/homepage/components/FeaturedBundlesSection.js +1 -1
- package/dist/features/homepage/components/ShopByCategorySection.js +1 -1
- package/dist/features/layout/AppLayoutShell.js +2 -2
- package/dist/features/layout/BottomNavLayout.d.ts +9 -3
- package/dist/features/layout/BottomNavLayout.js +9 -3
- package/dist/features/media/upload/MediaUploadField.js +21 -3
- package/dist/features/orders/components/OrdersList.js +2 -1
- package/dist/features/orders/index.d.ts +1 -0
- package/dist/features/orders/index.js +1 -0
- package/dist/features/orders/types/index.d.ts +2 -0
- package/dist/features/orders/utils/order-ref.d.ts +45 -0
- package/dist/features/orders/utils/order-ref.js +58 -0
- package/dist/features/products/components/MakeOfferButton.d.ts +18 -1
- package/dist/features/products/components/MakeOfferButton.js +23 -1
- package/dist/features/products/components/ProductDetailPageView.d.ts +5 -0
- package/dist/features/products/components/ProductDetailPageView.js +3 -2
- package/dist/features/products/repository/products.repository.js +29 -2
- package/dist/features/seller/actions/offer-actions.js +32 -0
- package/dist/features/seller/components/QuickProductForm.js +15 -1
- package/dist/features/seller/components/SellerBidsView.js +3 -1
- package/dist/features/seller/components/SellerOffersView.js +2 -2
- package/dist/features/seller/components/SellerOrdersView.js +49 -6
- package/dist/features/seller/components/SellerProductsCards.js +23 -1
- package/dist/features/seller/components/SellerProductsView.js +27 -2
- package/dist/features/seller/hooks/useSellerListingData.d.ts +0 -1
- package/dist/features/seller/hooks/useSellerListingData.js +17 -19
- package/dist/features/shell/SectionForm.js +33 -2
- package/dist/features/tester/seed-data/_happy-path.d.ts +23 -0
- package/dist/features/tester/seed-data/_happy-path.js +710 -0
- package/dist/features/tester/seed-data/_money-flows.js +34 -23
- package/dist/features/tester/seed-data/authored/account-auth__profile-settings.js +22 -3
- package/dist/features/tester/seed-data/authored/addresses__address-filters.js +17 -12
- package/dist/features/tester/seed-data/authored/addresses__postal-lookup.js +7 -6
- package/dist/features/tester/seed-data/authored/addresses__postal-validation.js +10 -4
- package/dist/features/tester/seed-data/authored/addresses__state-picker.js +13 -8
- package/dist/features/tester/seed-data/authored/addresses__unban-request.js +49 -11
- package/dist/features/tester/seed-data/authored/admin__admin-detail-round-trips.js +10 -6
- package/dist/features/tester/seed-data/authored/admin__bans-and-trust.js +71 -32
- package/dist/features/tester/seed-data/authored/admin__blog-faqs.js +80 -31
- package/dist/features/tester/seed-data/authored/admin__bug-hunter-rewards.js +62 -25
- package/dist/features/tester/seed-data/authored/admin__bulk-actions.js +61 -31
- package/dist/features/tester/seed-data/authored/admin__bundles.js +84 -37
- package/dist/features/tester/seed-data/authored/admin__buyer-data-admin.js +90 -57
- package/dist/features/tester/seed-data/authored/admin__catalog-listings.js +38 -26
- package/dist/features/tester/seed-data/authored/admin__category-brand-authoring.js +47 -28
- package/dist/features/tester/seed-data/authored/admin__classifieds-digitalcodes-live.js +118 -31
- package/dist/features/tester/seed-data/authored/admin__content-deletes.js +30 -24
- package/dist/features/tester/seed-data/authored/admin__content-marketing.js +83 -46
- package/dist/features/tester/seed-data/authored/admin__coupons.js +8 -8
- package/dist/features/tester/seed-data/authored/admin__events-raffles-spin.js +9 -9
- package/dist/features/tester/seed-data/authored/admin__firebase-function-effects.js +19 -4
- package/dist/features/tester/seed-data/authored/admin__media-watermark.js +77 -33
- package/dist/features/tester/seed-data/authored/admin__orders-fulfillment.js +5 -5
- package/dist/features/tester/seed-data/authored/admin__prize-draws-lotteries.js +29 -5
- package/dist/features/tester/seed-data/authored/admin__site-system.js +45 -23
- package/dist/features/tester/seed-data/authored/admin__uncovered-admin-pages.js +53 -28
- package/dist/features/tester/seed-data/authored/admin__users-trust.js +20 -20
- package/dist/features/tester/seed-data/authored/buying__bidding.js +19 -2
- package/dist/features/tester/seed-data/authored/buying__browsing-search.js +20 -5
- package/dist/features/tester/seed-data/authored/buying__buying-checkout.js +28 -10
- package/dist/features/tester/seed-data/authored/buying__cart.js +10 -3
- package/dist/features/tester/seed-data/authored/buying__image-tile-layout.js +0 -16
- package/dist/features/tester/seed-data/authored/buying__my-orders.js +27 -5
- package/dist/features/tester/seed-data/authored/buying__offers.js +22 -7
- package/dist/features/tester/seed-data/authored/buying__order-detail-actions.js +3 -3
- package/dist/features/tester/seed-data/authored/buying__product-detail.js +35 -4
- package/dist/features/tester/seed-data/authored/buying__return-request.js +19 -6
- package/dist/features/tester/seed-data/authored/buying__reviews-pagination.js +36 -18
- package/dist/features/tester/seed-data/authored/buying__reviews.js +16 -1
- package/dist/features/tester/seed-data/authored/buying__user-dashboard-navigation.js +8 -6
- package/dist/features/tester/seed-data/authored/buying__user-uncovered-pages.js +16 -1
- package/dist/features/tester/seed-data/authored/community-support__public-profile.js +3 -2
- package/dist/features/tester/seed-data/authored/community-support__support-tickets.js +4 -4
- package/dist/features/tester/seed-data/authored/content-discovery__blog.js +19 -2
- package/dist/features/tester/seed-data/authored/content-discovery__category-brand-relations.js +4 -4
- package/dist/features/tester/seed-data/authored/content-discovery__category-counts-and-rollup.js +5 -5
- package/dist/features/tester/seed-data/authored/content-discovery__coupons.js +41 -6
- package/dist/features/tester/seed-data/authored/content-discovery__event-detail-subroutes.js +63 -8
- package/dist/features/tester/seed-data/authored/content-discovery__event-participation.js +29 -29
- package/dist/features/tester/seed-data/authored/content-discovery__events.js +2 -2
- package/dist/features/tester/seed-data/authored/content-discovery__faq-help.js +23 -1
- package/dist/features/tester/seed-data/authored/content-discovery__notifications.js +6 -6
- package/dist/features/tester/seed-data/authored/content-discovery__search.js +1 -1
- package/dist/features/tester/seed-data/authored/content-discovery__store-reviews-aggregate.js +1 -1
- package/dist/features/tester/seed-data/authored/cta-layout__checkout-bottom-bar.js +31 -6
- package/dist/features/tester/seed-data/authored/cta-layout__dialog-footers.js +34 -10
- package/dist/features/tester/seed-data/authored/cta-layout__editor-action-bar.js +35 -8
- package/dist/features/tester/seed-data/authored/cta-layout__navbar-ctas.js +31 -9
- package/dist/features/tester/seed-data/authored/cta-layout__product-bottom-bar.js +29 -3
- package/dist/features/tester/seed-data/authored/design-ux__back-to-top-button.js +1 -1
- package/dist/features/tester/seed-data/authored/design-ux__carousel-arrow-bounds.js +10 -10
- package/dist/features/tester/seed-data/authored/design-ux__dashboard-layout.js +3 -3
- package/dist/features/tester/seed-data/authored/design-ux__footer-theme.js +2 -2
- package/dist/features/tester/seed-data/authored/design-ux__form-validation-errors.js +2 -2
- package/dist/features/tester/seed-data/authored/design-ux__general-design.js +4 -4
- package/dist/features/tester/seed-data/authored/design-ux__hand-mode-layout.js +4 -4
- package/dist/features/tester/seed-data/authored/design-ux__homepage-carousels.js +8 -8
- package/dist/features/tester/seed-data/authored/design-ux__status-badge-legibility.js +2 -2
- package/dist/features/tester/seed-data/authored/design-ux__sticky-cta-bar.js +2 -2
- package/dist/features/tester/seed-data/authored/page-wiring__data-loss.js +39 -16
- package/dist/features/tester/seed-data/authored/page-wiring__detail-pages.js +43 -8
- package/dist/features/tester/seed-data/authored/page-wiring__drawer-pages.js +40 -14
- package/dist/features/tester/seed-data/authored/page-wiring__reachability.js +31 -14
- package/dist/features/tester/seed-data/authored/public-pages__auth-error-pages.js +7 -6
- package/dist/features/tester/seed-data/authored/public-pages__bug-hunters.js +14 -5
- package/dist/features/tester/seed-data/authored/public-pages__core-listing-pages.js +3 -3
- package/dist/features/tester/seed-data/authored/public-pages__help-how-it-works.js +1 -1
- package/dist/features/tester/seed-data/authored/public-pages__help-scams-guides-subpages.js +4 -2
- package/dist/features/tester/seed-data/authored/public-pages__legal-policy-pages.js +3 -3
- package/dist/features/tester/seed-data/authored/public-pages__newly-wired-browse-indexes.js +5 -5
- package/dist/features/tester/seed-data/authored/public-pages__store-tabs.js +5 -5
- package/dist/features/tester/seed-data/authored/public-pages__stores-sellers-directories.js +3 -3
- package/dist/features/tester/seed-data/authored/search-and-nav__employee-permissions.js +45 -11
- package/dist/features/tester/seed-data/authored/search-and-nav__header-search.js +57 -17
- package/dist/features/tester/seed-data/authored/search-and-nav__settings-deep-links.js +36 -5
- package/dist/features/tester/seed-data/authored/search-and-nav__sidebar-search.js +29 -4
- package/dist/features/tester/seed-data/authored/selling__become-seller.js +23 -0
- package/dist/features/tester/seed-data/authored/selling__final-sale-authoring.js +14 -13
- package/dist/features/tester/seed-data/authored/selling__listing-a-product.js +14 -9
- package/dist/features/tester/seed-data/authored/selling__listing-edit-roundtrip.js +34 -7
- package/dist/features/tester/seed-data/authored/selling__listing-lifecycle.js +17 -7
- package/dist/features/tester/seed-data/authored/selling__listing-type-fields-roundtrip.js +9 -9
- package/dist/features/tester/seed-data/authored/selling__media-limits.js +9 -4
- package/dist/features/tester/seed-data/authored/selling__product-upload-details.js +3 -3
- package/dist/features/tester/seed-data/authored/selling__quick-add-minimum-details.js +3 -3
- package/dist/features/tester/seed-data/authored/selling__sectionised-forms.js +25 -1
- package/dist/features/tester/seed-data/authored/selling__seller-analytics-payouts.js +27 -6
- package/dist/features/tester/seed-data/authored/selling__seller-bids-bundles-filters.js +19 -1
- package/dist/features/tester/seed-data/authored/selling__seller-catalog-org.js +63 -22
- package/dist/features/tester/seed-data/authored/selling__seller-custom-brands.js +9 -5
- package/dist/features/tester/seed-data/authored/selling__seller-guide.js +7 -6
- package/dist/features/tester/seed-data/authored/selling__seller-listing-types.js +3 -2
- package/dist/features/tester/seed-data/authored/selling__seller-marketing-extras.js +18 -18
- package/dist/features/tester/seed-data/authored/selling__seller-ops-comms.js +13 -12
- package/dist/features/tester/seed-data/authored/selling__seller-orders-at-scale.js +19 -3
- package/dist/features/tester/seed-data/authored/selling__seller-orders.js +22 -4
- package/dist/features/tester/seed-data/authored/selling__seller-shipping-payouts-setup.js +20 -8
- package/dist/features/tester/seed-data/authored/selling__store-dashboard-navigation.js +10 -9
- package/dist/features/tester/seed-data/authored/selling__store-uncovered-pages.js +2 -2
- package/dist/features/tester/seed-data/authored/seo__canonical-and-host.js +5 -5
- package/dist/features/tester/seed-data/authored/seo__og-images.js +1 -1
- package/dist/features/tester/seed-data/authored/seo__page-metadata.js +7 -7
- package/dist/features/tester/seed-data/authored/seo__sitemap-and-robots.js +3 -3
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +126 -24
- package/dist/features/tester/utils/phases.d.ts +17 -0
- package/dist/features/tester/utils/phases.js +29 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/seo/json-ld.d.ts +23 -0
- package/dist/seo/json-ld.js +3 -2
- package/dist/server.d.ts +1 -0
- package/dist/server.js +2 -0
- package/dist/styles.css +1 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/PaginatedSelect.js +0 -0
- package/package.json +1 -1
|
@@ -16,6 +16,24 @@
|
|
|
16
16
|
* A filter or sort whose field is not marked sortable or filterable is dropped
|
|
17
17
|
* silently, so the control changes and nothing moves.
|
|
18
18
|
*
|
|
19
|
+
* 🛑 THE PRODUCT IS `product-beyblade-original-dranzer-s`, AND IT HAS TO BE.
|
|
20
|
+
*
|
|
21
|
+
* Every case here used to open `product-beyblade-burst-valkyrie`, which carries
|
|
22
|
+
* FOUR reviews. The tab pages at 12, so there was never a second page: nine
|
|
23
|
+
* cases about paginating, comparing page 2, and filtering by rating could not
|
|
24
|
+
* do the thing they describe, and would have been answered "could not test" on
|
|
25
|
+
* a feature that works.
|
|
26
|
+
*
|
|
27
|
+
* `reviews-seed-data.ts` builds this fixture for exactly this purpose — a
|
|
28
|
+
* DEEP_REVIEW_PRODUCT loop adding 14 reviews on top of its 5 from the main
|
|
29
|
+
* loop, 19 in all. Its comments say why: ratings cycle 1..5 so every star
|
|
30
|
+
* bucket is populated for the rating filter, and its dates are drawn from a
|
|
31
|
+
* different range than the main loop so the two sets interleave and
|
|
32
|
+
* "newest first" is verifiable by eye.
|
|
33
|
+
*
|
|
34
|
+
* Do not repoint these at a different product without counting its reviews
|
|
35
|
+
* first. Four is invisible; the pager simply never renders.
|
|
36
|
+
*
|
|
19
37
|
* @tag domain:tester
|
|
20
38
|
* @tag layer:seed
|
|
21
39
|
* @tag pattern:none
|
|
@@ -26,9 +44,9 @@
|
|
|
26
44
|
export const authored = {
|
|
27
45
|
"checklist-buying-reviews-pagination-detail-tab-paginates": {
|
|
28
46
|
roles: ["guest"],
|
|
29
|
-
startPage: "/products/product-beyblade-
|
|
47
|
+
startPage: "/products/product-beyblade-original-dranzer-s",
|
|
30
48
|
steps: [
|
|
31
|
-
"Open /products/product-beyblade-
|
|
49
|
+
"Open /products/product-beyblade-original-dranzer-s in a private window.",
|
|
32
50
|
"Open the reviews tab and count the reviews shown.",
|
|
33
51
|
"Read the total review count stated on the page.",
|
|
34
52
|
"Look for a pagination control and read what it offers.",
|
|
@@ -41,9 +59,9 @@ export const authored = {
|
|
|
41
59
|
},
|
|
42
60
|
"checklist-buying-reviews-pagination-detail-tab-newest-first": {
|
|
43
61
|
roles: ["guest"],
|
|
44
|
-
startPage: "/products/product-beyblade-
|
|
62
|
+
startPage: "/products/product-beyblade-original-dranzer-s",
|
|
45
63
|
steps: [
|
|
46
|
-
"Open /products/product-beyblade-
|
|
64
|
+
"Open /products/product-beyblade-original-dranzer-s in a private window.",
|
|
47
65
|
"Open the reviews tab without changing any control.",
|
|
48
66
|
"Read the date on every review down the page.",
|
|
49
67
|
"Check the dates descend from top to bottom.",
|
|
@@ -56,9 +74,9 @@ export const authored = {
|
|
|
56
74
|
},
|
|
57
75
|
"checklist-buying-reviews-pagination-detail-tab-page-2-differs": {
|
|
58
76
|
roles: ["guest"],
|
|
59
|
-
startPage: "/products/product-beyblade-
|
|
77
|
+
startPage: "/products/product-beyblade-original-dranzer-s",
|
|
60
78
|
steps: [
|
|
61
|
-
"Open /products/product-beyblade-
|
|
79
|
+
"Open /products/product-beyblade-original-dranzer-s in a private window.",
|
|
62
80
|
"Open the reviews tab and write down every review title on page 1.",
|
|
63
81
|
"Click to page 2.",
|
|
64
82
|
"Write down every review title on page 2.",
|
|
@@ -72,9 +90,9 @@ export const authored = {
|
|
|
72
90
|
},
|
|
73
91
|
"checklist-buying-reviews-pagination-detail-tab-url-unchanged": {
|
|
74
92
|
roles: ["guest"],
|
|
75
|
-
startPage: "/products/product-beyblade-
|
|
93
|
+
startPage: "/products/product-beyblade-original-dranzer-s",
|
|
76
94
|
steps: [
|
|
77
|
-
"Open /products/product-beyblade-
|
|
95
|
+
"Open /products/product-beyblade-original-dranzer-s in a private window and read the URL.",
|
|
78
96
|
"Open the reviews tab and read the URL again.",
|
|
79
97
|
"Click to page 2 and read the URL.",
|
|
80
98
|
"Apply a rating filter and read the URL.",
|
|
@@ -86,9 +104,9 @@ export const authored = {
|
|
|
86
104
|
},
|
|
87
105
|
"checklist-buying-reviews-pagination-detail-tab-sort": {
|
|
88
106
|
roles: ["guest"],
|
|
89
|
-
startPage: "/products/product-beyblade-
|
|
107
|
+
startPage: "/products/product-beyblade-original-dranzer-s",
|
|
90
108
|
steps: [
|
|
91
|
-
"Open /products/product-beyblade-
|
|
109
|
+
"Open /products/product-beyblade-original-dranzer-s in a private window and open the reviews tab.",
|
|
92
110
|
"Read the sort control's options and write them down.",
|
|
93
111
|
"Write down the review titles in the default order.",
|
|
94
112
|
"Select each other sort option in turn, writing down the resulting order each time.",
|
|
@@ -102,9 +120,9 @@ export const authored = {
|
|
|
102
120
|
},
|
|
103
121
|
"checklist-buying-reviews-pagination-detail-tab-rating-filter": {
|
|
104
122
|
roles: ["guest"],
|
|
105
|
-
startPage: "/products/product-beyblade-
|
|
123
|
+
startPage: "/products/product-beyblade-original-dranzer-s",
|
|
106
124
|
steps: [
|
|
107
|
-
"Open /products/product-beyblade-
|
|
125
|
+
"Open /products/product-beyblade-original-dranzer-s in a private window and open the reviews tab.",
|
|
108
126
|
"Note the unfiltered review count.",
|
|
109
127
|
"Filter to 5-star reviews and read the count and every review's rating.",
|
|
110
128
|
"Filter to 1-star and read the count and ratings.",
|
|
@@ -118,9 +136,9 @@ export const authored = {
|
|
|
118
136
|
},
|
|
119
137
|
"checklist-buying-reviews-pagination-detail-tab-summary-stable": {
|
|
120
138
|
roles: ["guest"],
|
|
121
|
-
startPage: "/products/product-beyblade-
|
|
139
|
+
startPage: "/products/product-beyblade-original-dranzer-s",
|
|
122
140
|
steps: [
|
|
123
|
-
"Open /products/product-beyblade-
|
|
141
|
+
"Open /products/product-beyblade-original-dranzer-s in a private window and open the reviews tab.",
|
|
124
142
|
"Read the rating summary — the average, the total count and any per-star breakdown.",
|
|
125
143
|
"Filter to 5-star reviews and read the summary again.",
|
|
126
144
|
"Go to page 2 and read the summary again.",
|
|
@@ -134,9 +152,9 @@ export const authored = {
|
|
|
134
152
|
},
|
|
135
153
|
"checklist-buying-reviews-pagination-detail-tab-filters-all-work": {
|
|
136
154
|
roles: ["guest"],
|
|
137
|
-
startPage: "/products/product-beyblade-
|
|
155
|
+
startPage: "/products/product-beyblade-original-dranzer-s",
|
|
138
156
|
steps: [
|
|
139
|
-
"Open /products/product-beyblade-
|
|
157
|
+
"Open /products/product-beyblade-original-dranzer-s in a private window and open the reviews tab.",
|
|
140
158
|
"Read every filter control offered and write the list down.",
|
|
141
159
|
"Note the unfiltered count.",
|
|
142
160
|
"Apply each filter in turn and read the resulting count and rows.",
|
|
@@ -150,9 +168,9 @@ export const authored = {
|
|
|
150
168
|
},
|
|
151
169
|
"checklist-buying-reviews-pagination-date-range-sort-options": {
|
|
152
170
|
roles: ["guest"],
|
|
153
|
-
startPage: "/products/product-beyblade-
|
|
171
|
+
startPage: "/products/product-beyblade-original-dranzer-s",
|
|
154
172
|
steps: [
|
|
155
|
-
"Open /products/product-beyblade-
|
|
173
|
+
"Open /products/product-beyblade-original-dranzer-s in a private window and open the reviews tab.",
|
|
156
174
|
"Read whether a date-range filter is offered.",
|
|
157
175
|
"Set a range covering only the oldest reviews and read the count and dates.",
|
|
158
176
|
"Set a range covering only the newest and read the count and dates.",
|
|
@@ -26,7 +26,22 @@ export const authored = {
|
|
|
26
26
|
steps: [
|
|
27
27
|
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
28
28
|
"Open /user/orders and open a delivered order.",
|
|
29
|
-
|
|
29
|
+
/*
|
|
30
|
+
* 🛑 THIS CONTROL MAY NOT EXIST, AND THAT IS THE FINDING — not a reason
|
|
31
|
+
* to soften the case.
|
|
32
|
+
*
|
|
33
|
+
* Measured 2026-09-28: the write path exists server-side
|
|
34
|
+
* (createReviewAction, useCreateReview) and the labels exist
|
|
35
|
+
* (UI_TEXT.WRITE_REVIEW, twice), but NO .tsx consumes any of them. The
|
|
36
|
+
* only review modal is ViewReviewModal, which is read-only.
|
|
37
|
+
*
|
|
38
|
+
* So the expected outcome is a real 'no' with evidence, not a 'could not
|
|
39
|
+
* test'. The step says where to look and what its absence means, so the
|
|
40
|
+
* two verdicts cannot be confused — a tester who simply cannot find a
|
|
41
|
+
* button otherwise records "could not test", and a missing feature then
|
|
42
|
+
* reads as a coverage gap.
|
|
43
|
+
*/
|
|
44
|
+
"On the delivered order's item row, use the control that leaves a review — 'Write a review' or equivalent. If no such control exists anywhere on the order or on the product page, that is the answer: record it as a FAILURE with a screenshot of the order row, not as 'could not test'.",
|
|
30
45
|
"Submit with no rating and no text, and read where the errors appear.",
|
|
31
46
|
"Select 4 stars, type 'QA Review leave-review' as the title and 'Written by the tester checklist.' as the body, and attach public/test-media/sample-image.png.",
|
|
32
47
|
"Submit and RELOAD.",
|
|
@@ -58,15 +58,16 @@ export const authored = {
|
|
|
58
58
|
steps: [
|
|
59
59
|
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
60
60
|
"Resize the browser window to 390 pixels wide and open /user.",
|
|
61
|
-
"
|
|
62
|
-
"
|
|
61
|
+
"Open the sidebar using the header's hamburger icon.",
|
|
62
|
+
"Read its entries, and navigate somewhere.",
|
|
63
63
|
"Check whether it closed on navigation.",
|
|
64
|
-
"Count the fixed bars at the bottom of the screen.",
|
|
64
|
+
"Count the fixed bars at the bottom of the screen and read every one of its slots, including the last ('More').",
|
|
65
|
+
"Tap the bottom bar's 'More' slot and read what it opens.",
|
|
65
66
|
"Try to scroll the page sideways.",
|
|
66
67
|
],
|
|
67
68
|
inputs: { mobileWidth: 390 },
|
|
68
|
-
expectedBehaviour: "
|
|
69
|
-
expectedUiState: "The sidebar
|
|
69
|
+
expectedBehaviour: "BEFORE (fixed 2026-09-28): /user rendered a dashboard-specific bottom bar — up to 5 flattened sidebar links, text-only, no icons — while the public bottom bar was suppressed on this route. AFTER: the dashboard sidebar opens from the header hamburger, exactly as on every dashboard route, and closes after navigating. The bottom tab bar itself is now the SAME shared bar every public page uses (same items, same order, same icons) — not a dashboard-specific one — and its own 'More' slot opens the public site menu, not this sidebar. Exactly one bottom bar is mounted either way, since it is the sole publisher of its own height.",
|
|
70
|
+
expectedUiState: "The header hamburger opens the dashboard sidebar, collapsed by default, closing after navigation. The bottom bar matches the public site's bar item-for-item, and tapping its 'More' slot opens the public menu rather than the dashboard sidebar. The page does not scroll sideways.",
|
|
70
71
|
expectedData: { bottomNavCount: 1 },
|
|
71
72
|
endResult: "Read-only; restore the window width afterwards.",
|
|
72
73
|
},
|
|
@@ -154,7 +155,8 @@ export const authored = {
|
|
|
154
155
|
startPage: "/user",
|
|
155
156
|
steps: [
|
|
156
157
|
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
157
|
-
|
|
158
|
+
/* 'Logout' is the rendered label (AppLayoutShell's sidebarProfileLabels). */
|
|
159
|
+
"Open /user and find 'Logout' in the sidebar's Profile section.",
|
|
158
160
|
"Click it and read where the browser lands.",
|
|
159
161
|
"Open /user again and read what happens.",
|
|
160
162
|
"Press the browser back button and read what is shown.",
|
|
@@ -68,7 +68,22 @@ export const authored = {
|
|
|
68
68
|
startPage: "/user/addresses/add",
|
|
69
69
|
steps: [
|
|
70
70
|
SIGN_IN_BUYER,
|
|
71
|
+
/*
|
|
72
|
+
* 🛑 THIS URL REDIRECTS, AND THAT IS THE POINT OF TESTING IT.
|
|
73
|
+
*
|
|
74
|
+
* /user/addresses/add is a three-line legacy shim that redirects to
|
|
75
|
+
* /user/addresses/new — kept deliberately, because the old path has been
|
|
76
|
+
* live and may be bookmarked. The form this case then fills is the /new
|
|
77
|
+
* one.
|
|
78
|
+
*
|
|
79
|
+
* The step used to say only "check the form is already open", which
|
|
80
|
+
* passes whether the redirect works or the browser merely happens to land
|
|
81
|
+
* somewhere with a form. Reading the URL is what actually tests the shim,
|
|
82
|
+
* and it is the only thing this case covers that its sibling on /new
|
|
83
|
+
* does not.
|
|
84
|
+
*/
|
|
71
85
|
"Open /user/addresses/add directly by URL.",
|
|
86
|
+
"Read the address bar: it must now be /user/addresses/new — the old path is a legacy redirect, not a page of its own.",
|
|
72
87
|
"Check the form is already open.",
|
|
73
88
|
"Fill it with the name 'QA Address Probe', phone 9876543210, line 1 '221B Test Street', landmark 'Opposite the QA park', postal code 560001.",
|
|
74
89
|
"Save it.",
|
|
@@ -84,7 +99,7 @@ export const authored = {
|
|
|
84
99
|
postalCode: "560001",
|
|
85
100
|
},
|
|
86
101
|
expectedBehaviour: "Every field the form collects is written and read back — the landmark specifically, because a form missing a field the server accepts sends nothing for it on every edit and quietly drops whatever was there. Reopening the saved address for edit is the only way to see it.",
|
|
87
|
-
expectedUiState: "The address appears in the list, and reopening it for edit shows all five values including the landmark. A landmark that is blank on reopen is the finding.",
|
|
102
|
+
expectedUiState: "The address bar reads /user/addresses/new after the redirect, not /add. The address appears in the list, and reopening it for edit shows all five values including the landmark. A landmark that is blank on reopen is the finding.",
|
|
88
103
|
endResult: "The QA address is deleted.",
|
|
89
104
|
},
|
|
90
105
|
};
|
|
@@ -40,10 +40,11 @@ export const authored = {
|
|
|
40
40
|
startPage: "/profile/user-tyson-blader",
|
|
41
41
|
steps: [
|
|
42
42
|
"Open /profile/user-tyson-blader in a private window with no session.",
|
|
43
|
-
"Read the display name, avatar and bio.",
|
|
43
|
+
"Read the display name, avatar and bio. The name is 'Mock User 6' — every seeded persona is literally Mock User N, so that is the fixture rather than a placeholder bug, and the bio is real prose.",
|
|
44
44
|
"Open each tab on the profile.",
|
|
45
45
|
"Search the page source for an email address and for a phone number.",
|
|
46
|
-
"Open /profile/user-yugi-muto and read the same things.",
|
|
46
|
+
"Open /profile/user-yugi-muto and read the same things — display name 'Mock User 3', its own bio.",
|
|
47
|
+
"On BOTH profiles, check what is NOT shown. Each seeded publicProfile sets showEmail, showPhone, showOrders and showWishlist to FALSE, so none of those may appear anywhere on the page. Open View Source and search for the personas' email addresses (tyson@beybladearena.in, rehan.sheikh@gmail.com) and for the strings phoneNumber, orders and wishlist — a value hidden in the rendered page but present in the HTML is still published, which is the shape the store case on this page checks for.",
|
|
47
48
|
],
|
|
48
49
|
inputs: { sellerProfile: "user-tyson-blader", buyerProfile: "user-yugi-muto" },
|
|
49
50
|
expectedBehaviour: "A public profile shows what its owner chose to publish and nothing drawn from their account record. Email and phone are PII-encrypted at rest and have no business on this page in any form, masked or otherwise.",
|
|
@@ -59,13 +59,13 @@ export const authored = {
|
|
|
59
59
|
startPage: "/user/support",
|
|
60
60
|
steps: [
|
|
61
61
|
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
62
|
-
"Open /user/support and read the total number of rows.",
|
|
63
|
-
"Type 'QA Ticket' in the search box.",
|
|
62
|
+
"Open /user/support and read the total number of rows. This account owns FIVE seeded tickets spanning all five statuses — open, in progress, waiting on user, resolved and closed — so the status filter and the hide-toggle below both have real rows to act on, and the starting count is five plus whatever this run has created.",
|
|
63
|
+
"Type 'QA Ticket' in the search box. 🛑 That row exists only if create-ticket has already run in this batch — work these three in order. If it has not, search a word from a seeded subject instead and say which you used.",
|
|
64
64
|
"Read the rows.",
|
|
65
65
|
"Clear the box and type 'zzzznope'.",
|
|
66
66
|
"Read the rows.",
|
|
67
|
-
"Clear the box, then use the status filter to select
|
|
68
|
-
"Toggle 'Hide resolved/closed' and read the rows.",
|
|
67
|
+
"Clear the box, then use the status filter to select each status in turn and read the rows. All five have at least one seeded ticket, so a status returning nothing is a finding rather than an empty corner of the fixture.",
|
|
68
|
+
"Toggle 'Hide resolved/closed' and read the rows. The seed carries one resolved AND one closed ticket for this account, so the count must FALL by at least two — a toggle that changes nothing is the inert-control failure this step exists for.",
|
|
69
69
|
],
|
|
70
70
|
inputs: { matchingQuery: "QA Ticket", nonsenseQuery: "zzzznope" },
|
|
71
71
|
expectedBehaviour: "This list moved onto the shared listing scaffold, which supplies search over subject, id and category for free. The pre-existing status filter and the hide-resolved toggle have to keep working across that conversion — a migration that adds one affordance and quietly drops two is a net loss.",
|
|
@@ -65,8 +65,7 @@ export const authored = {
|
|
|
65
65
|
roles: ["guest"],
|
|
66
66
|
startPage: "/blog",
|
|
67
67
|
steps: [
|
|
68
|
-
"Open /blog in a private window
|
|
69
|
-
"Open that post.",
|
|
68
|
+
"Open /blog/selling-tips-letitrip in a private window — '10 Tips to Sell Faster on LetItRip' is the ONLY seeded post carrying a youtubeId, so searching the listing for a video indicator finds nothing and a tester would answer null on a path that works.",
|
|
70
69
|
"Scroll to the embedded video.",
|
|
71
70
|
"Click play and watch for a few seconds.",
|
|
72
71
|
"Read any error text shown in or near the player.",
|
|
@@ -90,4 +89,22 @@ export const authored = {
|
|
|
90
89
|
expectedData: { selfLinkCount: 0 },
|
|
91
90
|
endResult: "Read-only; nothing persists.",
|
|
92
91
|
},
|
|
92
|
+
"checklist-content-discovery-blog-blog-search-filters-the-list": {
|
|
93
|
+
roles: ["guest"],
|
|
94
|
+
startPage: "/blog",
|
|
95
|
+
steps: [
|
|
96
|
+
"Open /blog in a private window with no session and count the posts listed.",
|
|
97
|
+
"Type beyblade into the search box ('Search posts...') and commit the search.",
|
|
98
|
+
"Read the count and confirm it is SMALLER than the unfiltered count, and that every remaining card is relevant.",
|
|
99
|
+
"Clear the box, type zzzznope, and commit.",
|
|
100
|
+
"Read the result — an empty state, not the full list.",
|
|
101
|
+
"RELOAD the page while zzzznope is still in the URL and read the FIRST PAINT, before anything settles.",
|
|
102
|
+
"Clear the search and confirm the original count returns.",
|
|
103
|
+
],
|
|
104
|
+
inputs: { realQuery: "beyblade", nonsenseQuery: "zzzznope" },
|
|
105
|
+
expectedBehaviour: "The blog listing filters server-side and the filtered result survives a reload. The nonsense control is the whole case: a real term returns plausible cards whether or not the query reached the server, so only zzzznope distinguishes filtering from returning everything. The reload matters separately — the SSR view and the API are two implementations of one query, and when the view ignored `q` the client hook's initialData froze the UNFILTERED list permanently, because a public listing hook sets staleTime Infinity once it is given SSR data. A page that shows the right rows only after a moment is that bug, not a slow render.",
|
|
106
|
+
expectedUiState: "'beyblade' returns fewer cards than the unfiltered list. 'zzzznope' returns a named empty state and zero cards, on first paint as well as after hydration. Clearing restores the original count.",
|
|
107
|
+
expectedData: { nonsenseResultCount: 0 },
|
|
108
|
+
endResult: "Read-only; nothing persists beyond the URL. A full list under zzzznope is the failure, and it is the same shape whether the query never left the browser or the SSR view dropped it.",
|
|
109
|
+
},
|
|
93
110
|
};
|
package/dist/features/tester/seed-data/authored/content-discovery__category-brand-relations.js
CHANGED
|
@@ -105,10 +105,10 @@ export const authored = {
|
|
|
105
105
|
roles: ["guest"],
|
|
106
106
|
startPage: "/categories/category-spinning-tops",
|
|
107
107
|
steps: [
|
|
108
|
-
"Open /categories/category-spinning-tops and open its Stores tab.",
|
|
109
|
-
"Read every store listed.",
|
|
110
|
-
"Open
|
|
111
|
-
"Read the stores listed there.",
|
|
108
|
+
"Open /categories/category-spinning-tops — the ROOT — and open its Stores tab.",
|
|
109
|
+
"Read every store listed. Four stores carry a storeCategory: store-letitrip-official and store-beyblade-arena at this root, store-blader-bazaar under category-beyblade-burst, and store-vintage-vault-co under category-beyblade-original. All four should appear here, because a store carries a SINGLE category with no ancestor chain, so the root must expand descendants to find the deeper two — the half that once listed direct children only. Note store-blader-bazaar is pending and store-vintage-vault-co suspended, so check whether the tab filters by status before calling a missing one a rollup failure.",
|
|
110
|
+
"Open /categories/category-beyblade-burst — one level down, and the category store-blader-bazaar is filed under — and open ITS Stores tab.",
|
|
111
|
+
"Read the stores listed there. Only stores filed at or beneath that category belong; the two filed at the root do not.",
|
|
112
112
|
"Check every store from the deeper page also appears on the root's tab.",
|
|
113
113
|
],
|
|
114
114
|
inputs: { rootId: "category-spinning-tops" },
|
package/dist/features/tester/seed-data/authored/content-discovery__category-counts-and-rollup.js
CHANGED
|
@@ -45,7 +45,7 @@ export const authored = {
|
|
|
45
45
|
roles: ["guest"],
|
|
46
46
|
startPage: "/categories",
|
|
47
47
|
steps: [
|
|
48
|
-
"Open /categories/x-tops — a parent whose children
|
|
48
|
+
"Open /categories/category-x-tops — a parent whose children are category-x-starters and category-x-boosters — every category id carries the `category-` prefix, and a URL without it does not resolve.",
|
|
49
49
|
"Write down the count on the parent's tile.",
|
|
50
50
|
"Open the parent and write down the count shown on each of its child chips.",
|
|
51
51
|
"Add the children's counts together.",
|
|
@@ -60,7 +60,7 @@ export const authored = {
|
|
|
60
60
|
roles: ["guest"],
|
|
61
61
|
startPage: "/categories",
|
|
62
62
|
steps: [
|
|
63
|
-
"Open /categories/x-tops.",
|
|
63
|
+
"Open /categories/category-x-tops.",
|
|
64
64
|
"Open one of its CHILD categories and write down the title of a product listed there.",
|
|
65
65
|
"Go back to the parent category's own page.",
|
|
66
66
|
"Search the parent's listing for that same product, paging through if necessary.",
|
|
@@ -74,7 +74,7 @@ export const authored = {
|
|
|
74
74
|
roles: ["guest"],
|
|
75
75
|
startPage: "/categories",
|
|
76
76
|
steps: [
|
|
77
|
-
"Open a parent
|
|
77
|
+
"Open /categories/category-x-tops, a parent that shows a row of child chips — category-x-starters and category-x-boosters.",
|
|
78
78
|
"Write down the number in the page header.",
|
|
79
79
|
"Write down the number on each child chip.",
|
|
80
80
|
"Open one child and compare its own header number to the number its chip showed.",
|
|
@@ -88,7 +88,7 @@ export const authored = {
|
|
|
88
88
|
roles: ["guest"],
|
|
89
89
|
startPage: "/categories",
|
|
90
90
|
steps: [
|
|
91
|
-
"Open /categories/spinning-tops — a root category.",
|
|
91
|
+
"Open /categories/category-spinning-tops — a root category.",
|
|
92
92
|
"Write down its count.",
|
|
93
93
|
"Open it and write down the count on each of its direct children.",
|
|
94
94
|
"Open each child in turn and write down its children's counts, until you reach leaves.",
|
|
@@ -103,7 +103,7 @@ export const authored = {
|
|
|
103
103
|
roles: ["guest"],
|
|
104
104
|
startPage: "/categories",
|
|
105
105
|
steps: [
|
|
106
|
-
"Open /categories/x-tops, which has several children.",
|
|
106
|
+
"Open /categories/category-x-tops, which has several children.",
|
|
107
107
|
"Open the first child and write down a product title from its listing.",
|
|
108
108
|
"Open the second child's listing.",
|
|
109
109
|
"Search the second child for that product.",
|
|
@@ -24,7 +24,7 @@ export const authored = {
|
|
|
24
24
|
steps: [
|
|
25
25
|
"Sign in as vivaan.kapoor@gmail.com / TempPass123!.",
|
|
26
26
|
"Open /user/coupons and read what is listed.",
|
|
27
|
-
"Open /promotions, click the 'Coupons' tab, and claim NEWBLADER.",
|
|
27
|
+
"Open /promotions — it redirects to /promotions/deals, which is expected — then click the 'Coupons' tab, landing on /promotions/coupons, and claim NEWBLADER.",
|
|
28
28
|
"Open /user/coupons again.",
|
|
29
29
|
"Read the NEWBLADER row — its code, discount, minimum spend and expiry.",
|
|
30
30
|
"Reload the page.",
|
|
@@ -39,7 +39,7 @@ export const authored = {
|
|
|
39
39
|
startPage: "/promotions",
|
|
40
40
|
steps: [
|
|
41
41
|
"Sign in as vivaan.kapoor@gmail.com / TempPass123!.",
|
|
42
|
-
"Open /promotions
|
|
42
|
+
"Open /promotions — it redirects to /promotions/deals — then click the 'Coupons' tab and read the ARENA25 card's stated discount and minimum spend.",
|
|
43
43
|
"Add product-beyblade-burst-regalia-genesis (₹1,399, Beyblade Arena) to the cart.",
|
|
44
44
|
"Open /checkout and complete the address and add-ons steps.",
|
|
45
45
|
"Type ARENA25 in the coupon field and click 'Apply'.",
|
|
@@ -70,12 +70,33 @@ export const authored = {
|
|
|
70
70
|
"Add product-beyblade-burst-regalia-genesis (₹1,399) to the cart.",
|
|
71
71
|
"Open /checkout and complete the address and add-ons steps.",
|
|
72
72
|
"Type SEALED20 in the coupon field and click 'Apply'.",
|
|
73
|
+
/*
|
|
74
|
+
* 🛑 EXPECT THIS TO FAIL TODAY, AND RECORD IT AS A FAILURE.
|
|
75
|
+
*
|
|
76
|
+
* Measured 2026-09-29: the only rejection this path can produce is
|
|
77
|
+
* "Coupon is not currently valid" (coupons.repository.ts:241). It is
|
|
78
|
+
* returned by one branch gated on isCouponValid(), which folds THREE
|
|
79
|
+
* separate reasons into one string — isActive false, the date window,
|
|
80
|
+
* and the total usage limit being exhausted.
|
|
81
|
+
*
|
|
82
|
+
* So the buyer is told the same thing whether the coupon expired
|
|
83
|
+
* yesterday, was switched off, or was claimed by someone else thirty
|
|
84
|
+
* seconds ago. Only the first is permanent; the third may well work on a
|
|
85
|
+
* retry. The message cannot tell them which, and there is no second
|
|
86
|
+
* message to fall back to.
|
|
87
|
+
*
|
|
88
|
+
* Kept as written rather than softened to match. This case previously
|
|
89
|
+
* demanded the string 'This coupon has expired', which exists NOWHERE in
|
|
90
|
+
* the codebase — so the assertion could never be satisfied and never
|
|
91
|
+
* fail informatively either. Naming the real string is what makes the
|
|
92
|
+
* failure actionable.
|
|
93
|
+
*/
|
|
73
94
|
"Read the exact wording of the rejection.",
|
|
74
95
|
"Sign back in as admin@letitrip.in and restore the end date written down in step 2.",
|
|
75
96
|
],
|
|
76
97
|
inputs: { coupon: "SEALED20" },
|
|
77
98
|
expectedBehaviour: "An expired coupon is refused with a reason that names expiry specifically. With the end date in the past and isActive still true, this exercises the date check rather than the active flag — the two are separate reasons and a single generic message cannot tell a buyer which applies.",
|
|
78
|
-
expectedUiState: "The rejection names
|
|
99
|
+
expectedUiState: "The rejection names EXPIRY. Today it reads 'Coupon is not currently valid', which names nothing — record that as the failure, quoting it. SEALED20 must still be kept out of the applied list; a coupon that is refused and applied anyway would be a far worse finding than the wording.",
|
|
79
100
|
expectedData: { couponApplied: false },
|
|
80
101
|
endResult: "Reloading /checkout shows SEALED20 absent. The end date is restored by the final step — leaving it in the past silently breaks every later coupon case.",
|
|
81
102
|
},
|
|
@@ -84,14 +105,28 @@ export const authored = {
|
|
|
84
105
|
startPage: "/checkout",
|
|
85
106
|
steps: [
|
|
86
107
|
"Sign in as vivaan.kapoor@gmail.com / TempPass123!.",
|
|
87
|
-
"Add product-beyblade-
|
|
108
|
+
"Add product-beyblade-x-wizard-arrow (₹899 — the cheapest in-stock listing in the catalogue, and below ARENA25's ₹1,000 minimum) to the cart and nothing else.",
|
|
88
109
|
"Open /checkout and complete the address and add-ons steps.",
|
|
89
110
|
"Type ARENA25 in the coupon field and click 'Apply'.",
|
|
111
|
+
/*
|
|
112
|
+
* 🛑 THE SECOND HALF OF THIS EXPECTS TO FAIL TODAY.
|
|
113
|
+
*
|
|
114
|
+
* Measured 2026-09-29: the message is "Minimum purchase requirement not
|
|
115
|
+
* met" — the same literal from both producing branches, and no UI
|
|
116
|
+
* composes the threshold into it (zero .tsx read `minPurchase` outside
|
|
117
|
+
* the admin editor). So the buyer is told they are short without being
|
|
118
|
+
* told of what, on a cart they can see is ₹99 against a threshold they
|
|
119
|
+
* cannot see at all.
|
|
120
|
+
*
|
|
121
|
+
* The first half — that it names the minimum-purchase REASON rather than
|
|
122
|
+
* being a bare "Invalid coupon" — does hold, and is worth keeping
|
|
123
|
+
* separate: reason and amount are two assertions and only one fails.
|
|
124
|
+
*/
|
|
90
125
|
"Read the exact wording of the rejection and whether it names the required amount.",
|
|
91
126
|
],
|
|
92
|
-
inputs: { coupon: "ARENA25", cartSubtotal:
|
|
127
|
+
inputs: { coupon: "ARENA25", cartSubtotal: 899, minPurchase: 1000 },
|
|
93
128
|
expectedBehaviour: "A coupon below its minimum spend is refused with a message that names the threshold, so the buyer knows how much more to add. The minimum is measured against the items the coupon could actually discount, not the whole cart.",
|
|
94
|
-
expectedUiState: "The rejection names
|
|
129
|
+
expectedUiState: "The rejection names the minimum-purchase reason — today 'Minimum purchase requirement not met', which satisfies that half — and states the AMOUNT, which it does not. Record the missing amount as the failure, quoting the message. ARENA25 does not enter the applied list.",
|
|
95
130
|
expectedData: { couponApplied: false },
|
|
96
131
|
endResult: "Reloading /checkout shows ARENA25 absent.",
|
|
97
132
|
},
|
package/dist/features/tester/seed-data/authored/content-discovery__event-detail-subroutes.js
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
export const authored = {
|
|
23
23
|
"checklist-content-discovery-event-detail-subroutes-detail-tabs-match-event-type": {
|
|
24
24
|
roles: ["guest"],
|
|
25
|
-
startPage: "/events",
|
|
25
|
+
startPage: "/events/event-favourite-blader-poll",
|
|
26
26
|
steps: [
|
|
27
27
|
"Open /events/event-favourite-blader-poll — a poll.",
|
|
28
28
|
"Write down every tab shown.",
|
|
@@ -43,7 +43,7 @@ export const authored = {
|
|
|
43
43
|
},
|
|
44
44
|
"checklist-content-discovery-event-detail-subroutes-participate-records-an-entry": {
|
|
45
45
|
roles: ["buyer"],
|
|
46
|
-
startPage: "/events",
|
|
46
|
+
startPage: "/events/event-favourite-blader-poll",
|
|
47
47
|
steps: [
|
|
48
48
|
"Sign in as the buyer rehan.sheikh@gmail.com / TempPass123!.",
|
|
49
49
|
"Open /events/event-favourite-blader-poll.",
|
|
@@ -60,13 +60,13 @@ export const authored = {
|
|
|
60
60
|
},
|
|
61
61
|
"checklist-content-discovery-event-detail-subroutes-participate-twice-is-refused": {
|
|
62
62
|
roles: ["buyer"],
|
|
63
|
-
startPage: "/events",
|
|
63
|
+
startPage: "/events/event-favourite-blader-poll",
|
|
64
64
|
steps: [
|
|
65
65
|
"Sign in as the buyer rehan.sheikh@gmail.com / TempPass123! and open /events/event-favourite-blader-poll.",
|
|
66
66
|
"Participate once if you have not already.",
|
|
67
67
|
"Reload, and try to participate a second time with a different option.",
|
|
68
68
|
"Read what happens.",
|
|
69
|
-
"Open
|
|
69
|
+
"Open /events/event-favourite-blader-poll, then its Leaderboard tab, and read the total entry count. This case reads the state the previous one left behind, so run them in order — but it still has to start somewhere, and the index is not it.",
|
|
70
70
|
],
|
|
71
71
|
inputs: { eventId: "event-favourite-blader-poll" },
|
|
72
72
|
expectedBehaviour: "A second entry from the same account is refused with a reason. Silently accepting it doubles that account's weight in the result, which is invisible until somebody reconciles the entry count against the participant count.",
|
|
@@ -76,7 +76,7 @@ export const authored = {
|
|
|
76
76
|
},
|
|
77
77
|
"checklist-content-discovery-event-detail-subroutes-leaderboard-ranks-by-a-real-number": {
|
|
78
78
|
roles: ["guest"],
|
|
79
|
-
startPage: "/events",
|
|
79
|
+
startPage: "/events/event-favourite-blader-poll/leaderboard",
|
|
80
80
|
steps: [
|
|
81
81
|
"Open /events/event-favourite-blader-poll and open its Leaderboard tab.",
|
|
82
82
|
"Read the number beside each of the first five rows — the vote or score the row is ranked on.",
|
|
@@ -92,7 +92,7 @@ export const authored = {
|
|
|
92
92
|
},
|
|
93
93
|
"checklist-content-discovery-event-detail-subroutes-winner-page-before-draw": {
|
|
94
94
|
roles: ["guest"],
|
|
95
|
-
startPage: "/events",
|
|
95
|
+
startPage: "/events/event-win-burst-regalia-genesis/winner",
|
|
96
96
|
steps: [
|
|
97
97
|
"Open /events/event-win-burst-regalia-genesis — an ACTIVE raffle that has not been drawn.",
|
|
98
98
|
"Open its Winner tab.",
|
|
@@ -106,7 +106,7 @@ export const authored = {
|
|
|
106
106
|
},
|
|
107
107
|
"checklist-content-discovery-event-detail-subroutes-winner-page-after-draw": {
|
|
108
108
|
roles: ["guest"],
|
|
109
|
-
startPage: "/events",
|
|
109
|
+
startPage: "/events/event-won-original-set-raffle/winner",
|
|
110
110
|
steps: [
|
|
111
111
|
"Open /events/event-won-original-set-raffle — an ENDED raffle with a recorded winner.",
|
|
112
112
|
"Open its Winner tab.",
|
|
@@ -121,7 +121,7 @@ export const authored = {
|
|
|
121
121
|
},
|
|
122
122
|
"checklist-content-discovery-event-detail-subroutes-cancelled-event-refuses-participation": {
|
|
123
123
|
roles: ["buyer"],
|
|
124
|
-
startPage: "/events",
|
|
124
|
+
startPage: "/events/event-x-launch-raffle-cancelled",
|
|
125
125
|
steps: [
|
|
126
126
|
"Sign in as the buyer rehan.sheikh@gmail.com / TempPass123!.",
|
|
127
127
|
"Open /events/event-x-launch-raffle-cancelled — a CANCELLED raffle.",
|
|
@@ -151,4 +151,59 @@ export const authored = {
|
|
|
151
151
|
expectedData: { eventContentReadableByGuest: true },
|
|
152
152
|
endResult: "No entry is recorded and no session is created.",
|
|
153
153
|
},
|
|
154
|
+
/*
|
|
155
|
+
* 🛑 SPLIT IN TWO, 2026-09-29, after this case failed for a reason that was
|
|
156
|
+
* not a bug in the code it was testing.
|
|
157
|
+
*
|
|
158
|
+
* It asserted that /events/{id}/spin-results lists "this account's own spins".
|
|
159
|
+
* The route was a PUBLIC feed — `getSpinResultsCached(id)` took only the event
|
|
160
|
+
* id and returned the ten most recent spins across all users — so read by a
|
|
161
|
+
* buyer who had never spun it listed three strangers' prizes and showed no
|
|
162
|
+
* empty state, because from the feed's point of view nothing was empty.
|
|
163
|
+
*
|
|
164
|
+
* Both readings turned out to be wanted, so the page now has two sections and
|
|
165
|
+
* there are two cases. Rewriting the single case to assert whatever the code
|
|
166
|
+
* already did would have made it a tautology; deleting the account-scoped
|
|
167
|
+
* claim would have thrown away the one a human actually cared about.
|
|
168
|
+
*/
|
|
169
|
+
"checklist-content-discovery-event-detail-subroutes-spin-results-subroute": {
|
|
170
|
+
roles: ["buyer"],
|
|
171
|
+
startPage: "/events/event-daily-beyblade-pull-wheel/spin-results",
|
|
172
|
+
steps: [
|
|
173
|
+
"Sign in as the buyer rehan.sheikh@gmail.com / TempPass123!.",
|
|
174
|
+
"Open /events/event-daily-beyblade-pull-wheel — a SPIN_WHEEL event, active, with real spinPrizes and spinMaxPerUser of 2.",
|
|
175
|
+
"Read which tabs the detail page offers and check a results tab is among them.",
|
|
176
|
+
"Open /events/event-daily-beyblade-pull-wheel/spin-results directly by URL.",
|
|
177
|
+
"Find the 'Last 10 Spin Results' section — the PUBLIC feed of everyone's recent spins, which is a different section from 'Your Spins'.",
|
|
178
|
+
"Read the participant name on each row.",
|
|
179
|
+
],
|
|
180
|
+
inputs: {
|
|
181
|
+
eventId: "event-daily-beyblade-pull-wheel",
|
|
182
|
+
},
|
|
183
|
+
expectedBehaviour: "The public feed lists recent spins by ANY participant, and every display name is masked. This is a public page on a public event, so a real winner's full name must not be published beside the prize they won — the same rule that applies to bidder names on public bid history.",
|
|
184
|
+
expectedUiState: "A 'Last 10 Spin Results' heading over rows of participant, prize and relative time. Every signed-in participant's name is masked to initials in the 'R*** K***' shape; a guest row reads 'Guest'. No row shows a full first and last name.",
|
|
185
|
+
expectedData: { fullNamesVisibleInPublicFeed: 0 },
|
|
186
|
+
endResult: "Read-only. Nothing is spun and nothing is written.",
|
|
187
|
+
},
|
|
188
|
+
"checklist-content-discovery-event-detail-subroutes-my-spins-scoped-to-viewer": {
|
|
189
|
+
roles: ["buyer"],
|
|
190
|
+
startPage: "/events/event-daily-beyblade-pull-wheel/spin-results",
|
|
191
|
+
steps: [
|
|
192
|
+
"Sign in as the buyer rehan.sheikh@gmail.com / TempPass123!.",
|
|
193
|
+
"Open /events/event-daily-beyblade-pull-wheel/spin-results.",
|
|
194
|
+
"Find the 'Your Spins' section — it sits ABOVE the public 'Last 10 Spin Results' feed.",
|
|
195
|
+
"Before spinning, read what it shows. It must name YOUR state, not the event's: 'You have not spun on this event yet.' Reading 'No spins yet' here would be the bug this case exists for, because the public feed below is not empty.",
|
|
196
|
+
"Go back to the event, spin once, and read the prize awarded.",
|
|
197
|
+
"Return to spin-results and check 'Your Spins' lists exactly that one spin with that prize.",
|
|
198
|
+
"Confirm no other participant's row appears inside 'Your Spins' — the strangers visible in the feed below must not be in your own section.",
|
|
199
|
+
],
|
|
200
|
+
inputs: {
|
|
201
|
+
eventId: "event-daily-beyblade-pull-wheel",
|
|
202
|
+
spinMaxPerUser: 2,
|
|
203
|
+
},
|
|
204
|
+
expectedBehaviour: "'Your Spins' is scoped to the signed-in caller and answers what did I win. Its empty state is about the viewer, so someone who has never spun is told so plainly rather than being shown other people's prizes with nothing to distinguish them.",
|
|
205
|
+
expectedUiState: "Before spinning: a 'Your Spins' heading over the text 'You have not spun on this event yet.' After one spin: exactly one row naming the prize just awarded and its relative time, and no participant names at all — every row in this section is yours by construction.",
|
|
206
|
+
expectedData: { mySpinRowsBeforeSpinning: 0, mySpinRowsAfterOneSpin: 1 },
|
|
207
|
+
endResult: "One spin is recorded against this account and 'Your Spins' still shows it after a reload. Signed out, the section reads 'Sign in to see your own spins and the prizes you have won.' rather than showing anyone else's.",
|
|
208
|
+
},
|
|
154
209
|
};
|