@mohasinac/appkit 4.34.0 → 4.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +32 -2
- package/dist/_internal/server/features/seo/sitemap.js +2 -2
- package/dist/_internal/server/functions/scheduled.d.ts +1 -2
- package/dist/_internal/server/functions/scheduled.js +8 -9
- package/dist/_internal/server/jobs/core/testerSandboxCleanup.d.ts +15 -0
- package/dist/_internal/server/jobs/core/testerSandboxCleanup.js +15 -6
- package/dist/_internal/server/jobs/handlers/index.d.ts +0 -1
- package/dist/_internal/server/jobs/handlers/index.js +0 -1
- package/dist/features/auth/schemas/firestore.d.ts +1 -0
- package/dist/features/tester/components/TesterChecklistStepRow.d.ts +9 -1
- package/dist/features/tester/components/TesterChecklistStepRow.js +31 -2
- package/dist/features/tester/components/TesterHubView.js +8 -0
- package/dist/features/tester/repository/tester-checklist-item.repository.d.ts +16 -1
- package/dist/features/tester/repository/tester-checklist-item.repository.js +32 -6
- package/dist/features/tester/schemas/firestore.d.ts +109 -0
- package/dist/features/tester/schemas/firestore.js +14 -0
- package/dist/features/tester/seed-data/_money-flows.d.ts +23 -0
- package/dist/features/tester/seed-data/_money-flows.js +430 -0
- package/dist/features/tester/seed-data/authored/_types.d.ts +33 -0
- package/dist/features/tester/seed-data/authored/_types.js +35 -0
- package/dist/features/tester/seed-data/authored/account-auth__profile-settings.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/account-auth__profile-settings.js +207 -0
- package/dist/features/tester/seed-data/authored/account-auth__signup-login.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/account-auth__signup-login.js +298 -0
- package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.js +33 -0
- package/dist/features/tester/seed-data/authored/account-auth__testing-program.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/account-auth__testing-program.js +138 -0
- package/dist/features/tester/seed-data/authored/addresses__address-filters.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/addresses__address-filters.js +36 -0
- package/dist/features/tester/seed-data/authored/addresses__postal-lookup.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/addresses__postal-lookup.js +75 -0
- package/dist/features/tester/seed-data/authored/addresses__postal-validation.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/addresses__postal-validation.js +72 -0
- package/dist/features/tester/seed-data/authored/addresses__state-picker.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/addresses__state-picker.js +54 -0
- package/dist/features/tester/seed-data/authored/addresses__unban-request.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/addresses__unban-request.js +39 -0
- package/dist/features/tester/seed-data/authored/admin__bans-and-trust.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__bans-and-trust.js +226 -0
- package/dist/features/tester/seed-data/authored/admin__blog-faqs.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__blog-faqs.js +82 -0
- package/dist/features/tester/seed-data/authored/admin__bulk-actions.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__bulk-actions.js +177 -0
- package/dist/features/tester/seed-data/authored/admin__bundles.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__bundles.js +97 -0
- package/dist/features/tester/seed-data/authored/admin__buyer-data-admin.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__buyer-data-admin.js +232 -0
- package/dist/features/tester/seed-data/authored/admin__catalog-listings.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__catalog-listings.js +306 -0
- package/dist/features/tester/seed-data/authored/admin__category-brand-authoring.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__category-brand-authoring.js +158 -0
- package/dist/features/tester/seed-data/authored/admin__classifieds-digitalcodes-live.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__classifieds-digitalcodes-live.js +78 -0
- package/dist/features/tester/seed-data/authored/admin__content-deletes.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__content-deletes.js +261 -0
- package/dist/features/tester/seed-data/authored/admin__content-marketing.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__content-marketing.js +151 -0
- package/dist/features/tester/seed-data/authored/admin__coupons.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__coupons.js +214 -0
- package/dist/features/tester/seed-data/authored/admin__events-raffles-spin.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__events-raffles-spin.js +160 -0
- package/dist/features/tester/seed-data/authored/admin__media-watermark.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__media-watermark.js +104 -0
- package/dist/features/tester/seed-data/authored/admin__orders-fulfillment.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__orders-fulfillment.js +350 -0
- package/dist/features/tester/seed-data/authored/admin__prize-draws-lotteries.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__prize-draws-lotteries.js +105 -0
- package/dist/features/tester/seed-data/authored/admin__site-system.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__site-system.js +590 -0
- package/dist/features/tester/seed-data/authored/admin__uncovered-admin-pages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__uncovered-admin-pages.js +235 -0
- package/dist/features/tester/seed-data/authored/admin__users-trust.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/admin__users-trust.js +569 -0
- package/dist/features/tester/seed-data/authored/buying__bidding.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__bidding.js +417 -0
- package/dist/features/tester/seed-data/authored/buying__browsing-search.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__browsing-search.js +653 -0
- package/dist/features/tester/seed-data/authored/buying__buying-checkout.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__buying-checkout.js +533 -0
- package/dist/features/tester/seed-data/authored/buying__buying-coupons.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__buying-coupons.js +379 -0
- package/dist/features/tester/seed-data/authored/buying__cart.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__cart.js +1171 -0
- package/dist/features/tester/seed-data/authored/buying__image-tile-layout.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__image-tile-layout.js +140 -0
- package/dist/features/tester/seed-data/authored/buying__my-orders.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__my-orders.js +257 -0
- package/dist/features/tester/seed-data/authored/buying__offers.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__offers.js +1111 -0
- package/dist/features/tester/seed-data/authored/buying__order-status-lifecycle.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__order-status-lifecycle.js +252 -0
- package/dist/features/tester/seed-data/authored/buying__product-detail.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__product-detail.js +387 -0
- package/dist/features/tester/seed-data/authored/buying__return-request.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__return-request.js +152 -0
- package/dist/features/tester/seed-data/authored/buying__reviews-pagination.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__reviews-pagination.js +242 -0
- package/dist/features/tester/seed-data/authored/buying__reviews.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__reviews.js +113 -0
- package/dist/features/tester/seed-data/authored/buying__user-dashboard-extras.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__user-dashboard-extras.js +283 -0
- package/dist/features/tester/seed-data/authored/buying__user-dashboard-navigation.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__user-dashboard-navigation.js +167 -0
- package/dist/features/tester/seed-data/authored/buying__user-uncovered-pages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__user-uncovered-pages.js +90 -0
- package/dist/features/tester/seed-data/authored/buying__wishlist-history.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/buying__wishlist-history.js +344 -0
- package/dist/features/tester/seed-data/authored/community-support__public-profile.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/community-support__public-profile.js +53 -0
- package/dist/features/tester/seed-data/authored/community-support__support-tickets.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/community-support__support-tickets.js +76 -0
- package/dist/features/tester/seed-data/authored/content-discovery__blog.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__blog.js +93 -0
- package/dist/features/tester/seed-data/authored/content-discovery__category-brand-relations.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__category-brand-relations.js +149 -0
- package/dist/features/tester/seed-data/authored/content-discovery__coupons.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__coupons.js +121 -0
- package/dist/features/tester/seed-data/authored/content-discovery__event-participation.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__event-participation.js +207 -0
- package/dist/features/tester/seed-data/authored/content-discovery__events.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__events.js +318 -0
- package/dist/features/tester/seed-data/authored/content-discovery__faq-help.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__faq-help.js +65 -0
- package/dist/features/tester/seed-data/authored/content-discovery__notifications.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__notifications.js +147 -0
- package/dist/features/tester/seed-data/authored/content-discovery__search.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/content-discovery__search.js +332 -0
- package/dist/features/tester/seed-data/authored/cta-layout__checkout-bottom-bar.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/cta-layout__checkout-bottom-bar.js +53 -0
- package/dist/features/tester/seed-data/authored/cta-layout__dialog-footers.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/cta-layout__dialog-footers.js +52 -0
- package/dist/features/tester/seed-data/authored/cta-layout__editor-action-bar.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/cta-layout__editor-action-bar.js +35 -0
- package/dist/features/tester/seed-data/authored/cta-layout__navbar-ctas.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/cta-layout__navbar-ctas.js +141 -0
- package/dist/features/tester/seed-data/authored/cta-layout__product-bottom-bar.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/cta-layout__product-bottom-bar.js +35 -0
- package/dist/features/tester/seed-data/authored/design-ux__back-to-top-button.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__back-to-top-button.js +95 -0
- package/dist/features/tester/seed-data/authored/design-ux__carousel-arrow-bounds.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__carousel-arrow-bounds.js +191 -0
- package/dist/features/tester/seed-data/authored/design-ux__dashboard-layout.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__dashboard-layout.js +158 -0
- package/dist/features/tester/seed-data/authored/design-ux__footer-theme.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__footer-theme.js +106 -0
- package/dist/features/tester/seed-data/authored/design-ux__form-validation-errors.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__form-validation-errors.js +88 -0
- package/dist/features/tester/seed-data/authored/design-ux__general-design.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__general-design.js +204 -0
- package/dist/features/tester/seed-data/authored/design-ux__hand-mode-layout.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__hand-mode-layout.js +301 -0
- package/dist/features/tester/seed-data/authored/design-ux__homepage-carousels.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__homepage-carousels.js +407 -0
- package/dist/features/tester/seed-data/authored/design-ux__status-badge-legibility.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__status-badge-legibility.js +214 -0
- package/dist/features/tester/seed-data/authored/design-ux__sticky-cta-bar.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/design-ux__sticky-cta-bar.js +275 -0
- package/dist/features/tester/seed-data/authored/index.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/index.js +237 -0
- package/dist/features/tester/seed-data/authored/page-wiring__data-loss.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/page-wiring__data-loss.js +102 -0
- package/dist/features/tester/seed-data/authored/page-wiring__detail-pages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/page-wiring__detail-pages.js +50 -0
- package/dist/features/tester/seed-data/authored/page-wiring__drawer-pages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/page-wiring__drawer-pages.js +66 -0
- package/dist/features/tester/seed-data/authored/page-wiring__reachability.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/page-wiring__reachability.js +115 -0
- package/dist/features/tester/seed-data/authored/public-pages__auth-error-pages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/public-pages__auth-error-pages.js +136 -0
- package/dist/features/tester/seed-data/authored/public-pages__bug-hunters.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/public-pages__bug-hunters.js +69 -0
- package/dist/features/tester/seed-data/authored/public-pages__core-listing-pages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/public-pages__core-listing-pages.js +263 -0
- package/dist/features/tester/seed-data/authored/public-pages__help-how-it-works.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/public-pages__help-how-it-works.js +102 -0
- package/dist/features/tester/seed-data/authored/public-pages__help-scams-guides-subpages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/public-pages__help-scams-guides-subpages.js +234 -0
- package/dist/features/tester/seed-data/authored/public-pages__legal-policy-pages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/public-pages__legal-policy-pages.js +126 -0
- package/dist/features/tester/seed-data/authored/public-pages__stores-sellers-directories.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/public-pages__stores-sellers-directories.js +255 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__employee-permissions.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__employee-permissions.js +59 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__header-search.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__header-search.js +88 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__settings-deep-links.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__settings-deep-links.js +51 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__sidebar-search.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/search-and-nav__sidebar-search.js +35 -0
- package/dist/features/tester/seed-data/authored/selling__become-seller.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__become-seller.js +94 -0
- package/dist/features/tester/seed-data/authored/selling__final-sale-authoring.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__final-sale-authoring.js +107 -0
- package/dist/features/tester/seed-data/authored/selling__listing-a-product.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__listing-a-product.js +285 -0
- package/dist/features/tester/seed-data/authored/selling__listing-lifecycle.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__listing-lifecycle.js +326 -0
- package/dist/features/tester/seed-data/authored/selling__listing-type-fields-roundtrip.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__listing-type-fields-roundtrip.js +136 -0
- package/dist/features/tester/seed-data/authored/selling__media-limits.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__media-limits.js +128 -0
- package/dist/features/tester/seed-data/authored/selling__sectionised-forms.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__sectionised-forms.js +167 -0
- package/dist/features/tester/seed-data/authored/selling__seller-analytics-payouts.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-analytics-payouts.js +117 -0
- package/dist/features/tester/seed-data/authored/selling__seller-bids-bundles-filters.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-bids-bundles-filters.js +88 -0
- package/dist/features/tester/seed-data/authored/selling__seller-catalog-org.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-catalog-org.js +151 -0
- package/dist/features/tester/seed-data/authored/selling__seller-custom-brands.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-custom-brands.js +105 -0
- package/dist/features/tester/seed-data/authored/selling__seller-guide.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-guide.js +33 -0
- package/dist/features/tester/seed-data/authored/selling__seller-listing-types.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-listing-types.js +347 -0
- package/dist/features/tester/seed-data/authored/selling__seller-marketing-extras.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-marketing-extras.js +166 -0
- package/dist/features/tester/seed-data/authored/selling__seller-ops-comms.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-ops-comms.js +89 -0
- package/dist/features/tester/seed-data/authored/selling__seller-orders.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-orders.js +195 -0
- package/dist/features/tester/seed-data/authored/selling__seller-shipping-payouts-setup.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__seller-shipping-payouts-setup.js +180 -0
- package/dist/features/tester/seed-data/authored/selling__store-dashboard-navigation.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__store-dashboard-navigation.js +164 -0
- package/dist/features/tester/seed-data/authored/selling__store-uncovered-pages.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/selling__store-uncovered-pages.js +116 -0
- package/dist/features/tester/seed-data/authored/seo__canonical-and-host.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/seo__canonical-and-host.js +111 -0
- package/dist/features/tester/seed-data/authored/seo__og-images.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/seo__og-images.js +91 -0
- package/dist/features/tester/seed-data/authored/seo__page-metadata.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/seo__page-metadata.js +122 -0
- package/dist/features/tester/seed-data/authored/seo__sitemap-and-robots.d.ts +2 -0
- package/dist/features/tester/seed-data/authored/seo__sitemap-and-robots.js +105 -0
- package/dist/features/tester/seed-data/events-tester-seed-data.js +77 -5
- package/dist/features/tester/seed-data/offers-tester-seed-data.js +23 -9
- package/dist/features/tester/seed-data/products-tester-seed-data.js +65 -49
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +744 -1
- package/dist/features/tester/seed-data/tester-window.d.ts +25 -0
- package/dist/features/tester/seed-data/tester-window.js +66 -0
- package/dist/seed/carousel-slides-seed-data.js +1 -1
- package/dist/seed/products-standard-seed-data.js +2 -2
- package/dist/seed/reviews-seed-data.js +6 -1
- package/dist/seed/users-seed-data.js +107 -4
- package/package.json +1 -1
- package/scripts/seed-cli.mjs +6 -0
|
@@ -18,20 +18,50 @@
|
|
|
18
18
|
* @tag sideEffects:none
|
|
19
19
|
*/
|
|
20
20
|
import { assignDefaultPhases } from "../utils/phases";
|
|
21
|
+
import { moneyFlowsPages } from "./_money-flows";
|
|
22
|
+
import { AUTHORED_CASES } from "./authored";
|
|
21
23
|
const ADMIN_TESTING_GROUP_LABEL = "Admin (Testing)";
|
|
22
24
|
const BUG_HUNTER_REWARDS_PAGE_LABEL = "Bug Hunter Rewards";
|
|
25
|
+
/**
|
|
26
|
+
* Step phrases reused across cases. Extracted so the wording stays identical —
|
|
27
|
+
* two steps that mean the same thing should not read differently, or a tester
|
|
28
|
+
* starts wondering whether the difference is significant.
|
|
29
|
+
*/
|
|
30
|
+
const STEP_PLACE_ORDER = "Place the order.";
|
|
23
31
|
function group(groupKey, groupLabel, pages, opts) {
|
|
24
32
|
const items = [];
|
|
25
33
|
pages.forEach((page, pageIdx) => {
|
|
26
34
|
page.cases.forEach((c, caseIdx) => {
|
|
35
|
+
const id = `checklist-${groupKey}-${page.pageKey}-${c.key}`;
|
|
36
|
+
/**
|
|
37
|
+
* Authored steps live in ./authored/<group>__<page>.ts and merge in here.
|
|
38
|
+
*
|
|
39
|
+
* INLINE WINS. A case written inline in this file — the 22 money-flows
|
|
40
|
+
* reference cases — is the more deliberate artefact, so the overlay may
|
|
41
|
+
* only fill a field that is absent. So never write an overlay entry for a
|
|
42
|
+
* case that already has inline steps: it would be silently ignored, and
|
|
43
|
+
* the page would read as authored twice over while one copy did nothing.
|
|
44
|
+
*/
|
|
45
|
+
const authored = AUTHORED_CASES[id];
|
|
27
46
|
items.push({
|
|
28
|
-
id
|
|
47
|
+
id,
|
|
29
48
|
groupKey,
|
|
30
49
|
groupLabel,
|
|
31
50
|
pageKey: page.pageKey,
|
|
32
51
|
pageLabel: page.pageLabel,
|
|
33
52
|
label: c.label,
|
|
34
53
|
description: c.description,
|
|
54
|
+
roles: c.roles ?? authored?.roles,
|
|
55
|
+
// A case starting somewhere other than its page default says so; otherwise
|
|
56
|
+
// the page's own href is the start, which is what makes `startPage` safe
|
|
57
|
+
// to require on every case without repeating it 990 times.
|
|
58
|
+
startPage: c.startPage ?? authored?.startPage ?? c.href ?? page.href,
|
|
59
|
+
steps: c.steps ?? authored?.steps,
|
|
60
|
+
inputs: c.inputs ?? authored?.inputs,
|
|
61
|
+
expectedBehaviour: c.expectedBehaviour ?? authored?.expectedBehaviour,
|
|
62
|
+
expectedUiState: c.expectedUiState ?? authored?.expectedUiState,
|
|
63
|
+
expectedData: c.expectedData ?? authored?.expectedData,
|
|
64
|
+
endResult: c.endResult ?? authored?.endResult,
|
|
35
65
|
// Every case gets a link: its own href, or the page's default —
|
|
36
66
|
// guarantees "Go test this ->" always has somewhere real to send
|
|
37
67
|
// the tester, even for cases nobody bothered to link individually.
|
|
@@ -1969,6 +1999,68 @@ const rawTesterChecklistItems = [
|
|
|
1969
1999
|
},
|
|
1970
2000
|
],
|
|
1971
2001
|
},
|
|
2002
|
+
{
|
|
2003
|
+
pageKey: "order-status-lifecycle",
|
|
2004
|
+
pageLabel: "Order statuses & transitions",
|
|
2005
|
+
href: "/user/orders",
|
|
2006
|
+
cases: [
|
|
2007
|
+
{ key: "all-statuses-render", label: "Every order status renders with its own readable badge, and no order shows a blank or raw status value", href: "/user/orders" },
|
|
2008
|
+
{
|
|
2009
|
+
key: "active-closed-all-tabs",
|
|
2010
|
+
label: "The Active / Closed / All tabs each return the right orders, and every status belongs to exactly one of the first two",
|
|
2011
|
+
description: "An order in neither tab is invisible to the buyer while still existing. Check every status you can find lands in one of them.",
|
|
2012
|
+
href: "/user/orders",
|
|
2013
|
+
},
|
|
2014
|
+
{
|
|
2015
|
+
key: "return-requested-is-active",
|
|
2016
|
+
label: "An order in Return Requested appears under Active, not Closed",
|
|
2017
|
+
description: "A return request is the next action item, not an ending \u2014 filing it under Closed hides the orders that most need attention.",
|
|
2018
|
+
href: "/user/orders",
|
|
2019
|
+
},
|
|
2020
|
+
{ key: "status-change-visible-to-buyer", label: "A status change made by the seller shows on the buyer's order without the buyer having to do anything but reload", href: "/user/orders" },
|
|
2021
|
+
{
|
|
2022
|
+
key: "status-timeline-real-dates",
|
|
2023
|
+
label: "The order timeline shows the real recorded date for each status it reached, and a dash for steps that have no recorded date",
|
|
2024
|
+
description: "BEFORE: a fabricated or estimated timestamp makes the record lie. A step with no date must read as having none.",
|
|
2025
|
+
href: "/user/orders",
|
|
2026
|
+
},
|
|
2027
|
+
{ key: "status-timeline-future-steps", label: "The timeline shows the statuses an order has not reached yet as upcoming rather than omitting them", href: "/user/orders" },
|
|
2028
|
+
{ key: "cancel-allowed-only-before-shipping", label: "Cancelling is offered before shipping and refused afterwards, with the refusal explaining why", href: "/user/orders" },
|
|
2029
|
+
{ key: "cancellation-reason-recorded", label: "A cancellation reason typed by the buyer is stored and visible to the seller", href: "/user/orders" },
|
|
2030
|
+
{
|
|
2031
|
+
key: "refund-appears-in-timeline",
|
|
2032
|
+
label: "A refund, including a partial one, appears in the order timeline rather than leaving no trace",
|
|
2033
|
+
description: "A partial refund changes no tracked status field, so a plain difference between two versions would record nothing at all.",
|
|
2034
|
+
href: "/user/orders",
|
|
2035
|
+
},
|
|
2036
|
+
{ key: "tracking-number-shows-when-set", label: "Adding a tracking number and carrier makes both appear on the buyer's order with a working tracking link", href: "/user/orders" },
|
|
2037
|
+
{
|
|
2038
|
+
key: "order-scope-filter-and-status-filter",
|
|
2039
|
+
label: "Combining the Active/Closed tab with an explicit status filter returns a sensible result rather than nothing",
|
|
2040
|
+
description: "Two equality filters on one field can never both match, so the tab must stand down when an explicit status is chosen.",
|
|
2041
|
+
href: "/user/orders",
|
|
2042
|
+
},
|
|
2043
|
+
{ key: "seller-status-controls-match-state", label: "The seller's status controls offer only the transitions valid from the order's current status", href: "/store/orders" },
|
|
2044
|
+
{ key: "status-history-actor-recorded", label: "Each status change records who made it \u2014 buyer, seller, admin or the system \u2014 and the timeline says so", href: "/user/orders" },
|
|
2045
|
+
{
|
|
2046
|
+
key: "orders-list-shows-item-not-id",
|
|
2047
|
+
label: "An order row names the item it was for, with a thumbnail, rather than only an order identifier",
|
|
2048
|
+
description: "BEFORE: rows read \"Order {id}\" while the item title and image were already on the record, unread by the row builder.",
|
|
2049
|
+
href: "/user/orders",
|
|
2050
|
+
},
|
|
2051
|
+
],
|
|
2052
|
+
},
|
|
2053
|
+
{
|
|
2054
|
+
pageKey: "user-uncovered-pages",
|
|
2055
|
+
pageLabel: "Buyer pages with no other coverage",
|
|
2056
|
+
href: "/user",
|
|
2057
|
+
cases: [
|
|
2058
|
+
{ key: "user-preorders-renders", label: "The buyer's Pre-orders page lists their pre-orders with each one's production status", href: "/user/pre-orders" },
|
|
2059
|
+
{ key: "user-support-new-renders", label: "Opening the new-support-ticket page directly shows the form already open, and cancelling lands back on the ticket list", href: "/user/support/new" },
|
|
2060
|
+
{ key: "user-catalogue-new-renders", label: "Opening the new-catalogue-item page directly shows the form already open and a saved item appears in the buyer's catalogue", href: "/user/catalogue/new" },
|
|
2061
|
+
{ key: "user-addresses-add-renders", label: "Opening the add-address page directly shows the form already open and a saved address appears in the address list", href: "/user/addresses/add" },
|
|
2062
|
+
],
|
|
2063
|
+
},
|
|
1972
2064
|
]),
|
|
1973
2065
|
...group("selling", "Selling", [
|
|
1974
2066
|
{
|
|
@@ -2592,6 +2684,59 @@ const rawTesterChecklistItems = [
|
|
|
2592
2684
|
},
|
|
2593
2685
|
],
|
|
2594
2686
|
},
|
|
2687
|
+
{
|
|
2688
|
+
pageKey: "listing-lifecycle",
|
|
2689
|
+
pageLabel: "Listing lifecycle, per type",
|
|
2690
|
+
href: "/store/products",
|
|
2691
|
+
cases: [
|
|
2692
|
+
{ key: "standard-create-publish-sell", label: "A standard listing can be created, published, bought and marked sold, and each step shows on the public page", href: "/store/products" },
|
|
2693
|
+
{ key: "auction-create-publish-bid-close", label: "An auction can be created with a start price and increment, published, bid on, and closes at its end time with a winner", href: "/store/products" },
|
|
2694
|
+
{
|
|
2695
|
+
key: "auction-reserve-respected-at-close",
|
|
2696
|
+
label: "An auction whose highest bid is below its reserve closes WITHOUT awarding a winner",
|
|
2697
|
+
description: "BEFORE: settlement awarded the top bid unconditionally and never read the reserve, while the reserve was displayed, editable and promised in the seller guide.",
|
|
2698
|
+
href: "/store/products",
|
|
2699
|
+
},
|
|
2700
|
+
{ key: "preorder-create-publish-deposit", label: "A pre-order can be created with a delivery date and deposit, published, and bought at the deposit amount", href: "/store/products" },
|
|
2701
|
+
{ key: "preorder-production-status-visible", label: "Changing a pre-order's production status shows on the public listing", href: "/store/products" },
|
|
2702
|
+
{ key: "prizedraw-create-publish-close-reveal", label: "A prize draw can be created with entries, published, sold down and revealed with a real winner", href: "/store/products" },
|
|
2703
|
+
{ key: "classified-create-publish-contact", label: "A classified can be created with a city and contact method, published, and offers contact rather than a cart button", href: "/store/products" },
|
|
2704
|
+
{ key: "digitalcode-create-publish-claim", label: "A digital code listing can be created with a code pool, published, bought and fulfilled from that pool", href: "/store/products" },
|
|
2705
|
+
{
|
|
2706
|
+
key: "digitalcode-pool-depletes",
|
|
2707
|
+
label: "A digital-code listing whose pool empties stops being buyable, even though its stock number may not be zero",
|
|
2708
|
+
description: "Availability for this type is the nested codes-available count, not the stock field \u2014 the two disagree on purpose.",
|
|
2709
|
+
href: "/store/products",
|
|
2710
|
+
},
|
|
2711
|
+
{ key: "live-create-publish-jurisdiction", label: "A live-item listing can be created with a species and jurisdiction, published, and refuses purchase from a disallowed jurisdiction", href: "/store/products" },
|
|
2712
|
+
{ key: "art-create-publish-sell", label: "An art listing can be created with its size, material and edition fields, published, and checks out through the standard flow", href: "/store/products" },
|
|
2713
|
+
{ key: "sticker-create-publish-sell", label: "A sticker listing can be created with its print fields, published, and checks out through the standard flow", href: "/store/products" },
|
|
2714
|
+
{ key: "type-badge-correct-on-card", label: "Every listing type shows its own badge on a card, and no two types share one", href: "/store/products" },
|
|
2715
|
+
{
|
|
2716
|
+
key: "type-detail-route-correct",
|
|
2717
|
+
label: "Clicking a card of each type lands on that type's own detail page, not the standard product page",
|
|
2718
|
+
description: "BEFORE: three types were routed to the standard product page despite each having a working dedicated route \u2014 every card, carousel and related link sent them to the wrong page.",
|
|
2719
|
+
href: "/store/products",
|
|
2720
|
+
},
|
|
2721
|
+
{ key: "type-survives-edit", label: "Editing a non-standard listing and saving does not silently convert it to a standard one", href: "/store/products" },
|
|
2722
|
+
{ key: "unpublish-removes-from-public", label: "Unpublishing a listing of any type removes it from public grids while keeping it editable", href: "/store/products" },
|
|
2723
|
+
{ key: "sold-listing-leaves-available-tab", label: "A listing that sells out moves from the Available tab to Sold & Ended without disappearing from All", href: "/store/products" },
|
|
2724
|
+
{ key: "closed-listing-still-viewable", label: "A closed or ended listing's detail page still loads and states its outcome rather than 404ing", href: "/store/products" },
|
|
2725
|
+
],
|
|
2726
|
+
},
|
|
2727
|
+
{
|
|
2728
|
+
pageKey: "store-uncovered-pages",
|
|
2729
|
+
pageLabel: "Seller pages with no other coverage",
|
|
2730
|
+
href: "/store",
|
|
2731
|
+
cases: [
|
|
2732
|
+
{ key: "store-stickers-renders", label: "The seller's Stickers page lists their sticker listings and a new one can be created from it", href: "/store/stickers" },
|
|
2733
|
+
{ key: "store-support-renders", label: "The seller's Support page renders and a ticket can be opened from it", href: "/store/support" },
|
|
2734
|
+
{ key: "store-analytics-cards-renders", label: "The Analytics Cards page renders real figures rather than an empty or placeholder set", href: "/store/analytics/cards" },
|
|
2735
|
+
{ key: "store-preorders-renders", label: "The seller's Pre-orders page lists their pre-order listings and a new one can be created from it", href: "/store/pre-orders" },
|
|
2736
|
+
{ key: "store-guides-all-render", label: "Every seller guide page renders real content and none of them 404s", href: "/store/guide" },
|
|
2737
|
+
{ key: "store-listing-templates-new-renders", label: "Opening the new-listing-template page directly shows the form already open and a saved template is usable when creating a listing", href: "/store/listing-templates/new" },
|
|
2738
|
+
],
|
|
2739
|
+
},
|
|
2595
2740
|
]),
|
|
2596
2741
|
...group("content-discovery", "Content & Discovery", [
|
|
2597
2742
|
{
|
|
@@ -2850,6 +2995,80 @@ const rawTesterChecklistItems = [
|
|
|
2850
2995
|
},
|
|
2851
2996
|
],
|
|
2852
2997
|
},
|
|
2998
|
+
{
|
|
2999
|
+
pageKey: "category-brand-relations",
|
|
3000
|
+
pageLabel: "Category tree & brand matching",
|
|
3001
|
+
href: "/categories",
|
|
3002
|
+
cases: [
|
|
3003
|
+
{
|
|
3004
|
+
key: "tier-depth-reachable",
|
|
3005
|
+
label: "The category tree is four tiers deep and every tier is reachable by clicking down from a root",
|
|
3006
|
+
description: "Two roots exist — Spinning Tops and Living Collectibles. Walk one of them all the way to a leaf without typing a URL.",
|
|
3007
|
+
href: "/categories",
|
|
3008
|
+
},
|
|
3009
|
+
{
|
|
3010
|
+
key: "second-root-reachable",
|
|
3011
|
+
label: "Both category roots appear on the categories index, not just the Beyblade one",
|
|
3012
|
+
description: "BEFORE: the tree had ONE root and TWO tiers, so the live-item listings carried no category at all and were unreachable from every category and brand page.",
|
|
3013
|
+
href: "/categories",
|
|
3014
|
+
},
|
|
3015
|
+
{
|
|
3016
|
+
key: "root-page-shows-descendant-products",
|
|
3017
|
+
label: "A ROOT category's page shows products filed under its deepest descendants, not only ones tagged with the root itself",
|
|
3018
|
+
description: "A product carries its full ancestor chain, which is what lets a category page match on its own id alone. If the root's page is empty while its leaves have stock, the chain is missing on the product side.",
|
|
3019
|
+
href: "/categories/category-spinning-tops",
|
|
3020
|
+
},
|
|
3021
|
+
{
|
|
3022
|
+
key: "root-page-not-blank-on-large-tree",
|
|
3023
|
+
label: "A root category page over a large tree renders products rather than a blank grid",
|
|
3024
|
+
description: "BEFORE: expanding a root into itself plus every descendant exceeded the query's value cap, the query threw, and the failure was swallowed into an empty grid with no error anywhere — a blank page that looks exactly like an empty category.",
|
|
3025
|
+
href: "/categories/category-spinning-tops",
|
|
3026
|
+
},
|
|
3027
|
+
{
|
|
3028
|
+
key: "mid-tier-scopes-to-own-subtree",
|
|
3029
|
+
label: "A mid-tier category shows its own subtree only, not its parent's whole catalogue",
|
|
3030
|
+
description: "Compare Beyblade Burst against Spinning Tops. The child must be a strict subset — equal counts mean the scoping is not applied.",
|
|
3031
|
+
href: "/categories/category-beyblade-burst",
|
|
3032
|
+
},
|
|
3033
|
+
{
|
|
3034
|
+
key: "store-under-deep-category-visible-at-root",
|
|
3035
|
+
label: "A store filed under a deep category appears on that category's ROOT page too",
|
|
3036
|
+
description: "BEFORE: the store lookup expanded direct children only, so a store filed three tiers down was invisible on its root. Stores carry a single category with no ancestor chain, so this side genuinely needs the descendant list — the opposite of how products work.",
|
|
3037
|
+
href: "/categories/category-spinning-tops",
|
|
3038
|
+
},
|
|
3039
|
+
{
|
|
3040
|
+
key: "brand-page-lists-its-products",
|
|
3041
|
+
label: "A brand page lists the products that belong to that brand",
|
|
3042
|
+
description: "Brand matching is by DISPLAY NAME rather than by id, so a brand whose name and its products' brand strings disagree silently orphans its whole catalogue — the page renders perfectly and lists nothing.",
|
|
3043
|
+
href: "/brands/brand-takara-tomy",
|
|
3044
|
+
},
|
|
3045
|
+
{
|
|
3046
|
+
key: "brand-and-category-are-one-collection",
|
|
3047
|
+
label: "A brand page and a category page render as different things even though both are rows in the same collection",
|
|
3048
|
+
description: "A brand shows an About-this-brand panel with website, country and founding year; a category does not. Neither should show the other's chrome.",
|
|
3049
|
+
href: "/brands/brand-takara-tomy",
|
|
3050
|
+
},
|
|
3051
|
+
],
|
|
3052
|
+
},
|
|
3053
|
+
{
|
|
3054
|
+
pageKey: "event-participation",
|
|
3055
|
+
pageLabel: "Participating in events",
|
|
3056
|
+
href: "/events",
|
|
3057
|
+
cases: [
|
|
3058
|
+
{ key: "join-event-as-participant", label: "A buyer can join an open event and their entry is confirmed or waitlisted with the reason stated", href: "/events" },
|
|
3059
|
+
{ key: "own-entry-visible-after-join", label: "After joining, the participant can see their OWN entry with its status, without asking anyone", href: "/events" },
|
|
3060
|
+
{ key: "entry-survives-reload-and-relogin", label: "A participant's entry survives a reload and a sign-out and back in", href: "/events" },
|
|
3061
|
+
{ key: "cannot-join-twice", label: "Joining the same event twice is refused rather than creating a second entry", href: "/events" },
|
|
3062
|
+
{ key: "leave-or-cancel-entry", label: "A participant can withdraw from an event they joined, and their entry reflects it", href: "/events" },
|
|
3063
|
+
{ key: "closed-event-cannot-be-joined", label: "An event that has ended or been cancelled cannot be joined, and says why rather than failing on submit", href: "/events" },
|
|
3064
|
+
{ key: "leaderboard-shows-real-participants", label: "An event leaderboard lists real participants with real scores, not placeholders", href: "/events" },
|
|
3065
|
+
{ key: "leaderboard-own-row-findable", label: "A participant can find their own row on the leaderboard without scrolling the whole list", href: "/events" },
|
|
3066
|
+
{ key: "leaderboard-ordering-correct", label: "The leaderboard is ordered by score with ties broken consistently, and the order is the same after a reload", href: "/events" },
|
|
3067
|
+
{ key: "leaderboard-empty-state", label: "An event with no entries shows a clear empty state on its leaderboard rather than a blank panel", href: "/events" },
|
|
3068
|
+
{ key: "raffle-winner-announced-to-participants", label: "When a raffle is drawn, the winner is announced on the event page and the winning participant is notified", href: "/events" },
|
|
3069
|
+
{ key: "spin-wheel-one-use-enforced", label: "A spin-wheel event enforces its per-user spin limit, and a won prize is claimable", href: "/events" },
|
|
3070
|
+
],
|
|
3071
|
+
},
|
|
2853
3072
|
]),
|
|
2854
3073
|
...group("community-support", "Community & Support", [
|
|
2855
3074
|
{
|
|
@@ -3573,6 +3792,12 @@ const rawTesterChecklistItems = [
|
|
|
3573
3792
|
{ key: "contact-page", label: "The contact page loads and the form submits correctly", href: "/contact" },
|
|
3574
3793
|
{ key: "help-page", label: "The help page loads correctly", href: "/help" },
|
|
3575
3794
|
{ key: "how-it-works-pages", label: "All 7 how-it-works pages (auctions, checkout, offers, orders, payouts, pre-orders, reviews) load correctly" },
|
|
3795
|
+
{
|
|
3796
|
+
key: "how-emi-works-page",
|
|
3797
|
+
label: "The how-EMI-works page loads and its worked example matches what checkout actually charges",
|
|
3798
|
+
description: "There are EIGHT how-it-works pages; the case above enumerates seven. This is the eighth, and it is the one describing money, so a stale example on it misstates a charge.",
|
|
3799
|
+
href: "/how-emi-works",
|
|
3800
|
+
},
|
|
3576
3801
|
{ key: "fees-page", label: "The fees page loads correctly", href: "/fees" },
|
|
3577
3802
|
],
|
|
3578
3803
|
},
|
|
@@ -3624,10 +3849,98 @@ const rawTesterChecklistItems = [
|
|
|
3624
3849
|
{ key: "forgot-reset-password-pages", label: "Forgot-password and reset-password pages both work" },
|
|
3625
3850
|
{ key: "verify-email-page", label: "The verify-email page correctly confirms a pending verification" },
|
|
3626
3851
|
{ key: "oauth-loading-redirect", label: "The OAuth-loading redirect page transitions correctly after a Google sign-in" },
|
|
3852
|
+
{
|
|
3853
|
+
key: "auth-close-terminates-popup",
|
|
3854
|
+
label: "The OAuth popup-close page closes its own window and hands the result back to the page that opened it",
|
|
3855
|
+
description: "A popup that renders this page and stays open leaves the opener waiting forever — the sign-in succeeded and the site never learns it.",
|
|
3856
|
+
href: "/auth/close",
|
|
3857
|
+
},
|
|
3627
3858
|
{ key: "checkout-success-page", label: "The checkout-success page shows correct order details after payment", href: "/checkout/success" },
|
|
3628
3859
|
{ key: "unauthorized-404-pages", label: "Unauthorized and 404 error pages render correctly instead of crashing" },
|
|
3629
3860
|
],
|
|
3630
3861
|
},
|
|
3862
|
+
{
|
|
3863
|
+
pageKey: "help-scams-guides-subpages",
|
|
3864
|
+
pageLabel: "Help, Scams & Seller-Guide sub-pages",
|
|
3865
|
+
href: "/help",
|
|
3866
|
+
cases: [
|
|
3867
|
+
{
|
|
3868
|
+
key: "help-subpages-load",
|
|
3869
|
+
label: "All four help sub-pages \u2014 account, auctions, orders, shopping \u2014 load with real content and are reachable from /help",
|
|
3870
|
+
description: "The parent /help page is covered elsewhere; these four are not. A sub-page that exists but is linked from nowhere is unreachable to anyone who did not type the URL.",
|
|
3871
|
+
href: "/help",
|
|
3872
|
+
},
|
|
3873
|
+
{
|
|
3874
|
+
key: "help-subpages-linked-both-ways",
|
|
3875
|
+
label: "Each help sub-page links back to /help, and /help links forward to each of them",
|
|
3876
|
+
href: "/help",
|
|
3877
|
+
},
|
|
3878
|
+
{
|
|
3879
|
+
key: "help-subpage-content-matches-title",
|
|
3880
|
+
label: "Each help sub-page's content is about its own topic rather than repeating the parent page's text",
|
|
3881
|
+
href: "/help",
|
|
3882
|
+
},
|
|
3883
|
+
{
|
|
3884
|
+
key: "scams-types-page-loads",
|
|
3885
|
+
label: "The scam types page lists the real scam categories the registry uses, not a shorter hand-written subset",
|
|
3886
|
+
description: "The registry recognises a fixed set of scam types. A page listing fewer of them teaches reporters a vocabulary the report form will not accept.",
|
|
3887
|
+
href: "/scams/types",
|
|
3888
|
+
},
|
|
3889
|
+
{
|
|
3890
|
+
key: "scams-faqs-page-loads",
|
|
3891
|
+
label: "The scams FAQ page loads with real questions and answers rather than an empty accordion",
|
|
3892
|
+
href: "/scams/faqs",
|
|
3893
|
+
},
|
|
3894
|
+
{
|
|
3895
|
+
key: "scams-report-form-submits",
|
|
3896
|
+
label: "The scam report form validates its fields and submits, and the reporter is told what happens next",
|
|
3897
|
+
href: "/scams/report",
|
|
3898
|
+
},
|
|
3899
|
+
{
|
|
3900
|
+
key: "scams-report-errors-inline",
|
|
3901
|
+
label: "Submitting the scam report form with a required field empty shows the error on that field, not as a banner",
|
|
3902
|
+
href: "/scams/report",
|
|
3903
|
+
},
|
|
3904
|
+
{
|
|
3905
|
+
key: "scams-report-reaches-admin",
|
|
3906
|
+
label: "A submitted scam report reaches an admin surface where it can be actioned",
|
|
3907
|
+
description: "A form with no admin surface behind it tells a reporter their report was received and nobody will ever read it.",
|
|
3908
|
+
href: "/scams/report",
|
|
3909
|
+
},
|
|
3910
|
+
{
|
|
3911
|
+
key: "scams-subpages-linked-from-registry",
|
|
3912
|
+
label: "The /scams registry page links to the types, FAQ and report pages",
|
|
3913
|
+
href: "/scams",
|
|
3914
|
+
},
|
|
3915
|
+
{
|
|
3916
|
+
key: "public-seller-guide-loads",
|
|
3917
|
+
label: "The PUBLIC seller guide at /seller-guide loads and is distinct from the seller dashboard's own guide",
|
|
3918
|
+
description: "These are two different route families \u2014 /seller-guide is public marketing, /store/guide is the signed-in seller's manual. Coverage of one is not coverage of the other.",
|
|
3919
|
+
href: "/seller-guide",
|
|
3920
|
+
},
|
|
3921
|
+
{
|
|
3922
|
+
key: "public-seller-guide-subpages-load",
|
|
3923
|
+
label: "The seller-guide bundles and prize-draws pages load with real content and are linked from /seller-guide",
|
|
3924
|
+
href: "/seller-guide",
|
|
3925
|
+
},
|
|
3926
|
+
{
|
|
3927
|
+
key: "public-seller-guide-matches-product",
|
|
3928
|
+
label: "What the public seller guide promises about bundles and prize draws matches what the product actually does",
|
|
3929
|
+
description: "A guide is documentation with no compiler behind it. A promise the product no longer keeps is worse than no guide \u2014 a prospective seller signs up for something that is not there.",
|
|
3930
|
+
href: "/seller-guide",
|
|
3931
|
+
},
|
|
3932
|
+
{
|
|
3933
|
+
key: "seller-guide-reachable-signed-out",
|
|
3934
|
+
label: "A signed-out visitor can reach the public seller guide from the site, without being asked to sign in first",
|
|
3935
|
+
href: "/seller-guide",
|
|
3936
|
+
},
|
|
3937
|
+
{
|
|
3938
|
+
key: "item-requests-new-form-opens",
|
|
3939
|
+
label: "Opening the new-item-request page directly shows the form already open, and a submitted request appears in the item-requests list",
|
|
3940
|
+
href: "/item-requests/new",
|
|
3941
|
+
},
|
|
3942
|
+
],
|
|
3943
|
+
},
|
|
3631
3944
|
{
|
|
3632
3945
|
pageKey: "bug-hunters",
|
|
3633
3946
|
pageLabel: "Bug Hunters Leaderboard",
|
|
@@ -3644,6 +3957,166 @@ const rawTesterChecklistItems = [
|
|
|
3644
3957
|
],
|
|
3645
3958
|
},
|
|
3646
3959
|
]),
|
|
3960
|
+
...group("seo", "SEO & Metadata", [
|
|
3961
|
+
{
|
|
3962
|
+
pageKey: "canonical-and-host",
|
|
3963
|
+
pageLabel: "Canonical host & redirects",
|
|
3964
|
+
href: "/",
|
|
3965
|
+
cases: [
|
|
3966
|
+
{
|
|
3967
|
+
key: "apex-redirects-to-www",
|
|
3968
|
+
label: "The apex host redirects to the www host, and does so permanently rather than temporarily",
|
|
3969
|
+
description: "BEFORE: the apex 307'd to www. A 307 is TEMPORARY and explicitly tells a search engine NOT to move the index entry, so every page kept two competing addresses. AFTER: the redirect is permanent and the destination is the host the sitemap advertises.",
|
|
3970
|
+
},
|
|
3971
|
+
{
|
|
3972
|
+
key: "locale-prefix-redirects-to-bare",
|
|
3973
|
+
label: "A locale-prefixed path redirects to the unprefixed one",
|
|
3974
|
+
description: "BEFORE: /en/products 307'd to /products, so both spellings existed and every internal link that carried the prefix paid a redirect. AFTER: the prefixed form resolves to the bare path.",
|
|
3975
|
+
},
|
|
3976
|
+
{
|
|
3977
|
+
key: "canonical-matches-visited-host",
|
|
3978
|
+
label: "Every page's canonical link points at the same host the visitor is on, and that host is the one the sitemap uses",
|
|
3979
|
+
description: "BEFORE: the site had TWO owners of the hostname — one hardcoded, one read from an environment variable — and a comment claimed they were kept in sync. They were not, so the sitemap advertised the apex while the pages declared www. AFTER: one definition, one host, everywhere.",
|
|
3980
|
+
},
|
|
3981
|
+
{
|
|
3982
|
+
key: "no-inherited-homepage-canonical",
|
|
3983
|
+
label: "A page that declares no canonical of its own does NOT inherit the homepage's canonical",
|
|
3984
|
+
description: "BEFORE: the root layout set a static absolute canonical, so /promotions and /reviews each declared themselves duplicates of the homepage. AFTER: a page either declares its own canonical or has none — never the homepage's.",
|
|
3985
|
+
},
|
|
3986
|
+
{
|
|
3987
|
+
key: "tab-family-single-canonical",
|
|
3988
|
+
label: "A store's tab pages all share ONE canonical — the store's own URL — rather than four competing ones",
|
|
3989
|
+
description: "Tabs are views of one page. Four per-tab canonicals split the section into four addresses, none of which is the one in the sitemap. Per-tab titles and descriptions SHOULD still differ; only the canonical is shared.",
|
|
3990
|
+
href: "/stores/store-beyblade-arena",
|
|
3991
|
+
},
|
|
3992
|
+
{
|
|
3993
|
+
key: "redirect-only-page-no-canonical",
|
|
3994
|
+
label: "A page that only redirects carries no metadata of its own",
|
|
3995
|
+
description: "A redirect fires before the document is produced, so any metadata on it never reaches a browser — a crawler follows the redirect and reads the canonical of the page it LANDS on. Metadata there reads as though it were doing something.",
|
|
3996
|
+
href: "/promotions",
|
|
3997
|
+
},
|
|
3998
|
+
],
|
|
3999
|
+
},
|
|
4000
|
+
{
|
|
4001
|
+
pageKey: "sitemap-and-robots",
|
|
4002
|
+
pageLabel: "Sitemap & robots",
|
|
4003
|
+
href: "/sitemap.xml",
|
|
4004
|
+
cases: [
|
|
4005
|
+
{
|
|
4006
|
+
key: "sitemap-loads-and-parses",
|
|
4007
|
+
label: "The sitemap loads as valid XML with a non-trivial number of URLs",
|
|
4008
|
+
href: "/sitemap.xml",
|
|
4009
|
+
},
|
|
4010
|
+
{
|
|
4011
|
+
key: "sitemap-urls-do-not-redirect",
|
|
4012
|
+
label: "Every URL the sitemap advertises resolves directly — none of them redirects",
|
|
4013
|
+
description: "BEFORE: all 182 sitemap URLs redirected, because the sitemap named the apex host while the pages canonicalised to www. A sitemap full of redirects is how a site leaves the index without anything erroring.",
|
|
4014
|
+
href: "/sitemap.xml",
|
|
4015
|
+
},
|
|
4016
|
+
{
|
|
4017
|
+
key: "robots-loads-and-allows",
|
|
4018
|
+
label: "robots.txt loads, does not disallow the whole site, and names the same host as the sitemap",
|
|
4019
|
+
href: "/robots.txt",
|
|
4020
|
+
},
|
|
4021
|
+
{
|
|
4022
|
+
key: "robots-sitemap-line-correct",
|
|
4023
|
+
label: "The Sitemap: line in robots.txt points at a sitemap URL that actually loads",
|
|
4024
|
+
href: "/robots.txt",
|
|
4025
|
+
},
|
|
4026
|
+
{
|
|
4027
|
+
key: "sitemap-excludes-private-routes",
|
|
4028
|
+
label: "The sitemap lists no dashboard, checkout or auth route",
|
|
4029
|
+
description: "A signed-out crawler reaching /admin or /checkout gets a redirect or a shell, so listing them wastes crawl budget on pages that can never rank.",
|
|
4030
|
+
href: "/sitemap.xml",
|
|
4031
|
+
},
|
|
4032
|
+
{
|
|
4033
|
+
key: "sitemap-excludes-test-data",
|
|
4034
|
+
label: "The sitemap lists no tester-sandbox fixture",
|
|
4035
|
+
description: "Sandbox content is wiped and re-seeded by every tester run, so a sitemap entry for it is a URL that repeatedly 404s. Search for \"tester-sandbox\" in the sitemap.",
|
|
4036
|
+
href: "/sitemap.xml",
|
|
4037
|
+
},
|
|
4038
|
+
],
|
|
4039
|
+
},
|
|
4040
|
+
{
|
|
4041
|
+
pageKey: "page-metadata",
|
|
4042
|
+
pageLabel: "Per-page titles & descriptions",
|
|
4043
|
+
href: "/products",
|
|
4044
|
+
cases: [
|
|
4045
|
+
{
|
|
4046
|
+
key: "listing-pages-distinct-titles",
|
|
4047
|
+
label: "Each public listing page has its own title and description, not a shared site-wide default",
|
|
4048
|
+
href: "/products",
|
|
4049
|
+
},
|
|
4050
|
+
{
|
|
4051
|
+
key: "detail-page-title-from-record",
|
|
4052
|
+
label: "A product detail page's title and description come from that product, not from a template with the slug pasted in",
|
|
4053
|
+
description: "BEFORE: one listing type interpolated the raw slug into the title, so the tab read a hyphenated id rather than the product's name.",
|
|
4054
|
+
href: "/products/product-beyblade-burst-valkyrie",
|
|
4055
|
+
},
|
|
4056
|
+
{
|
|
4057
|
+
key: "detail-pages-have-canonical",
|
|
4058
|
+
label: "Every listing type's detail page declares a canonical — including classifieds, digital codes and live items",
|
|
4059
|
+
description: "BEFORE: three listing types were called without the site URL, so their metadata builder returned nothing and those pages shipped with NO canonical at all. Check all three, not just the standard product page.",
|
|
4060
|
+
href: "/classified/classified-tester-sandbox-1",
|
|
4061
|
+
},
|
|
4062
|
+
{
|
|
4063
|
+
key: "detail-canonical-uses-slug-not-id",
|
|
4064
|
+
label: "A detail page's canonical uses the slug the route actually takes",
|
|
4065
|
+
description: "BEFORE: a canonical was built from the record's id while the route was keyed on its slug, so the canonical named a URL that does not exist.",
|
|
4066
|
+
href: "/classified/classified-tester-sandbox-1",
|
|
4067
|
+
},
|
|
4068
|
+
{
|
|
4069
|
+
key: "single-h1-per-page",
|
|
4070
|
+
label: "Every page has exactly one top-level heading",
|
|
4071
|
+
href: "/products",
|
|
4072
|
+
},
|
|
4073
|
+
{
|
|
4074
|
+
key: "404-page-not-indexable",
|
|
4075
|
+
label: "A page that does not exist returns a 404 status and is marked not-indexable, rather than returning 200 with a 'not found' message",
|
|
4076
|
+
description: "A 'soft 404' — a 200 response whose body says the page is missing — keeps the URL in the index indefinitely. Use a product path whose trailing segment is a nonsense word.",
|
|
4077
|
+
href: "/products",
|
|
4078
|
+
},
|
|
4079
|
+
{
|
|
4080
|
+
key: "title-length-reasonable",
|
|
4081
|
+
label: "Titles are not truncated mid-word by the brand suffix and stay within a length a result page will show",
|
|
4082
|
+
href: "/products",
|
|
4083
|
+
},
|
|
4084
|
+
],
|
|
4085
|
+
},
|
|
4086
|
+
{
|
|
4087
|
+
pageKey: "og-images",
|
|
4088
|
+
pageLabel: "Social preview cards",
|
|
4089
|
+
href: "/",
|
|
4090
|
+
cases: [
|
|
4091
|
+
{
|
|
4092
|
+
key: "og-image-renders-homepage",
|
|
4093
|
+
label: "The homepage's social preview image renders as a real image, not a blank or errored one",
|
|
4094
|
+
href: "/",
|
|
4095
|
+
},
|
|
4096
|
+
{
|
|
4097
|
+
key: "og-image-product",
|
|
4098
|
+
label: "A product's social preview image shows that product's own title and image",
|
|
4099
|
+
href: "/products/product-beyblade-burst-valkyrie",
|
|
4100
|
+
},
|
|
4101
|
+
{
|
|
4102
|
+
key: "og-image-brand-logo-present",
|
|
4103
|
+
label: "A brand's social preview card shows the brand's cover image rather than an empty slot",
|
|
4104
|
+
description: "BEFORE: the brand card's image reader named a field that does not exist on the record at all, so the logo was always undefined and the card rendered without it — silently.",
|
|
4105
|
+
href: "/brands/brand-takara-tomy",
|
|
4106
|
+
},
|
|
4107
|
+
{
|
|
4108
|
+
key: "og-tags-present-and-absolute",
|
|
4109
|
+
label: "Open Graph and Twitter tags are present on public pages and their URLs are absolute, on the canonical host",
|
|
4110
|
+
href: "/products/product-beyblade-burst-valkyrie",
|
|
4111
|
+
},
|
|
4112
|
+
{
|
|
4113
|
+
key: "og-image-missing-media-fallback",
|
|
4114
|
+
label: "A record with no image of its own still produces a readable social card rather than a broken image",
|
|
4115
|
+
href: "/classified/classified-tester-sandbox-1",
|
|
4116
|
+
},
|
|
4117
|
+
],
|
|
4118
|
+
},
|
|
4119
|
+
]),
|
|
3647
4120
|
...group("admin", ADMIN_TESTING_GROUP_LABEL, [
|
|
3648
4121
|
{
|
|
3649
4122
|
pageKey: "catalog-listings",
|
|
@@ -4318,6 +4791,235 @@ const rawTesterChecklistItems = [
|
|
|
4318
4791
|
},
|
|
4319
4792
|
],
|
|
4320
4793
|
},
|
|
4794
|
+
{
|
|
4795
|
+
pageKey: "category-brand-authoring",
|
|
4796
|
+
pageLabel: "Category & Brand Authoring",
|
|
4797
|
+
href: "/admin/categories",
|
|
4798
|
+
cases: [
|
|
4799
|
+
{
|
|
4800
|
+
key: "create-child-under-parent",
|
|
4801
|
+
label: "Creating a category under a chosen parent files it at the right depth and it appears under that parent on the public tree",
|
|
4802
|
+
href: "/admin/categories",
|
|
4803
|
+
},
|
|
4804
|
+
{
|
|
4805
|
+
key: "structural-fields-derived-not-typed",
|
|
4806
|
+
label: "The category editor has no field for tier, path, ancestors or children — those are derived from the parent",
|
|
4807
|
+
description: "BEFORE: hand-writing any structural field is how a tree ends up internally inconsistent. Picking a parent must be the only structural input.",
|
|
4808
|
+
href: "/admin/categories",
|
|
4809
|
+
},
|
|
4810
|
+
{
|
|
4811
|
+
key: "reparent-moves-whole-subtree",
|
|
4812
|
+
label: "Re-parenting a category moves its whole subtree with it, and its descendants stay reachable",
|
|
4813
|
+
href: "/admin/categories",
|
|
4814
|
+
},
|
|
4815
|
+
{
|
|
4816
|
+
key: "product-created-with-deep-category-visible-at-root",
|
|
4817
|
+
label: "A product created through the form against a deep category appears on that category's ROOT page too",
|
|
4818
|
+
description: "🛑 KNOWN GAP, not a regression: nothing on the write side appends ancestors today, so a listing filed at tier 3 gets a one-element chain and is invisible on every ancestor page. Record what actually happens rather than assuming either answer.",
|
|
4819
|
+
href: "/admin/products",
|
|
4820
|
+
},
|
|
4821
|
+
{
|
|
4822
|
+
key: "brand-rename-orphan-check",
|
|
4823
|
+
label: "Renaming a brand does not silently orphan its products",
|
|
4824
|
+
description: "Products match a brand by DISPLAY NAME. Rename a brand, then reload its page: an empty grid where products used to be is the finding. Restore the original name afterwards.",
|
|
4825
|
+
href: "/admin/brands",
|
|
4826
|
+
},
|
|
4827
|
+
{
|
|
4828
|
+
key: "brand-cover-image-is-the-hero",
|
|
4829
|
+
label: "The brand editor's image field controls the image that actually renders as the brand page's hero",
|
|
4830
|
+
description: "BEFORE: a form had a Logo input and a Banner input side by side; Logo wrote the field the hero renders and Banner wrote a field with no readers at all, so every uploaded banner was silently discarded.",
|
|
4831
|
+
href: "/admin/brands",
|
|
4832
|
+
},
|
|
4833
|
+
{
|
|
4834
|
+
key: "category-type-not-guessable",
|
|
4835
|
+
label: "The category editor makes the row's kind explicit — a normal listing category, a brand, a sub-listing group or a bundle — rather than leaving it to be guessed",
|
|
4836
|
+
href: "/admin/categories",
|
|
4837
|
+
},
|
|
4838
|
+
{
|
|
4839
|
+
key: "delete-category-with-children-refused",
|
|
4840
|
+
label: "Deleting a category that still has children or products is refused with a reason naming what depends on it",
|
|
4841
|
+
description: "A delete that succeeds and orphans its subtree is unrecoverable. Refusing it, with the count, is the correct outcome.",
|
|
4842
|
+
href: "/admin/categories",
|
|
4843
|
+
},
|
|
4844
|
+
],
|
|
4845
|
+
},
|
|
4846
|
+
{
|
|
4847
|
+
pageKey: "uncovered-admin-pages",
|
|
4848
|
+
pageLabel: "Admin pages with no other coverage",
|
|
4849
|
+
href: "/admin",
|
|
4850
|
+
cases: [
|
|
4851
|
+
{ key: "action-index-renders", label: "The Action Index page renders the CTA registry rather than a blank shell", href: "/admin/action-index" },
|
|
4852
|
+
{ key: "admin-notifications-renders", label: "The Admin Notifications page lists notifications with a working row detail", href: "/admin/admin-notifications" },
|
|
4853
|
+
{ key: "maintenance-analysis-renders", label: "The Maintenance → Analysis page renders without an error boundary", href: "/admin/maintenance/analysis" },
|
|
4854
|
+
{
|
|
4855
|
+
key: "maintenance-client-errors-renders",
|
|
4856
|
+
label: "The Client Errors page lists browser-reported errors, newest first",
|
|
4857
|
+
description: "This is where a digest a user quotes from an error screen must be findable. An empty list is only correct if no client error has been reported.",
|
|
4858
|
+
href: "/admin/maintenance/client-errors",
|
|
4859
|
+
},
|
|
4860
|
+
{
|
|
4861
|
+
key: "maintenance-function-errors-renders",
|
|
4862
|
+
label: "The Function Errors page renders and states clearly when it has nothing to show",
|
|
4863
|
+
description: "This source has no production producer today, so an empty list is the expected state — but it must read as 'none recorded', not as a blank page.",
|
|
4864
|
+
href: "/admin/maintenance/function-errors",
|
|
4865
|
+
},
|
|
4866
|
+
{ key: "maintenance-payment-rollbacks-renders", label: "The Payment Rollbacks page renders and its rows open", href: "/admin/maintenance/payment-rollbacks" },
|
|
4867
|
+
{ key: "payment-method-clusters-renders", label: "The Payment Method Clusters page renders and each cluster opens", href: "/admin/payment-methods/clusters" },
|
|
4868
|
+
{ key: "settings-actions-renders", label: "The Settings → Actions page renders and a change to an action saves", href: "/admin/settings/actions" },
|
|
4869
|
+
{ key: "shipments-projections-renders", label: "The Shipment Projections page renders real figures rather than an empty chart", href: "/admin/shipments/projections" },
|
|
4870
|
+
{ key: "admin-stickers-renders", label: "The admin Stickers page lists sticker listings and its filters return results", href: "/admin/stickers" },
|
|
4871
|
+
{ key: "admin-deals-renders", label: "The Deals page renders and its rows open", href: "/admin/deals" },
|
|
4872
|
+
{ key: "admin-featured-renders", label: "The Featured page renders and a feature toggle persists across a reload", href: "/admin/featured" },
|
|
4873
|
+
{ key: "admin-features-renders", label: "The Product Features page lists features and a new one can be created", href: "/admin/features" },
|
|
4874
|
+
{
|
|
4875
|
+
key: "admin-guides-all-render",
|
|
4876
|
+
label: "Every admin guide page renders real content and none of them 404s",
|
|
4877
|
+
description: "Walk each guide in the Admin → Guide section. A guide describing a screen that no longer exists is a finding worth recording even though the page itself loads.",
|
|
4878
|
+
href: "/admin/guide",
|
|
4879
|
+
},
|
|
4880
|
+
],
|
|
4881
|
+
},
|
|
4882
|
+
{
|
|
4883
|
+
pageKey: "bans-and-trust",
|
|
4884
|
+
pageLabel: "Bans, Unbans & Trust",
|
|
4885
|
+
href: "/admin/users",
|
|
4886
|
+
cases: [
|
|
4887
|
+
{ key: "soft-ban-blocks-signin", label: "Soft-banning a user prevents them signing in and tells them why", href: "/admin/users" },
|
|
4888
|
+
{ key: "soft-ban-requires-reason", label: "A ban cannot be applied without a reason, and that reason reaches the banned user", href: "/admin/users" },
|
|
4889
|
+
{
|
|
4890
|
+
key: "unban-restores-access",
|
|
4891
|
+
label: "Unbanning restores access without the user having to sign out and back in on a new device",
|
|
4892
|
+
description: "Cached session fields refresh only periodically, so a just-unbanned user can keep hitting the block. The guard must re-read on navigation rather than trusting the cached snapshot.",
|
|
4893
|
+
href: "/admin/users",
|
|
4894
|
+
},
|
|
4895
|
+
{
|
|
4896
|
+
key: "hard-ban-cascade-runs",
|
|
4897
|
+
label: "A hard ban runs its full cascade rather than only flagging the account",
|
|
4898
|
+
description: "It is queued as a background job because it exceeds a request's time budget. The job's completion must be reported, not assumed.",
|
|
4899
|
+
href: "/admin/users",
|
|
4900
|
+
},
|
|
4901
|
+
{ key: "hard-ban-recorded-in-audit-log", label: "A hard ban, a soft ban and an unban each appear in the admin audit log with the acting admin and the reason", href: "/admin/audit-log" },
|
|
4902
|
+
{ key: "ban-status-visible-in-list", label: "A banned user is visibly marked in the users list without opening their record", href: "/admin/users" },
|
|
4903
|
+
{
|
|
4904
|
+
key: "ban-filter-returns-banned-only",
|
|
4905
|
+
label: "Filtering the users list by ban status returns only banned users",
|
|
4906
|
+
description: "A status chip whose value does not exactly match a stored value returns nothing forever, with no error anywhere.",
|
|
4907
|
+
href: "/admin/users",
|
|
4908
|
+
},
|
|
4909
|
+
{
|
|
4910
|
+
key: "session-ip-masked",
|
|
4911
|
+
label: "A session's IP address is masked wherever it is shown, and the unmasked value never reaches the browser",
|
|
4912
|
+
description: "Check the rendered value AND the page's own data payload — a masked display over an unmasked payload is still a leak.",
|
|
4913
|
+
href: "/admin/sessions",
|
|
4914
|
+
},
|
|
4915
|
+
{ key: "sessions-list-device-details", label: "The sessions list shows browser, operating system and last activity for each session", href: "/admin/sessions" },
|
|
4916
|
+
{ key: "revoke-session-signs-out", label: "Revoking a session signs that device out rather than only removing the row", href: "/admin/sessions" },
|
|
4917
|
+
{
|
|
4918
|
+
key: "unban-request-reaches-admin",
|
|
4919
|
+
label: "An unban request submitted by a banned user reaches an admin surface where it can be actioned",
|
|
4920
|
+
href: "/admin/users",
|
|
4921
|
+
},
|
|
4922
|
+
{
|
|
4923
|
+
key: "banned-user-content-handling",
|
|
4924
|
+
label: "A banned seller's listings stop being publicly visible, and unbanning restores them",
|
|
4925
|
+
href: "/admin/users",
|
|
4926
|
+
},
|
|
4927
|
+
],
|
|
4928
|
+
},
|
|
4929
|
+
{
|
|
4930
|
+
pageKey: "bulk-actions",
|
|
4931
|
+
pageLabel: "Bulk Actions",
|
|
4932
|
+
href: "/admin/products",
|
|
4933
|
+
cases: [
|
|
4934
|
+
{ key: "select-all-count-matches-page", label: "\"Select all\" selects the rows on the current page and its count matches what is visible", href: "/admin/products" },
|
|
4935
|
+
{
|
|
4936
|
+
key: "bulk-bar-appears-on-selection",
|
|
4937
|
+
label: "The bulk action bar appears when the first row is selected and disappears when the last is deselected",
|
|
4938
|
+
description: "It must hide by collapsing rather than by sliding away — a bar that keeps its layout height while invisible pushes every floating control up the screen on pages that have no bar.",
|
|
4939
|
+
href: "/admin/products",
|
|
4940
|
+
},
|
|
4941
|
+
{
|
|
4942
|
+
key: "bulk-destructive-confirms",
|
|
4943
|
+
label: "Every destructive bulk action asks for confirmation naming how many rows it will affect",
|
|
4944
|
+
description: "A destructive action with no confirmation executes immediately and irreversibly on a selection the admin may have built by accident.",
|
|
4945
|
+
href: "/admin/products",
|
|
4946
|
+
},
|
|
4947
|
+
{ key: "bulk-action-reports-result", label: "A bulk action reports how many rows succeeded and how many failed, rather than a bare success message", href: "/admin/products" },
|
|
4948
|
+
{ key: "bulk-partial-failure-named", label: "When some rows in a bulk action fail, the failures are named rather than folded into a count", href: "/admin/products" },
|
|
4949
|
+
{ key: "bulk-selection-clears-after-run", label: "The selection clears after a bulk action completes and the list reflects the change without a manual reload", href: "/admin/products" },
|
|
4950
|
+
{
|
|
4951
|
+
key: "bulk-selection-survives-filter-change",
|
|
4952
|
+
label: "Changing a filter while rows are selected either keeps the selection meaningful or clears it visibly — never acts on rows that are no longer shown",
|
|
4953
|
+
href: "/admin/products",
|
|
4954
|
+
},
|
|
4955
|
+
{
|
|
4956
|
+
key: "bulk-actions-from-registry",
|
|
4957
|
+
label: "The bulk actions offered are the registered ones for that resource, with consistent labels across admin and seller lists",
|
|
4958
|
+
href: "/admin/products",
|
|
4959
|
+
},
|
|
4960
|
+
{
|
|
4961
|
+
key: "bulk-no-dead-actions",
|
|
4962
|
+
label: "No bulk action is offered that does nothing when clicked",
|
|
4963
|
+
description: "BEFORE: a destructively-labelled bulk action's handler only cleared the selection — it read as working and cancelled nothing.",
|
|
4964
|
+
href: "/admin/offers",
|
|
4965
|
+
},
|
|
4966
|
+
{ key: "bulk-users-actions", label: "Bulk actions on the users list apply to every selected user and are recorded in the audit log", href: "/admin/users" },
|
|
4967
|
+
],
|
|
4968
|
+
},
|
|
4969
|
+
{
|
|
4970
|
+
pageKey: "content-deletes",
|
|
4971
|
+
pageLabel: "Editing & Deleting Content",
|
|
4972
|
+
href: "/admin/sections",
|
|
4973
|
+
cases: [
|
|
4974
|
+
{ key: "homepage-section-edit-persists", label: "Editing a homepage section's configuration persists and the public homepage reflects it", href: "/admin/sections" },
|
|
4975
|
+
{ key: "homepage-section-delete", label: "Deleting a homepage section removes it from the public homepage and the remaining sections keep their order", href: "/admin/sections" },
|
|
4976
|
+
{ key: "homepage-section-reorder", label: "Reordering homepage sections persists across a reload and the public page follows the new order", href: "/admin/sections" },
|
|
4977
|
+
{ key: "homepage-section-disable-vs-delete", label: "Disabling a section and deleting it are different actions with different outcomes, and the interface makes which is which obvious", href: "/admin/sections" },
|
|
4978
|
+
{ key: "carousel-slide-edit-persists", label: "Editing a carousel slide's background, cards and settings persists and shows on the homepage", href: "/admin/carousel" },
|
|
4979
|
+
{
|
|
4980
|
+
key: "carousel-slide-delete",
|
|
4981
|
+
label: "Deleting a carousel slide removes it from the homepage rotation and the remaining slides still autoplay",
|
|
4982
|
+
href: "/admin/carousel",
|
|
4983
|
+
},
|
|
4984
|
+
{
|
|
4985
|
+
key: "carousel-active-limit-enforced",
|
|
4986
|
+
label: "Activating more slides than the allowed maximum is refused with a reason rather than silently ignoring the extra ones",
|
|
4987
|
+
href: "/admin/carousel",
|
|
4988
|
+
},
|
|
4989
|
+
{ key: "blog-edit-persists", label: "Editing a blog post's title, body and cover image persists and the public post reflects every change", href: "/admin/blog" },
|
|
4990
|
+
{
|
|
4991
|
+
key: "blog-delete-removes-public-page",
|
|
4992
|
+
label: "Deleting a blog post removes its public page, which then returns a 404 rather than a blank article",
|
|
4993
|
+
href: "/admin/blog",
|
|
4994
|
+
},
|
|
4995
|
+
{
|
|
4996
|
+
key: "blog-unpublish-vs-delete",
|
|
4997
|
+
label: "Unpublishing a blog post hides it from the public list while keeping it editable; deleting removes it entirely",
|
|
4998
|
+
href: "/admin/blog",
|
|
4999
|
+
},
|
|
5000
|
+
{
|
|
5001
|
+
key: "listing-delete-removes-public-page",
|
|
5002
|
+
label: "Deleting a listing removes its public detail page and takes it out of every listing grid it appeared in",
|
|
5003
|
+
href: "/admin/products",
|
|
5004
|
+
},
|
|
5005
|
+
{
|
|
5006
|
+
key: "listing-delete-with-orders-refused-or-archived",
|
|
5007
|
+
label: "Deleting a listing that already has orders against it is refused or archived rather than hard-deleted",
|
|
5008
|
+
description: "An order's rows denormalise what they display, so an existing order survives — but the buyer's link into the product breaks. Record which of the two behaviours actually happens.",
|
|
5009
|
+
href: "/admin/products",
|
|
5010
|
+
},
|
|
5011
|
+
{
|
|
5012
|
+
key: "delete-confirmations-name-the-record",
|
|
5013
|
+
label: "Every delete confirmation names the specific record it will remove, not just 'this item'",
|
|
5014
|
+
href: "/admin/products",
|
|
5015
|
+
},
|
|
5016
|
+
{
|
|
5017
|
+
key: "delete-reflected-immediately",
|
|
5018
|
+
label: "A deleted record disappears from its list without a manual reload, and stays gone after one",
|
|
5019
|
+
href: "/admin/products",
|
|
5020
|
+
},
|
|
5021
|
+
],
|
|
5022
|
+
},
|
|
4321
5023
|
], { adminOnly: true }),
|
|
4322
5024
|
// Demo fixture pair — deliberately outside group() since these two items
|
|
4323
5025
|
// exercise the confirm-bug → reopen-as-new-version lifecycle directly
|
|
@@ -4375,6 +5077,11 @@ const rawTesterChecklistItems = [
|
|
|
4375
5077
|
label: "A deep link to an editor survives a reload",
|
|
4376
5078
|
description: "Open a team member's edit page, then reload. The panel is still open, on the same record. This is the whole reason these pages exist — a drawer alone cannot be bookmarked, shared with a colleague, or reopened after a crash.",
|
|
4377
5079
|
},
|
|
5080
|
+
{
|
|
5081
|
+
key: "every-new-editor-route-opens",
|
|
5082
|
+
label: "EVERY editor-as-a-page route across admin and store opens with its form showing \u2014 not just the three named above",
|
|
5083
|
+
description: "Sweep them all: admin categories, brands, bundles, faqs, ads, shipments, addresses, grouped-listings, sublisting-categories, carousel and carousels; store addresses, sublisting-categories, stickers, pre-orders and listing-templates. Each is a real route; a blank one is a working URL with nothing on it.",
|
|
5084
|
+
},
|
|
4378
5085
|
],
|
|
4379
5086
|
},
|
|
4380
5087
|
{
|
|
@@ -4520,6 +5227,26 @@ const rawTesterChecklistItems = [
|
|
|
4520
5227
|
},
|
|
4521
5228
|
],
|
|
4522
5229
|
},
|
|
5230
|
+
{
|
|
5231
|
+
pageKey: "navbar-ctas",
|
|
5232
|
+
pageLabel: "Navbar & header CTAs",
|
|
5233
|
+
href: "/",
|
|
5234
|
+
cases: [
|
|
5235
|
+
{ key: "header-ctas-all-navigate", label: "Every control in the public header navigates somewhere real \u2014 none is inert", href: "/" },
|
|
5236
|
+
{ key: "header-cart-badge-live", label: "The header's cart control shows a live item count that follows the cart", href: "/" },
|
|
5237
|
+
{ key: "header-signed-out-vs-in", label: "The header offers sign-in when signed out and an account menu when signed in, and switches without a reload", href: "/" },
|
|
5238
|
+
{ key: "account-menu-links-resolve", label: "Every item in the account menu lands on a real page for that role", href: "/" },
|
|
5239
|
+
{ key: "role-specific-nav-entries", label: "A seller sees the store entry and a buyer does not, and an admin sees the admin entry", href: "/" },
|
|
5240
|
+
{ key: "mobile-nav-opens-and-closes", label: "The mobile navigation opens, closes, and closes again after a link is followed", href: "/" },
|
|
5241
|
+
{ key: "nav-active-state-correct", label: "The navigation marks the section the visitor is actually in", href: "/" },
|
|
5242
|
+
{
|
|
5243
|
+
key: "announcement-bar-message-renders",
|
|
5244
|
+
label: "An announcement configured by an admin appears in the announcement bar",
|
|
5245
|
+
description: "BEFORE: the admin editor saved the copy under a key no renderer has ever read, so announcements saved successfully and never appeared.",
|
|
5246
|
+
href: "/",
|
|
5247
|
+
},
|
|
5248
|
+
],
|
|
5249
|
+
},
|
|
4523
5250
|
]),
|
|
4524
5251
|
...group("addresses", "Addresses", [
|
|
4525
5252
|
{
|
|
@@ -4683,6 +5410,22 @@ const rawTesterChecklistItems = [
|
|
|
4683
5410
|
],
|
|
4684
5411
|
},
|
|
4685
5412
|
]),
|
|
5413
|
+
/* ══════════════════════════════════════════════════════════════════════════
|
|
5414
|
+
* END-TO-END MONEY FLOWS
|
|
5415
|
+
*
|
|
5416
|
+
* These are the flows that move money or ownership, and they were the largest
|
|
5417
|
+
* hole in the catalogue: offers had cases for making one but none for the
|
|
5418
|
+
* seller ACCEPTING it and the buyer then PAYING, and a won auction had no
|
|
5419
|
+
* payment path tested at all — which is exactly where Root Cause #60 lived
|
|
5420
|
+
* (settlement wrote an order nobody could pay for, and no case would have
|
|
5421
|
+
* caught it).
|
|
5422
|
+
*
|
|
5423
|
+
* Every case here is written as numbered steps against a NAMED fixture, with
|
|
5424
|
+
* the expectation stated separately. A step is something a person does; the
|
|
5425
|
+
* expectation is what they then see. Keeping them apart is what stops a
|
|
5426
|
+
* tester reporting "I did the actions" as if it were "the outcome was right".
|
|
5427
|
+
* ══════════════════════════════════════════════════════════════════════════ */
|
|
5428
|
+
...group("money-flows", "Money Flows (end to end)", moneyFlowsPages),
|
|
4686
5429
|
];
|
|
4687
5430
|
const defaultPhases = assignDefaultPhases(rawTesterChecklistItems);
|
|
4688
5431
|
export const testerChecklistSeedData = rawTesterChecklistItems.map((item, index) => ({
|