@mohasinac/appkit 4.11.3 → 4.12.1
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/server/features/auctions/service.d.ts +7 -1
- package/dist/_internal/server/features/auctions/service.js +13 -5
- package/dist/_internal/server/features/checkout/actions.d.ts +36 -18
- package/dist/_internal/server/features/checkout/actions.js +127 -45
- package/dist/_internal/server/features/orders/actions.js +5 -3
- package/dist/_internal/server/features/orders/adapters.js +13 -0
- package/dist/_internal/server/features/products/list-public.d.ts +28 -0
- package/dist/_internal/server/features/products/list-public.js +92 -0
- package/dist/_internal/server/functions/firestore.d.ts +1 -2
- package/dist/_internal/server/functions/firestore.js +1 -9
- package/dist/_internal/server/jobs/core/auctionSettlement.js +5 -2
- package/dist/_internal/server/jobs/core/index.d.ts +0 -1
- package/dist/_internal/server/jobs/core/index.js +0 -1
- package/dist/_internal/server/jobs/core/offerExpiry.js +33 -1
- package/dist/_internal/server/jobs/handlers/index.d.ts +1 -2
- package/dist/_internal/server/jobs/handlers/index.js +1 -2
- package/dist/_internal/shared/checkout/lanes.d.ts +20 -0
- package/dist/_internal/shared/checkout/lanes.js +28 -0
- package/dist/_internal/shared/features/auctions/config.d.ts +34 -0
- package/dist/_internal/shared/features/auctions/config.js +47 -3
- package/dist/_internal/shared/features/checkout/config.d.ts +4 -0
- package/dist/_internal/shared/features/checkout/config.js +8 -0
- package/dist/_internal/shared/fees/calculator.d.ts +34 -2
- package/dist/_internal/shared/fees/calculator.js +45 -1
- package/dist/_internal/shared/listing-types/auction/config.js +1 -1
- package/dist/_internal/shared/listing-types/digital-code/config.js +1 -1
- package/dist/_internal/shared/listing-types/live/config.js +1 -1
- package/dist/_internal/shared/listing-types/pre-order/config.js +1 -1
- package/dist/client.d.ts +7 -1
- package/dist/client.js +4 -1
- package/dist/constants/api-endpoints.d.ts +6 -0
- package/dist/constants/api-endpoints.js +2 -0
- package/dist/features/account/components/NotificationBell.js +1 -1
- package/dist/features/admin/components/AdminAddressesView.js +18 -10
- package/dist/features/admin/components/AdminArtView.d.ts +9 -0
- package/dist/features/admin/components/AdminArtView.js +11 -35
- package/dist/features/admin/components/AdminClassifiedView.d.ts +9 -0
- package/dist/features/admin/components/AdminClassifiedView.js +11 -35
- package/dist/features/admin/components/AdminDigitalCodesView.d.ts +9 -0
- package/dist/features/admin/components/AdminDigitalCodesView.js +11 -42
- package/dist/features/admin/components/AdminLiveView.d.ts +9 -0
- package/dist/features/admin/components/AdminLiveView.js +11 -41
- package/dist/features/admin/components/AdminNotificationsView.js +4 -1
- package/dist/features/admin/components/AdminOrderEditorView.d.ts +14 -1
- package/dist/features/admin/components/AdminOrderEditorView.js +18 -5
- package/dist/features/admin/components/AdminOrdersView.js +15 -1
- package/dist/features/admin/components/AdminPaymentMethodsView.js +15 -10
- package/dist/features/admin/components/AdminSiteConfigGuideView.js +1 -1
- package/dist/features/admin/components/AdminSiteSettingsView.js +4 -2
- package/dist/features/admin/components/AdminStickersView.d.ts +9 -0
- package/dist/features/admin/components/AdminStickersView.js +11 -35
- package/dist/features/admin/hooks/useAdminListing.js +7 -2
- package/dist/features/admin/schemas/firestore.d.ts +5 -0
- package/dist/features/admin/schemas/firestore.js +1 -0
- package/dist/features/auctions/actions/bid-actions.js +73 -11
- package/dist/features/auctions/components/AuctionDetailPageView.js +8 -2
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +3 -3
- package/dist/features/auctions/components/PlaceBidFormClient.js +89 -14
- package/dist/features/auctions/schemas/bid-input.d.ts +19 -6
- package/dist/features/auctions/schemas/bid-input.js +19 -7
- package/dist/features/auth/repository/user.repository.js +6 -0
- package/dist/features/cart/components/CartDrawer.d.ts +9 -1
- package/dist/features/cart/components/CartDrawer.js +4 -3
- package/dist/features/cart/components/CartPriceBreakdown.d.ts +61 -0
- package/dist/features/cart/components/CartPriceBreakdown.js +25 -0
- package/dist/features/cart/components/StoreAddonsPicker.d.ts +47 -0
- package/dist/features/cart/components/StoreAddonsPicker.js +21 -0
- package/dist/features/cart/components/index.d.ts +4 -0
- package/dist/features/cart/components/index.js +2 -0
- package/dist/features/cart/repository/cart.repository.d.ts +20 -2
- package/dist/features/cart/repository/cart.repository.js +49 -0
- package/dist/features/cart/schemas/firestore.d.ts +26 -0
- package/dist/features/faq/components/FAQHelpfulButtons.js +2 -2
- package/dist/features/filters/FilterFacetSection.js +1 -1
- package/dist/features/homepage/components/WhatsAppCommunitySection.js +1 -1
- package/dist/features/layout/BackToTop.js +1 -1
- package/dist/features/layout/BottomActions.js +38 -5
- package/dist/features/layout/BottomActionsContext.d.ts +12 -0
- package/dist/features/layout/BottomActionsContext.js +5 -0
- package/dist/features/layout/FooterLayout.js +2 -2
- package/dist/features/layout/TitleBarLayout.js +1 -1
- package/dist/features/layout/hooks/useBottomActions.d.ts +6 -0
- package/dist/features/layout/hooks/useBottomActions.js +11 -1
- package/dist/features/orders/components/OrderAddonBadges.d.ts +36 -0
- package/dist/features/orders/components/OrderAddonBadges.js +28 -0
- package/dist/features/orders/components/index.d.ts +1 -0
- package/dist/features/orders/components/index.js +1 -0
- package/dist/features/orders/repository/orders.repository.d.ts +32 -0
- package/dist/features/orders/repository/orders.repository.js +14 -0
- package/dist/features/orders/types/index.d.ts +22 -0
- package/dist/features/pre-orders/components/MarketplacePreorderCard.js +3 -3
- package/dist/features/products/components/ArtStickersListView.js +5 -4
- package/dist/features/products/components/MarketplaceBundleCard.js +2 -2
- package/dist/features/products/components/MarketplacePrizeDrawCard.js +2 -2
- package/dist/features/products/components/PrizeDrawCollage.js +1 -1
- package/dist/features/products/components/PrizeDrawItemsEditor.js +1 -1
- package/dist/features/products/components/PrizeDrawsListingView.js +18 -33
- package/dist/features/products/components/ProductDetailPageView.js +1 -1
- package/dist/features/products/components/ProductGrid.js +3 -3
- package/dist/features/products/components/ProductsIndexListing.js +87 -11
- package/dist/features/products/components/ProductsIndexPageView.js +14 -2
- package/dist/features/products/config/listing-type-listing-config.d.ts +31 -0
- package/dist/features/products/config/listing-type-listing-config.js +74 -0
- package/dist/features/products/hooks/useProducts.js +14 -0
- package/dist/features/products/repository/products.repository.d.ts +0 -4
- package/dist/features/products/repository/products.repository.js +0 -15
- package/dist/features/products/types/index.d.ts +15 -0
- package/dist/features/promotions/repository/coupons.repository.d.ts +12 -0
- package/dist/features/promotions/repository/coupons.repository.js +12 -0
- package/dist/features/seller/components/SellerOrdersView.js +2 -1
- package/dist/features/seller/components/SellerSidebar.js +1 -1
- package/dist/features/stores/components/StoreArtStickersPageView.d.ts +21 -0
- package/dist/features/stores/components/StoreArtStickersPageView.js +30 -0
- package/dist/features/stores/components/StoreAuctionsPageView.d.ts +4 -1
- package/dist/features/stores/components/StoreAuctionsPageView.js +17 -17
- package/dist/features/stores/components/StoreClassifiedsListing.js +7 -0
- package/dist/features/stores/components/StoreClassifiedsPageView.d.ts +4 -1
- package/dist/features/stores/components/StoreClassifiedsPageView.js +16 -12
- package/dist/features/stores/components/StoreDetailLayoutView.js +4 -3
- package/dist/features/stores/components/StoreDigitalCodesListing.js +5 -0
- package/dist/features/stores/components/StoreDigitalCodesPageView.d.ts +4 -1
- package/dist/features/stores/components/StoreDigitalCodesPageView.js +16 -12
- package/dist/features/stores/components/StoreLiveItemsListing.js +7 -0
- package/dist/features/stores/components/StoreLiveItemsPageView.d.ts +4 -1
- package/dist/features/stores/components/StoreLiveItemsPageView.js +16 -12
- package/dist/features/stores/components/StorePreOrdersPageView.d.ts +4 -1
- package/dist/features/stores/components/StorePreOrdersPageView.js +17 -17
- package/dist/features/stores/components/StorePrizeDrawsPageView.d.ts +4 -8
- package/dist/features/stores/components/StorePrizeDrawsPageView.js +17 -22
- package/dist/features/stores/components/StoreProductsListing.d.ts +7 -1
- package/dist/features/stores/components/StoreProductsListing.js +3 -2
- package/dist/features/stores/components/StoreProductsPageView.d.ts +1 -1
- package/dist/features/stores/components/StoreProductsPageView.js +16 -21
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +875 -0
- package/dist/features/whatsapp-bot/components/WhatsAppChatButton.js +1 -1
- package/dist/jobs.d.ts +1 -1
- package/dist/jobs.js +1 -1
- package/dist/next/routing/route-map.d.ts +2 -0
- package/dist/next/routing/route-map.js +5 -0
- package/dist/seed/homepage-sections-seed-data.js +5 -1
- package/dist/seed/reviews-seed-data.js +52 -0
- package/dist/seed/site-settings-seed-data.js +18 -0
- package/dist/server-entry.d.ts +1 -0
- package/dist/server-entry.js +1 -0
- package/dist/styles.css +66 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/color-pairs.js +1 -0
- package/dist/tokens/tokens.css +33 -0
- package/dist/ui/components/Button.style.css +21 -0
- package/dist/ui/components/Checkbox.d.ts +10 -1
- package/dist/ui/components/Checkbox.js +14 -2
- package/dist/ui/components/Checkbox.style.css +11 -0
- package/dist/ui/components/ImageLightbox.js +7 -4
- package/dist/ui/components/surface-tokens.d.ts +7 -0
- package/dist/ui/components/surface-tokens.js +7 -0
- package/package.json +1 -1
- package/dist/_internal/server/jobs/core/onBidPlaced.d.ts +0 -15
- package/dist/_internal/server/jobs/core/onBidPlaced.js +0 -63
- package/dist/_internal/server/jobs/handlers/onBidPlaced.d.ts +0 -3
- package/dist/_internal/server/jobs/handlers/onBidPlaced.js +0 -9
|
@@ -99,6 +99,18 @@ const rawTesterChecklistItems = [
|
|
|
99
99
|
description: "Changed 2026-08-21 — this flow now calls Firebase directly from the browser instead of going through a server route, so the client must swallow Firebase's auth/user-not-found error. Submit a made-up address like nobody-here-12345@example.com and confirm you see \"If an account exists for that email, a reset link is on its way.\" — the same wording a real address produces, with no error toast and nothing in the UI distinguishing the two cases.",
|
|
100
100
|
href: "/auth/forgot-password",
|
|
101
101
|
},
|
|
102
|
+
{
|
|
103
|
+
key: "auth-emails-sender-identity-and-inbox",
|
|
104
|
+
label: "Signup-verification and password-reset emails arrive in the real inbox, from the site's own sender identity — not spam, not a stranger's domain",
|
|
105
|
+
description: "Added 2026-08-21. Register with an address you can actually open, and separately request a password reset. For BOTH emails confirm: (a) it arrives within a few minutes; (b) the From name and address are the site's configured sender, and the display name is spelled \"LetItRip\" exactly — not \"Letitrip\" or \"LetiTrip\"; (c) it landed in the inbox rather than spam or promotions; (d) the button/link inside opens the live site and completes the flow. Try it once with a Gmail address and once with a non-Gmail address if you can — deliverability often differs between providers.",
|
|
106
|
+
href: "/auth/register",
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
key: "auth-email-links-single-use",
|
|
110
|
+
label: "A used or expired verification / password-reset link fails cleanly with a readable message — it never silently succeeds twice",
|
|
111
|
+
description: "Added 2026-08-21. Complete a password reset, then click the SAME link in that email a second time. Confirm you get a clear, human-readable \"this link has already been used or has expired\" style message with a way to request a fresh one — not a blank page, not a raw Firebase error code, and definitely not a second successful password change. Repeat the same double-click test with a signup verification link.",
|
|
112
|
+
href: "/auth/forgot-password",
|
|
113
|
+
},
|
|
102
114
|
],
|
|
103
115
|
},
|
|
104
116
|
{
|
|
@@ -185,6 +197,72 @@ const rawTesterChecklistItems = [
|
|
|
185
197
|
description: "Verify against the seeded fixtures: \"Test Collectible — Sold Out\" (standard, hidden until \"Show sold\" is on), \"Test Auction — Already Won\" (hidden until \"Show ended\" is on), \"Test Prize Draw — Already Closed\" (hidden until \"Show closed\" is on). All three should be genuinely absent by default, not just from an unrelated broken query.",
|
|
186
198
|
href: "/products",
|
|
187
199
|
},
|
|
200
|
+
{
|
|
201
|
+
key: "product-type-chips-cover-all-types",
|
|
202
|
+
label: "The TYPE chip row on /products lists ALL nine listing types — Standard, Auctions, Pre-Orders, Prize Draws, Classifieds, Digital Codes, Live Items, Art and Stickers",
|
|
203
|
+
description: "Fixed 2026-08-21 — the row used to show only 5 chips (All / Standard / Classified / Digital Codes / Live Items), so auctions, pre-orders, prize draws, art and stickers were unreachable from the main catalogue even though items of those types existed. Count the chips: there should be nine, and none labelled \"Bundles\" (bundles are not a listing type).",
|
|
204
|
+
href: "/products",
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
key: "product-type-chips-multi-select",
|
|
208
|
+
label: "The TYPE chips behave as CHECKBOXES, not radio buttons — several can be ticked at once, and ticking Auctions + Pre-Orders shows both types in one grid",
|
|
209
|
+
description: "Tick Auctions, then tick Pre-Orders WITHOUT unticking Auctions. Both must stay highlighted and the grid must contain items of both types. Untick both and the grid returns to showing every type.",
|
|
210
|
+
href: "/products",
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
key: "product-type-chips-none-means-all",
|
|
214
|
+
label: "With NO type chip ticked, /products shows a mix of listing types — check the coloured type badges on the cards",
|
|
215
|
+
description: "\"Nothing ticked\" means \"every type\", so you should be able to spot at least two different badges (e.g. an \"Auction\" and a \"Digital Code\") within the first page without filtering.",
|
|
216
|
+
href: "/products",
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
key: "product-type-chip-drives-sort-options",
|
|
220
|
+
label: "Ticking exactly ONE type changes the Sort dropdown to that type's own sorts — Auctions alone offers \"Ending Soon\", Pre-Orders alone offers \"Earliest Delivery\"",
|
|
221
|
+
description: "Tick only Auctions and open Sort: \"Ending Soon\" must be present. Untick it, tick only Pre-Orders: \"Earliest Delivery\" must be present and \"Ending Soon\" gone. With two types ticked only the sorts valid for both remain (Newest / Price / Name) — that is correct, not a bug.",
|
|
222
|
+
href: "/products",
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
key: "product-type-chip-sort-resets-no-empty-page",
|
|
226
|
+
label: "Choosing a type-specific sort and THEN changing the type selection never leaves an empty grid or an error",
|
|
227
|
+
description: "The important regression check. Tick Auctions, sort by \"Ending Soon\", then untick Auctions and tick Standard instead. The grid must repopulate with products. A blank page here means a stale sort leaked into the new query.",
|
|
228
|
+
href: "/products",
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
key: "product-type-toggles-follow-selection",
|
|
232
|
+
label: "The toolbar toggles follow the type selection — \"Show ended\" appears only when a time-limited type is in play, \"Show sold\" only when a sellable type is",
|
|
233
|
+
description: "Tick only Auctions: a \"Show ended\" toggle appears. Tick only Standard instead: \"Show ended\" disappears and \"Show sold\" remains. With nothing ticked (= all types) both may appear, which is correct.",
|
|
234
|
+
href: "/products",
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
key: "product-type-chip-dedicated-page-link",
|
|
238
|
+
label: "Ticking exactly one type that has its own browse page shows a \"Full <type> filters\" link that lands on the right page",
|
|
239
|
+
description: "Tick only Auctions — a \"Full Auctions filters\" link should appear beside the chips and open /auctions. Repeat for Pre-Orders and Prize Draws.",
|
|
240
|
+
href: "/products",
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
key: "product-type-selection-survives-reload",
|
|
244
|
+
label: "The ticked type chips are reflected in the URL and survive a reload and the browser Back button",
|
|
245
|
+
description: "Tick Auctions + Art, copy the URL, open it in a new tab: the same two chips must come back ticked with the same grid. Then press Back and confirm the previous selection returns.",
|
|
246
|
+
href: "/products",
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
key: "free-shipping-toggle-actually-filters",
|
|
250
|
+
label: "The \"Free shipping\" toggle on /products actually REDUCES the number of results — it is not a no-op",
|
|
251
|
+
description: "Fixed 2026-08-21 — the toggle sent a filter on a field that was not permitted, so it was silently discarded and the toggle did nothing at all. Note the result count with it off, switch it on, and confirm the count drops and every remaining card really is free-shipping.",
|
|
252
|
+
href: "/products",
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
key: "filter-drawer-facets-actually-filter",
|
|
256
|
+
label: "The Tags, Sublisting Type and Features sections in the Filters drawer actually change the results — not just the number on the Filters button",
|
|
257
|
+
description: "Fixed 2026-08-21 — all three were drawn and counted toward the Filters badge but were never sent to the server. Pick a value in each, Apply, and confirm the result set genuinely narrows instead of staying identical while the badge increments.",
|
|
258
|
+
href: "/products",
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
key: "pre-orders-reachable-from-products",
|
|
262
|
+
label: "Pre-orders are reachable from /products — tick the Pre-Orders chip and confirm real pre-order items appear with a \"Pre-Order\" badge",
|
|
263
|
+
description: "This was the original report: pre-orders (and auctions, prize draws, art, stickers) had no chip at all, so they could only be found via their own dedicated pages.",
|
|
264
|
+
href: "/products",
|
|
265
|
+
},
|
|
188
266
|
{
|
|
189
267
|
key: "art-stickers-default-not-empty",
|
|
190
268
|
label: "The Art & Stickers listing (/art) shows real items by default — not an empty grid that only populates after clicking \"Show sold\"",
|
|
@@ -258,6 +336,12 @@ const rawTesterChecklistItems = [
|
|
|
258
336
|
label: "Product image gallery thumbnails load reliably (no broken-image icons) and click-to-zoom/rotate works in the lightbox",
|
|
259
337
|
description: "The thumbnail strip occasionally showed a broken-image icon instead of the photo (transient 3rd-party fetch failures with no retry, fixed 2026-08-19). Reload an auction or product detail page a few times and confirm every thumbnail — not just the main image — renders correctly each time.",
|
|
260
338
|
},
|
|
339
|
+
{
|
|
340
|
+
key: "image-gallery-thumbnails-not-blank",
|
|
341
|
+
label: "The mini thumbnail strip under the main gallery image shows the ACTUAL photos — not empty/blank boxes",
|
|
342
|
+
description: "Fixed 2026-08-21 — the thumbnails rendered as blank bordered squares while the large main image above them was fine. Cause: a wrapper element inside the appkit <Button> primitive collapsed to zero size, so every image inside a button-shaped image tile had nothing to fill. Open \"Beyblade Burst B-01 Valkyrie\" (product-beyblade-burst-valkyrie) or any product with 2-3 photos and confirm each mini thumbnail below the main image shows its own picture, that the active one is outlined, and that clicking one swaps the large image.",
|
|
343
|
+
href: "/products/product-beyblade-burst-valkyrie",
|
|
344
|
+
},
|
|
261
345
|
{
|
|
262
346
|
key: "video-playback",
|
|
263
347
|
label: "A product's video slide opens in theater mode with playback, zoom, and rotate controls",
|
|
@@ -299,6 +383,12 @@ const rawTesterChecklistItems = [
|
|
|
299
383
|
description: "Verify against \"Test Product Set — Standard #1 + Standard #2\" (group-tester-sandbox-bundle) and either of its two children (product-tester-standard-1 / product-tester-standard-2), findable from the products listing page — all three should show the panel with each other listed, the arrow/triangle expand icons should render as real glyphs (not garbled text), and \"View whole group\" should open a working modal/drawer.",
|
|
300
384
|
href: "/products/group-tester-sandbox-bundle",
|
|
301
385
|
},
|
|
386
|
+
{
|
|
387
|
+
key: "grouped-listings-carousel-on-detail",
|
|
388
|
+
label: "A \"Grouped listings\" themed carousel appears on a product detail page with real, clickable member items",
|
|
389
|
+
description: "Added 2026-08-21 — this carousel previously had no test case of its own outside the category/brand check. It is DIFFERENT from the \"Part of / Parts in this group\" set panel: this one is a horizontal themed scroller (titled by the group's theme, e.g. \"Same character\" / \"From the same set\"), it sits lower down near the related-items carousels, and it only shows for products that belong to an active, visible group. Confirm the cards show real titles and images (not placeholders) and that clicking one lands on that item's own detail page.",
|
|
390
|
+
href: "/products/product-tester-standard-1",
|
|
391
|
+
},
|
|
302
392
|
{ key: "classified-contact-flow", label: "A classified listing shows a contact-seller flow with deliberately no checkout/buy button", href: "/classified/classified-tester-sandbox-1" },
|
|
303
393
|
{ key: "digitalcode-delivery", label: "Purchasing a digital-code listing delivers the code to the buyer post-purchase", href: "/digital-codes/digitalcode-tester-sandbox-1" },
|
|
304
394
|
{ key: "live-item-detail", label: "A live-item listing's detail page shows the livestream link correctly", href: "/live/live-tester-sandbox-1" },
|
|
@@ -394,6 +484,18 @@ const rawTesterChecklistItems = [
|
|
|
394
484
|
label: "Each order row has a visible \"View Details\" button (in addition to the row itself being clickable) that opens that exact order's detail page",
|
|
395
485
|
href: "/user/orders",
|
|
396
486
|
},
|
|
487
|
+
{
|
|
488
|
+
key: "orders-type-tabs-actually-filter",
|
|
489
|
+
label: "The Type filter (All / Normal / Auction wins / Offer wins) on My Orders actually narrows the list — picking \"Auction wins\" must show only auction-won orders, not the full list",
|
|
490
|
+
description: "Fixed 2026-08-21. The tabs rendered and were clickable but the server never read the orderType filter, so every tab returned the complete unfiltered list with no error. Pick each tab in turn and confirm the row count and contents genuinely change. Against the tester sandbox, \"Auction wins\" should surface the won-auction order and \"Normal\" should not.",
|
|
491
|
+
href: "/user/orders",
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
key: "orders-normal-tab-includes-legacy",
|
|
495
|
+
label: "The \"Normal\" Type tab also lists older orders placed before order types existed — it must not silently drop them",
|
|
496
|
+
description: "Legacy orders carry no orderType value at all, so a strict database match would exclude every one of them. \"Normal\" is deliberately resolved differently for that reason. Confirm your oldest seeded orders still appear under \"Normal\", not only under \"All\".",
|
|
497
|
+
href: "/user/orders",
|
|
498
|
+
},
|
|
397
499
|
{
|
|
398
500
|
key: "dashboard-recent-orders-linked",
|
|
399
501
|
label: "The My Account dashboard's \"Recent Orders\" widget rows are clickable and each shows a \"View Details\" button linking to the correct order — not a dead, non-interactive preview",
|
|
@@ -446,6 +548,12 @@ const rawTesterChecklistItems = [
|
|
|
446
548
|
description: "Pair with the admin-side case `admin-orders-reject-fraud`. Use a throwaway buyer account — this really does ban it for 7 days.",
|
|
447
549
|
href: "/user/orders",
|
|
448
550
|
},
|
|
551
|
+
{
|
|
552
|
+
key: "order-lifecycle-emails-arrive",
|
|
553
|
+
label: "As a buyer you get an email at each real order milestone — placed, shipped, delivered, cancelled/refunded — and each one names the right item and order",
|
|
554
|
+
description: "Added 2026-08-21. Walk one throwaway order through its whole life with a seller account driving the status changes, keeping the buyer's real inbox open. At each transition confirm an email arrives and that it names the actual product (not a bare order id / GUID), shows the correct status, and links to that specific order. Note which transitions produce NO email — a missing \"delivered\" or \"refunded\" email is exactly the kind of gap this case exists to surface, so record it in the comment rather than passing the case.",
|
|
555
|
+
href: "/user/orders",
|
|
556
|
+
},
|
|
449
557
|
],
|
|
450
558
|
},
|
|
451
559
|
{
|
|
@@ -494,6 +602,51 @@ const rawTesterChecklistItems = [
|
|
|
494
602
|
key: "bid-increment-live-tier-change",
|
|
495
603
|
label: "The displayed \"min increment\" on an open auction updates live (without a page refresh) if another bidder's bid pushes the current bid across a tier boundary",
|
|
496
604
|
},
|
|
605
|
+
{
|
|
606
|
+
key: "bid-presets-are-increment-multiples",
|
|
607
|
+
label: "The quick-bid buttons above the amount field are multiples of the auction's OWN minimum increment — never a flat +₹1 / +₹5 / +₹10",
|
|
608
|
+
description: "Fixed 2026-08-21 — the presets were always 1x/5x/10x of the effective increment, but `resolveTieredBidIncrement` treated an empty `auctionConfig.bidIncrementTiers` array as \"no rule\" and fell through to the ₹1 last-resort constant, so every auction on the site rendered +₹1 / +₹5 / +₹10. On an auction whose current bid is in the ₹100-₹1,000 band (₹100 increment) the three buttons must read +₹100 / +₹500 / +₹1,000; on one above ₹10,000 (₹1,000 increment) they must read +₹1,000 / +₹5,000 / +₹10,000. Each button also shows the resulting bid amount underneath the step.",
|
|
609
|
+
href: "/auctions/auction-tester-sandbox-cycle-1",
|
|
610
|
+
},
|
|
611
|
+
{
|
|
612
|
+
key: "bid-preset-follows-live-price",
|
|
613
|
+
label: "With a quick-bid preset selected, another bidder raising the price updates the amount in the field too — it does not leave a now-too-low number behind",
|
|
614
|
+
description: "Fixed 2026-08-21 — the amount was only ever written on mount or on button click, while the current bid keeps updating over SSE. Open the auction in two tabs, select the +1x preset in tab A, place a higher bid from tab B, then watch tab A: the preset button labels, the \"minimum next bid\" helper text AND the number in the field must all move up together. Before the fix the buttons relabelled but the field kept its stale value, so pressing Place Bid was a guaranteed \"bid must exceed the current winning bid\" rejection.",
|
|
615
|
+
href: "/auctions/auction-tester-sandbox-cycle-2",
|
|
616
|
+
},
|
|
617
|
+
{
|
|
618
|
+
key: "bid-below-current-plus-increment-rejected",
|
|
619
|
+
label: "A bid below current bid + minimum increment is rejected with a clear inline error on the amount field — and the rejection is identical whether it is typed in Custom mode or forced through the API",
|
|
620
|
+
description: "Switch the preset row to \"Custom\", type an amount between the current bid and current+increment, and submit. Expect an inline error on the field (not a toast, not a silent no-op). Also confirm an amount BELOW the current bid gives the distinct \"must exceed the current winning bid\" message rather than the increment one.",
|
|
621
|
+
href: "/auctions/auction-tester-sandbox-cycle-1",
|
|
622
|
+
},
|
|
623
|
+
{
|
|
624
|
+
key: "bid-custom-need-not-be-exact-multiple",
|
|
625
|
+
label: "In Custom mode any amount at or above the minimum is accepted — it does NOT have to be an exact multiple of the increment",
|
|
626
|
+
description: "With a ₹100 increment and a ₹1,000 current bid, ₹1,137 must be accepted (it is above the ₹1,100 minimum). The helper text under the field states this explicitly. A client-side rule claiming to enforce exact multiples existed but was a no-op; it was removed rather than made real, because the server never enforced multiples and a real client rule would have rejected bids the server accepts.",
|
|
627
|
+
href: "/auctions/auction-tester-sandbox-cycle-1",
|
|
628
|
+
},
|
|
629
|
+
{
|
|
630
|
+
key: "first-bid-can-equal-starting-bid",
|
|
631
|
+
label: "On an auction with NO bids yet, the seller's starting bid is itself an acceptable opening bid — you are not forced to bid starting bid + increment",
|
|
632
|
+
description: "Changed 2026-08-21. On a bid-free auction the card's big number is labelled \"Starting bid\" (not \"Current bid\" beside an identical \"Starting bid\"), the first quick-bid button reads \"Minimum\" rather than \"+₹0\", and bidding exactly the starting bid succeeds. Previously a ₹100 auction could only be opened at ₹110, contradicting the \"Starting bid ₹100\" label right next to the field. The increment applies from the second bid onward — confirm the second bidder IS held to current + increment.",
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
key: "first-bid-displays-at-starting-price",
|
|
636
|
+
label: "The opening bid displays at the starting price, even when the opening bidder's maximum is much higher",
|
|
637
|
+
description: "Proxy-bid semantics: the amount submitted is a MAXIMUM, and with no competition the visible price should sit at the seller's starting price. On a bid-free ₹100 auction with a ₹100 increment, bid ₹500 — the auction's current bid must then read ₹100, not ₹200. Place a second, competing bid from another account and confirm the price then steps up in increments against that ₹500 proxy maximum as expected.",
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
key: "bid-count-increments-by-one",
|
|
641
|
+
label: "Placing one bid increases the auction's bid count by exactly ONE, and the current bid never moves backwards",
|
|
642
|
+
description: "Fixed 2026-08-21 — the `onBidPlaced` Firestore trigger duplicated work `placeBid` already did atomically: it incremented the bid count a second time (so one bid read as two), force-marked every new bid as winning, and overwrote the current bid with the new bid's amount. On the proxy path where a new bid LOSES to a standing higher maximum, that last part actually lowered the current bid to the loser's amount and named the loser as the leading bidder. Place a single bid and confirm the count goes up by 1, not 2. Then, from a second account, bid BELOW the standing proxy maximum: your bid must be recorded as outbid, and the auction's current bid must go UP (or hold), never down.",
|
|
643
|
+
href: "/auctions/auction-tester-sandbox-cycle-3",
|
|
644
|
+
},
|
|
645
|
+
{
|
|
646
|
+
key: "outbid-notification-goes-to-outbid-user",
|
|
647
|
+
label: "The outbid notification goes to the bidder who actually lost the lead — and only when someone genuinely takes the lead from them",
|
|
648
|
+
description: "Fixed 2026-08-21 alongside bid-count-increments-by-one — the notification used to be sent from a Firestore trigger that re-read \"who is winning\" AFTER the fact, racing the write that had just changed it, so it could notify the wrong account or nobody. It now fires from the same code path that decides the outcome. Check both directions: (a) outbid the leader and confirm THEY get the notification; (b) place a bid that loses to a standing proxy maximum and confirm the existing leader is NOT sent an \"outbid\" notification, since they never lost the lead.",
|
|
649
|
+
},
|
|
497
650
|
],
|
|
498
651
|
},
|
|
499
652
|
{
|
|
@@ -556,6 +709,13 @@ const rawTesterChecklistItems = [
|
|
|
556
709
|
{
|
|
557
710
|
key: "cart-mobile-no-overflow",
|
|
558
711
|
label: "On mobile, cart item cards stay fully within the screen width per seller group — no horizontal overflow/clipping — and a floating checkout bar (styled like the bulk-action bar, sitting above the bottom nav) shows the total and a Checkout button, with enough bottom margin that the last cart item is never hidden behind it",
|
|
712
|
+
description: "Root-caused 2026-08-21 — the appkit <Checkbox> root div is width:100%, and the caller's className landed on the inner <input> instead of that root, so the select-item checkbox claimed the whole row, squeezed each item card to ~0px, and pushed its 80px thumbnail outside the seller card's border (same defect class as <Select>/wrapperClassName, Root Cause #29). Test at a 360px viewport with at least two sellers.",
|
|
713
|
+
href: "/cart",
|
|
714
|
+
},
|
|
715
|
+
{
|
|
716
|
+
key: "cart-seller-group-contains-items",
|
|
717
|
+
label: "At a 360px viewport, every cart item row sits fully inside its seller's rounded card, separated by thin divider lines — no card-inside-a-card look, nothing overlapping or extending past the card border, and no horizontal scrolling of the page",
|
|
718
|
+
description: "Add items from two different sellers, ideally one with a very long product title. The seller card should be the only card: header with \"Sold by <store>\" and that seller's subtotal, then divider-separated item rows, then that seller's fees and add-ons.",
|
|
559
719
|
href: "/cart",
|
|
560
720
|
},
|
|
561
721
|
{
|
|
@@ -569,6 +729,18 @@ const rawTesterChecklistItems = [
|
|
|
569
729
|
label: "With an accepted offer pending (and no won auction), only the Cart tab's checkout is disabled — the Offers tab itself is checkoutable",
|
|
570
730
|
href: "/cart",
|
|
571
731
|
},
|
|
732
|
+
{
|
|
733
|
+
key: "auction-win-countdown-visible",
|
|
734
|
+
label: "A won-auction cart line shows a live countdown next to \"payment required\" — days/hours/minutes remaining out of the 48-hour window — that ticks down while you watch",
|
|
735
|
+
description: "Payment for a won auction is MANDATORY (unlike an accepted offer, which the buyer may walk away from). The deadline was being written by settlement and enforced by the expiry sweep, but nothing ever rendered it, so a win could silently lapse and be forfeited with no warning anywhere in the UI. Use auction-tester-sandbox-won.",
|
|
736
|
+
href: "/cart",
|
|
737
|
+
},
|
|
738
|
+
{
|
|
739
|
+
key: "auction-win-forfeits-after-deadline",
|
|
740
|
+
label: "A won auction left unpaid past its 48-hour deadline is forfeited — the cart line disappears, the bid shows as forfeited, and the buyer is notified that repeated non-payment can restrict their account",
|
|
741
|
+
description: "An accepted offer past its deadline must lapse quietly instead, with no penalty — walking away from your own offer is allowed. Confirm the two behave differently.",
|
|
742
|
+
href: "/user/bids",
|
|
743
|
+
},
|
|
572
744
|
{
|
|
573
745
|
key: "checkout-lanes-totals-scoped",
|
|
574
746
|
label: "Each cart tab's summary total reflects ONLY that tab's items — the Cart tab total never includes a pending auction or offer amount, and vice versa",
|
|
@@ -579,6 +751,154 @@ const rawTesterChecklistItems = [
|
|
|
579
751
|
label: "Opening checkout from a specific cart tab lands on the matching lane, shows only that lane's items and total, and (for Auction/Offer lanes) shows an info banner and hides the coupon field",
|
|
580
752
|
href: "/checkout",
|
|
581
753
|
},
|
|
754
|
+
// --- Mobile bar parity with the desktop summary ---------------------
|
|
755
|
+
{
|
|
756
|
+
key: "cart-mobile-bar-lane-scoped",
|
|
757
|
+
label: "The mobile bottom bar's total matches the desktop Summary total on every cart tab, and both name which lane the total covers (\"This total covers your cart only\" / \"…your won auctions only\")",
|
|
758
|
+
description: "The desktop Summary was converted to per-lane totals but the mobile bar was left reading the old blended figure, so the two disagreed on the same cart. Needs items in more than one lane — e.g. a normal product plus auction-tester-sandbox-won. Switch tabs and compare both viewports.",
|
|
759
|
+
href: "/cart",
|
|
760
|
+
},
|
|
761
|
+
{
|
|
762
|
+
key: "cart-mobile-bar-lane-gated",
|
|
763
|
+
label: "On a cart tab that is not currently payable, the mobile Checkout button is disabled and shows the same blocking reason the desktop button shows — tapping it does nothing",
|
|
764
|
+
description: "On a phone viewport with a won auction pending, open the Cart tab. The total still shows (so you can see what's there), but Checkout must be disabled with a reason naming the blocking lane. Previously the mobile button stayed enabled and navigated.",
|
|
765
|
+
href: "/cart",
|
|
766
|
+
},
|
|
767
|
+
{
|
|
768
|
+
key: "cart-mobile-checkout-carries-lane",
|
|
769
|
+
label: "Tapping Checkout from the Won Auctions or Accepted Offers tab on mobile lands on the checkout page already on that lane (URL contains ?lane=auction or ?lane=offer)",
|
|
770
|
+
description: "The desktop button already carried the lane; the mobile one navigated to a lane-less /checkout.",
|
|
771
|
+
href: "/cart",
|
|
772
|
+
},
|
|
773
|
+
{
|
|
774
|
+
key: "cart-select-all-lane-scoped",
|
|
775
|
+
label: "\"Select all (N)\" counts only the items on the current tab, and \"Remove all\" never deletes won-auction or accepted-offer lines",
|
|
776
|
+
href: "/cart",
|
|
777
|
+
},
|
|
778
|
+
// --- Expandable price breakdown -------------------------------------
|
|
779
|
+
{
|
|
780
|
+
key: "cart-breakdown-expand-mobile",
|
|
781
|
+
label: "On mobile, the total row in the bottom bar shows an up-arrow; tapping it opens a panel ABOVE the checkout bar with the full price breakdown, and tapping again (or outside) closes it",
|
|
782
|
+
href: "/cart",
|
|
783
|
+
},
|
|
784
|
+
{
|
|
785
|
+
key: "cart-breakdown-expand-desktop",
|
|
786
|
+
label: "On desktop, \"Show details\" in the Summary panel expands the same breakdown below the subtotal, and \"Hide details\" collapses it",
|
|
787
|
+
href: "/cart",
|
|
788
|
+
},
|
|
789
|
+
{
|
|
790
|
+
key: "cart-breakdown-aggregate-only",
|
|
791
|
+
label: "The expanded breakdown shows ONE line per fee type (Shipping, WhatsApp updates, Gift wrap, Platform fee, GST…) with a \"(N stores)\" qualifier where a fee applies to several sellers — not a separate block per store",
|
|
792
|
+
description: "Per-store detail belongs on each seller card, not in this panel. Confirm the two don't duplicate each other.",
|
|
793
|
+
href: "/cart",
|
|
794
|
+
},
|
|
795
|
+
{
|
|
796
|
+
key: "cart-breakdown-checked-items-only",
|
|
797
|
+
label: "Deselecting an item lowers the breakdown's item count and every affected line; deselecting ALL of one seller's items removes that seller's shipping and add-on fees from the total entirely",
|
|
798
|
+
description: "Use a two-seller cart. Deselect everything from seller B and confirm B's shipping leaves the breakdown and the total drops — the preview prices only what is actually being checked out.",
|
|
799
|
+
href: "/cart",
|
|
800
|
+
},
|
|
801
|
+
{
|
|
802
|
+
key: "cart-breakdown-no-coupon-on-locked-lanes",
|
|
803
|
+
label: "The Won Auctions and Accepted Offers tabs show no coupon-discount line in the breakdown (those prices are already won/negotiated)",
|
|
804
|
+
href: "/cart",
|
|
805
|
+
},
|
|
806
|
+
{
|
|
807
|
+
key: "cart-guest-breakdown-fallback",
|
|
808
|
+
label: "Signed out, the cart shows subtotals plus a \"Sign in to see shipping & fees\" note instead of fee lines — no error and no blank panel",
|
|
809
|
+
href: "/cart",
|
|
810
|
+
},
|
|
811
|
+
// --- Per-store add-ons ----------------------------------------------
|
|
812
|
+
{
|
|
813
|
+
key: "cart-store-card-fee-lines",
|
|
814
|
+
label: "Each seller card shows that seller's own shipping and add-on fees below its items, and those per-store figures add up to the matching lines in the expanded breakdown",
|
|
815
|
+
href: "/cart",
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
key: "cart-addons-per-store",
|
|
819
|
+
label: "Ticking \"WhatsApp order updates\" on ONE seller's card charges the fee once (₹10, not ₹20 on a two-seller cart) and shows it under that seller only",
|
|
820
|
+
description: "Requires Site Settings → Fees → WhatsApp notify fee enabled. Core regression guard: the selection used to be a single cart-wide checkbox while the fee was billed per seller, so one tick charged every store in the cart.",
|
|
821
|
+
href: "/cart",
|
|
822
|
+
},
|
|
823
|
+
{
|
|
824
|
+
key: "cart-addons-deselected-store-excluded",
|
|
825
|
+
label: "Deselecting all of a seller's items disables that seller's add-on checkboxes with an explanation and removes their fees from the total; re-selecting restores both",
|
|
826
|
+
href: "/cart",
|
|
827
|
+
},
|
|
828
|
+
{
|
|
829
|
+
key: "cart-addons-persist-to-checkout",
|
|
830
|
+
label: "Add-ons ticked per seller in the cart are still ticked against the SAME seller at checkout, and survive a page reload",
|
|
831
|
+
description: "Tick gift wrap for seller A only, go to checkout, confirm A's block is ticked and B's is not, then reload and confirm it holds.",
|
|
832
|
+
href: "/checkout",
|
|
833
|
+
},
|
|
834
|
+
{
|
|
835
|
+
key: "cart-addons-editable-at-checkout",
|
|
836
|
+
label: "Add-ons can still be changed on the checkout page itself, per seller — important because Buy Now skips the cart entirely",
|
|
837
|
+
description: "Use Buy Now on a product without touching the cart page, and confirm checkout still offers that seller's add-on checkboxes and that ticking one updates the Order Summary total.",
|
|
838
|
+
href: "/checkout",
|
|
839
|
+
},
|
|
840
|
+
{
|
|
841
|
+
key: "cart-addons-hidden-when-disabled",
|
|
842
|
+
label: "With an add-on disabled in Site Settings → Fees, its checkbox does not appear on any seller card in the cart or at checkout",
|
|
843
|
+
href: "/cart",
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
key: "cart-addons-order-record",
|
|
847
|
+
label: "After placing a multi-seller order, only the seller whose add-on was ticked has that fee on their order — the other seller's order shows no add-on fee",
|
|
848
|
+
href: "/user/orders",
|
|
849
|
+
},
|
|
850
|
+
{
|
|
851
|
+
key: "order-addon-icons-visible",
|
|
852
|
+
label: "An order that included add-ons shows icon chips for them (WhatsApp updates / Gift wrap / Protected) plus the coupon code, on the buyer's order page, the seller's order detail AND the admin order drawer",
|
|
853
|
+
description: "These are fulfilment instructions, not decoration: WhatsApp tells the notifier to message this buyer on status change, and gift wrap tells the packer to wrap the parcel. Check all three surfaces — they render from one shared component, so if one is missing something is unwired.",
|
|
854
|
+
href: "/user/orders",
|
|
855
|
+
},
|
|
856
|
+
{
|
|
857
|
+
key: "order-gift-message-visible-to-seller",
|
|
858
|
+
label: "When a buyer bought gift wrap and left a message, the seller sees the full message text on the order detail — not truncated and not hidden behind a tooltip",
|
|
859
|
+
description: "The packer has to physically write or enclose it, so it must be readable in full.",
|
|
860
|
+
href: "/store/orders",
|
|
861
|
+
},
|
|
862
|
+
{
|
|
863
|
+
key: "order-addons-queryable",
|
|
864
|
+
label: "Admin can filter the orders list down to orders that opted into a given add-on (e.g. only gift-wrap orders), so \"who do I need to do this for?\" is answered from the orders list itself and not a side list",
|
|
865
|
+
href: "/admin/orders",
|
|
866
|
+
},
|
|
867
|
+
{
|
|
868
|
+
key: "order-coupon-shown-all-lanes",
|
|
869
|
+
label: "A coupon applied to an order is shown on the order for every lane — standard, won-auction and accepted-offer orders alike",
|
|
870
|
+
href: "/user/orders",
|
|
871
|
+
},
|
|
872
|
+
// --- Platform fee ----------------------------------------------------
|
|
873
|
+
{
|
|
874
|
+
key: "platform-fee-capped",
|
|
875
|
+
label: "The buyer's platform fee stops at the configured maximum instead of scaling with cart value",
|
|
876
|
+
description: "With Site Settings → Fees at platform fee 5%, maximum platform fee ₹10, GST 18%: a ₹100 cart must show a ₹5.00 platform fee and ₹0.90 GST on it; a ₹700 cart must show ₹10.00 and ₹1.80 — NOT ₹35.00. Check the arithmetic, not just that a line exists.",
|
|
877
|
+
href: "/checkout",
|
|
878
|
+
},
|
|
879
|
+
{
|
|
880
|
+
key: "platform-fee-all-methods",
|
|
881
|
+
label: "The platform fee is charged on every payment method — COD, UPI-manual/cash and Razorpay all include it; COD additionally shows the COD handling fee and the 10% token",
|
|
882
|
+
description: "It used to be added only on the Razorpay path, so COD and UPI buyers were never charged it. Compare the same cart across each available method.",
|
|
883
|
+
href: "/checkout",
|
|
884
|
+
},
|
|
885
|
+
{
|
|
886
|
+
key: "platform-fee-charged-once",
|
|
887
|
+
label: "A three-seller cart is charged the platform fee ONCE for the checkout, not once per seller",
|
|
888
|
+
href: "/checkout",
|
|
889
|
+
},
|
|
890
|
+
{
|
|
891
|
+
key: "platform-fee-sums-across-orders",
|
|
892
|
+
label: "After placing a multi-seller order, the platform fees recorded on the resulting orders add up to exactly the single figure the cart and checkout showed — no rupee of drift",
|
|
893
|
+
href: "/user/orders",
|
|
894
|
+
},
|
|
895
|
+
// --- The money has to agree everywhere -------------------------------
|
|
896
|
+
{
|
|
897
|
+
key: "cart-checkout-order-totals-agree",
|
|
898
|
+
label: "For the same cart, the expanded cart breakdown, the sum of the per-seller card fee lines, the checkout Order Summary and the created orders all show the SAME total",
|
|
899
|
+
description: "Repeat on COD, UPI-manual and Razorpay. Acceptance test for the whole pricing change — if any two of those four disagree, something is reading a different source than it charges from.",
|
|
900
|
+
href: "/checkout",
|
|
901
|
+
},
|
|
582
902
|
],
|
|
583
903
|
},
|
|
584
904
|
{
|
|
@@ -767,6 +1087,87 @@ const rawTesterChecklistItems = [
|
|
|
767
1087
|
},
|
|
768
1088
|
],
|
|
769
1089
|
},
|
|
1090
|
+
{
|
|
1091
|
+
pageKey: "reviews-pagination",
|
|
1092
|
+
pageLabel: "Reviews — Pagination, Sort & Filter",
|
|
1093
|
+
// "Beyblade Original Dranzer S" is the deep-review fixture: 19 approved reviews
|
|
1094
|
+
// spread across all five star ratings, so it is the only product where page 2
|
|
1095
|
+
// and the rating filter have anything to show.
|
|
1096
|
+
href: "/products/product-beyblade-original-dranzer-s",
|
|
1097
|
+
cases: [
|
|
1098
|
+
{
|
|
1099
|
+
key: "detail-tab-paginates",
|
|
1100
|
+
label: "The Reviews tab on a product page shows at most 10 reviews with page controls underneath — it does NOT dump every review into one endlessly long tab",
|
|
1101
|
+
description: "Open the Dranzer S product page and click the Reviews tab. It has 19 approved reviews, so you should see 10 and a pager offering page 2. Before this change every approved review rendered at once, which is what made these pages so long.",
|
|
1102
|
+
},
|
|
1103
|
+
{
|
|
1104
|
+
key: "detail-tab-newest-first",
|
|
1105
|
+
label: "Reviews are ordered newest first by default (the dates run downward as you read down the list)",
|
|
1106
|
+
},
|
|
1107
|
+
{
|
|
1108
|
+
key: "detail-tab-page-2-differs",
|
|
1109
|
+
label: "Page 2 shows DIFFERENT reviews from page 1 — not a repeat of the same 10",
|
|
1110
|
+
description: "This is the one to be fussy about. The first page is server-rendered and handed to the browser cache; if that hand-off is wired wrong, page 2 silently re-displays page 1's reviews. Note the top review's title on page 1, go to page 2, and confirm it is not there.",
|
|
1111
|
+
},
|
|
1112
|
+
{
|
|
1113
|
+
key: "detail-tab-url-unchanged",
|
|
1114
|
+
label: "Paging through reviews on a product page does NOT change the page URL, and does not reload/flicker the rest of the product page (gallery, price, Add to Cart all stay put)",
|
|
1115
|
+
description: "Deliberate: on a detail page the review pager keeps its state in the component, because writing it to the URL would re-run the whole product page just to turn a page of reviews.",
|
|
1116
|
+
},
|
|
1117
|
+
{
|
|
1118
|
+
key: "detail-tab-sort",
|
|
1119
|
+
label: "The sort dropdown in the Reviews tab works — Newest / Oldest / Highest rated / Lowest rated each reorder the list correctly",
|
|
1120
|
+
},
|
|
1121
|
+
{
|
|
1122
|
+
key: "detail-tab-rating-filter",
|
|
1123
|
+
label: "Filtering by star rating in the Reviews tab works — picking 5★ shows only 5-star reviews, and the result count/pager updates to match",
|
|
1124
|
+
description: "Open the Filters drawer in the Reviews tab. The fixture has reviews at every star level from 1 to 5. If this shows an error or an empty list for every rating, the Firestore index for it has not been deployed yet — report that.",
|
|
1125
|
+
},
|
|
1126
|
+
{
|
|
1127
|
+
key: "detail-tab-summary-stable",
|
|
1128
|
+
label: "The average rating and total review count above the list describe ALL reviews — they do not shrink when you apply a rating filter",
|
|
1129
|
+
description: "Note the \"x.x / 5 · N reviews\" line, then filter to 5★ only. The list shortens but that summary line should stay the same, because it describes the product overall, not the current filter.",
|
|
1130
|
+
},
|
|
1131
|
+
{
|
|
1132
|
+
key: "detail-tab-filters-all-work",
|
|
1133
|
+
label: "Every control shown in the Reviews tab's Filters drawer actually does something — there is no filter you can set that changes nothing",
|
|
1134
|
+
description: "A filter that renders but is never applied looks broken to a buyer. Set each control in turn and confirm the list responds.",
|
|
1135
|
+
},
|
|
1136
|
+
{
|
|
1137
|
+
key: "date-range-sort-options",
|
|
1138
|
+
label: "While a review date range is set, the sort dropdown offers only the date-based sorts — and choosing a date range never produces an error page",
|
|
1139
|
+
description: "Set a From/To date in the Filters drawer. \"Highest rated\"/\"Lowest rated\" are withdrawn on purpose while a date range is active — the database cannot serve that combination, so it is hidden rather than allowed to fail.",
|
|
1140
|
+
},
|
|
1141
|
+
{
|
|
1142
|
+
key: "other-listing-types-paginate",
|
|
1143
|
+
label: "The Reviews tab paginates the same way on a digital-code and a live-item page, not just standard products",
|
|
1144
|
+
href: "/digital-codes/digitalcode-beyblade-x-app-unlock",
|
|
1145
|
+
},
|
|
1146
|
+
{
|
|
1147
|
+
key: "auction-store-reviews-paginated",
|
|
1148
|
+
label: "An auction page's \"Store Reviews\" section is paginated and genuinely newest-first — not a fixed block of 10 with no way to see more",
|
|
1149
|
+
description: "Previously this section showed exactly 10 reviews with no pager, and they were grouped by product rather than ordered by date, so the \"latest\" reviews were not actually the latest. Scroll to Store Reviews on this auction and confirm you can page through and that the dates run downward.",
|
|
1150
|
+
href: "/auctions/auction-beyblade-original-dragoon-storm",
|
|
1151
|
+
},
|
|
1152
|
+
{
|
|
1153
|
+
key: "store-reviews-tab-url-state",
|
|
1154
|
+
label: "On the store's own Reviews tab (a full page, not a tab inside a product), the page number and sort DO appear in the URL and survive a browser refresh / can be shared as a link",
|
|
1155
|
+
description: "Open the store below and click its Reviews tab. The opposite of the product-page behaviour above, and intentional: this is a page in its own right, so its state belongs in the URL. Go to page 2, refresh, and confirm you are still on page 2.",
|
|
1156
|
+
href: "/stores/store-beyblade-arena",
|
|
1157
|
+
},
|
|
1158
|
+
{
|
|
1159
|
+
key: "reviews-index-unchanged",
|
|
1160
|
+
label: "The site-wide /reviews page still works exactly as before — search, sort, filters, paging, and grid/list toggle",
|
|
1161
|
+
description: "This page was rebuilt on shared internals during the pagination work, so it is worth a regression pass even though nothing about it was meant to change.",
|
|
1162
|
+
href: "/reviews",
|
|
1163
|
+
},
|
|
1164
|
+
{
|
|
1165
|
+
key: "empty-state",
|
|
1166
|
+
label: "A product with no reviews yet shows \"No reviews yet — be the first to review this product.\" and no pager, rather than an empty box or a stray page control",
|
|
1167
|
+
href: "/products/product-beyblade-x-dran-sword-video-demo",
|
|
1168
|
+
},
|
|
1169
|
+
],
|
|
1170
|
+
},
|
|
770
1171
|
{
|
|
771
1172
|
pageKey: "messaging",
|
|
772
1173
|
pageLabel: "Messaging a Seller",
|
|
@@ -868,12 +1269,49 @@ const rawTesterChecklistItems = [
|
|
|
868
1269
|
{ key: "seller-quick-add-drawer-flips", label: "With Left-hand mode ON, the seller's quick-add-listing side drawer opens from the left instead of the right" },
|
|
869
1270
|
],
|
|
870
1271
|
},
|
|
1272
|
+
{
|
|
1273
|
+
pageKey: "seller-bids-bundles-filters",
|
|
1274
|
+
pageLabel: "Seller — Bids & Bundles Filtering",
|
|
1275
|
+
href: "/store/bids",
|
|
1276
|
+
cases: [
|
|
1277
|
+
{
|
|
1278
|
+
key: "seller-bids-status-filter",
|
|
1279
|
+
label: "The status filter on the seller Bids page actually narrows the list",
|
|
1280
|
+
description: "Fixed 2026-08-21. The status chips, the sort dropdown AND the bidder search box on this page were all inert — the server read none of the three, so every control silently returned the same unfiltered list. Pick a status and confirm the rows genuinely change.",
|
|
1281
|
+
href: "/store/bids",
|
|
1282
|
+
},
|
|
1283
|
+
{
|
|
1284
|
+
key: "seller-bids-sort-dropdown",
|
|
1285
|
+
label: "Changing the Sort dropdown on the seller Bids page reorders the rows",
|
|
1286
|
+
description: "The sort was hardcoded to bid date server-side regardless of what the dropdown said. Switch to a different sort (e.g. bid amount) and confirm the ordering visibly changes.",
|
|
1287
|
+
href: "/store/bids",
|
|
1288
|
+
},
|
|
1289
|
+
{
|
|
1290
|
+
key: "seller-bids-bidder-search",
|
|
1291
|
+
label: "Typing a bidder's name into the search box on the seller Bids page and pressing Enter narrows the list to that bidder",
|
|
1292
|
+
description: "Search matches from the START of the bidder name (a database limitation — mid-name fragments will not match), so type the first part of the name rather than a middle fragment.",
|
|
1293
|
+
href: "/store/bids",
|
|
1294
|
+
},
|
|
1295
|
+
{
|
|
1296
|
+
key: "seller-bundles-active-filter",
|
|
1297
|
+
label: "The Active / Inactive and \"Sold out\" chips on the seller Bundles page actually narrow the list",
|
|
1298
|
+
description: "Fixed 2026-08-21 — these chips existed and were clickable but the seller endpoint ignored them entirely, unlike the admin Bundles page which honoured the same chips. Compare the two pages: they should now behave identically.",
|
|
1299
|
+
href: "/store/bundles",
|
|
1300
|
+
},
|
|
1301
|
+
],
|
|
1302
|
+
},
|
|
871
1303
|
{
|
|
872
1304
|
pageKey: "seller-orders",
|
|
873
1305
|
pageLabel: "Seller Order Management & Shipping/Tracking",
|
|
874
1306
|
href: "/store/orders",
|
|
875
1307
|
cases: [
|
|
876
1308
|
{ key: "view-orders", label: "Seller order list shows accurate incoming orders", href: "/store/orders" },
|
|
1309
|
+
{
|
|
1310
|
+
key: "seller-auction-forfeit-notification",
|
|
1311
|
+
label: "When a winning bidder fails to pay by the deadline, the SELLER also receives a notification that the win was forfeited and the item is unsold",
|
|
1312
|
+
description: "Added 2026-08-21. Only the buyer was told, so to a seller a forfeited win looked like a completed sale that simply never paid out. Check the seller's notification bell after an auction win lapses — the message should say the item can be relisted or offered to the next highest bidder.",
|
|
1313
|
+
href: "/store/orders",
|
|
1314
|
+
},
|
|
877
1315
|
{
|
|
878
1316
|
key: "seller-order-manual-payment-badge",
|
|
879
1317
|
label: "A manual-payment (UPI/Cash) order's seller detail shows a payment badge — Awaiting payment / Awaiting verification / Verified / Re-upload requested / Rejected — next to the Payment heading, plus the UTR once the buyer submits one",
|
|
@@ -892,6 +1330,12 @@ const rawTesterChecklistItems = [
|
|
|
892
1330
|
description: "Added 2026-08-21 — sellers previously had no dedicated order-detail page, only a drawer, unlike buyer/admin. The drawer and the new page now share one content component (SellerOrderDetailPanel) so they can't drift.",
|
|
893
1331
|
href: "/store/orders",
|
|
894
1332
|
},
|
|
1333
|
+
{
|
|
1334
|
+
key: "seller-new-order-notification-reaches-seller",
|
|
1335
|
+
label: "A seller is actually told when an order lands — in-app AND by email — without having to sit refreshing the orders page",
|
|
1336
|
+
description: "Added 2026-08-21. Place an order against your store from a separate buyer account, then check the seller side WITHOUT opening /store/orders first: does the notification bell update, and does an email reach the seller account's inbox? A marketplace where sellers only discover orders by polling the dashboard is a real (and easily-missed) failure. Also confirm the notification/email names the buyer's item and links straight to that order.",
|
|
1337
|
+
href: "/store/orders",
|
|
1338
|
+
},
|
|
895
1339
|
],
|
|
896
1340
|
},
|
|
897
1341
|
{
|
|
@@ -928,6 +1372,24 @@ const rawTesterChecklistItems = [
|
|
|
928
1372
|
pageLabel: "Seller — All Listing Types (Coupons, Bundles, Classifieds, Digital Codes, Live, Prize Draws, Art, Stickers)",
|
|
929
1373
|
href: "/store/products",
|
|
930
1374
|
cases: [
|
|
1375
|
+
{
|
|
1376
|
+
key: "seller-listing-type-dropdown-all-types",
|
|
1377
|
+
label: "The \"Listing type\" dropdown on the seller Products page offers all nine types including Art and Stickers, and no longer offers \"Bundle\"",
|
|
1378
|
+
description: "Fixed 2026-08-21 — the dropdown was a hand-written list missing art and stickers, and still offered \"Bundle\", which is a category type rather than a listing type and therefore always returned zero rows. Open the dropdown and check every option returns results for a store that has that type.",
|
|
1379
|
+
href: "/store/products",
|
|
1380
|
+
},
|
|
1381
|
+
{
|
|
1382
|
+
key: "seller-products-badge-per-type",
|
|
1383
|
+
label: "Each row in the seller Products list shows a badge naming its real listing type — a classified row says \"classified\", a sticker row says \"stickers\", and so on",
|
|
1384
|
+
description: "Fixed 2026-08-21 — the row mapper collapsed classified, digital-code, live, art and stickers all down to \"standard\", so five of the nine types were mislabelled in the table. Create or find one listing of each type and confirm each badge is correct.",
|
|
1385
|
+
href: "/store/products",
|
|
1386
|
+
},
|
|
1387
|
+
{
|
|
1388
|
+
key: "seller-products-featured-promoted-sorts",
|
|
1389
|
+
label: "The seller Products \"Featured first\" and \"Promoted first\" sorts actually reorder the list",
|
|
1390
|
+
description: "Same fix as the admin equivalent — both sorts previously did nothing at all. Confirm the order genuinely changes.",
|
|
1391
|
+
href: "/store/products",
|
|
1392
|
+
},
|
|
931
1393
|
{ key: "seller-coupons-crud", label: "Seller can create, edit, and list their own coupons", href: "/store/coupons" },
|
|
932
1394
|
{
|
|
933
1395
|
key: "seller-coupon-auto-scoped-to-own-store",
|
|
@@ -1009,6 +1471,12 @@ const rawTesterChecklistItems = [
|
|
|
1009
1471
|
{ key: "seller-features-crud", label: "Seller can create and edit product features", href: "/store/features" },
|
|
1010
1472
|
{ key: "seller-google-reviews-sync", label: "Google Reviews sync pulls in real reviews correctly", href: "/store/google-reviews" },
|
|
1011
1473
|
{ key: "seller-whatsapp-catalog", label: "WhatsApp catalog import/push works", href: "/store/whatsapp" },
|
|
1474
|
+
{
|
|
1475
|
+
key: "seller-whatsapp-token-save",
|
|
1476
|
+
label: "Saving a WhatsApp access token on the store succeeds and comes back masked — it must not error out",
|
|
1477
|
+
description: "Added 2026-08-21. The store's WhatsApp access token is encrypted before storage by the same mechanism as the admin Integrations keys, and that mechanism was failing in production — so this save path was broken too, in a place nobody would think to check. Enter a throwaway token value, save, reload the page, and confirm you got a success toast and the field shows a masked value rather than an error or a blank field.",
|
|
1478
|
+
href: "/store/whatsapp",
|
|
1479
|
+
},
|
|
1012
1480
|
{ key: "seller-reviews-response", label: "Seller can view and respond to product reviews", href: "/store/reviews" },
|
|
1013
1481
|
],
|
|
1014
1482
|
},
|
|
@@ -1131,6 +1599,24 @@ const rawTesterChecklistItems = [
|
|
|
1131
1599
|
{ key: "notification-channel-prefs", label: "Per-channel notification preferences (in-app / email / WhatsApp) save and are respected" },
|
|
1132
1600
|
{ key: "notification-type-sample", label: "A sample of notification types (order status change, bid outbid, message received, payout) each trigger correctly end-to-end" },
|
|
1133
1601
|
{ key: "notification-tab-filters", label: "Notification tab filters correctly narrow the list", href: "/user/notifications" },
|
|
1602
|
+
{
|
|
1603
|
+
key: "notification-email-actually-arrives",
|
|
1604
|
+
label: "With email enabled for a notification type, the email really lands in your inbox — and comes from the site's configured sender name and address",
|
|
1605
|
+
description: "Added 2026-08-21. Existing cases only checked that the preference SAVES and that the in-app notification appears; nobody ever checked the email itself leaves the building. Turn email on for one notification type, trigger that event for real (e.g. have a seller mark your order shipped), then open the actual inbox for the address on your account. Confirm: (a) an email arrives within a few minutes; (b) the From name and address match what Site Settings → Notifications is configured with, not a stranger's domain or a bare no-reply; (c) it landed in the inbox, not spam; (d) the links inside it open the right page on the live site and don't 404.",
|
|
1606
|
+
href: "/user/notifications",
|
|
1607
|
+
},
|
|
1608
|
+
{
|
|
1609
|
+
key: "notification-email-opt-out-respected",
|
|
1610
|
+
label: "Turning email OFF for a notification type stops the emails but still shows the in-app notification",
|
|
1611
|
+
description: "Added 2026-08-21. The two channels are meant to be independent — opting out of email must never silently opt you out of the in-app bell too. Turn email off for a type you can trigger on demand, trigger it, then confirm: no new email arrives, but the notification still appears in /user/notifications. Then turn it back on, trigger again, and confirm the email resumes — an opt-out that can't be reversed is just as much a bug.",
|
|
1612
|
+
href: "/user/notifications",
|
|
1613
|
+
},
|
|
1614
|
+
{
|
|
1615
|
+
key: "notification-links-to-right-entity",
|
|
1616
|
+
label: "Clicking a notification opens the exact order / bid / message it refers to — not a generic list page",
|
|
1617
|
+
description: "Added 2026-08-21. Click through several different notification types and confirm each one lands on the specific record it names. A notification that says \"Your order was shipped\" must open THAT order, not /user/orders. Also confirm nothing dead-ends on a 404 or an \"unauthorized\" page.",
|
|
1618
|
+
href: "/user/notifications",
|
|
1619
|
+
},
|
|
1134
1620
|
],
|
|
1135
1621
|
},
|
|
1136
1622
|
{
|
|
@@ -1184,6 +1670,17 @@ const rawTesterChecklistItems = [
|
|
|
1184
1670
|
{ key: "error-states", label: "Error states (404, form validation) look correct" },
|
|
1185
1671
|
{ key: "card-row-heights-aligned", label: "Product/auction/pre-order/event cards in the same row are the same height, with their action button (Reserve now, Place bid, View details, etc.) aligned along a common bottom edge even when one card's description is longer than another's" },
|
|
1186
1672
|
{ key: "image-watermark-subtle", label: "Product and listing images show a small, subtle watermark (not oversized or fully opaque, doesn't obscure the image)" },
|
|
1673
|
+
{
|
|
1674
|
+
key: "clickable-image-tiles-not-blank",
|
|
1675
|
+
label: "Every CLICKABLE image tile across the site shows its picture, not an empty box — check all six surfaces listed below",
|
|
1676
|
+
description: "Fixed 2026-08-21. All of these are the same shape (a small image inside a clickable tile) and all broke together, so they must be re-checked together: (1) the mini thumbnail strip under a product's main gallery image; (2) the \"Photos (N)\" grid on a review detail page, AND the thumbnail strip along the bottom of that page's photo lightbox; (3) the image thumbnails inside a review popup/modal; (4) the tile grid on a prize-draw's collage of prizes; (5) the tile grid on a bundle's collage of included items; (6) the \"choose an existing file\" grid in the media picker when adding an image as a seller/admin. In every case the picture itself must be visible — a bordered but empty square is a fail.",
|
|
1677
|
+
href: "/products/product-beyblade-burst-valkyrie",
|
|
1678
|
+
},
|
|
1679
|
+
{
|
|
1680
|
+
key: "icon-button-label-spacing",
|
|
1681
|
+
label: "Buttons that show an icon next to their text have a normal gap between the icon and the word — the two are not jammed together",
|
|
1682
|
+
description: "Same 2026-08-21 fix as the blank image tiles: the button's spacing setting had stopped reaching its contents, so icon+label buttons were rendering with no gap at all. Scan a few pages with icon buttons (product detail actions, dashboard toolbars, the cart) and confirm the spacing looks deliberate rather than cramped.",
|
|
1683
|
+
},
|
|
1187
1684
|
{ key: "section-cta-buttons-visible", label: "Homepage section \"View all →\" / \"Go to…\" buttons use a solid primary-colored fill so they're clearly identifiable as clickable CTAs, not a plain white/outline box that blends into the page" },
|
|
1188
1685
|
{
|
|
1189
1686
|
key: "mobile-search-bar-proportions",
|
|
@@ -1192,6 +1689,197 @@ const rawTesterChecklistItems = [
|
|
|
1192
1689
|
},
|
|
1193
1690
|
],
|
|
1194
1691
|
},
|
|
1692
|
+
{
|
|
1693
|
+
pageKey: "sticky-cta-bar",
|
|
1694
|
+
pageLabel: "Sticky Buy/Bid Bar on Scroll",
|
|
1695
|
+
href: "/products/product-beyblade-original-dranzer-s",
|
|
1696
|
+
cases: [
|
|
1697
|
+
{
|
|
1698
|
+
key: "desktop-hidden-at-top",
|
|
1699
|
+
label: "ON DESKTOP: when a product page first loads, there is NO floating bar across the bottom of the window — the page looks exactly as it always has",
|
|
1700
|
+
description: "Use a full-size browser window (not a phone or a narrow window). The bar is meant to stay out of the way while the real Add to Cart / Buy Now buttons are still visible on screen.",
|
|
1701
|
+
},
|
|
1702
|
+
{
|
|
1703
|
+
key: "desktop-appears-on-scroll",
|
|
1704
|
+
label: "ON DESKTOP: after scrolling down past the product images and buy buttons, a bar slides up from the bottom of the window with the price and the same Add to Cart / Buy Now actions",
|
|
1705
|
+
description: "This is the whole point of the change: on a long page the buy buttons used to scroll away with no way back except scrolling up.",
|
|
1706
|
+
},
|
|
1707
|
+
{
|
|
1708
|
+
key: "desktop-hides-scrolling-back-up",
|
|
1709
|
+
label: "ON DESKTOP: scrolling back to the top of the page slides the bar away again",
|
|
1710
|
+
},
|
|
1711
|
+
{
|
|
1712
|
+
key: "desktop-buttons-work",
|
|
1713
|
+
label: "ON DESKTOP: the buttons in the floating bar actually work — Add to Cart adds the item, Buy Now starts checkout, and the wishlist button saves it",
|
|
1714
|
+
description: "They should behave identically to the buttons in the main product panel, including going disabled for an out-of-stock item.",
|
|
1715
|
+
},
|
|
1716
|
+
{
|
|
1717
|
+
key: "desktop-not-covering-footer",
|
|
1718
|
+
label: "ON DESKTOP: scrolling to the very bottom of the page, the floating bar does not permanently cover the footer — you can still read and click footer links",
|
|
1719
|
+
},
|
|
1720
|
+
{
|
|
1721
|
+
key: "mobile-unchanged",
|
|
1722
|
+
label: "ON MOBILE: the bottom action bar behaves exactly as it did before — visible while you browse the product, sitting above the bottom navigation, not overlapping it",
|
|
1723
|
+
description: "Regression check. Nothing about the phone experience was supposed to change; only desktop gained the bar.",
|
|
1724
|
+
},
|
|
1725
|
+
{
|
|
1726
|
+
key: "auction-countdown-in-bar",
|
|
1727
|
+
label: "On an auction page the sticky bar shows the live countdown (\"Ends in …\"), the current bid and bid count, and its Place Bid button jumps to the bidding form",
|
|
1728
|
+
description: "The countdown should tick, not sit frozen.",
|
|
1729
|
+
href: "/auctions/auction-beyblade-original-dragoon-storm",
|
|
1730
|
+
},
|
|
1731
|
+
{
|
|
1732
|
+
key: "ended-auction-no-bar",
|
|
1733
|
+
label: "An auction that has already ended shows NO sticky bar at all — there is nothing left to bid on",
|
|
1734
|
+
href: "/auctions/auction-tester-sandbox-won",
|
|
1735
|
+
},
|
|
1736
|
+
{
|
|
1737
|
+
key: "preorder-bar",
|
|
1738
|
+
label: "A pre-order page's sticky bar says Reserve Now and shows the price, and the button jumps to the reserve panel",
|
|
1739
|
+
href: "/pre-orders/preorder-tester-sandbox-1",
|
|
1740
|
+
},
|
|
1741
|
+
{
|
|
1742
|
+
key: "prize-draw-bar-label",
|
|
1743
|
+
label: "A prize-draw page's sticky bar CTA reads \"Enter Draw\" (not \"Buy Now\") and the info line shows the price per entry",
|
|
1744
|
+
description: "Label changed on purpose — you are entering a draw, not buying a specific item. Flag it if \"Buy Now\" still appears.",
|
|
1745
|
+
href: "/prize-draws/prizedraw-tester-sandbox-1",
|
|
1746
|
+
},
|
|
1747
|
+
{
|
|
1748
|
+
key: "closed-prize-draw-no-bar",
|
|
1749
|
+
label: "A closed prize draw shows NO sticky bar",
|
|
1750
|
+
href: "/prize-draws/prizedraw-tester-sandbox-closed",
|
|
1751
|
+
},
|
|
1752
|
+
{
|
|
1753
|
+
key: "classified-bar-no-cart",
|
|
1754
|
+
label: "A classified listing's sticky bar offers \"Make an Offer\" and does NOT offer Add to Cart or Buy Now — classifieds are arranged directly with the seller",
|
|
1755
|
+
description: "Tapping it should jump to the contact-seller panel. An Add to Cart button appearing here is a real bug.",
|
|
1756
|
+
href: "/classified/classified-tester-sandbox-1",
|
|
1757
|
+
},
|
|
1758
|
+
{
|
|
1759
|
+
key: "digital-code-bar",
|
|
1760
|
+
label: "A digital-code listing has a sticky Buy Now bar, and a sold-out one has no bar at all",
|
|
1761
|
+
href: "/digital-codes/digitalcode-tester-sandbox-1",
|
|
1762
|
+
},
|
|
1763
|
+
{
|
|
1764
|
+
key: "live-item-bar",
|
|
1765
|
+
label: "A live-item listing has a sticky Buy Now bar that jumps to its buy panel",
|
|
1766
|
+
href: "/live/live-tester-sandbox-1",
|
|
1767
|
+
},
|
|
1768
|
+
{
|
|
1769
|
+
key: "bar-not-overlapping-content",
|
|
1770
|
+
label: "On every page above, nothing at the bottom of the page is left permanently hidden behind the sticky bar — you can always scroll far enough to read the last line of content",
|
|
1771
|
+
},
|
|
1772
|
+
{
|
|
1773
|
+
key: "no-bar-on-non-listing-pages",
|
|
1774
|
+
label: "Pages that never had a bottom bar still do not have one — homepage, blog posts, FAQ, and the site-wide listing pages show no floating buy bar on desktop",
|
|
1775
|
+
description: "The bar is opt-in per page; a stray one on the homepage would be a bug.",
|
|
1776
|
+
href: "/",
|
|
1777
|
+
},
|
|
1778
|
+
{
|
|
1779
|
+
key: "bar-with-keyboard-open",
|
|
1780
|
+
label: "ON MOBILE: opening the on-screen keyboard (e.g. tapping a bid amount or search field) does not leave the sticky bar floating in the middle of the screen or hidden behind the keyboard",
|
|
1781
|
+
},
|
|
1782
|
+
],
|
|
1783
|
+
},
|
|
1784
|
+
{
|
|
1785
|
+
pageKey: "status-badge-legibility",
|
|
1786
|
+
pageLabel: "Listing Tags & Status Chips — Light vs Dark Mode",
|
|
1787
|
+
href: "/products",
|
|
1788
|
+
cases: [
|
|
1789
|
+
{
|
|
1790
|
+
key: "listing-type-tags-readable-light",
|
|
1791
|
+
label: "IN LIGHT MODE: on the main Products grid, every listing-type tag on a card — Auction, Pre-Order, Live Item, Digital Code, Prize Draw, Classified, Art Print, Sticker Sheet — is clearly readable, with a solid colored pill behind dark-enough text",
|
|
1792
|
+
description: "This is the headline fix for 2026-08-21. Reported as \"the auction tag / live tag is white text on a white pill, or a faint grey you cannot read.\" Switch the site to LIGHT mode first (theme toggle in the header) — the bug only appeared there. Read every tag out loud; a tag you have to squint at, tilt the screen for, or that shows text with no pill behind it at all, is still a bug.",
|
|
1793
|
+
href: "/products",
|
|
1794
|
+
},
|
|
1795
|
+
{
|
|
1796
|
+
key: "listing-type-tags-readable-dark",
|
|
1797
|
+
label: "IN DARK MODE: the same listing-type tags on the Products grid are still clearly readable — fixing light mode must not have broken dark mode",
|
|
1798
|
+
description: "Regression check, and a real risk here: the two modes use inverted color tokens, so it is genuinely possible to fix one and break the other. Toggle between light and dark a few times on the same page and confirm every tag survives both.",
|
|
1799
|
+
href: "/products",
|
|
1800
|
+
},
|
|
1801
|
+
{
|
|
1802
|
+
key: "live-item-tag-has-background",
|
|
1803
|
+
label: "The \"Live Item\" tag has an actual colored pill behind it — not bare red text floating directly on the product photo with no background",
|
|
1804
|
+
description: "This tag was a separate bug from the others: its background color name did not exist at all, so the browser threw the style away and rendered nothing behind the text. Easiest to spot on a card whose photo is busy or light-colored.",
|
|
1805
|
+
href: "/live",
|
|
1806
|
+
},
|
|
1807
|
+
{
|
|
1808
|
+
key: "promo-badges-readable",
|
|
1809
|
+
label: "IN LIGHT MODE: the small promotional badges on product cards — NEW, SALE, LIMITED, the bundle discount percentage, an auction's \"Ending soon\" / \"Reserve\" pill — are all readable against their colored background",
|
|
1810
|
+
href: "/products",
|
|
1811
|
+
},
|
|
1812
|
+
{
|
|
1813
|
+
key: "notification-count-bubbles-readable",
|
|
1814
|
+
label: "The unread-count bubbles (the small number circles on the header bell icon, the Messages nav item, and the cart/bottom action bar) show a readable number in BOTH light and dark mode — not a colored blob with an invisible digit",
|
|
1815
|
+
description: "You need at least one unread notification or message for the bubble to appear. Check both themes.",
|
|
1816
|
+
href: "/user/messages",
|
|
1817
|
+
},
|
|
1818
|
+
{
|
|
1819
|
+
key: "admin-status-chips-colored",
|
|
1820
|
+
label: "Admin and seller listing pages show status chips (Pending / Verified / Resolved / High priority / Featured / Sale, etc.) as genuinely COLORED pills — amber for pending, green for success, red for problems — not plain uncolored text",
|
|
1821
|
+
description: "Found 2026-08-21: a configuration gap meant every one of these colored chips authored inside the shared component library compiled to no CSS at all, so they had silently always rendered as plain unstyled text. Spot-check across a few pages: /admin/support-tickets, /admin/scammers, /admin/orders, /store/orders.",
|
|
1822
|
+
href: "/admin/support-tickets",
|
|
1823
|
+
},
|
|
1824
|
+
{
|
|
1825
|
+
key: "faq-helpful-buttons-readable",
|
|
1826
|
+
label: "On a FAQ, after clicking Yes or No on \"Was this helpful?\", the button you picked stays readable in BOTH light and dark mode — the selected button is a solid color with legible text, not white-on-pale",
|
|
1827
|
+
href: "/faqs",
|
|
1828
|
+
},
|
|
1829
|
+
{
|
|
1830
|
+
key: "detail-page-tags-readable",
|
|
1831
|
+
label: "Opening an individual auction, pre-order, prize draw, classified, digital code and live-item page, each one's type tag and status chips are readable in light mode",
|
|
1832
|
+
description: "Card grids and detail pages don't always share the same component, so check both. Use the sandbox listings linked from the Tester Hub if you need one of each type.",
|
|
1833
|
+
href: "/auctions/auction-beyblade-original-dragoon-storm",
|
|
1834
|
+
},
|
|
1835
|
+
{
|
|
1836
|
+
key: "whatsapp-community-member-pill",
|
|
1837
|
+
label: "IN LIGHT MODE: on the homepage's green WhatsApp community card, the member-count pill in its top-right corner (e.g. \"5,000+ members\") is readable — white text on a translucent darker pill, not white text on a white pill",
|
|
1838
|
+
description: "Reported alongside the tag bug: this pill was invisible in light mode. The people icon next to the number should be visible too.",
|
|
1839
|
+
href: "/",
|
|
1840
|
+
},
|
|
1841
|
+
{
|
|
1842
|
+
key: "image-lightbox-close-hover",
|
|
1843
|
+
label: "Opening a product image in the full-screen lightbox and hovering the X close button, the X stays visible as the button turns red — it does not vanish on hover",
|
|
1844
|
+
href: "/products/product-beyblade-original-dranzer-s",
|
|
1845
|
+
},
|
|
1846
|
+
],
|
|
1847
|
+
},
|
|
1848
|
+
{
|
|
1849
|
+
pageKey: "back-to-top-button",
|
|
1850
|
+
pageLabel: "Back-to-Top Button",
|
|
1851
|
+
href: "/products",
|
|
1852
|
+
cases: [
|
|
1853
|
+
{
|
|
1854
|
+
key: "appears-and-clickable-on-long-page",
|
|
1855
|
+
label: "Scrolling down a long listing page, the floating back-to-top arrow appears in the bottom corner AND actually responds to a click — it is not sitting behind the bottom navigation bar, a sticky toolbar, or a buy bar",
|
|
1856
|
+
description: "Fixed 2026-08-21 — it previously shared a stacking level with the bottom navigation bar, so on many pages it was either partly covered or completely unclickable. Try it on a page that also has a sticky bottom bar (a product page scrolled down) — that is where it used to fail.",
|
|
1857
|
+
href: "/products",
|
|
1858
|
+
},
|
|
1859
|
+
{
|
|
1860
|
+
key: "above-sticky-buy-bar",
|
|
1861
|
+
label: "On a product page scrolled far enough for BOTH the sticky buy bar and the back-to-top arrow to be showing, the arrow sits above/clear of the buy bar rather than being hidden underneath it",
|
|
1862
|
+
href: "/products/product-beyblade-original-dranzer-s",
|
|
1863
|
+
},
|
|
1864
|
+
{
|
|
1865
|
+
key: "scrolls-to-top",
|
|
1866
|
+
label: "Clicking the back-to-top arrow smoothly scrolls the page back to the very top",
|
|
1867
|
+
href: "/products",
|
|
1868
|
+
},
|
|
1869
|
+
{
|
|
1870
|
+
key: "dismiss-returns-on-navigation",
|
|
1871
|
+
label: "Clicking the small X next to the back-to-top arrow hides it for the current page, and navigating to a different page brings it back",
|
|
1872
|
+
description: "Regression check on an older fix — dismissing it must not hide it for the rest of the browsing session.",
|
|
1873
|
+
href: "/products",
|
|
1874
|
+
},
|
|
1875
|
+
{
|
|
1876
|
+
key: "not-covering-toast-or-modal-actions",
|
|
1877
|
+
label: "The back-to-top arrow does not cover anything you need to click — check that a toast message, an open confirmation dialog's buttons, and the footer's bottom-right links are all still fully clickable while it is on screen",
|
|
1878
|
+
description: "It was deliberately raised to the frontmost layer, so this is the specific risk that change introduces. It should only ever float in the empty corner gutter.",
|
|
1879
|
+
href: "/products",
|
|
1880
|
+
},
|
|
1881
|
+
],
|
|
1882
|
+
},
|
|
1195
1883
|
{
|
|
1196
1884
|
pageKey: "form-validation-errors",
|
|
1197
1885
|
pageLabel: "Form Validation & Error Summary",
|
|
@@ -1281,6 +1969,27 @@ const rawTesterChecklistItems = [
|
|
|
1281
1969
|
description: "Added 2026-08-20 — GITHUB was a new socialUrls key with no footer icon before this. Confirm the icon renders (not a broken/missing glyph) and the link target is a real, working github.com profile, not a placeholder or dead link.",
|
|
1282
1970
|
href: "/",
|
|
1283
1971
|
},
|
|
1972
|
+
{
|
|
1973
|
+
key: "footer-text-weight-readable",
|
|
1974
|
+
label: "Footer text is comfortably readable, not thin and washed out — the link lists, the brand description paragraph, the copyright line and the small sitemap/legal links at the very bottom all render in a slightly heavier weight than plain body text",
|
|
1975
|
+
description: "Changed 2026-08-21 — the footer's greyed text was previously at the lightest weight, which made it hard to read against the page background, especially on a laptop screen at an angle. Compare the footer against the same grey text elsewhere on the page; the footer should read as more solid, without looking bold.",
|
|
1976
|
+
href: "/",
|
|
1977
|
+
},
|
|
1978
|
+
{
|
|
1979
|
+
key: "footer-column-headings-stand-out",
|
|
1980
|
+
label: "On DESKTOP, each footer link column's heading (Shop, Company, Support, etc.) clearly stands out as a heading above its list of links, rather than looking like just another link in the list",
|
|
1981
|
+
href: "/",
|
|
1982
|
+
},
|
|
1983
|
+
{
|
|
1984
|
+
key: "footer-weight-both-themes",
|
|
1985
|
+
label: "The footer text weight change looks right in BOTH light and dark mode — heavier but not bold, and it never turns into an unreadable smudge in dark mode",
|
|
1986
|
+
href: "/",
|
|
1987
|
+
},
|
|
1988
|
+
{
|
|
1989
|
+
key: "footer-mobile-accordions",
|
|
1990
|
+
label: "ON MOBILE, the footer's collapsible link sections still open and close correctly, and their links are as readable as the desktop columns",
|
|
1991
|
+
href: "/",
|
|
1992
|
+
},
|
|
1284
1993
|
],
|
|
1285
1994
|
},
|
|
1286
1995
|
{
|
|
@@ -1393,6 +2102,12 @@ const rawTesterChecklistItems = [
|
|
|
1393
2102
|
href: "/",
|
|
1394
2103
|
cases: [
|
|
1395
2104
|
{ key: "homepage-loads", label: "The homepage loads without errors on both desktop and mobile", href: "/" },
|
|
2105
|
+
{
|
|
2106
|
+
key: "whatsapp-community-link-real",
|
|
2107
|
+
label: "The \"Join the Community\" WhatsApp button on the homepage opens the real LetItRip WhatsApp group, not a dead link",
|
|
2108
|
+
description: "Fixed 2026-08-21 — the seeded link was a placeholder that was never a valid WhatsApp invite code, so the button opened a page that could not resolve to any group. Tap it on a device with WhatsApp installed and confirm it offers to join an actual group. The Contact page's WhatsApp link must open the same group.",
|
|
2109
|
+
href: "/",
|
|
2110
|
+
},
|
|
1396
2111
|
{ key: "about-us-in-main-nav", label: "\"About Us\" appears as an item in the main public top navigation, not just the footer", href: "/about" },
|
|
1397
2112
|
{
|
|
1398
2113
|
key: "about-team-real-founder",
|
|
@@ -1444,12 +2159,64 @@ const rawTesterChecklistItems = [
|
|
|
1444
2159
|
cases: [
|
|
1445
2160
|
{ key: "store-directory", label: "The store directory page loads correctly", href: "/stores" },
|
|
1446
2161
|
{ key: "store-detail-tabs", label: "A store detail page's listing-type dropdown (Products/Auctions/Pre-Orders/Prize Draws/Bundles/Classifieds/Digital Codes/Live Items/Art & Stickers) switches correctly between listing types, and the separate Coupons/Reviews/About tabs next to it all load correctly", description: "The listing-type dropdown is always a dropdown (not just on narrow/mobile widths, unlike category/brand/product/event tabs) since a store can have up to 9 listing types — Coupons, Reviews, and About stay as standalone tabs beside it, never folded into the dropdown." },
|
|
2162
|
+
{
|
|
2163
|
+
key: "category-tabs-every-type-renders",
|
|
2164
|
+
label: "On a category page, EVERY listing-type tab that is offered renders real content when opened — none show a blank panel",
|
|
2165
|
+
description: "Fixed 2026-08-21 — the Classifieds, Digital Codes, Live Items and Art & Stickers tabs were clickable but had no content behind them, so selecting one highlighted the tab and showed nothing at all. Open every tab the page offers, one by one.",
|
|
2166
|
+
href: "/categories/category-beyblade-burst",
|
|
2167
|
+
},
|
|
2168
|
+
{
|
|
2169
|
+
key: "brand-tabs-every-type-offered",
|
|
2170
|
+
label: "A brand page offers the same listing-type tabs a category page does (minus Stores) — Classifieds, Digital Codes, Live Items and Art & Stickers are not silently missing",
|
|
2171
|
+
description: "Fixed 2026-08-21 — the brand page dropped those four tabs entirely rather than rendering them, so those listing types were unreachable from any brand. Compare the tab row on a brand page against the same brand's category page.",
|
|
2172
|
+
href: "/brands/brand-beyblade",
|
|
2173
|
+
},
|
|
2174
|
+
{
|
|
2175
|
+
key: "category-brand-tab-counts-match",
|
|
2176
|
+
label: "Each category/brand tab's count badge matches the number of items the tab actually shows",
|
|
2177
|
+
href: "/categories/category-beyblade-burst",
|
|
2178
|
+
},
|
|
1447
2179
|
{
|
|
1448
2180
|
key: "empty-tabs-hidden",
|
|
1449
2181
|
label: "A store/category/brand detail page never shows a tab for a listing type it has zero items of — e.g. a store with no products doesn't show a \"Products\" tab at all, not an empty products page",
|
|
1450
2182
|
description: "Fixed 2026-08-20 — tab visibility now checks the already-fetched per-type count and omits the tab entirely when it's zero, instead of always rendering all tabs regardless of whether they'd show anything. \"About\" always stays visible on store pages (no item-count concept). Verify on a real store/category/brand that's genuinely missing at least one listing type.",
|
|
1451
2183
|
href: "/stores",
|
|
1452
2184
|
},
|
|
2185
|
+
{
|
|
2186
|
+
key: "store-art-stickers-tab-shows-items",
|
|
2187
|
+
label: "A store's \"Art & Stickers\" tab opens a real page with art and sticker items on it — not an empty grid or a page full of ordinary products",
|
|
2188
|
+
description: "Fixed 2026-08-21 — the tab showed a genuine non-zero count but linked to the store's Products tab, which filters to standard products only, so it always landed on a page containing none of the items it had just counted. It now has its own /stores/{slug}/art page.",
|
|
2189
|
+
href: "/stores/store-beyblade-arena/art",
|
|
2190
|
+
},
|
|
2191
|
+
{
|
|
2192
|
+
key: "store-tab-counts-match-contents",
|
|
2193
|
+
label: "Every store tab's count badge matches what the tab actually contains — open each of Products, Auctions, Pre-Orders, Prize Draws, Classifieds, Digital Codes, Live Items, Art & Stickers and Bundles in turn",
|
|
2194
|
+
description: "A tab showing \"5\" and then rendering an empty grid (or somebody else's items) is the bug class this checks for. Any mismatch is a failure.",
|
|
2195
|
+
href: "/stores/store-beyblade-arena",
|
|
2196
|
+
},
|
|
2197
|
+
{
|
|
2198
|
+
key: "store-tab-sort-survives-reload",
|
|
2199
|
+
label: "Changing the sort on a store tab and reloading the page keeps that sort applied — the first paint matches what the Sort dropdown shows",
|
|
2200
|
+
description: "Fixed 2026-08-21 — store tab pages ignored the URL when rendering server-side, so a reload always painted page 1 in the default order while the toolbar still displayed the sort you had picked. Set a non-default sort, reload, and confirm the item order matches the dropdown.",
|
|
2201
|
+
href: "/stores/store-beyblade-arena/auctions",
|
|
2202
|
+
},
|
|
2203
|
+
{
|
|
2204
|
+
key: "store-preorders-tab-default-sort",
|
|
2205
|
+
label: "A store's Pre-Orders tab opens in the same default order as the public /pre-orders page (earliest delivery first)",
|
|
2206
|
+
description: "Fixed 2026-08-21 — the store tab had its own drifted copy of the sort list and opened Newest-first while /pre-orders opened Earliest-Delivery-first for the same items. Compare the two side by side; the first item should match.",
|
|
2207
|
+
href: "/stores/store-beyblade-arena/pre-orders",
|
|
2208
|
+
},
|
|
2209
|
+
{
|
|
2210
|
+
key: "store-classified-live-facets-filter",
|
|
2211
|
+
label: "The type-specific filters on a store's Classifieds and Live Items tabs actually narrow the results (city / negotiable / accepts shipping, and species / sex / jurisdiction)",
|
|
2212
|
+
description: "Fixed 2026-08-21 — these were rendered and counted toward the Filters badge but never sent to the server, so they changed nothing. Apply one and confirm the grid genuinely shrinks.",
|
|
2213
|
+
href: "/stores/store-beyblade-arena/classified",
|
|
2214
|
+
},
|
|
2215
|
+
{
|
|
2216
|
+
key: "store-tab-empty-state-not-error",
|
|
2217
|
+
label: "A store tab with genuinely no items shows a friendly empty state — never a blank white area, a spinner that never stops, or an error toast about a missing index",
|
|
2218
|
+
href: "/stores/store-tester-qa-seller",
|
|
2219
|
+
},
|
|
1453
2220
|
{ key: "sellers-directory", label: "The sellers directory page loads correctly", href: "/sellers" },
|
|
1454
2221
|
{ key: "seller-detail-page", label: "An individual seller's public detail page loads correctly" },
|
|
1455
2222
|
{ key: "scams-registry", label: "The scams registry page and an individual scam detail page load correctly", href: "/scams" },
|
|
@@ -1531,6 +2298,48 @@ const rawTesterChecklistItems = [
|
|
|
1531
2298
|
description: "Verify against the seeded \"Test Inactive Category\" fixture (isActive:false) — it should only appear when the Active filter is switched to show inactive categories.",
|
|
1532
2299
|
href: "/admin/categories",
|
|
1533
2300
|
},
|
|
2301
|
+
{
|
|
2302
|
+
key: "admin-products-type-chips-all-types",
|
|
2303
|
+
label: "The admin Products \"Type\" filter lists all nine listing types including Art and Stickers, and does NOT offer \"Bundles\"",
|
|
2304
|
+
description: "Fixed 2026-08-21 — the chips used display labels as the underlying filter values, and had no entry at all for art or stickers, so admin could never filter to either. Bundles are a category type, not a listing type; a Bundles chip here would always return zero rows.",
|
|
2305
|
+
href: "/admin/products",
|
|
2306
|
+
},
|
|
2307
|
+
{
|
|
2308
|
+
key: "admin-products-type-chips-multi-select",
|
|
2309
|
+
label: "The admin Products \"Type\" chips are multi-select — ticking Auctions AND Prize Draws lists both, and every single chip on its own returns rows (never zero)",
|
|
2310
|
+
description: "Tick each of the nine chips one at a time and confirm each returns results (given seeded data exists for that type). A chip that always returns nothing means its value no longer matches what the database stores.",
|
|
2311
|
+
href: "/admin/products",
|
|
2312
|
+
},
|
|
2313
|
+
{
|
|
2314
|
+
key: "admin-products-featured-promoted-sorts",
|
|
2315
|
+
label: "The admin Products \"Featured first\" and \"Promoted first\" sorts actually reorder the list — featured/promoted items move to the top",
|
|
2316
|
+
description: "Fixed 2026-08-21 — both options existed in the code but targeted fields that were not sortable, so the sort was silently discarded and the list never changed order. Toggle a couple of items' Featured flags first so there is something to sort, then pick the sort and confirm they rise to the top.",
|
|
2317
|
+
href: "/admin/products",
|
|
2318
|
+
},
|
|
2319
|
+
{
|
|
2320
|
+
key: "admin-per-type-pages-have-filters",
|
|
2321
|
+
label: "The admin Art, Stickers, Classified, Digital Codes and Live Items pages each have a working Status filter and a sort dropdown, and clicking a row opens the product editor",
|
|
2322
|
+
description: "Fixed 2026-08-21 — all five pages were near-identical copies with no filter drawer at all. They now share one config. Check each page: a Status filter exists, sorting works, and a row click lands on the real product edit page.",
|
|
2323
|
+
href: "/admin/art",
|
|
2324
|
+
},
|
|
2325
|
+
{
|
|
2326
|
+
key: "admin-listing-reset-restores-defaults",
|
|
2327
|
+
label: "The \"Reset\" button on an admin listing returns it to exactly what a fresh page load shows — not to a wider, unfiltered list",
|
|
2328
|
+
description: "Fixed 2026-08-21 — Reset cleared every filter to empty instead of restoring each view's configured default, so Reset could show MORE rows than opening the page fresh. Compare: load the page, note the row count, apply some filters, hit Reset, and the count should return to the original.",
|
|
2329
|
+
href: "/admin/tester-checklist",
|
|
2330
|
+
},
|
|
2331
|
+
{
|
|
2332
|
+
key: "admin-address-payment-status-chips-in-url",
|
|
2333
|
+
label: "The status chips on Admin > Addresses and Admin > Payment Methods are reflected in the URL and survive a reload and the Back button",
|
|
2334
|
+
description: "Fixed 2026-08-21 — these chips were held in local component state only, so the selection vanished on reload, could not be shared as a link, and the browser Back button skipped past it. Pick a status, reload, and confirm it is still selected.",
|
|
2335
|
+
href: "/admin/addresses",
|
|
2336
|
+
},
|
|
2337
|
+
{
|
|
2338
|
+
key: "admin-listing-sort-dropdown-preselected",
|
|
2339
|
+
label: "Every admin listing opens with its Sort dropdown showing a selected option — never blank",
|
|
2340
|
+
description: "Fixed 2026-08-21 on Addresses and Payment Methods, whose default sort was not among the options they offered, so the dropdown opened with nothing selected. Spot-check several admin listings.",
|
|
2341
|
+
href: "/admin/addresses",
|
|
2342
|
+
},
|
|
1534
2343
|
{ key: "sublisting-categories-crud", label: "Admin can create, edit, and list sublisting categories", href: "/admin/sublisting-categories" },
|
|
1535
2344
|
{ key: "carousel-crud", label: "Admin can create, edit, and reorder carousel slides", href: "/admin/carousel" },
|
|
1536
2345
|
{ key: "sections-crud", label: "Admin can create, edit, and reorder homepage sections", href: "/admin/sections" },
|
|
@@ -1653,6 +2462,18 @@ const rawTesterChecklistItems = [
|
|
|
1653
2462
|
href: "/admin/orders",
|
|
1654
2463
|
cases: [
|
|
1655
2464
|
{ key: "orders-status-change", label: "Admin orders list shows accurate orders and status changes save correctly", href: "/admin/orders" },
|
|
2465
|
+
{
|
|
2466
|
+
key: "admin-emi-order-reviewable",
|
|
2467
|
+
label: "Opening an EMI order in admin shows the full Payment Proof panel — screenshot, UTR, expected-vs-reported UPI, and the Verify / Request re-upload / Reject-as-fraud buttons",
|
|
2468
|
+
description: "Fixed 2026-08-21. The panel used to check only for cash and UPI orders and omitted EMI entirely, so an admin could see an EMI order sitting in the queue labelled \"Awaiting verification\" and have literally no way to action it. Check BOTH the row drawer and the full /admin/orders/[id]/view page — they must behave identically.",
|
|
2469
|
+
href: "/admin/orders",
|
|
2470
|
+
},
|
|
2471
|
+
{
|
|
2472
|
+
key: "admin-decided-order-no-live-buttons",
|
|
2473
|
+
label: "An order already rejected as fraud, or already sent back for re-upload, shows that state instead of offering live Verify / Reject buttons again",
|
|
2474
|
+
description: "Previously only the payment status was consulted, so a decided order still rendered as a fresh \"please verify\" and could be actioned a second time. Reject one order as fraud, reopen it, and confirm it now reads as rejected with no action buttons.",
|
|
2475
|
+
href: "/admin/orders",
|
|
2476
|
+
},
|
|
1656
2477
|
{
|
|
1657
2478
|
key: "admin-orders-payment-review-filters",
|
|
1658
2479
|
label: "The Admin Orders filter drawer has a \"Manual payment\" chip group with \"Awaiting payment\" and \"Awaiting verification\" — and each one actually returns the right orders",
|
|
@@ -1704,6 +2525,12 @@ const rawTesterChecklistItems = [
|
|
|
1704
2525
|
description: "Fixed 2026-08-21 — AdminOrdersView.mapRows built \"Order {id}\" from a nonexistent orderNumber field, and AdminOrderEditorView showed zero items even when opened. Both now read the order's already-denormalized items[] (Root Cause #52).",
|
|
1705
2526
|
href: "/admin/orders",
|
|
1706
2527
|
},
|
|
2528
|
+
{
|
|
2529
|
+
key: "admin-order-detail-standalone-page",
|
|
2530
|
+
label: "An admin order's \"Open full page\" action lands on a real bookmarkable /admin/orders/[id]/view page — not just the side drawer",
|
|
2531
|
+
description: "Added 2026-08-21 — the standalone admin order page had no case of its own; it was only tested indirectly through the list-row check. Open an order's row menu, choose \"Open full page\", and confirm: (a) the URL changes to a real per-order path you can copy and reopen in a fresh tab; (b) the page shows the full items list with thumbnails, the shipping address, and the payment breakdown; (c) reloading that URL directly still works rather than bouncing you back to the list.",
|
|
2532
|
+
href: "/admin/orders",
|
|
2533
|
+
},
|
|
1707
2534
|
{
|
|
1708
2535
|
key: "admin-payout-detail-view",
|
|
1709
2536
|
label: "Every admin payout row has an \"Open full page\" action + a working \"Mark as paid\" action, landing on a real /admin/payouts/[id]/view page with a full gross/platform-fee/gateway-fee/GST/refund-deduction/net breakdown and linked order ids — not just a bare \"transaction ID\" modal",
|
|
@@ -1794,6 +2621,30 @@ const rawTesterChecklistItems = [
|
|
|
1794
2621
|
description: "Added 2026-08-21. The digest runs automatically at 10:00 IST, but you don't need to wait — an admin can trigger it on demand by POSTing to /api/admin/daily-digest/trigger (e.g. from the browser console while logged in as admin: fetch('/api/admin/daily-digest/trigger',{method:'POST'})). Confirm the email reaches every configured recipient AND any CC addresses, and that the numbers match what the admin orders list actually shows for the last 24 hours. Note: this requires the Firebase Functions deploy to have happened for the scheduled 10:00 run — the manual trigger works regardless.",
|
|
1795
2622
|
href: "/admin/site",
|
|
1796
2623
|
},
|
|
2624
|
+
{
|
|
2625
|
+
key: "site-settings-credentials-save",
|
|
2626
|
+
label: "Site Settings → Integrations: saving a real API key succeeds, shows back masked after reload, and never throws an error toast",
|
|
2627
|
+
description: "Added 2026-08-21 — this path was BROKEN in production and nothing caught it. Every key here is AES-encrypted before storage, and the encrypt call throws outright when the server's encryption key is unset, so \"Save\" failed for every integration. Enter any non-empty value in one field (a throwaway value is fine — do NOT paste a real production secret just to test), hit Save, and confirm: (a) you get a success toast, NOT an error; (b) after a full page reload the field shows a MASKED value (e.g. \"re_abc...wxyz\"), not blank and not the raw value you typed; (c) the page doesn't show a red error banner anywhere.",
|
|
2628
|
+
href: "/admin/site",
|
|
2629
|
+
},
|
|
2630
|
+
{
|
|
2631
|
+
key: "site-settings-credentials-partial-save-keeps-others",
|
|
2632
|
+
label: "Site Settings → Integrations: saving one API key does NOT wipe the other keys that were already saved",
|
|
2633
|
+
description: "Added 2026-08-21. Fields left blank are meant to keep whatever was stored before, not overwrite it with empty. Save a value into ONE integration field, reload, then save a value into a DIFFERENT field while leaving the first one showing its masked value untouched. Reload again and confirm BOTH fields still show masked values — if the first one came back blank, that's the bug.",
|
|
2634
|
+
href: "/admin/site",
|
|
2635
|
+
},
|
|
2636
|
+
{
|
|
2637
|
+
key: "site-settings-themes-tab",
|
|
2638
|
+
label: "Site Settings → Themes: a theme can be duplicated, edited, previewed and set as the light/dark default, and the site actually restyles",
|
|
2639
|
+
description: "Added 2026-08-21 — this tab had no test case at all. Duplicate one of the two built-in themes, change a colour or gradient on the copy, confirm the live preview updates, then set it as the default for light mode and save. Reload the public homepage and confirm the new colour is actually in use. Also confirm the two built-in themes (default-light / default-dark) cannot be deleted.",
|
|
2640
|
+
href: "/admin/site",
|
|
2641
|
+
},
|
|
2642
|
+
{
|
|
2643
|
+
key: "site-settings-notifications-non-digest",
|
|
2644
|
+
label: "Site Settings → Notifications: the non-digest settings (sender name, from address, reply-to, per-channel toggles) save and survive a reload",
|
|
2645
|
+
description: "Added 2026-08-21 — only the digest recipient lists on this tab had a test case. Change the sender display name and reply-to address, toggle a notification channel, save, then reload Site Settings and confirm every value came back as entered. Then trigger any real notification (e.g. place a test order) and confirm the email that arrives actually uses the sender name / from address you just set, rather than an older hardcoded one.",
|
|
2646
|
+
href: "/admin/site",
|
|
2647
|
+
},
|
|
1797
2648
|
{ key: "admin-dashboard-widgets", label: "Admin dashboard widgets show accurate data", href: "/admin/dashboard" },
|
|
1798
2649
|
{ key: "analytics-admin", label: "Admin analytics dashboard shows accurate data", href: "/admin/analytics" },
|
|
1799
2650
|
{
|
|
@@ -1811,6 +2662,30 @@ const rawTesterChecklistItems = [
|
|
|
1811
2662
|
{ key: "maintenance-pages-admin", label: "The maintenance pages (analysis, client-errors, cloud-logs, function-errors, payment-rollbacks, server-errors + detail) all load correctly", href: "/admin/maintenance" },
|
|
1812
2663
|
{ key: "copilot-admin", label: "Admin copilot page works correctly", href: "/admin/copilot" },
|
|
1813
2664
|
{ key: "team-admin", label: "Admin team page works correctly", href: "/admin/team" },
|
|
2665
|
+
{
|
|
2666
|
+
key: "team-permission-group-filter",
|
|
2667
|
+
label: "The permission-group filter on /admin/team actually narrows the employee list",
|
|
2668
|
+
description: "Fixed 2026-08-21. The filter emitted a field the database layer was never told to accept, so the clause was discarded silently and every group showed the complete employee list. Pick a group and confirm the rows genuinely change.",
|
|
2669
|
+
href: "/admin/team",
|
|
2670
|
+
},
|
|
2671
|
+
{
|
|
2672
|
+
key: "audit-log-actor-search",
|
|
2673
|
+
label: "The \"Search by actor uid\" box on /admin/audit-log narrows results to that actor",
|
|
2674
|
+
description: "Fixed 2026-08-21 — the box was inert, the endpoint never read it. Paste a full actor uid from a visible row and confirm only that actor's entries remain.",
|
|
2675
|
+
href: "/admin/audit-log",
|
|
2676
|
+
},
|
|
2677
|
+
{
|
|
2678
|
+
key: "notifications-user-search",
|
|
2679
|
+
label: "The search box on /admin/notifications narrows results to one user, and its placeholder reads \"Search by user ID\"",
|
|
2680
|
+
description: "Fixed 2026-08-21 — the box was inert. Its placeholder also used to promise title search, which is not possible against this collection, so the wording was corrected rather than left as a promise the search cannot keep. Paste a user ID from a visible row and confirm only that user's notifications remain.",
|
|
2681
|
+
href: "/admin/notifications",
|
|
2682
|
+
},
|
|
2683
|
+
{
|
|
2684
|
+
key: "carousel-edit-and-delete",
|
|
2685
|
+
label: "A named carousel can be renamed, switched between draft and active, and deleted after it has been created",
|
|
2686
|
+
description: "Fixed 2026-08-21 — the editor could only CREATE. There was no way to load an existing carousel back, so a typo'd or draft carousel was stuck permanently. Create one, reopen it, rename it, publish it, then delete it.",
|
|
2687
|
+
href: "/admin/carousels",
|
|
2688
|
+
},
|
|
1814
2689
|
{ key: "guide-pages-admin", label: "The 8 admin guide pages all load correctly", href: "/admin/guide" },
|
|
1815
2690
|
{ key: "tester-checklist-crud-admin", label: "Admin can create, edit, and toggle adminOnly on tester checklist items", href: "/admin/tester-checklist" },
|
|
1816
2691
|
{ key: "tester-feedback-report-export", label: "Admin tester-feedback report shows Yes/No analytics grouped correctly and the Download Report export works", href: "/admin/tester-feedback" },
|