@mohasinac/appkit 4.40.1 → 4.41.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/features/categories/repository/categories.repository.js +2 -2
- package/dist/features/tester/seed-data/_money-flows.js +65 -49
- package/dist/features/tester/seed-data/authored/admin__admin-detail-round-trips.js +6 -4
- package/dist/features/tester/seed-data/authored/admin__coupons.js +14 -13
- package/dist/features/tester/seed-data/authored/buying__bidding.js +154 -140
- package/dist/features/tester/seed-data/authored/buying__browsing-search.js +4 -4
- package/dist/features/tester/seed-data/authored/buying__buying-checkout.js +59 -56
- package/dist/features/tester/seed-data/authored/buying__buying-coupons.js +18 -18
- package/dist/features/tester/seed-data/authored/buying__cart.js +105 -79
- package/dist/features/tester/seed-data/authored/buying__image-tile-layout.js +6 -8
- package/dist/features/tester/seed-data/authored/buying__my-orders.js +13 -13
- package/dist/features/tester/seed-data/authored/buying__offers.js +6 -6
- package/dist/features/tester/seed-data/authored/buying__order-detail-actions.js +8 -7
- package/dist/features/tester/seed-data/authored/buying__product-detail.js +62 -56
- package/dist/features/tester/seed-data/authored/buying__return-request.js +6 -6
- package/dist/features/tester/seed-data/authored/buying__reviews-pagination.js +4 -4
- package/dist/features/tester/seed-data/authored/buying__reviews.js +1 -1
- package/dist/features/tester/seed-data/authored/buying__user-dashboard-extras.js +8 -8
- package/dist/features/tester/seed-data/authored/content-discovery__category-counts-and-rollup.js +1 -1
- package/dist/features/tester/seed-data/authored/content-discovery__coupons.js +29 -16
- package/dist/features/tester/seed-data/authored/content-discovery__event-detail-subroutes.js +9 -9
- package/dist/features/tester/seed-data/authored/content-discovery__events.js +69 -36
- package/dist/features/tester/seed-data/authored/content-discovery__notifications.js +1 -1
- package/dist/features/tester/seed-data/authored/cta-layout__checkout-bottom-bar.js +2 -2
- package/dist/features/tester/seed-data/authored/design-ux__back-to-top-button.js +2 -2
- package/dist/features/tester/seed-data/authored/design-ux__general-design.js +1 -1
- package/dist/features/tester/seed-data/authored/design-ux__status-badge-legibility.js +1 -1
- package/dist/features/tester/seed-data/authored/design-ux__sticky-cta-bar.js +3 -3
- package/dist/features/tester/seed-data/authored/index.js +0 -2
- package/dist/features/tester/seed-data/authored/page-wiring__data-loss.js +2 -2
- package/dist/features/tester/seed-data/authored/page-wiring__reachability.js +6 -4
- package/dist/features/tester/seed-data/authored/public-pages__auth-error-pages.js +2 -2
- package/dist/features/tester/seed-data/authored/public-pages__core-listing-pages.js +1 -1
- package/dist/features/tester/seed-data/authored/public-pages__stores-sellers-directories.js +8 -10
- package/dist/features/tester/seed-data/authored/selling__become-seller.js +2 -2
- package/dist/features/tester/seed-data/authored/selling__digital-content-delivery.js +2 -2
- package/dist/features/tester/seed-data/authored/selling__listing-a-product.js +2 -2
- package/dist/features/tester/seed-data/authored/selling__listing-edit-roundtrip.js +2 -2
- package/dist/features/tester/seed-data/authored/selling__listing-lifecycle.js +2 -2
- package/dist/features/tester/seed-data/authored/selling__seller-listing-types.js +2 -2
- package/dist/features/tester/seed-data/authored/seo__og-images.js +3 -4
- package/dist/features/tester/seed-data/authored/seo__page-metadata.js +6 -8
- package/dist/features/tester/seed-data/authored/seo__sitemap-and-robots.js +5 -5
- package/dist/features/tester/seed-data/index.d.ts +0 -10
- package/dist/features/tester/seed-data/index.js +0 -10
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +75 -89
- package/dist/features/tester/seed-data/tester-responses-seed-data.js +5 -5
- package/dist/index.d.ts +0 -8
- package/dist/index.js +0 -21
- package/dist/seed/addresses-seed-data.js +0 -34
- package/dist/seed/index.d.ts +1 -1
- package/dist/seed/index.js +4 -3
- package/dist/seed/manifest.js +11 -12
- package/dist/seed/notifications-seed-data.js +4 -4
- package/dist/seed/stores-seed-data.js +7 -52
- package/dist/seed/users-seed-data.js +3 -83
- package/package.json +1 -1
- package/scripts/seed-cli.mjs +15 -20
|
@@ -50,28 +50,41 @@ export const authored = {
|
|
|
50
50
|
expectedUiState: "The applied amount matches the card's stated terms, including any maximum-discount cap the card should also be stating. ARENA25 appears in the applied list with no error.",
|
|
51
51
|
endResult: "Reloading /checkout shows the same coupon and amount. A discrepancy between the card and the applied amount is a copy bug at minimum and a pricing bug at worst.",
|
|
52
52
|
},
|
|
53
|
+
/*
|
|
54
|
+
* 🛑 THE EXPIRY IS NOW AUTHORED, 2026-09-15.
|
|
55
|
+
*
|
|
56
|
+
* This used to use a coupon seeded past its end date while still flagged
|
|
57
|
+
* active — the one shape that exercises the DATE check rather than the flag.
|
|
58
|
+
* That fixture is gone and every permanent coupon has a future end date, so
|
|
59
|
+
* the admin sets one back by hand. Leaving Active ON is the whole point: a
|
|
60
|
+
* validator that reads only the flag accepts this coupon, and that is the bug.
|
|
61
|
+
*/
|
|
53
62
|
"checklist-content-discovery-coupons-coupon-expired-rejected": {
|
|
54
|
-
roles: ["buyer"],
|
|
55
|
-
startPage: "/
|
|
63
|
+
roles: ["admin", "buyer"],
|
|
64
|
+
startPage: "/admin/coupons",
|
|
56
65
|
steps: [
|
|
57
|
-
"Sign in as
|
|
66
|
+
"Sign in as admin@letitrip.in / TempPass123!.",
|
|
67
|
+
"Open /admin/coupons, open SEALED20 for editing, and write down its end date.",
|
|
68
|
+
"Set its end date to yesterday and LEAVE the Active toggle ON, then save.",
|
|
69
|
+
"Sign out and sign in as vivaan.kapoor@gmail.com / TempPass123!.",
|
|
58
70
|
"Add product-beyblade-burst-regalia-genesis (₹1,399) to the cart.",
|
|
59
71
|
"Open /checkout and complete the address and add-ons steps.",
|
|
60
|
-
"Type
|
|
72
|
+
"Type SEALED20 in the coupon field and click 'Apply'.",
|
|
61
73
|
"Read the exact wording of the rejection.",
|
|
74
|
+
"Sign back in as admin@letitrip.in and restore the end date written down in step 2.",
|
|
62
75
|
],
|
|
63
|
-
inputs: { coupon: "
|
|
64
|
-
expectedBehaviour: "An expired coupon is refused with a reason that names expiry specifically.
|
|
65
|
-
expectedUiState: "The rejection names expiry, in the shape 'This coupon has expired'. It does not read 'Invalid coupon', which would leave the buyer retyping a code that will never work.
|
|
76
|
+
inputs: { coupon: "SEALED20" },
|
|
77
|
+
expectedBehaviour: "An expired coupon is refused with a reason that names expiry specifically. With the end date in the past and isActive still true, this exercises the date check rather than the active flag — the two are separate reasons and a single generic message cannot tell a buyer which applies.",
|
|
78
|
+
expectedUiState: "The rejection names expiry, in the shape 'This coupon has expired'. It does not read 'Invalid coupon', which would leave the buyer retyping a code that will never work. SEALED20 does not enter the applied list.",
|
|
66
79
|
expectedData: { couponApplied: false },
|
|
67
|
-
endResult: "Reloading /checkout shows
|
|
80
|
+
endResult: "Reloading /checkout shows SEALED20 absent. The end date is restored by the final step — leaving it in the past silently breaks every later coupon case.",
|
|
68
81
|
},
|
|
69
82
|
"checklist-content-discovery-coupons-coupon-below-min-purchase": {
|
|
70
83
|
roles: ["buyer"],
|
|
71
84
|
startPage: "/checkout",
|
|
72
85
|
steps: [
|
|
73
86
|
"Sign in as vivaan.kapoor@gmail.com / TempPass123!.",
|
|
74
|
-
"Add product-
|
|
87
|
+
"Add product-beyblade-metal-storm-pegasus (₹99) to the cart and nothing else.",
|
|
75
88
|
"Open /checkout and complete the address and add-ons steps.",
|
|
76
89
|
"Type ARENA25 in the coupon field and click 'Apply'.",
|
|
77
90
|
"Read the exact wording of the rejection and whether it names the required amount.",
|
|
@@ -105,15 +118,15 @@ export const authored = {
|
|
|
105
118
|
startPage: "/checkout",
|
|
106
119
|
steps: [
|
|
107
120
|
"Sign in as vivaan.kapoor@gmail.com / TempPass123!.",
|
|
108
|
-
"Add product-beyblade-
|
|
109
|
-
"Open /checkout, complete the address and add-ons steps, apply
|
|
110
|
-
"Add product-beyblade-
|
|
111
|
-
"Open /checkout, complete the address and add-ons steps, and type
|
|
121
|
+
"Add 2 × product-beyblade-original-dranzer-s (₹1,499 each, ₹2,998 total — above ARENAVIP's ₹2,000 minimum and in an eligible category) to the cart.",
|
|
122
|
+
"Open /checkout, complete the address and add-ons steps, apply ARENAVIP, and place the order with Cash on Delivery.",
|
|
123
|
+
"Add 2 × product-beyblade-original-dranzer-s to the cart again.",
|
|
124
|
+
"Open /checkout, complete the address and add-ons steps, and type ARENAVIP in the coupon field.",
|
|
112
125
|
"Read the rejection.",
|
|
113
|
-
"Sign out, sign in as rehan.sheikh@gmail.com / TempPass123!, add the same
|
|
126
|
+
"Sign out, sign in as rehan.sheikh@gmail.com / TempPass123!, add the same two items, and apply ARENAVIP at checkout.",
|
|
114
127
|
],
|
|
115
|
-
inputs: { coupon: "
|
|
116
|
-
expectedBehaviour: "
|
|
128
|
+
inputs: { coupon: "ARENAVIP", perUserLimit: 1 },
|
|
129
|
+
expectedBehaviour: "ARENAVIP allows one use per user, and its total limit of 50 has 38 uses left — so exhausting it for one buyer must leave it usable by the next. Enforcing a per-user limit as if it were global would withdraw the coupon from everybody after a single redemption.",
|
|
117
130
|
expectedUiState: "The second attempt by the same buyer is refused with a limit-reached message. The DIFFERENT buyer's attempt is accepted and the coupon appears in their applied list. A refusal for the second buyer means the limit is being read as global.",
|
|
118
131
|
expectedData: { perUserLimit: 1 },
|
|
119
132
|
endResult: "One order carries the discount and a second buyer can still use the code. The cross-account half is the case — the same-account half alone passes under either reading.",
|
package/dist/features/tester/seed-data/authored/content-discovery__event-detail-subroutes.js
CHANGED
|
@@ -45,7 +45,7 @@ export const authored = {
|
|
|
45
45
|
roles: ["buyer"],
|
|
46
46
|
startPage: "/events",
|
|
47
47
|
steps: [
|
|
48
|
-
"Sign in as the
|
|
48
|
+
"Sign in as the buyer rehan.sheikh@gmail.com / TempPass123!.",
|
|
49
49
|
"Open /events/event-favourite-blader-poll.",
|
|
50
50
|
"Open its Participate tab.",
|
|
51
51
|
"Submit the first available option.",
|
|
@@ -62,7 +62,7 @@ export const authored = {
|
|
|
62
62
|
roles: ["buyer"],
|
|
63
63
|
startPage: "/events",
|
|
64
64
|
steps: [
|
|
65
|
-
"Sign in as the
|
|
65
|
+
"Sign in as the buyer rehan.sheikh@gmail.com / TempPass123! and open /events/event-favourite-blader-poll.",
|
|
66
66
|
"Participate once if you have not already.",
|
|
67
67
|
"Reload, and try to participate a second time with a different option.",
|
|
68
68
|
"Read what happens.",
|
|
@@ -78,15 +78,15 @@ export const authored = {
|
|
|
78
78
|
roles: ["guest"],
|
|
79
79
|
startPage: "/events",
|
|
80
80
|
steps: [
|
|
81
|
-
"Open /events/event-
|
|
82
|
-
"Read the
|
|
83
|
-
"Check that
|
|
81
|
+
"Open /events/event-favourite-blader-poll and open its Leaderboard tab.",
|
|
82
|
+
"Read the number beside each of the first five rows — the vote or score the row is ranked on.",
|
|
83
|
+
"Check that those numbers are in descending order.",
|
|
84
84
|
"Read the total entry count the event reports.",
|
|
85
85
|
"Count the rows the leaderboard lists, paging if needed.",
|
|
86
86
|
],
|
|
87
|
-
inputs: { eventId: "event-
|
|
88
|
-
expectedBehaviour: "The leaderboard orders by a stored
|
|
89
|
-
expectedUiState: "
|
|
87
|
+
inputs: { eventId: "event-favourite-blader-poll" },
|
|
88
|
+
expectedBehaviour: "The leaderboard orders by a stored number and covers the same entries the event counts. A ranking that is merely insertion order looks correct whenever the data happens to arrive sorted, so the descending check has to be explicit.",
|
|
89
|
+
expectedUiState: "The numbers descend down the list, and the number of entries listed matches the count the event reports. A leaderboard showing no number at all beside each row is the failure — there is then nothing it can be ranking by.",
|
|
90
90
|
expectedData: { scoresDescending: true },
|
|
91
91
|
endResult: "Nothing is changed; this case only reads.",
|
|
92
92
|
},
|
|
@@ -123,7 +123,7 @@ export const authored = {
|
|
|
123
123
|
roles: ["buyer"],
|
|
124
124
|
startPage: "/events",
|
|
125
125
|
steps: [
|
|
126
|
-
"Sign in as the
|
|
126
|
+
"Sign in as the buyer rehan.sheikh@gmail.com / TempPass123!.",
|
|
127
127
|
"Open /events/event-x-launch-raffle-cancelled — a CANCELLED raffle.",
|
|
128
128
|
"Read the event header for its status.",
|
|
129
129
|
"Open the Participate tab.",
|
|
@@ -52,13 +52,13 @@ export const authored = {
|
|
|
52
52
|
roles: ["guest"],
|
|
53
53
|
startPage: "/events",
|
|
54
54
|
steps: [
|
|
55
|
-
"Open /events in a private window and find event-
|
|
55
|
+
"Open /events in a private window and find event-pokemon-number-draw-july-2026.",
|
|
56
56
|
"Look at its card image.",
|
|
57
57
|
"Open the lottery's detail page.",
|
|
58
58
|
"Look at the image at the top of that page.",
|
|
59
59
|
"Note whether either shows an emoji instead of a photograph.",
|
|
60
60
|
],
|
|
61
|
-
inputs: { eventId: "event-
|
|
61
|
+
inputs: { eventId: "event-pokemon-number-draw-july-2026" },
|
|
62
62
|
expectedBehaviour: "A lottery renders its stored cover image on both the card and the detail page. The 🎰 emoji is the fallback for an event with no image, and seeing it where one is set means the field is not reaching the renderer.",
|
|
63
63
|
expectedUiState: "Both the card and the detail hero show the cover photograph. Neither shows the 🎰 emoji placeholder.",
|
|
64
64
|
endResult: "Read-only; nothing persists.",
|
|
@@ -67,7 +67,7 @@ export const authored = {
|
|
|
67
67
|
roles: ["guest"],
|
|
68
68
|
startPage: "/events",
|
|
69
69
|
steps: [
|
|
70
|
-
"Open event-
|
|
70
|
+
"Open event-pokemon-number-draw-july-2026's detail page in a private window.",
|
|
71
71
|
"Find the 'Prizes' collage above the numbered slot grid.",
|
|
72
72
|
"Count the tiles in the collage.",
|
|
73
73
|
"Count the slots in the numbered grid below it.",
|
|
@@ -163,13 +163,13 @@ export const authored = {
|
|
|
163
163
|
startPage: "/events",
|
|
164
164
|
steps: [
|
|
165
165
|
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
166
|
-
"Open event-
|
|
166
|
+
"Open event-buy-3-get-1-beyblades and read the coupon code displayed.",
|
|
167
167
|
"Click the copy control beside it.",
|
|
168
168
|
"Read any confirmation shown.",
|
|
169
169
|
"Open /checkout with an item in the cart and paste into the coupon field.",
|
|
170
170
|
"Read what was pasted and click 'Apply'.",
|
|
171
171
|
],
|
|
172
|
-
inputs: { eventId: "event-
|
|
172
|
+
inputs: { eventId: "event-buy-3-get-1-beyblades" },
|
|
173
173
|
expectedBehaviour: "The code is shown in full and the copy control puts exactly that string on the clipboard. A copy control that copies a truncated or differently-cased value produces a rejection the buyer cannot explain.",
|
|
174
174
|
expectedUiState: "The code is legible in full on the page. Copying shows a confirmation. The pasted value matches the displayed code character for character, and applying it is accepted.",
|
|
175
175
|
endResult: "Remove the coupon afterwards so later checkout cases start from an empty coupon list.",
|
|
@@ -191,47 +191,68 @@ export const authored = {
|
|
|
191
191
|
expectedData: { entriesPerUser: 1 },
|
|
192
192
|
endResult: "The entry survives the reload.",
|
|
193
193
|
},
|
|
194
|
+
/*
|
|
195
|
+
* 🛑 THESE TWO CASES CHANGED SHAPE, 2026-09-15.
|
|
196
|
+
*
|
|
197
|
+
* They used to open one fixture per raffleType — a `top_n_scorers` event and a
|
|
198
|
+
* `top_n_participants` one — and compare their leaderboards side by side. Both
|
|
199
|
+
* fixtures are gone and the permanent seed carries only `open_raffle`, so the
|
|
200
|
+
* comparison has no second half to make.
|
|
201
|
+
*
|
|
202
|
+
* Rather than delete the coverage, each case now AUTHORS the raffle type it is
|
|
203
|
+
* about, on a real event, and then reads the leaderboard back. That is a
|
|
204
|
+
* stronger test than the old one — it exercises the admin write path as well as
|
|
205
|
+
* the render — and it is the only form the current seed can express.
|
|
206
|
+
*/
|
|
194
207
|
"checklist-content-discovery-events-raffle-entry-top-n-scorers": {
|
|
195
|
-
roles: ["buyer"],
|
|
196
|
-
startPage: "/events",
|
|
208
|
+
roles: ["admin", "buyer"],
|
|
209
|
+
startPage: "/admin/events",
|
|
197
210
|
steps: [
|
|
198
|
-
"Sign in as
|
|
199
|
-
"Open event-
|
|
211
|
+
"Sign in as admin@letitrip.in / TempPass123!.",
|
|
212
|
+
"Open /admin/events, open event-win-burst-regalia-genesis for editing, and write down its current raffle type.",
|
|
213
|
+
"Set the raffle type to 'Top N scorers', set the N to 3, and save.",
|
|
214
|
+
"Sign out and sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
215
|
+
"Open /events/event-win-burst-regalia-genesis and read the Overview tab's description of how winners are chosen.",
|
|
200
216
|
"Click the Participate tab and enter.",
|
|
201
217
|
"Click the Leaderboard tab and read how entries are ranked.",
|
|
202
|
-
"Read whether the ranking is by score and whether the eligible cut-off is stated.",
|
|
218
|
+
"Read whether the ranking is by score and whether the eligible cut-off of 3 is stated.",
|
|
219
|
+
"Sign back in as admin@letitrip.in and restore the raffle type written down in step 2.",
|
|
203
220
|
],
|
|
204
|
-
inputs: { eventId: "event-
|
|
205
|
-
expectedBehaviour: "A top-N-scorers raffle draws from the highest-scoring entries, so the leaderboard must rank by score and the page must say how many qualify. Ranking by entry time instead would silently change who can win.",
|
|
206
|
-
expectedUiState: "The leaderboard is ordered by score, highest first, and the
|
|
207
|
-
endResult: "The entry survives a reload.",
|
|
221
|
+
inputs: { eventId: "event-win-burst-regalia-genesis", raffleTopN: 3 },
|
|
222
|
+
expectedBehaviour: "A top-N-scorers raffle draws from the highest-scoring entries, so the leaderboard must rank by score and the page must say how many qualify. Ranking by entry time instead would silently change who can win. The saved raffle type must also reach the public page — an admin field that saves and never renders is the commonest shape of this bug.",
|
|
223
|
+
expectedUiState: "The Overview tab names the top-3-by-score rule after the save. The leaderboard is ordered by score, highest first, and the cut-off is stated. Entering is confirmed. A leaderboard still ordered by entry time is the failure.",
|
|
224
|
+
endResult: "The entry survives a reload. The raffle type is restored by the final step.",
|
|
208
225
|
},
|
|
209
226
|
"checklist-content-discovery-events-raffle-entry-top-n-participants": {
|
|
210
|
-
roles: ["buyer"],
|
|
211
|
-
startPage: "/events",
|
|
227
|
+
roles: ["admin", "buyer"],
|
|
228
|
+
startPage: "/admin/events",
|
|
212
229
|
steps: [
|
|
213
|
-
"Sign in as
|
|
214
|
-
"Open event-
|
|
230
|
+
"Sign in as admin@letitrip.in / TempPass123!.",
|
|
231
|
+
"Open /admin/events, open event-win-burst-regalia-genesis for editing, and write down its current raffle type.",
|
|
232
|
+
"Set the raffle type to 'Top N participants', set the N to 3, and save.",
|
|
233
|
+
"Sign out and sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
234
|
+
"Open /events/event-win-burst-regalia-genesis and read the Overview tab's description of how winners are chosen.",
|
|
215
235
|
"Click the Participate tab and enter.",
|
|
216
236
|
"Click the Leaderboard tab and read how entries are ranked.",
|
|
217
|
-
"Compare the
|
|
237
|
+
"Compare the stated rule with the top-N-scorers rule from the previous case.",
|
|
238
|
+
"Sign back in as admin@letitrip.in and restore the raffle type written down in step 2.",
|
|
218
239
|
],
|
|
219
|
-
inputs: { eventId: "event-
|
|
220
|
-
expectedBehaviour: "A top-N-participants raffle draws from the earliest or most active participants rather than the highest scorers — a different rule from the scorers variant.
|
|
221
|
-
expectedUiState: "
|
|
222
|
-
endResult: "The entry survives a reload.",
|
|
240
|
+
inputs: { eventId: "event-win-burst-regalia-genesis", raffleTopN: 3 },
|
|
241
|
+
expectedBehaviour: "A top-N-participants raffle draws from the earliest or most active participants rather than the highest scorers — a different rule from the scorers variant. Running both against the same event is what makes the difference checkable now that there is no fixture per type.",
|
|
242
|
+
expectedUiState: "The Overview tab names a participation rule, not a score rule, and the leaderboard is ordered accordingly. Wording identical to the previous case means the raffle type is not reaching the leaderboard.",
|
|
243
|
+
endResult: "The entry survives a reload. The raffle type is restored by the final step.",
|
|
223
244
|
},
|
|
224
245
|
"checklist-content-discovery-events-spin-wheel": {
|
|
225
246
|
roles: ["buyer"],
|
|
226
247
|
startPage: "/events",
|
|
227
248
|
steps: [
|
|
228
249
|
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
229
|
-
"Open event-
|
|
250
|
+
"Open event-daily-beyblade-pull-wheel and click the Participate tab.",
|
|
230
251
|
"Click the spin control ONCE and watch the wheel.",
|
|
231
252
|
"Read the prize shown and how long it took to appear.",
|
|
232
253
|
"Reload the page and read the Participate tab.",
|
|
233
254
|
],
|
|
234
|
-
inputs: { eventId: "event-
|
|
255
|
+
inputs: { eventId: "event-daily-beyblade-pull-wheel" },
|
|
235
256
|
expectedBehaviour: "The very first spin succeeds and the prize is shown immediately over the realtime channel. A first attempt that fails and a second that works is the signature of a subscription established after the result was already written.",
|
|
236
257
|
expectedUiState: "The wheel spins and lands on a named prize within a few seconds. No 'Spin failed' error appears on the first attempt. After reloading, the result is still shown rather than the wheel offering another free spin.",
|
|
237
258
|
expectedData: { spinsUsed: 1 },
|
|
@@ -242,7 +263,7 @@ export const authored = {
|
|
|
242
263
|
startPage: "/events",
|
|
243
264
|
steps: [
|
|
244
265
|
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
245
|
-
"Open event-
|
|
266
|
+
"Open event-daily-beyblade-pull-wheel and read the stated maximum spins per user.",
|
|
246
267
|
"Spin until that maximum is reached, reading the remaining count each time.",
|
|
247
268
|
"Attempt one more spin.",
|
|
248
269
|
"Read the refusal.",
|
|
@@ -253,25 +274,37 @@ export const authored = {
|
|
|
253
274
|
expectedData: { spinsAfterReload: 0 },
|
|
254
275
|
endResult: "The exhausted state persists across reloads.",
|
|
255
276
|
},
|
|
277
|
+
/*
|
|
278
|
+
* 🛑 THE CLOSED WINDOW IS NOW AUTHORED, NOT WAITED FOR, 2026-09-15.
|
|
279
|
+
*
|
|
280
|
+
* This used to sit on a fixture whose spin window was a fraction of the run's
|
|
281
|
+
* testing window, so a tester could watch it close. That fixture is gone, and
|
|
282
|
+
* the permanent seed's wheel is open for another three weeks — a duration no
|
|
283
|
+
* session can outlast. Narrowing the window from the admin editor reaches the
|
|
284
|
+
* same refusal in a few seconds, and restoring it is one field.
|
|
285
|
+
*/
|
|
256
286
|
"checklist-content-discovery-events-spin-wheel-window-blocked": {
|
|
257
|
-
roles: ["buyer"],
|
|
258
|
-
startPage: "/events",
|
|
287
|
+
roles: ["admin", "buyer"],
|
|
288
|
+
startPage: "/admin/events",
|
|
259
289
|
steps: [
|
|
260
|
-
"Sign in as
|
|
261
|
-
"Open event-
|
|
262
|
-
"
|
|
263
|
-
"
|
|
290
|
+
"Sign in as admin@letitrip.in / TempPass123!.",
|
|
291
|
+
"Open /admin/events, open event-daily-beyblade-pull-wheel for editing, and write down its current spin window start and end.",
|
|
292
|
+
"Set the spin window end to yesterday's date so the window is closed, and save.",
|
|
293
|
+
"Sign out and sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
294
|
+
"Open /events/event-daily-beyblade-pull-wheel, read the stated spin window, and attempt a spin.",
|
|
264
295
|
"Read the refusal and check it names the window rather than a generic failure.",
|
|
296
|
+
"Sign back in as admin@letitrip.in and restore the two dates written down in step 2.",
|
|
265
297
|
],
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
298
|
+
inputs: { eventId: "event-daily-beyblade-pull-wheel" },
|
|
299
|
+
expectedBehaviour: "Spins outside the configured window are refused with a reason naming the window, and the check runs server-side — a window enforced only by hiding the button is no window at all.",
|
|
300
|
+
expectedUiState: "With the window closed the spin control is refused and the message names the window or its times. It is not a generic 'Spin failed', which would be indistinguishable from the realtime failure above.",
|
|
301
|
+
endResult: "No spin is recorded outside the window. The original window is restored by the final step; if the restore fails, say so rather than leaving the wheel closed for later cases.",
|
|
269
302
|
},
|
|
270
303
|
"checklist-content-discovery-events-spin-results-tab": {
|
|
271
304
|
roles: ["guest"],
|
|
272
305
|
startPage: "/events",
|
|
273
306
|
steps: [
|
|
274
|
-
"Open event-
|
|
307
|
+
"Open event-daily-beyblade-pull-wheel in a private window with no session.",
|
|
275
308
|
"Find the 'Last 10 Spin Results' tab and open it.",
|
|
276
309
|
"Read every row — the name shown and the prize.",
|
|
277
310
|
"Count the rows.",
|
|
@@ -26,7 +26,7 @@ export const authored = {
|
|
|
26
26
|
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
27
27
|
"Open /user/notifications and read the unread count on the header bell.",
|
|
28
28
|
"In a second window, sign in as vivaan.kapoor@gmail.com / TempPass123!.",
|
|
29
|
-
"As that second buyer, open /auctions/auction-
|
|
29
|
+
"As that second buyer, open /auctions/auction-beyblade-original-dragoon-storm and place a bid high enough to outbid the first buyer.",
|
|
30
30
|
"Return to the first window and open /user/notifications.",
|
|
31
31
|
"Read the newest entry and the bell's unread count.",
|
|
32
32
|
],
|
|
@@ -25,7 +25,7 @@ export const authored = {
|
|
|
25
25
|
steps: [
|
|
26
26
|
"Resize the browser window to 320 pixels wide.",
|
|
27
27
|
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
28
|
-
"Open /products/product-
|
|
28
|
+
"Open /products/product-beyblade-burst-valkyrie and click 'Add to Cart'.",
|
|
29
29
|
"Open /checkout, select the first saved address, and continue to the Extras step.",
|
|
30
30
|
"Read the two buttons in the bottom action bar and compare their widths.",
|
|
31
31
|
],
|
|
@@ -40,7 +40,7 @@ export const authored = {
|
|
|
40
40
|
steps: [
|
|
41
41
|
"Resize the browser window to 320 pixels wide.",
|
|
42
42
|
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
43
|
-
"Open /products/product-
|
|
43
|
+
"Open /products/product-beyblade-burst-valkyrie and click 'Add to Cart'.",
|
|
44
44
|
"Open /checkout and continue through to the payment step.",
|
|
45
45
|
"Read the primary button's label in full.",
|
|
46
46
|
"Select each payment method in turn and read the primary label after each.",
|
|
@@ -79,10 +79,10 @@ export const authored = {
|
|
|
79
79
|
},
|
|
80
80
|
"checklist-design-ux-back-to-top-button-not-covering-toast-or-modal-actions": {
|
|
81
81
|
roles: ["buyer"],
|
|
82
|
-
startPage: "/products/product-
|
|
82
|
+
startPage: "/products/product-beyblade-burst-valkyrie",
|
|
83
83
|
steps: [
|
|
84
84
|
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
85
|
-
"Open /products/product-
|
|
85
|
+
"Open /products/product-beyblade-burst-valkyrie and scroll past 400 pixels so the control appears.",
|
|
86
86
|
"Click 'Add to Cart' and watch for a toast.",
|
|
87
87
|
"Look at whether the control overlaps the toast or any control inside it.",
|
|
88
88
|
"Open any modal on the page and look at its footer buttons.",
|
|
@@ -148,7 +148,7 @@ export const authored = {
|
|
|
148
148
|
"Click a thumbnail and check the main image changes.",
|
|
149
149
|
"Open a product page that has reviews with photos and look at the 'Photos' grid.",
|
|
150
150
|
"Open the review lightbox and look at its thumbnail strip.",
|
|
151
|
-
"Open /bundles/bundle-
|
|
151
|
+
"Open /bundles/bundle-original-collectors-set and look at its member collage.",
|
|
152
152
|
],
|
|
153
153
|
expectedBehaviour: "An image inside a button renders at its intended size. A fill-style image resolves its percentages against its parent, so a shrink-to-fit wrapper between the button and the image collapses both to nothing — the tile becomes an empty bordered square while the button still looks and clicks correctly.",
|
|
154
154
|
expectedUiState: "Every clickable image tile shows its picture at the same size as its neighbours, on all four surfaces. An empty bordered square where a photo should be is the failure, and it is the same failure on each of them.",
|
|
@@ -60,7 +60,7 @@ export const authored = {
|
|
|
60
60
|
"Look at its badge and check whether it has a filled background at all.",
|
|
61
61
|
"Compare it against the Classified and Digital Code badges beside it, then against the Auction badge on /auctions.",
|
|
62
62
|
"Switch to dark mode and look again.",
|
|
63
|
-
"Open /live/live-
|
|
63
|
+
"Open /live/live-golden-retriever-puppy and look at the badge on the detail page too.",
|
|
64
64
|
],
|
|
65
65
|
expectedBehaviour: "The Live Item badge names a colour the build can actually generate. Its background once used a flat alias that has no tint variant and is absent from the app's own palette entirely, so the class compiled to nothing and the badge rendered with no fill — which reads as a deliberate outline style rather than a dropped class.",
|
|
66
66
|
expectedUiState: "The Live Item badge has a visible filled background in both themes, like every other type badge. A badge that is text-only while its neighbours are filled is the failure.",
|
|
@@ -68,16 +68,16 @@ export const authored = {
|
|
|
68
68
|
},
|
|
69
69
|
"checklist-design-ux-sticky-cta-bar-desktop-buttons-work": {
|
|
70
70
|
roles: ["buyer"],
|
|
71
|
-
startPage: "/products/product-
|
|
71
|
+
startPage: "/products/product-beyblade-burst-valkyrie",
|
|
72
72
|
steps: [
|
|
73
73
|
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
74
|
-
"Open /products/product-
|
|
74
|
+
"Open /products/product-beyblade-burst-valkyrie at 1280 pixels wide and scroll until the sticky bar appears.",
|
|
75
75
|
"Click 'Add to Cart' in the STICKY BAR, not in the page panel.",
|
|
76
76
|
"Watch the label while the request runs.",
|
|
77
77
|
"Open /cart and read what is in it.",
|
|
78
78
|
"Go back, scroll to the bar again, and click the wishlist control in the bar.",
|
|
79
79
|
],
|
|
80
|
-
inputs: { productId: "product-
|
|
80
|
+
inputs: { productId: "product-beyblade-burst-valkyrie", quantity: 1 },
|
|
81
81
|
expectedBehaviour: "The bar's controls are the real controls, not decorative copies — each performs the same action as its counterpart in the page panel and reflects its own loading state.",
|
|
82
82
|
expectedUiState: "The label changes while the request runs and the cart badge increases. /cart holds 'Test Gadget — Standard Listing #1'. The wishlist control in the bar also acts rather than doing nothing.",
|
|
83
83
|
endResult: "Empty the cart and the wishlist afterwards so later cases start clean.",
|
|
@@ -50,7 +50,6 @@ import { authored as a_cta_layout__navbar_ctas } from "./cta-layout__navbar-ctas
|
|
|
50
50
|
import { authored as a_public_pages__help_scams_guides_subpages } from "./public-pages__help-scams-guides-subpages";
|
|
51
51
|
import { authored as a_account_auth__profile_settings } from "./account-auth__profile-settings";
|
|
52
52
|
import { authored as a_account_auth__signup_login } from "./account-auth__signup-login";
|
|
53
|
-
import { authored as a_account_auth__testing_program } from "./account-auth__testing-program";
|
|
54
53
|
import { authored as a_addresses__address_filters } from "./addresses__address-filters";
|
|
55
54
|
import { authored as a_addresses__postal_lookup } from "./addresses__postal-lookup";
|
|
56
55
|
import { authored as a_addresses__postal_validation } from "./addresses__postal-validation";
|
|
@@ -171,7 +170,6 @@ export const AUTHORED_CASES = {
|
|
|
171
170
|
...a_public_pages__help_scams_guides_subpages,
|
|
172
171
|
...a_account_auth__profile_settings,
|
|
173
172
|
...a_account_auth__signup_login,
|
|
174
|
-
...a_account_auth__testing_program,
|
|
175
173
|
...a_addresses__address_filters,
|
|
176
174
|
...a_addresses__postal_lookup,
|
|
177
175
|
...a_addresses__postal_validation,
|
|
@@ -23,7 +23,7 @@ export const authored = {
|
|
|
23
23
|
roles: ["buyer", "admin"],
|
|
24
24
|
startPage: "/admin/lotteries",
|
|
25
25
|
steps: [
|
|
26
|
-
"Sign in as rehan.sheikh@gmail.com / TempPass123! and open the lottery event event-
|
|
26
|
+
"Sign in as rehan.sheikh@gmail.com / TempPass123! and open the lottery event event-pokemon-number-draw-july-2026.",
|
|
27
27
|
"Pull slot number 3 and complete the purchase.",
|
|
28
28
|
"Read the slot grid and note that slot 3 now shows as booked, with the buyer name and lottery number against it.",
|
|
29
29
|
"Sign out and sign in as admin@letitrip.in / TempPass123!.",
|
|
@@ -44,7 +44,7 @@ export const authored = {
|
|
|
44
44
|
startPage: "/admin/lotteries",
|
|
45
45
|
steps: [
|
|
46
46
|
"Sign in as admin@letitrip.in / TempPass123!.",
|
|
47
|
-
"Open /admin/lotteries and open the editor for event-
|
|
47
|
+
"Open /admin/lotteries and open the editor for event-pokemon-number-draw-july-2026.",
|
|
48
48
|
"Find the slot that has already been pulled, slot number 3.",
|
|
49
49
|
"Remove that slot from the list.",
|
|
50
50
|
"Save.",
|
|
@@ -96,20 +96,22 @@ export const authored = {
|
|
|
96
96
|
endResult: "Read-only; nothing persists. Record every broken href in the comment, not just the first — one report naming all of them is worth more than a verdict.",
|
|
97
97
|
},
|
|
98
98
|
"checklist-page-wiring-reachability-user-tester-hub-reachable-from-user-sidebar": {
|
|
99
|
-
roles: ["buyer"],
|
|
99
|
+
roles: ["admin", "buyer"],
|
|
100
100
|
startPage: "/user",
|
|
101
101
|
steps: [
|
|
102
|
-
"Sign in as
|
|
102
|
+
"Sign in as admin@letitrip.in / TempPass123!, open /admin/users, and turn the tester flag ON for vivaan.kapoor@gmail.com — no seeded account carries it, so the case sets up the flag it is about.",
|
|
103
|
+
"Sign out and sign in as vivaan.kapoor@gmail.com / TempPass123!, which now carries the tester flag.",
|
|
103
104
|
"Open /user and read the sidebar.",
|
|
104
105
|
"Find the Testing group and click Tester Hub.",
|
|
105
106
|
"Read where it lands.",
|
|
106
107
|
"Sign out and sign in as rehan.sheikh@gmail.com / TempPass123!, which does not carry the flag.",
|
|
107
108
|
"Open /user and read the sidebar for a Testing group.",
|
|
109
|
+
"Sign back in as admin@letitrip.in and turn the tester flag on vivaan.kapoor@gmail.com back off.",
|
|
108
110
|
],
|
|
109
|
-
inputs: { testerAccount: "
|
|
111
|
+
inputs: { testerAccount: "vivaan.kapoor@gmail.com", nonTesterAccount: "rehan.sheikh@gmail.com" },
|
|
110
112
|
expectedBehaviour: "The Testing group is injected at runtime for accounts carrying the tester flag and is empty for everyone else. An empty group must not render as a heading with nothing under it.",
|
|
111
113
|
expectedUiState: "The tester sees a Testing group containing Tester Hub, and clicking it opens /user/tester with the checklist. The non-tester sees no Testing group at all — not a heading with no children, and not a link that leads to a 'Testers only' warning.",
|
|
112
114
|
expectedData: { testingGroupVisibleForNonTester: false },
|
|
113
|
-
endResult: "
|
|
115
|
+
endResult: "The flag is revoked by the final step, leaving vivaan.kapoor@gmail.com on its seeded settings. Checking both accounts is the case — a group that renders for everybody would pass the first half alone.",
|
|
114
116
|
},
|
|
115
117
|
};
|
|
@@ -96,13 +96,13 @@ export const authored = {
|
|
|
96
96
|
startPage: "/checkout",
|
|
97
97
|
steps: [
|
|
98
98
|
"Sign in as rehan.sheikh@gmail.com / TempPass123!.",
|
|
99
|
-
"Open /products/product-
|
|
99
|
+
"Open /products/product-beyblade-burst-valkyrie and click 'Add to Cart'.",
|
|
100
100
|
"Open /checkout, select the first saved address, continue through the add-ons step, choose Cash on Delivery and place the order.",
|
|
101
101
|
"Read the success page for an order number, the item, the address and the total.",
|
|
102
102
|
"Copy the URL and reload it.",
|
|
103
103
|
"Open the same URL in a private window with no session.",
|
|
104
104
|
],
|
|
105
|
-
inputs: { productId: "product-
|
|
105
|
+
inputs: { productId: "product-beyblade-burst-valkyrie", price: 199, paymentMethod: "Cash on Delivery" },
|
|
106
106
|
expectedBehaviour: "The success page reads the real order rather than whatever the checkout had in memory, so it survives a reload. It is also order-scoped data, so a signed-out visitor with the URL must not be shown someone's delivery address.",
|
|
107
107
|
expectedUiState: "The page names an order number, 'Test Gadget — Standard Listing #1' at ₹199.00, the delivery address and a total. After the reload it shows the same. In the private window it does not render the order details — it asks for sign-in or reports not-found.",
|
|
108
108
|
expectedData: { orderTotal: 199 },
|
|
@@ -160,7 +160,7 @@ export const authored = {
|
|
|
160
160
|
steps: [
|
|
161
161
|
"Open /bundles in a private window with no session.",
|
|
162
162
|
"Read each bundle card's price and its discount badge.",
|
|
163
|
-
"Open bundle-
|
|
163
|
+
"Open bundle-original-collectors-set and read its price and its members.",
|
|
164
164
|
"Add up the members' individual prices and compare with the bundle price.",
|
|
165
165
|
"Read the page for anything containing 'Tester' or 'Test' while signed out.",
|
|
166
166
|
],
|
|
@@ -94,12 +94,11 @@ export const authored = {
|
|
|
94
94
|
},
|
|
95
95
|
"checklist-public-pages-stores-sellers-directories-empty-tabs-hidden": {
|
|
96
96
|
roles: ["guest"],
|
|
97
|
-
startPage: "/stores/store-
|
|
97
|
+
startPage: "/stores/store-beyblade-arena",
|
|
98
98
|
steps: [
|
|
99
|
-
"
|
|
100
|
-
"Open /stores/store-tester-qa-seller and write down every tab offered.",
|
|
99
|
+
"Open /stores/store-beyblade-arena in a private window and write down every tab offered.",
|
|
101
100
|
"Open each tab and note which are empty.",
|
|
102
|
-
"Open /stores/store-
|
|
101
|
+
"Open /stores/store-letitrip-official — a store whose whole catalogue is prize draws — and write down its tabs.",
|
|
103
102
|
"Compare the two stores' tab lists.",
|
|
104
103
|
],
|
|
105
104
|
expectedBehaviour: "A tab is hidden when its count is genuinely zero, and shown when the count could not be computed. That distinction is the whole rule: a count map that does not cover an option returns undefined, which reads as unknown and keeps the tab — so an uncovered option is structurally unhideable while a covered one vanishes correctly.",
|
|
@@ -209,17 +208,16 @@ export const authored = {
|
|
|
209
208
|
},
|
|
210
209
|
"checklist-public-pages-stores-sellers-directories-seller-detail-page": {
|
|
211
210
|
roles: ["guest"],
|
|
212
|
-
startPage: "/stores/store-
|
|
211
|
+
startPage: "/stores/store-beyblade-arena",
|
|
213
212
|
steps: [
|
|
214
|
-
"
|
|
215
|
-
"Open /stores/store-tester-qa-seller.",
|
|
213
|
+
"Open /stores/store-beyblade-arena in a private window.",
|
|
216
214
|
"Read the header, the tabs and the listings.",
|
|
217
215
|
"Open the store's own listing-type dropdown, if it offers one, and select each option in turn.",
|
|
218
216
|
"Note any option that returns nothing.",
|
|
219
217
|
],
|
|
220
|
-
inputs: { storeId: "store-
|
|
221
|
-
expectedBehaviour: "This store
|
|
222
|
-
expectedUiState: "The page renders with its header and tabs. Every option
|
|
218
|
+
inputs: { storeId: "store-beyblade-arena" },
|
|
219
|
+
expectedBehaviour: "This store carries standard products, auctions, pre-orders, classifieds, digital codes, live items, art and stickers — every type except prize draws, which all belong to store-letitrip-official. So the dropdown must offer the eight it has and not the one it does not: an option for an absent type silently returns nothing, which reads as a broken query rather than an empty catalogue.",
|
|
220
|
+
expectedUiState: "The page renders with its header and tabs. Every option the listing-type dropdown offers returns at least one item, and Prize Draws is not offered. An offered option that returns nothing means either the type is absent from this store or it is being dropped from the query.",
|
|
223
221
|
expectedData: { emptyTypeOptionCount: 0 },
|
|
224
222
|
endResult: "Read-only; nothing persists.",
|
|
225
223
|
},
|
|
@@ -55,7 +55,7 @@ export const authored = {
|
|
|
55
55
|
roles: ["seller"],
|
|
56
56
|
startPage: "/store",
|
|
57
57
|
steps: [
|
|
58
|
-
"Sign in as
|
|
58
|
+
"Sign in as tyson@beybladearena.in / TempPass123!, whose store-beyblade-arena is approved and public.",
|
|
59
59
|
"Open /store and read the dashboard.",
|
|
60
60
|
"Open the store's own settings and read its name, description, logo and banner.",
|
|
61
61
|
"Change the description to 'QA Store store-setup description' and save.",
|
|
@@ -64,7 +64,7 @@ export const authored = {
|
|
|
64
64
|
"Restore the original description.",
|
|
65
65
|
],
|
|
66
66
|
inputs: { description: "QA Store store-setup description" },
|
|
67
|
-
expectedBehaviour: "
|
|
67
|
+
expectedBehaviour: "An approved store is approved on both documents at once — the user record's status AND the store's own status and public flag. Flipping only the user's leaves the seller with a working dashboard and a store invisible to the public, because every visibility check reads the store's own status. That is why this case reads the PUBLIC page and not only the dashboard.",
|
|
68
68
|
expectedUiState: "The dashboard loads rather than showing a pending-approval gate. The edited description survives the reload AND appears on the public store page. A description that saves in the dashboard but never reaches the public page means the store is not actually public.",
|
|
69
69
|
endResult: "The description is restored by the final step. The public page rendering at all is the real assertion here.",
|
|
70
70
|
},
|
|
@@ -58,7 +58,7 @@ export const authored = {
|
|
|
58
58
|
roles: ["buyer"],
|
|
59
59
|
startPage: "/digital-codes",
|
|
60
60
|
steps: [
|
|
61
|
-
"Sign in as the
|
|
61
|
+
"Sign in as the buyer rehan.sheikh@gmail.com / TempPass123!.",
|
|
62
62
|
"Open /digital-codes and open a listing that shows codes available.",
|
|
63
63
|
"Add it to the cart and complete checkout.",
|
|
64
64
|
"Open /user/digital-codes.",
|
|
@@ -75,7 +75,7 @@ export const authored = {
|
|
|
75
75
|
startPage: "/digital-codes",
|
|
76
76
|
steps: [
|
|
77
77
|
"Open a digital-code listing's public page and write down the codes-available number it shows.",
|
|
78
|
-
"Sign in as the
|
|
78
|
+
"Sign in as the buyer rehan.sheikh@gmail.com / TempPass123! and buy that listing.",
|
|
79
79
|
"Reload the listing's public page and read the number again.",
|
|
80
80
|
],
|
|
81
81
|
expectedBehaviour: "The counter is derived from the pool, so a claim reduces it. A counter a human typed into the seller form and that nothing recomputes will sit at its original value forever — which lets a sold-out listing keep advertising stock, because the availability predicate reads exactly that field.",
|
|
@@ -107,8 +107,8 @@ export const authored = {
|
|
|
107
107
|
"Open its public page and read the seller line at the bottom of the info panel.",
|
|
108
108
|
"Click the 'Visit Store' link and read where it lands.",
|
|
109
109
|
"Open /stores/store-beyblade-arena and find the listing in the Products tab.",
|
|
110
|
-
"Sign out and sign in as
|
|
111
|
-
"Open that seller's own products list and check the listing is NOT there.",
|
|
110
|
+
"Sign out and sign in as admin@letitrip.in / TempPass123!, a different seller who owns store-letitrip-official.",
|
|
111
|
+
"Open /store/products — that seller's own products list — and check the listing is NOT there.",
|
|
112
112
|
"Sign back in as tyson and delete the listing.",
|
|
113
113
|
],
|
|
114
114
|
inputs: { title: "QA Product belongs-to-store", price: 300 },
|