@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
|
@@ -23,10 +23,10 @@ const SIGN_IN_BUYER = "Sign in as rehan.sheikh@gmail.com / TempPass123!.";
|
|
|
23
23
|
export const authored = {
|
|
24
24
|
"checklist-content-discovery-event-participation-join-event-as-participant": {
|
|
25
25
|
roles: ["buyer"],
|
|
26
|
-
startPage: "/events",
|
|
26
|
+
startPage: "/events/event-favourite-blader-poll",
|
|
27
27
|
steps: [
|
|
28
28
|
SIGN_IN_BUYER,
|
|
29
|
-
"Open /events
|
|
29
|
+
"Open /events/event-favourite-blader-poll — an ACTIVE poll with 3 seeded entries. 🛑 THE NEXT FOUR CASES READ THE ENTRY THIS ONE CREATES, so they must all use this same event; picking a different active event each time breaks the chain and each case then tests a state nobody set up.",
|
|
30
30
|
"Open it and find the control for joining.",
|
|
31
31
|
"Use it.",
|
|
32
32
|
"Read the outcome shown.",
|
|
@@ -38,7 +38,7 @@ export const authored = {
|
|
|
38
38
|
},
|
|
39
39
|
"checklist-content-discovery-event-participation-own-entry-visible-after-join": {
|
|
40
40
|
roles: ["buyer"],
|
|
41
|
-
startPage: "/events",
|
|
41
|
+
startPage: "/events/event-favourite-blader-poll",
|
|
42
42
|
steps: [
|
|
43
43
|
SIGN_IN_BUYER,
|
|
44
44
|
"Join an active event.",
|
|
@@ -53,13 +53,13 @@ export const authored = {
|
|
|
53
53
|
},
|
|
54
54
|
"checklist-content-discovery-event-participation-entry-survives-reload-and-relogin": {
|
|
55
55
|
roles: ["buyer"],
|
|
56
|
-
startPage: "/events",
|
|
56
|
+
startPage: "/events/event-favourite-blader-poll",
|
|
57
57
|
steps: [
|
|
58
58
|
SIGN_IN_BUYER,
|
|
59
59
|
"Join an active event and note the entry's status.",
|
|
60
60
|
"Reload the event page and read the entry again.",
|
|
61
61
|
"Sign out and sign back in as the same account.",
|
|
62
|
-
"Open
|
|
62
|
+
"Open /events/event-favourite-blader-poll and read the entry this account created.",
|
|
63
63
|
"Open the event in a different browser signed in as the same account.",
|
|
64
64
|
],
|
|
65
65
|
expectedBehaviour: "The entry is a stored record keyed to the account, so it survives a reload, a sign-out and a different device. An entry held only in the browser disappears the moment the participant switches devices, which is exactly when they check whether they got in.",
|
|
@@ -68,13 +68,13 @@ export const authored = {
|
|
|
68
68
|
},
|
|
69
69
|
"checklist-content-discovery-event-participation-cannot-join-twice": {
|
|
70
70
|
roles: ["buyer"],
|
|
71
|
-
startPage: "/events",
|
|
71
|
+
startPage: "/events/event-favourite-blader-poll",
|
|
72
72
|
steps: [
|
|
73
73
|
SIGN_IN_BUYER,
|
|
74
74
|
"Join an active event.",
|
|
75
75
|
"Attempt to join the same event again from the page.",
|
|
76
76
|
"Read what happens.",
|
|
77
|
-
"Open
|
|
77
|
+
"Open /events/event-favourite-blader-poll in a second tab and attempt to join from there as well.",
|
|
78
78
|
"Check the account has exactly one entry.",
|
|
79
79
|
],
|
|
80
80
|
expectedBehaviour: "A second join is refused rather than creating a duplicate. Two entries for one account inflate the entry count, double the account's odds in any draw, and are indistinguishable from two different people once the names are masked.",
|
|
@@ -84,11 +84,11 @@ export const authored = {
|
|
|
84
84
|
},
|
|
85
85
|
"checklist-content-discovery-event-participation-leave-or-cancel-entry": {
|
|
86
86
|
roles: ["buyer"],
|
|
87
|
-
startPage: "/events",
|
|
87
|
+
startPage: "/events/event-favourite-blader-poll",
|
|
88
88
|
steps: [
|
|
89
89
|
SIGN_IN_BUYER,
|
|
90
90
|
"Join an active event.",
|
|
91
|
-
"
|
|
91
|
+
"On /events/event-favourite-blader-poll, find the control for withdrawing and use it.",
|
|
92
92
|
"Read the confirmation, if one is shown.",
|
|
93
93
|
"Read the entry's state afterwards.",
|
|
94
94
|
"Reload and read it again.",
|
|
@@ -100,10 +100,10 @@ export const authored = {
|
|
|
100
100
|
},
|
|
101
101
|
"checklist-content-discovery-event-participation-closed-event-cannot-be-joined": {
|
|
102
102
|
roles: ["buyer"],
|
|
103
|
-
startPage: "/events",
|
|
103
|
+
startPage: "/events/event-won-original-set-raffle",
|
|
104
104
|
steps: [
|
|
105
105
|
SIGN_IN_BUYER,
|
|
106
|
-
"Open /events
|
|
106
|
+
"Open /events/event-won-original-set-raffle — an ENDED raffle, which is the seed's only ended event.",
|
|
107
107
|
"Open it and read whether a join control is offered.",
|
|
108
108
|
"If one is offered, use it and read what happens.",
|
|
109
109
|
"Repeat with an event whose status is cancelled.",
|
|
@@ -115,10 +115,10 @@ export const authored = {
|
|
|
115
115
|
},
|
|
116
116
|
"checklist-content-discovery-event-participation-leaderboard-shows-real-participants": {
|
|
117
117
|
roles: ["buyer"],
|
|
118
|
-
startPage: "/events",
|
|
118
|
+
startPage: "/events/event-favourite-blader-poll/leaderboard",
|
|
119
119
|
steps: [
|
|
120
120
|
SIGN_IN_BUYER,
|
|
121
|
-
"Open
|
|
121
|
+
"Open /events/event-favourite-blader-poll and open its Leaderboard tab — it carries 3 seeded entries, so the board is not empty.",
|
|
122
122
|
"Read the rows — the names and the scores.",
|
|
123
123
|
"Check the names are masked rather than showing full identities.",
|
|
124
124
|
"Check the scores are real numbers rather than zeros or placeholders.",
|
|
@@ -130,11 +130,11 @@ export const authored = {
|
|
|
130
130
|
},
|
|
131
131
|
"checklist-content-discovery-event-participation-leaderboard-own-row-findable": {
|
|
132
132
|
roles: ["buyer"],
|
|
133
|
-
startPage: "/events",
|
|
133
|
+
startPage: "/events/event-favourite-blader-poll/leaderboard",
|
|
134
134
|
steps: [
|
|
135
135
|
SIGN_IN_BUYER,
|
|
136
136
|
"Join an event that has a leaderboard and take part enough to appear on it.",
|
|
137
|
-
"Open
|
|
137
|
+
"Open /events/event-favourite-blader-poll and its Leaderboard tab.",
|
|
138
138
|
"Look for the participant's own row without scrolling the whole list.",
|
|
139
139
|
"Check it is highlighted, pinned, or otherwise findable.",
|
|
140
140
|
"Read the position shown for it.",
|
|
@@ -145,10 +145,10 @@ export const authored = {
|
|
|
145
145
|
},
|
|
146
146
|
"checklist-content-discovery-event-participation-leaderboard-ordering-correct": {
|
|
147
147
|
roles: ["buyer"],
|
|
148
|
-
startPage: "/events",
|
|
148
|
+
startPage: "/events/event-favourite-blader-poll/leaderboard",
|
|
149
149
|
steps: [
|
|
150
150
|
SIGN_IN_BUYER,
|
|
151
|
-
"Open
|
|
151
|
+
"Open /events/event-favourite-blader-poll and its Leaderboard tab, and write down every row in order with its score — the seed has 3 entries, so read all of them rather than expecting ten.",
|
|
152
152
|
"Check each score is not greater than the one above it.",
|
|
153
153
|
"Find two rows with equal scores and note their order.",
|
|
154
154
|
"Reload the page and read the first ten again.",
|
|
@@ -160,10 +160,10 @@ export const authored = {
|
|
|
160
160
|
},
|
|
161
161
|
"checklist-content-discovery-event-participation-leaderboard-empty-state": {
|
|
162
162
|
roles: ["buyer"],
|
|
163
|
-
startPage: "/events",
|
|
163
|
+
startPage: "/events/event-beyblade-slot-raffle-draft",
|
|
164
164
|
steps: [
|
|
165
165
|
SIGN_IN_BUYER,
|
|
166
|
-
"Open /events
|
|
166
|
+
"Open /events/event-beyblade-slot-raffle-draft — a DRAFT raffle with no seeded entries, which is what makes the empty state reachable.",
|
|
167
167
|
"Open its leaderboard.",
|
|
168
168
|
"Read what is shown.",
|
|
169
169
|
"Check it states there are no entries rather than showing a blank panel.",
|
|
@@ -175,12 +175,12 @@ export const authored = {
|
|
|
175
175
|
},
|
|
176
176
|
"checklist-content-discovery-event-participation-raffle-winner-announced-to-participants": {
|
|
177
177
|
roles: ["admin", "buyer"],
|
|
178
|
-
startPage: "/events",
|
|
178
|
+
startPage: "/events/event-won-original-set-raffle",
|
|
179
179
|
steps: [
|
|
180
180
|
"Sign in as admin@letitrip.in / TempPass123! and open an event with a raffle configured.",
|
|
181
181
|
"Draw the raffle and note who won.",
|
|
182
182
|
"Sign in as the winning participant.",
|
|
183
|
-
"Open
|
|
183
|
+
"Open /events/event-won-original-set-raffle — ENDED and carrying a recorded raffleWinnerUserId — and read whether the result is announced.",
|
|
184
184
|
"Open the account's notifications and look for one about the win.",
|
|
185
185
|
"Sign in as a non-winning participant and check the result is visible to them too.",
|
|
186
186
|
],
|
|
@@ -190,18 +190,18 @@ export const authored = {
|
|
|
190
190
|
},
|
|
191
191
|
"checklist-content-discovery-event-participation-spin-wheel-one-use-enforced": {
|
|
192
192
|
roles: ["buyer"],
|
|
193
|
-
startPage: "/events",
|
|
193
|
+
startPage: "/events/event-daily-beyblade-pull-wheel",
|
|
194
194
|
steps: [
|
|
195
195
|
SIGN_IN_BUYER,
|
|
196
|
-
"Open /events
|
|
196
|
+
"Open /events/event-daily-beyblade-pull-wheel — the seed's only SPIN_WHEEL event, active, with real spinPrizes and spinMaxPerUser of 2. Note the cap is TWO, not one: a case asserting a single use would fail on a correct system.",
|
|
197
197
|
"Take a spin and read the result.",
|
|
198
|
-
"
|
|
199
|
-
"
|
|
200
|
-
"Reload the page and attempt once more.",
|
|
198
|
+
"Spin a SECOND time — this one is allowed, because spinMaxPerUser is 2.",
|
|
199
|
+
"Attempt a THIRD spin and read what happens.",
|
|
200
|
+
"Reload the page and attempt a third spin once more.",
|
|
201
201
|
"If a prize was won, follow whatever the interface offers for claiming it.",
|
|
202
202
|
],
|
|
203
|
-
expectedBehaviour: "The per-user spin limit is enforced server-side and survives a reload
|
|
204
|
-
expectedUiState: "The
|
|
205
|
-
endResult: "
|
|
203
|
+
expectedBehaviour: "The per-user spin limit is TWO, enforced server-side, and it survives a reload; a won prize is claimable. A limit held only in the browser is defeated by refreshing — which is the first thing anyone does after a disappointing spin.",
|
|
204
|
+
expectedUiState: "The first two spins succeed and the THIRD is refused, before and after the reload, with a message naming the limit; a won prize can actually be claimed. A refusal on the second spin is a failure in the other direction — the cap is 2 — and a third spin that works after a reload is the finding.",
|
|
205
|
+
endResult: "Both spins are used; claim any prize won. The key still reads one-use-enforced and is deliberately unchanged — a case id is the response document id, so renaming it orphans every verdict recorded against it.",
|
|
206
206
|
},
|
|
207
207
|
};
|
|
@@ -54,7 +54,7 @@ export const authored = {
|
|
|
54
54
|
steps: [
|
|
55
55
|
"Open /events in a private window and find event-pokemon-number-draw-july-2026.",
|
|
56
56
|
"Look at its card image.",
|
|
57
|
-
"Open the lottery
|
|
57
|
+
"Open /lottery/event-pokemon-number-draw-july-2026 — the lottery detail route is /lottery/{id}, not /events/{id}.",
|
|
58
58
|
"Look at the image at the top of that page.",
|
|
59
59
|
"Note whether either shows an emoji instead of a photograph.",
|
|
60
60
|
],
|
|
@@ -229,7 +229,7 @@ export const authored = {
|
|
|
229
229
|
steps: [
|
|
230
230
|
"Sign in as admin@letitrip.in / TempPass123!.",
|
|
231
231
|
"Open /admin/events, open event-win-burst-regalia-genesis for editing, and write down its current raffle type.",
|
|
232
|
-
"Set the raffle type to 'Top N participants'
|
|
232
|
+
"Set the raffle type to 'Top N earliest participants' — the dropdown carries the word 'earliest' and the stored value is top_n_participants — set the N to 3, and save.",
|
|
233
233
|
"Sign out and sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
234
234
|
"Open /events/event-win-burst-regalia-genesis and read the Overview tab's description of how winners are chosen.",
|
|
235
235
|
"Click the Participate tab and enter.",
|
|
@@ -35,8 +35,9 @@ export const authored = {
|
|
|
35
35
|
steps: [
|
|
36
36
|
"Resize the browser window to 390 pixels wide.",
|
|
37
37
|
"Open /faqs in a private window with no session.",
|
|
38
|
+
"WAIT for the page to settle before reading any number. This page has been measured showing zero questions at 2.5 seconds and 62 at 6 — a count taken early is confidently wrong, and this case is entirely about comparing counts.",
|
|
38
39
|
"Read the count shown against each category.",
|
|
39
|
-
"Open one category and count the questions it actually holds.",
|
|
40
|
+
"Open one category and count the questions it actually holds, waiting again before counting.",
|
|
40
41
|
"Compare the two numbers.",
|
|
41
42
|
"Try to scroll the page sideways.",
|
|
42
43
|
],
|
|
@@ -62,4 +63,25 @@ export const authored = {
|
|
|
62
63
|
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
64
|
endResult: "Read-only; nothing persists. Restore the window width afterwards.",
|
|
64
65
|
},
|
|
66
|
+
"checklist-content-discovery-faq-help-faq-search-filters-and-survives-reload": {
|
|
67
|
+
roles: ["guest"],
|
|
68
|
+
startPage: "/faqs",
|
|
69
|
+
steps: [
|
|
70
|
+
"Open /faqs in a private window with no session.",
|
|
71
|
+
"WAIT for the questions to appear before counting anything. 🛑 This page hydrates client-side and the difference is not subtle — it has been measured showing zero questions at 2.5 seconds and 62 at 6. A count taken early produces a confident, wrong answer, and that has already happened twice on this exact page.",
|
|
72
|
+
"Count the questions visible across all categories once the page has settled.",
|
|
73
|
+
"Type shipping into the search box and commit it.",
|
|
74
|
+
"Read the count and confirm it is SMALLER than the unfiltered count, and that the remaining questions are about shipping.",
|
|
75
|
+
"Read the address bar and check the term is in the URL as ?q=shipping.",
|
|
76
|
+
"RELOAD with that URL and confirm the same filtered set comes back, waiting again before judging.",
|
|
77
|
+
"Clear the box, type zzzznope, and commit.",
|
|
78
|
+
"Read the result — a named empty state and zero questions, not the full list.",
|
|
79
|
+
"Clear the search and confirm the original count returns.",
|
|
80
|
+
],
|
|
81
|
+
inputs: { realQuery: "shipping", nonsenseQuery: "zzzznope" },
|
|
82
|
+
expectedBehaviour: "The search box filters the questions and the term round-trips through the URL, so a filtered view is shareable and survives a reload. The nonsense control is the whole case: a real term returns plausible questions whether or not the filter ran at all, so only zzzznope separates filtering from returning everything. The seed ships 63 FAQs across seven categories, which is enough for a real term to narrow visibly rather than by one row.",
|
|
83
|
+
expectedUiState: "'shipping' shows fewer questions than the unfiltered list and they are about shipping. The URL carries ?q=shipping and reloading reproduces that view. 'zzzznope' shows a named empty state with zero questions — a blank panel with no message is a different failure and should be recorded as such. Clearing restores the original count.",
|
|
84
|
+
expectedData: { nonsenseResultCount: 0 },
|
|
85
|
+
endResult: "Read-only; nothing persists beyond the URL. A full list under zzzznope is the failure. So is an empty page under a real term, which on this page is far more likely to be a count taken before hydration than a broken filter — wait, then look again, before recording either.",
|
|
86
|
+
},
|
|
65
87
|
};
|
|
@@ -99,12 +99,12 @@ export const authored = {
|
|
|
99
99
|
roles: ["buyer"],
|
|
100
100
|
startPage: "/user/settings",
|
|
101
101
|
steps: [
|
|
102
|
-
"Sign in as
|
|
103
|
-
"Open /user/settings, click the 'Notifications' tab, and make sure Email is on for order updates.",
|
|
102
|
+
"Sign in as the harness mailbox account. 🛑 NO SEEDED PERSONA CAN RECEIVE TESTABLE EMAIL — both instruments key on TESTER_EMAIL_ID, and every seeded persona uses a real-looking address the harness does not own. Register a plus-addressed signup on that mailbox, or run this as whichever account already uses it.",
|
|
103
|
+
"Open /user/settings, click the 'Notifications' tab, and make sure Email is on for order updates. order_confirmed is one of the 18 email-eligible types, so it should send.",
|
|
104
104
|
"Place an order that will produce an order-confirmed notification.",
|
|
105
105
|
"Open /user/notifications and confirm the in-app entry is there.",
|
|
106
|
-
"
|
|
107
|
-
"Read the email's From name and address, its subject and its body.",
|
|
106
|
+
"Capture a timestamp BEFORE the order — node -e \"console.log(Date.now())\" — then ask the mailbox: node tester/scripts/check-inbox.mjs --since <that number> --subject \"order\". --since is the whole correctness argument: the mailbox is shared across every case in every run, so 'newest matching message' happily returns one an earlier case left behind.",
|
|
107
|
+
"Read the exit code. 0 means it arrived; 1 means it did not (a product defect); 2 means the mailbox could not be opened (a harness problem, answer null). Then read the email's From name and address, its subject and its body.",
|
|
108
108
|
"Click the button or link inside it.",
|
|
109
109
|
],
|
|
110
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.",
|
|
@@ -115,12 +115,12 @@ export const authored = {
|
|
|
115
115
|
roles: ["buyer"],
|
|
116
116
|
startPage: "/user/settings",
|
|
117
117
|
steps: [
|
|
118
|
-
"Sign in as
|
|
118
|
+
"Sign in as the harness mailbox account — see the arrival case above; no seeded persona can receive testable email.",
|
|
119
119
|
"Open /user/settings, click the 'Notifications' tab, and turn Email OFF for order updates.",
|
|
120
120
|
"Click 'Save preferences' and reload to confirm it stayed off.",
|
|
121
121
|
"Place an order that would produce an order-confirmed notification.",
|
|
122
122
|
"Open /user/notifications and read the entries.",
|
|
123
|
-
"
|
|
123
|
+
"Prove the SILENCE rather than waiting for it: node tester/scripts/check-inbox.mjs --since <timestamp captured before the order> --subject \"order\" --expect-none. Without --expect-none, 'nothing arrived' is unprovable — you wait and hope, and a slow inbox looks exactly like a working suppression. Exit 0 means the silence held.",
|
|
124
124
|
"Turn Email back on for order updates and save.",
|
|
125
125
|
],
|
|
126
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.",
|
|
@@ -312,7 +312,7 @@ export const authored = {
|
|
|
312
312
|
startPage: "/admin/team",
|
|
313
313
|
steps: [
|
|
314
314
|
"Sign in as admin@letitrip.in / TempPass123!.",
|
|
315
|
-
"Open
|
|
315
|
+
"Open these four admin listings in turn and look at each toolbar: /admin/products, /admin/orders, /admin/team, /admin/reviews. Naming them matters — two testers picking different pages cannot compare results, and a gap that appears on only one listing is the finding.",
|
|
316
316
|
"Note any toolbar with a visible empty gap where a control would sit.",
|
|
317
317
|
"Resize to 390 pixels wide and look at the same toolbars.",
|
|
318
318
|
],
|
package/dist/features/tester/seed-data/authored/content-discovery__store-reviews-aggregate.js
CHANGED
|
@@ -64,7 +64,7 @@ export const authored = {
|
|
|
64
64
|
"Search that body for the text enc:v1 and for the field names userNameIndex, searchTxt and userId.",
|
|
65
65
|
],
|
|
66
66
|
expectedBehaviour: "A reviewer's name is PII, stored encrypted, and shown masked in public. The generic repository returns the document verbatim, so a route that does not go through the reviews repository serves ciphertext — and a payload built by spreading the document also carries the HMAC blind index, which lets a caller confirm a guessed name.",
|
|
67
|
-
expectedUiState: "Names render masked,
|
|
67
|
+
expectedUiState: "Names render masked. maskName masks EVERY whitespace-separated word, and every seeded persona is literally 'Mock User N' — so the exact rendering is 'M*** U*** 3***', including the number. A two-word 'M*** U***' would mean the trailing word was dropped. No card shows a value beginning enc:v1.",
|
|
68
68
|
expectedData: { ciphertextInResponse: false, blindIndexInResponse: false },
|
|
69
69
|
endResult: "Nothing is changed; this case only reads.",
|
|
70
70
|
},
|
|
@@ -11,6 +11,27 @@
|
|
|
11
11
|
* "looks right". 320px is the narrowest viewport worth supporting and is where
|
|
12
12
|
* every squeeze shows up first.
|
|
13
13
|
*
|
|
14
|
+
* 🛑 THE PAYMENT STEP DOES NOT OFFER PhonePe BY DEFAULT (corrected 2026-09-29).
|
|
15
|
+
* CheckoutRouteClient defaults are showCashOption = true, showPhonePe = false,
|
|
16
|
+
* showCod = false, and the payment branch picks the first ENABLED method in
|
|
17
|
+
* that order — so the primary CTA on a default site reads 'Pay via UPI / Cash'.
|
|
18
|
+
* The second case asserted 'Pay Online (PhonePe)' is shown complete, which on a
|
|
19
|
+
* default site means asserting a button that is not there. It now reads whatever
|
|
20
|
+
* CTA the enabled method produces and lists all four labels so the tester can
|
|
21
|
+
* recognise which one they got:
|
|
22
|
+
*
|
|
23
|
+
* showCashOption 'Pay via UPI / Cash' (default ON, and the longest)
|
|
24
|
+
* showPhonePe 'Pay Online (PhonePe)' (default OFF)
|
|
25
|
+
* showCod 'Cash on Delivery' (default OFF)
|
|
26
|
+
* emiVisible 'Pay in EMI'
|
|
27
|
+
*
|
|
28
|
+
* 🛑 AND THE BUYER HAS NO SAVED ADDRESS. Three addresses are seeded, owned by
|
|
29
|
+
* user-yugi-muto, user-seto-kaiba and user-admin-letitrip. rehan.sheikh has none,
|
|
30
|
+
* so 'select the first saved address' cannot be followed on a fresh project. The
|
|
31
|
+
* addresses collection is PRESERVE tier, so one may exist from an earlier run
|
|
32
|
+
* — the step now covers both, because a case that assumes either is wrong half
|
|
33
|
+
* the time.
|
|
34
|
+
*
|
|
14
35
|
* @tag domain:tester
|
|
15
36
|
* @tag layer:seed
|
|
16
37
|
* @tag pattern:none
|
|
@@ -26,7 +47,8 @@ export const authored = {
|
|
|
26
47
|
"Resize the browser window to 320 pixels wide.",
|
|
27
48
|
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
28
49
|
"Open /products/product-beyblade-burst-valkyrie and click 'Add to Cart'.",
|
|
29
|
-
"Open /checkout
|
|
50
|
+
"Open /checkout. Select a saved address if one is offered; if the list is empty, add one, since no address is seeded for this buyer.",
|
|
51
|
+
"Continue to the Extras step — checkout is Address, then Extras and fees, then Payment.",
|
|
30
52
|
"Read the two buttons in the bottom action bar and compare their widths.",
|
|
31
53
|
],
|
|
32
54
|
inputs: { viewportWidth: 320 },
|
|
@@ -41,13 +63,16 @@ export const authored = {
|
|
|
41
63
|
"Resize the browser window to 320 pixels wide.",
|
|
42
64
|
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
43
65
|
"Open /products/product-beyblade-burst-valkyrie and click 'Add to Cart'.",
|
|
44
|
-
"Open /checkout and continue through to the
|
|
45
|
-
"Read the primary button's label in full.",
|
|
46
|
-
"Select each payment method in turn and read the primary label after each.",
|
|
66
|
+
"Open /checkout, supply an address if none is saved, and continue through Extras to the Payment step.",
|
|
67
|
+
"Read the primary button's label in full and write down which of the four it is: 'Pay via UPI / Cash', 'Pay Online (PhonePe)', 'Cash on Delivery' or 'Pay in EMI'.",
|
|
68
|
+
"Select each payment method the page offers in turn and read the primary label after each.",
|
|
47
69
|
],
|
|
48
|
-
inputs: {
|
|
70
|
+
inputs: {
|
|
71
|
+
viewportWidth: 320,
|
|
72
|
+
defaultPrimaryCta: "Pay via UPI / Cash",
|
|
73
|
+
},
|
|
49
74
|
expectedBehaviour: "A label too long for one line makes its button taller rather than truncating. Height is cheap in a bottom bar; a clipped verb is not, because the buyer cannot tell what the button will do.",
|
|
50
|
-
expectedUiState: "
|
|
75
|
+
expectedUiState: "Whichever CTA the enabled method produces is shown complete, wrapping onto two lines if it needs to. On a default site that is 'Pay via UPI / Cash' — the longest of the four, and therefore the one most likely to clip. An ellipsis anywhere in the bar is a failure, on any method. Do NOT record the absence of 'Pay Online (PhonePe)' as a defect: PhonePe is off by default and a separate admin case covers switching it on.",
|
|
51
76
|
endResult: "Layout-only; nothing persists. Restore the window width afterwards.",
|
|
52
77
|
},
|
|
53
78
|
};
|
|
@@ -10,6 +10,21 @@
|
|
|
10
10
|
* compact while a mobile bar stretches — and that is exactly why they are one
|
|
11
11
|
* page. A single rule applied to both is what makes one of them wrong.
|
|
12
12
|
*
|
|
13
|
+
* 🛑 /admin/products HAS NO DELETE ROW ACTION (corrected 2026-09-29). Its row
|
|
14
|
+
* menu is Approve, Reject and Quick edit; nothing there opens a destructive
|
|
15
|
+
* dialog, so the first case could not start. It now uses the bundle editor's
|
|
16
|
+
* delete, which is a real ConfirmDeleteModal and names the record in its title.
|
|
17
|
+
*
|
|
18
|
+
* ConfirmDeleteModal's defaults are title 'Delete Item?', confirm 'Delete',
|
|
19
|
+
* cancel 'Cancel'; the bundle editor overrides the title to 'Delete this
|
|
20
|
+
* bundle?'. A dialog still reading the generic default IS the finding — a
|
|
21
|
+
* confirmation that does not say what it will destroy is barely a confirmation.
|
|
22
|
+
*
|
|
23
|
+
* The drawer footer's labels are exact and come from FilterDrawer itself:
|
|
24
|
+
* 'Reset all' (ghost) and 'Apply' (primary), which becomes 'Apply (N)' while
|
|
25
|
+
* changes are pending. A tester seeing the count variant is looking at correct
|
|
26
|
+
* behaviour, not a drifted label.
|
|
27
|
+
*
|
|
13
28
|
* @tag domain:tester
|
|
14
29
|
* @tag layer:seed
|
|
15
30
|
* @tag pattern:none
|
|
@@ -20,19 +35,24 @@
|
|
|
20
35
|
export const authored = {
|
|
21
36
|
"checklist-cta-layout-dialog-footers-modal-footer-stays-compact-on-desktop": {
|
|
22
37
|
roles: ["admin"],
|
|
23
|
-
startPage: "/admin/
|
|
38
|
+
startPage: "/admin/bundles",
|
|
24
39
|
steps: [
|
|
25
40
|
"Resize the browser window to 1280 pixels wide.",
|
|
26
41
|
"Sign in as admin@letitrip.in / TempPass123!.",
|
|
27
|
-
"Open /admin/
|
|
28
|
-
"
|
|
29
|
-
"Read the dialog's
|
|
30
|
-
"
|
|
42
|
+
"Open /admin/bundles and open any bundle for editing.",
|
|
43
|
+
"Click its delete control to open the confirmation dialog. Do NOT confirm.",
|
|
44
|
+
"Read the dialog's title: it should name the record, not read 'Delete Item?'.",
|
|
45
|
+
"Read the two footer buttons, 'Cancel' and 'Delete', and where they sit horizontally.",
|
|
46
|
+
"Dismiss with Cancel.",
|
|
31
47
|
],
|
|
32
|
-
inputs: {
|
|
48
|
+
inputs: {
|
|
49
|
+
viewportWidth: 1280,
|
|
50
|
+
dialogTitle: "Delete this bundle?",
|
|
51
|
+
genericDefault: "Delete Item?",
|
|
52
|
+
},
|
|
33
53
|
expectedBehaviour: "A dialog footer packs its buttons to the right at content width. A destructive dialog also has to HAVE a confirmation to open at all — every danger-kind action carries its confirmation copy in the action registry, and one without it executes immediately with no warning.",
|
|
34
|
-
expectedUiState: "Cancel and
|
|
35
|
-
endResult: "Cancel closes the dialog and nothing is deleted. The
|
|
54
|
+
expectedUiState: "'Cancel' and 'Delete' are each about as wide as their own label and sit together at the right edge of the dialog. They do not stretch edge to edge like banners. The title names the bundle rather than reading the component default 'Delete Item?' — a confirmation that does not say what it will destroy is barely a confirmation.",
|
|
55
|
+
endResult: "Cancel closes the dialog and nothing is deleted. The bundle is still in /admin/bundles after a reload — dismissing must not be a silent confirm.",
|
|
36
56
|
},
|
|
37
57
|
"checklist-cta-layout-dialog-footers-filter-drawer-footer-stacks-when-narrow": {
|
|
38
58
|
roles: ["guest"],
|
|
@@ -44,9 +64,13 @@ export const authored = {
|
|
|
44
64
|
"Scroll to the drawer's footer.",
|
|
45
65
|
"Read both buttons and note whether they sit side by side or one per line.",
|
|
46
66
|
],
|
|
47
|
-
inputs: {
|
|
67
|
+
inputs: {
|
|
68
|
+
viewportWidth: 320,
|
|
69
|
+
resetLabel: "Reset all",
|
|
70
|
+
applyLabel: "Apply",
|
|
71
|
+
},
|
|
48
72
|
expectedBehaviour: "Where a dialog footer stays compact, a drawer footer prefers legibility: if two buttons cannot both read at the available width they stack one per line rather than shrinking below their labels.",
|
|
49
|
-
expectedUiState: "'Reset all' and 'Apply' are both fully readable. If they cannot fit side by side at 320px they are stacked, one per line. Neither is crushed below its label and neither is truncated.",
|
|
73
|
+
expectedUiState: "'Reset all' and 'Apply' are both fully readable. If they cannot fit side by side at 320px they are stacked, one per line. Neither is crushed below its label and neither is truncated. The primary reads 'Apply (N)' once a facet has been changed but not yet applied, which is correct rather than a drifted label.",
|
|
50
74
|
endResult: "Layout-only; closing the drawer without applying changes nothing. Restore the window width afterwards.",
|
|
51
75
|
},
|
|
52
76
|
};
|
|
@@ -6,6 +6,27 @@
|
|
|
6
6
|
* generator: the authoring scripts were deleted once it was clear they were
|
|
7
7
|
* scaffolding around work that is simply writing.
|
|
8
8
|
*
|
|
9
|
+
* 🛑 /store/products/new OPENS THE QUICK FORM, NOT THIS BAR (corrected
|
|
10
|
+
* 2026-09-29). SellerProductShell picks formMode 'quick' whenever mode is
|
|
11
|
+
* create and the listing type is standard, and QuickProductForm's action row
|
|
12
|
+
* has TWO buttons — 'Publish' and 'Save Draft' — plus a ghost
|
|
13
|
+
* 'Show all fields (advanced)' beneath them. No Discard, no Preview, and no
|
|
14
|
+
* four-button bar to overflow. The case has to take the advanced switch first.
|
|
15
|
+
*
|
|
16
|
+
* 🛑 AND THE FULL FORM'S BAR HOLDS THREE, NOT FOUR. FormShell's ActionRow is
|
|
17
|
+
* Discard as the `anchor` (a ghost button, ALWAYS present rather than appearing
|
|
18
|
+
* when the form goes dirty), then Save draft, then Publish. Preview is not in
|
|
19
|
+
* this row at all — it lives in the FormShell TOP bar, and only when a preview
|
|
20
|
+
* slot is supplied. A case counting four buttons in one row is counting a
|
|
21
|
+
* button that is somewhere else.
|
|
22
|
+
*
|
|
23
|
+
* The labels differ between the generic shell and this editor, so the case asks
|
|
24
|
+
* the tester to RECORD what they read rather than asserting one spelling:
|
|
25
|
+
* FORM_ACTION_META says 'Discard' / 'Save Draft' / 'Publish', while
|
|
26
|
+
* SellerProductShell renders 'Save as draft & finish later' and
|
|
27
|
+
* 'Publish {listingTypeLabel}'. Either way the layout question — does anything
|
|
28
|
+
* run off the right edge at 375px — is unchanged, and that is the case.
|
|
29
|
+
*
|
|
9
30
|
* @tag domain:tester
|
|
10
31
|
* @tag layer:seed
|
|
11
32
|
* @tag pattern:none
|
|
@@ -20,16 +41,22 @@ export const authored = {
|
|
|
20
41
|
steps: [
|
|
21
42
|
"Resize the browser window to 375 pixels wide.",
|
|
22
43
|
"Sign in as tyson@beybladearena.in / TempPass123!.",
|
|
23
|
-
"Open /store/products/new.",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
44
|
+
"Open /store/products/new and read its action row. This is the QUICK form: expect two buttons, Publish and Save Draft, and a ghost link reading 'Show all fields (advanced)'.",
|
|
45
|
+
"Click 'Show all fields (advanced)' to reach the full editor.",
|
|
46
|
+
"Type 'QA Product editor-action-bar' in the Product Name field.",
|
|
47
|
+
"Read the action bar and write down every button in it, in order, with its exact label.",
|
|
26
48
|
"Try to scroll the page sideways.",
|
|
27
|
-
"Read the right edge of the bar for any button that is partly off screen.",
|
|
49
|
+
"Read the right edge of the bar for any button that is partly off screen, and the left edge for Discard — it is anchored there rather than sitting beside the other two.",
|
|
28
50
|
],
|
|
29
|
-
inputs: {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
51
|
+
inputs: {
|
|
52
|
+
viewportWidth: 375,
|
|
53
|
+
title: "QA Product editor-action-bar",
|
|
54
|
+
quickFormButtons: 2,
|
|
55
|
+
fullFormButtons: 3,
|
|
56
|
+
},
|
|
57
|
+
expectedBehaviour: "Actions that cannot fit one row wrap onto a second. They used to be non-shrinking children of a non-wrapping row, which does not overflow gracefully — it simply runs off the right edge, taking the last button with it. Discard is the row's anchor rather than a third sibling, because a flat justify-between row with three children opened the gap between Save draft and Publish instead of beside Discard.",
|
|
58
|
+
expectedUiState: "Every button in the bar is fully visible, wrapping onto a second line as needed. Nothing is cut off at the right edge and the page does not scroll sideways at all. Expect THREE in the full editor — a Discard anchored left, a save and a publish — and do not count Preview: it is in the top bar, not this row, and only when a preview slot is supplied. Record the exact labels you read; they differ between the generic shell and this editor.",
|
|
59
|
+
expectedData: { quickFormButtonCount: 2, fullFormButtonCount: 3, horizontalScroll: false },
|
|
33
60
|
endResult: "Leave the editor without saving, so no draft product is created. Restore the window width afterwards.",
|
|
34
61
|
},
|
|
35
62
|
};
|
|
@@ -8,6 +8,23 @@
|
|
|
8
8
|
* and an active-section marker has to be derived from the current path rather
|
|
9
9
|
* than set once on first render.
|
|
10
10
|
*
|
|
11
|
+
* 🛑 CLEARING THE ANNOUNCEMENT DOES NOT REMOVE THE BAR (corrected 2026-09-29).
|
|
12
|
+
* MarketplaceHomepageView reads
|
|
13
|
+
* announcementBar.message?.trim() || SECTION_COPY.announcementFallback
|
|
14
|
+
* and gates on `announcementBar.enabled ?? true`. So an empty message falls back
|
|
15
|
+
* to 'Free shipping on eligible orders — shop the latest arrivals.'
|
|
16
|
+
* and the bar stays. Removing it means turning OFF 'Show announcement bar'. The
|
|
17
|
+
* last case told the tester to clear the message and check the bar left the
|
|
18
|
+
* homepage, which would have reported correct fallback behaviour as a defect.
|
|
19
|
+
*
|
|
20
|
+
* The seed ships enabled:true with a real message, so no setup toggle is needed,
|
|
21
|
+
* and the ONLY surface that renders it is the homepage.
|
|
22
|
+
*
|
|
23
|
+
* Verified fixed before asserting: the editor writes announcementBar.message,
|
|
24
|
+
* which is the key the renderer reads — the historical bug wrote `text`, a key
|
|
25
|
+
* nothing has ever read, so every announcement saved and none appeared. A pass
|
|
26
|
+
* is the expected result here.
|
|
27
|
+
*
|
|
11
28
|
* @tag domain:tester
|
|
12
29
|
* @tag layer:seed
|
|
13
30
|
* @tag pattern:none
|
|
@@ -36,7 +53,7 @@ export const authored = {
|
|
|
36
53
|
roles: ["buyer"],
|
|
37
54
|
startPage: "/",
|
|
38
55
|
steps: [
|
|
39
|
-
"Sign in as rehan.sheikh@gmail.com / TempPass123
|
|
56
|
+
"Sign in as rehan.sheikh@gmail.com / TempPass123!. No cart is seeded for this buyer, so the badge should start empty — if it does not, empty the cart before continuing.",
|
|
40
57
|
"Read the header's cart control and its badge.",
|
|
41
58
|
"Add a product from /products and read the badge without reloading.",
|
|
42
59
|
"Add a second and read it again.",
|
|
@@ -114,7 +131,7 @@ export const authored = {
|
|
|
114
131
|
steps: [
|
|
115
132
|
"Open the homepage and read which navigation entry is marked as current.",
|
|
116
133
|
"Navigate to /products and read which is marked.",
|
|
117
|
-
"Navigate to
|
|
134
|
+
"Navigate to /products/product-beyblade-original-dranzer-s and read which is marked.",
|
|
118
135
|
"Navigate to /events and read which is marked.",
|
|
119
136
|
"Use the browser's back button twice and read the marker each time.",
|
|
120
137
|
],
|
|
@@ -127,15 +144,20 @@ export const authored = {
|
|
|
127
144
|
startPage: "/admin/site",
|
|
128
145
|
steps: [
|
|
129
146
|
"Sign in as admin@letitrip.in / TempPass123! and open Site Settings.",
|
|
130
|
-
"
|
|
131
|
-
"
|
|
132
|
-
"
|
|
133
|
-
"
|
|
134
|
-
"
|
|
147
|
+
"Open the 'Announcement' tab, write down the current message, and confirm 'Show announcement bar' is already on.",
|
|
148
|
+
"Set the message to 'QA announcement probe — checklist case.' and save.",
|
|
149
|
+
"Sign out and open / . Read whether the announcement appears and whether the text matches exactly.",
|
|
150
|
+
"Sign back in, CLEAR the message and save, then reload / . The bar should still be there, now reading the fallback: 'Free shipping on eligible orders — shop the latest arrivals.'",
|
|
151
|
+
"Turn 'Show announcement bar' OFF, save, and reload / . NOW the bar should be gone.",
|
|
152
|
+
"Restore the original message and turn the toggle back on.",
|
|
135
153
|
],
|
|
136
|
-
inputs: {
|
|
154
|
+
inputs: {
|
|
155
|
+
message: "QA announcement probe — checklist case.",
|
|
156
|
+
fallback: "Free shipping on eligible orders — shop the latest arrivals.",
|
|
157
|
+
toggle: "Show announcement bar",
|
|
158
|
+
},
|
|
137
159
|
expectedBehaviour: "An announcement an admin saves appears. The editor once wrote the copy under a key no renderer has ever read, so every announcement saved successfully and none of them appeared — a save that reports success while writing to a field with no reader is invisible from both ends.",
|
|
138
|
-
expectedUiState: "The exact text appears in the announcement bar on the
|
|
160
|
+
expectedUiState: "The exact text appears in the announcement bar on the homepage. Clearing the message does NOT remove the bar — it falls back to 'Free shipping on eligible orders — shop the latest arrivals.', which is correct and must not be reported as a defect. Only turning the toggle off removes it. A successful save with the OLD text still on the homepage is the finding.",
|
|
139
161
|
endResult: "The announcement is cleared.",
|
|
140
162
|
},
|
|
141
163
|
};
|
|
@@ -6,6 +6,26 @@
|
|
|
6
6
|
* generator: the authoring scripts were deleted once it was clear they were
|
|
7
7
|
* scaffolding around work that is simply writing.
|
|
8
8
|
*
|
|
9
|
+
* Verified against ProductDetailActions on 2026-09-29. The mobile bar registers
|
|
10
|
+
* three actions with DISTINCT variants, not two secondaries and a primary:
|
|
11
|
+
*
|
|
12
|
+
* ghost Wishlist (reads 'Saved' and is DISABLED once wishlisted)
|
|
13
|
+
* outline Add to Cart (reads 'Adding…' while busy)
|
|
14
|
+
* primary Buy Now (reads 'Out of Stock' when stock is 0)
|
|
15
|
+
*
|
|
16
|
+
* It also publishes an `infoLabel` carrying the price, which doubles as the
|
|
17
|
+
* bar's re-publish key. Signed in that reads the formatted price; signed out it
|
|
18
|
+
* reads 'Sign in to see price' — so the bar is also where the guest price gate
|
|
19
|
+
* is visible on this page, and a buyer who sees that string is looking at a
|
|
20
|
+
* session that did not resolve.
|
|
21
|
+
*
|
|
22
|
+
* 🛑 product-beyblade-original-dranzer-s is stock 4 and not sold, so the
|
|
23
|
+
* labels are Buy Now / Add to Cart rather than Out of Stock, and it is NOT in
|
|
24
|
+
* this buyer's wishlist: the three seeded wishlists belong to user-yugi-muto,
|
|
25
|
+
* user-seto-kaiba and user-admin-letitrip. So Wishlist is enabled and reads
|
|
26
|
+
* 'Wishlist'. If it reads 'Saved' and is disabled, an earlier case added it
|
|
27
|
+
* and that is not a defect.
|
|
28
|
+
*
|
|
9
29
|
* @tag domain:tester
|
|
10
30
|
* @tag layer:seed
|
|
11
31
|
* @tag pattern:none
|
|
@@ -23,13 +43,19 @@ export const authored = {
|
|
|
23
43
|
"Open /products/product-beyblade-original-dranzer-s.",
|
|
24
44
|
"Read the bottom action bar and note which buttons share a row.",
|
|
25
45
|
"Compare the widths of the two buttons on the upper row.",
|
|
46
|
+
"Read the price shown on the bar — signed in it should read the formatted price, 1,499 for this product.",
|
|
26
47
|
"Click 'Add to Cart' and watch the bar while the label changes.",
|
|
27
48
|
"Count the rows in the bar during and after the change.",
|
|
28
49
|
],
|
|
29
|
-
inputs: {
|
|
50
|
+
inputs: {
|
|
51
|
+
viewportWidth: 375,
|
|
52
|
+
productId: "product-beyblade-original-dranzer-s",
|
|
53
|
+
price: 1499,
|
|
54
|
+
expectedRows: 2,
|
|
55
|
+
},
|
|
30
56
|
expectedBehaviour: "Three actions of different weight are laid out as two secondaries sharing a row above one full-width primary. The secondaries share that row proportionally rather than one being pinned to its content width, which is what made the row read lopsided before.",
|
|
31
|
-
expectedUiState: "'Wishlist' and 'Add to Cart' occupy the upper row and neither is squeezed to a fraction of the other. 'Buy Now' spans the full width beneath them. While the label reads 'Adding…' the bar still has exactly two rows — a bar that reflows to three rows and back makes the whole page jump under the buyer's thumb mid-tap.",
|
|
32
|
-
expectedData: { barRowCount: 2 },
|
|
57
|
+
expectedUiState: "'Wishlist' and 'Add to Cart' occupy the upper row and neither is squeezed to a fraction of the other. 'Buy Now' spans the full width beneath them. The bar shows the price, which for a signed-in buyer reads the formatted amount and never 'Sign in to see price'. While the label reads 'Adding…' the bar still has exactly two rows — a bar that reflows to three rows and back makes the whole page jump under the buyer's thumb mid-tap.",
|
|
58
|
+
expectedData: { barRowCount: 2, priceOnBar: 1499 },
|
|
33
59
|
endResult: "The item is in the cart. Restore the window width and empty the cart afterwards so later cases start clean.",
|
|
34
60
|
},
|
|
35
61
|
};
|