@mohasinac/appkit 3.0.6 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.d.ts +42 -0
- package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +86 -0
- package/dist/_internal/client/features/lottery/LotteryAdminSlotView.d.ts +14 -0
- package/dist/_internal/client/features/lottery/LotteryAdminSlotView.js +46 -0
- package/dist/_internal/client/features/lottery/LotteryDetailView.d.ts +28 -0
- package/dist/_internal/client/features/lottery/LotteryDetailView.js +17 -0
- package/dist/_internal/client/features/lottery/LotteryEntriesView.d.ts +23 -0
- package/dist/_internal/client/features/lottery/LotteryEntriesView.js +58 -0
- package/dist/_internal/client/features/lottery/LotteryListView.d.ts +21 -0
- package/dist/_internal/client/features/lottery/LotteryListView.js +25 -0
- package/dist/_internal/client/features/lottery/LotteryPullForm.d.ts +19 -0
- package/dist/_internal/client/features/lottery/LotteryPullForm.js +65 -0
- package/dist/_internal/client/features/lottery/LotterySlotGrid.d.ts +13 -0
- package/dist/_internal/client/features/lottery/LotterySlotGrid.js +21 -0
- package/dist/_internal/client/features/lottery/PrizeDrawLotteryDetailView.d.ts +28 -0
- package/dist/_internal/client/features/lottery/PrizeDrawLotteryDetailView.js +18 -0
- package/dist/_internal/server/features/auctions/__tests__/service.test.d.ts +1 -0
- package/dist/_internal/server/features/auctions/__tests__/service.test.js +140 -0
- package/dist/_internal/server/features/checkout/__tests__/actions.test.d.ts +1 -0
- package/dist/_internal/server/features/checkout/__tests__/actions.test.js +600 -0
- package/dist/_internal/server/features/lottery/actions.d.ts +43 -0
- package/dist/_internal/server/features/lottery/actions.js +243 -0
- package/dist/_internal/server/features/lottery/adapters.d.ts +9 -0
- package/dist/_internal/server/features/lottery/adapters.js +21 -0
- package/dist/_internal/server/features/lottery/data.d.ts +20 -0
- package/dist/_internal/server/features/lottery/data.js +41 -0
- package/dist/_internal/server/features/lottery/metadata.d.ts +6 -0
- package/dist/_internal/server/features/lottery/metadata.js +31 -0
- package/dist/_internal/server/features/refunds/__tests__/actions.test.d.ts +1 -0
- package/dist/_internal/server/features/refunds/__tests__/actions.test.js +263 -0
- package/dist/_internal/server/jobs/core/__tests__/auctionSettlement.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/auctionSettlement.test.js +249 -0
- package/dist/_internal/server/jobs/core/__tests__/onBidPlaced.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/onBidPlaced.test.js +201 -0
- package/dist/_internal/server/jobs/core/__tests__/onOrderCreate.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/onOrderCreate.test.js +169 -0
- package/dist/_internal/server/jobs/core/__tests__/onOrderStatusChange.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/onOrderStatusChange.test.js +148 -0
- package/dist/_internal/server/jobs/core/__tests__/onProductStockChange.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/onProductStockChange.test.js +210 -0
- package/dist/_internal/server/jobs/core/__tests__/onReviewWrite.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/onReviewWrite.test.js +190 -0
- package/dist/_internal/server/jobs/core/__tests__/onUserBanChange.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/onUserBanChange.test.js +161 -0
- package/dist/_internal/server/jobs/core/__tests__/payoutBatch.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/payoutBatch.test.js +302 -0
- package/dist/_internal/server/jobs/core/__tests__/triggerEventRaffle.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/triggerEventRaffle.test.js +252 -0
- package/dist/_internal/server/jobs/core/__tests__/wrapJobHandler.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/wrapJobHandler.test.js +129 -0
- package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
- package/dist/_internal/shared/actions/action-registry.js +46 -0
- package/dist/_internal/shared/features/products/schema.d.ts +8 -8
- package/dist/client.d.ts +9 -0
- package/dist/client.js +9 -0
- package/dist/constants/field-names.d.ts +5 -1
- package/dist/constants/field-names.js +5 -1
- package/dist/features/addresses/repository/__tests__/addresses.repository.test.d.ts +1 -0
- package/dist/features/addresses/repository/__tests__/addresses.repository.test.js +386 -0
- package/dist/features/admin/api/bids/route.d.ts +2 -2
- package/dist/features/admin/api/coupons/route.d.ts +2 -2
- package/dist/features/admin/api/products/route.d.ts +2 -2
- package/dist/features/admin/api/reviews/route.d.ts +2 -2
- package/dist/features/admin/repository/__tests__/notification.repository.test.d.ts +1 -0
- package/dist/features/admin/repository/__tests__/notification.repository.test.js +356 -0
- package/dist/features/admin/repository/__tests__/site-settings.repository.test.d.ts +1 -0
- package/dist/features/admin/repository/__tests__/site-settings.repository.test.js +298 -0
- package/dist/features/auctions/repository/__tests__/bid.repository.test.d.ts +1 -0
- package/dist/features/auctions/repository/__tests__/bid.repository.test.js +290 -0
- package/dist/features/auth/api/route.d.ts +2 -2
- package/dist/features/auth/repository/__tests__/session.repository.test.d.ts +1 -0
- package/dist/features/auth/repository/__tests__/session.repository.test.js +310 -0
- package/dist/features/auth/repository/__tests__/session.test.d.ts +1 -0
- package/dist/features/auth/repository/__tests__/session.test.js +146 -0
- package/dist/features/auth/repository/__tests__/sms-counter.repository.test.d.ts +1 -0
- package/dist/features/auth/repository/__tests__/sms-counter.repository.test.js +171 -0
- package/dist/features/auth/repository/__tests__/sms-counter.test.d.ts +1 -0
- package/dist/features/auth/repository/__tests__/sms-counter.test.js +88 -0
- package/dist/features/auth/repository/__tests__/token.repository.test.d.ts +1 -0
- package/dist/features/auth/repository/__tests__/token.repository.test.js +260 -0
- package/dist/features/auth/repository/__tests__/token.test.d.ts +1 -0
- package/dist/features/auth/repository/__tests__/token.test.js +140 -0
- package/dist/features/auth/repository/__tests__/user.repository.test.d.ts +1 -0
- package/dist/features/auth/repository/__tests__/user.repository.test.js +352 -0
- package/dist/features/auth/repository/__tests__/user.test.d.ts +1 -0
- package/dist/features/auth/repository/__tests__/user.test.js +226 -0
- package/dist/features/auth/repository/session.repository.js +10 -1
- package/dist/features/cart/repository/__tests__/cart.repository.test.d.ts +1 -0
- package/dist/features/cart/repository/__tests__/cart.repository.test.js +371 -0
- package/dist/features/cart/repository/cart.repository.js +2 -2
- package/dist/features/categories/api/[id]/route.d.ts +4 -4
- package/dist/features/categories/api/route.d.ts +2 -2
- package/dist/features/categories/repository/__tests__/categories.repository.test.d.ts +1 -0
- package/dist/features/categories/repository/__tests__/categories.repository.test.js +813 -0
- package/dist/features/events/components/EventCard.js +1 -0
- package/dist/features/events/repository/__tests__/event.repository.test.d.ts +1 -0
- package/dist/features/events/repository/__tests__/event.repository.test.js +299 -0
- package/dist/features/events/schemas/firestore.d.ts +3 -0
- package/dist/features/events/schemas/index.d.ts +834 -14
- package/dist/features/events/schemas/index.js +80 -1
- package/dist/features/events/types/index.d.ts +4 -1
- package/dist/features/faq/repository/__tests__/faqs.repository.test.d.ts +1 -0
- package/dist/features/faq/repository/__tests__/faqs.repository.test.js +311 -0
- package/dist/features/history/repository/__tests__/user-history.repository.test.d.ts +1 -0
- package/dist/features/history/repository/__tests__/user-history.repository.test.js +180 -0
- package/dist/features/homepage/api/[id]/route.d.ts +4 -4
- package/dist/features/homepage/api/carousel/[id]/route.d.ts +4 -4
- package/dist/features/homepage/api/carousel/route.d.ts +2 -2
- package/dist/features/homepage/api/route.d.ts +2 -2
- package/dist/features/homepage/repository/__tests__/carousel.repository.test.d.ts +1 -0
- package/dist/features/homepage/repository/__tests__/carousel.repository.test.js +182 -0
- package/dist/features/homepage/repository/__tests__/homepage-sections.repository.test.d.ts +1 -0
- package/dist/features/homepage/repository/__tests__/homepage-sections.repository.test.js +185 -0
- package/dist/features/lottery/repository/lottery-entry.repository.d.ts +33 -0
- package/dist/features/lottery/repository/lottery-entry.repository.js +130 -0
- package/dist/features/lottery/schemas/firestore.d.ts +49 -0
- package/dist/features/lottery/schemas/firestore.js +25 -0
- package/dist/features/lottery/schemas/zod.d.ts +113 -0
- package/dist/features/lottery/schemas/zod.js +39 -0
- package/dist/features/lottery/types/index.d.ts +67 -0
- package/dist/features/lottery/types/index.js +55 -0
- package/dist/features/messages/repository/__tests__/conversations.repository.test.d.ts +1 -0
- package/dist/features/messages/repository/__tests__/conversations.repository.test.js +257 -0
- package/dist/features/orders/repository/__tests__/orders.repository.test.d.ts +1 -0
- package/dist/features/orders/repository/__tests__/orders.repository.test.js +211 -0
- package/dist/features/payments/repository/__tests__/payout.repository.test.d.ts +1 -0
- package/dist/features/payments/repository/__tests__/payout.repository.test.js +292 -0
- package/dist/features/products/api/[id]/route.d.ts +4 -4
- package/dist/features/products/api/route.d.ts +2 -2
- package/dist/features/products/repository/__tests__/product-features.repository.test.d.ts +1 -0
- package/dist/features/products/repository/__tests__/product-features.repository.test.js +329 -0
- package/dist/features/products/repository/__tests__/products.repository.test.d.ts +1 -0
- package/dist/features/products/repository/__tests__/products.repository.test.js +607 -0
- package/dist/features/products/schemas/firestore.d.ts +15 -1
- package/dist/features/products/schemas/index.d.ts +12 -12
- package/dist/features/products/schemas/index.js +4 -2
- package/dist/features/products/types/index.d.ts +1 -1
- package/dist/features/promotions/repository/__tests__/claimed-coupons.repository.test.d.ts +1 -0
- package/dist/features/promotions/repository/__tests__/claimed-coupons.repository.test.js +219 -0
- package/dist/features/promotions/repository/__tests__/coupons.repository.test.d.ts +1 -0
- package/dist/features/promotions/repository/__tests__/coupons.repository.test.js +480 -0
- package/dist/features/reviews/api/[id]/route.d.ts +4 -4
- package/dist/features/reviews/api/route.d.ts +2 -2
- package/dist/features/reviews/repository/__tests__/reviews.repository.test.d.ts +1 -0
- package/dist/features/reviews/repository/__tests__/reviews.repository.test.js +327 -0
- package/dist/features/scams/repository/__tests__/scammer.repository.test.d.ts +1 -0
- package/dist/features/scams/repository/__tests__/scammer.repository.test.js +385 -0
- package/dist/features/search/repository/__tests__/search.repository.test.d.ts +1 -0
- package/dist/features/search/repository/__tests__/search.repository.test.js +369 -0
- package/dist/features/seller/api/coupons/route.d.ts +2 -2
- package/dist/features/seller/api/offers/route.d.ts +2 -2
- package/dist/features/seller/api/products/route.d.ts +2 -2
- package/dist/features/seller/api/store/route.d.ts +2 -2
- package/dist/features/seller/repository/__tests__/offer.repository.test.d.ts +1 -0
- package/dist/features/seller/repository/__tests__/offer.repository.test.js +458 -0
- package/dist/features/stores/repository/__tests__/store.repository.test.d.ts +1 -0
- package/dist/features/stores/repository/__tests__/store.repository.test.js +261 -0
- package/dist/features/support/repository/__tests__/support.repository.test.d.ts +1 -0
- package/dist/features/support/repository/__tests__/support.repository.test.js +312 -0
- package/dist/features/wishlist/repository/__tests__/user-wishlist.repository.test.d.ts +1 -0
- package/dist/features/wishlist/repository/__tests__/user-wishlist.repository.test.js +139 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +17 -0
- package/dist/next/api/routeHandler.d.ts +1 -1
- package/dist/next/routing/route-map.d.ts +13 -0
- package/dist/next/routing/route-map.js +6 -0
- package/dist/repositories/index.d.ts +1 -0
- package/dist/repositories/index.js +2 -0
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.js +1 -1
- package/dist/security/pii-schemas.d.ts +2 -0
- package/dist/security/pii-schemas.js +6 -0
- package/dist/seed/actions/demo-seed-actions.d.ts +1 -1
- package/dist/seed/events-seed-data.js +85 -2
- package/dist/seed/grouped-listings-seed-data.d.ts +3 -1
- package/dist/seed/index.d.ts +1 -0
- package/dist/seed/index.js +1 -0
- package/dist/seed/lottery-entries-seed-data.d.ts +2 -0
- package/dist/seed/lottery-entries-seed-data.js +108 -0
- package/dist/seed/manifest.js +1 -0
- package/dist/seed/products-preorders-seed-data.d.ts +3 -1
- package/dist/server.d.ts +6 -0
- package/dist/server.js +6 -0
- package/dist/styles.css +1 -1
- package/dist/tailwind-utilities.css +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { SearchRepository } from "../search.repository";
|
|
3
|
+
function makePagedResult(overrides = {}) {
|
|
4
|
+
return {
|
|
5
|
+
data: [],
|
|
6
|
+
total: 0,
|
|
7
|
+
page: 1,
|
|
8
|
+
perPage: 24,
|
|
9
|
+
totalPages: 0,
|
|
10
|
+
...overrides,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
const mockFindAll = vi.fn().mockResolvedValue(makePagedResult());
|
|
14
|
+
const repo = new SearchRepository({ findAll: mockFindAll });
|
|
15
|
+
function captureFilters() {
|
|
16
|
+
const call = mockFindAll.mock.calls[0][0];
|
|
17
|
+
return call.filters;
|
|
18
|
+
}
|
|
19
|
+
function captureSieveQuery() {
|
|
20
|
+
return mockFindAll.mock.calls[0][0];
|
|
21
|
+
}
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
vi.clearAllMocks();
|
|
24
|
+
mockFindAll.mockResolvedValue(makePagedResult());
|
|
25
|
+
});
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Mandatory status filter
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
describe("SearchRepository.search — mandatory status==published", () => {
|
|
30
|
+
it("always appends status==published as the last filter", async () => {
|
|
31
|
+
await repo.search({});
|
|
32
|
+
const filters = captureFilters();
|
|
33
|
+
expect(filters.split(",").at(-1)).toBe("status==published");
|
|
34
|
+
});
|
|
35
|
+
it("includes status==published even when no other filters given", async () => {
|
|
36
|
+
await repo.search({});
|
|
37
|
+
const filters = captureFilters();
|
|
38
|
+
expect(filters).toBe("status==published");
|
|
39
|
+
});
|
|
40
|
+
it("includes status==published alongside other filters", async () => {
|
|
41
|
+
await repo.search({ q: "charizard", category: "category-trading-cards" });
|
|
42
|
+
const filters = captureFilters();
|
|
43
|
+
expect(filters).toContain("status==published");
|
|
44
|
+
});
|
|
45
|
+
it("status==published appears exactly once regardless of query shape", async () => {
|
|
46
|
+
await repo.search({ q: "test", category: "cat-1", minRating: 4 });
|
|
47
|
+
const filters = captureFilters();
|
|
48
|
+
const occurrences = filters.split(",").filter((p) => p === "status==published").length;
|
|
49
|
+
expect(occurrences).toBe(1);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Text search filter
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
describe("SearchRepository.search — text query (q)", () => {
|
|
56
|
+
it("sets title_=<q> when q is provided", async () => {
|
|
57
|
+
await repo.search({ q: "charizard" });
|
|
58
|
+
expect(captureFilters()).toContain("title_=charizard");
|
|
59
|
+
});
|
|
60
|
+
it("does NOT add a title filter when q is undefined", async () => {
|
|
61
|
+
await repo.search({});
|
|
62
|
+
expect(captureFilters()).not.toContain("title_=");
|
|
63
|
+
});
|
|
64
|
+
it("does NOT add a title filter when q is empty string", async () => {
|
|
65
|
+
await repo.search({ q: "" });
|
|
66
|
+
expect(captureFilters()).not.toContain("title_=");
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// Category filter
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
describe("SearchRepository.search — category", () => {
|
|
73
|
+
it("adds category==<slug> filter when category is provided", async () => {
|
|
74
|
+
await repo.search({ category: "category-trading-cards" });
|
|
75
|
+
expect(captureFilters()).toContain("category==category-trading-cards");
|
|
76
|
+
});
|
|
77
|
+
it("does NOT add category filter when category is undefined", async () => {
|
|
78
|
+
await repo.search({});
|
|
79
|
+
expect(captureFilters()).not.toContain("category==");
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
// Subcategory filter
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
describe("SearchRepository.search — subcategory", () => {
|
|
86
|
+
it("adds subcategory==<slug> filter when subcategory is provided", async () => {
|
|
87
|
+
await repo.search({ subcategory: "category-pokemon" });
|
|
88
|
+
expect(captureFilters()).toContain("subcategory==category-pokemon");
|
|
89
|
+
});
|
|
90
|
+
it("does NOT add subcategory filter when subcategory is undefined", async () => {
|
|
91
|
+
await repo.search({});
|
|
92
|
+
expect(captureFilters()).not.toContain("subcategory==");
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
// Price range filter
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
describe("SearchRepository.search — price range", () => {
|
|
99
|
+
it("adds price>=<min> filter when minPrice is provided", async () => {
|
|
100
|
+
await repo.search({ minPrice: 500 });
|
|
101
|
+
expect(captureFilters()).toContain("price>=500");
|
|
102
|
+
});
|
|
103
|
+
it("adds price<=<max> filter when maxPrice is provided", async () => {
|
|
104
|
+
await repo.search({ maxPrice: 10000 });
|
|
105
|
+
expect(captureFilters()).toContain("price<=10000");
|
|
106
|
+
});
|
|
107
|
+
it("adds both min and max when a price range is specified", async () => {
|
|
108
|
+
await repo.search({ minPrice: 100, maxPrice: 5000 });
|
|
109
|
+
const filters = captureFilters();
|
|
110
|
+
expect(filters).toContain("price>=100");
|
|
111
|
+
expect(filters).toContain("price<=5000");
|
|
112
|
+
});
|
|
113
|
+
it("does NOT add price filters when neither minPrice nor maxPrice provided", async () => {
|
|
114
|
+
await repo.search({});
|
|
115
|
+
expect(captureFilters()).not.toContain("price");
|
|
116
|
+
});
|
|
117
|
+
it("adds price>=0 filter when minPrice is 0", async () => {
|
|
118
|
+
await repo.search({ minPrice: 0 });
|
|
119
|
+
expect(captureFilters()).toContain("price>=0");
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
// Condition filter
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
describe("SearchRepository.search — condition", () => {
|
|
126
|
+
it("adds condition==<value> filter when condition is provided", async () => {
|
|
127
|
+
await repo.search({ condition: "mint" });
|
|
128
|
+
expect(captureFilters()).toContain("condition==mint");
|
|
129
|
+
});
|
|
130
|
+
it("does NOT add condition filter when condition is undefined", async () => {
|
|
131
|
+
await repo.search({});
|
|
132
|
+
expect(captureFilters()).not.toContain("condition==");
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
// listingType filter
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
describe("SearchRepository.search — listingType", () => {
|
|
139
|
+
it("adds listingType==auction filter for auction search", async () => {
|
|
140
|
+
await repo.search({ listingType: "auction" });
|
|
141
|
+
expect(captureFilters()).toContain("listingType==auction");
|
|
142
|
+
});
|
|
143
|
+
it("adds listingType==standard for standard search", async () => {
|
|
144
|
+
await repo.search({ listingType: "standard" });
|
|
145
|
+
expect(captureFilters()).toContain("listingType==standard");
|
|
146
|
+
});
|
|
147
|
+
it("adds listingType==pre-order for pre-order search", async () => {
|
|
148
|
+
await repo.search({ listingType: "pre-order" });
|
|
149
|
+
expect(captureFilters()).toContain("listingType==pre-order");
|
|
150
|
+
});
|
|
151
|
+
it("does NOT add listingType filter when listingType is undefined", async () => {
|
|
152
|
+
await repo.search({});
|
|
153
|
+
expect(captureFilters()).not.toContain("listingType==");
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
// In-stock filter
|
|
158
|
+
// ---------------------------------------------------------------------------
|
|
159
|
+
describe("SearchRepository.search — inStock", () => {
|
|
160
|
+
it("adds availableQuantity>0 filter when inStock: true", async () => {
|
|
161
|
+
await repo.search({ inStock: true });
|
|
162
|
+
expect(captureFilters()).toContain("availableQuantity>0");
|
|
163
|
+
});
|
|
164
|
+
it("does NOT add availableQuantity filter when inStock: false", async () => {
|
|
165
|
+
await repo.search({ inStock: false });
|
|
166
|
+
expect(captureFilters()).not.toContain("availableQuantity");
|
|
167
|
+
});
|
|
168
|
+
it("does NOT add availableQuantity filter when inStock is undefined", async () => {
|
|
169
|
+
await repo.search({});
|
|
170
|
+
expect(captureFilters()).not.toContain("availableQuantity");
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
// Minimum rating filter
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
describe("SearchRepository.search — minRating", () => {
|
|
177
|
+
it("adds averageRating>=<value> filter when minRating is provided", async () => {
|
|
178
|
+
await repo.search({ minRating: 4 });
|
|
179
|
+
expect(captureFilters()).toContain("averageRating>=4");
|
|
180
|
+
});
|
|
181
|
+
it("adds averageRating>=0 filter when minRating is 0", async () => {
|
|
182
|
+
await repo.search({ minRating: 0 });
|
|
183
|
+
expect(captureFilters()).toContain("averageRating>=0");
|
|
184
|
+
});
|
|
185
|
+
it("does NOT add averageRating filter when minRating is undefined", async () => {
|
|
186
|
+
await repo.search({});
|
|
187
|
+
expect(captureFilters()).not.toContain("averageRating");
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
// ---------------------------------------------------------------------------
|
|
191
|
+
// All filters combined
|
|
192
|
+
// ---------------------------------------------------------------------------
|
|
193
|
+
describe("SearchRepository.search — combined filters", () => {
|
|
194
|
+
it("builds combined filter string for full-featured query", async () => {
|
|
195
|
+
const query = {
|
|
196
|
+
q: "pikachu",
|
|
197
|
+
category: "category-trading-cards",
|
|
198
|
+
subcategory: "category-pokemon",
|
|
199
|
+
minPrice: 100,
|
|
200
|
+
maxPrice: 5000,
|
|
201
|
+
condition: "near-mint",
|
|
202
|
+
listingType: "standard",
|
|
203
|
+
inStock: true,
|
|
204
|
+
minRating: 3,
|
|
205
|
+
};
|
|
206
|
+
await repo.search(query);
|
|
207
|
+
const filters = captureFilters();
|
|
208
|
+
expect(filters).toContain("title_=pikachu");
|
|
209
|
+
expect(filters).toContain("category==category-trading-cards");
|
|
210
|
+
expect(filters).toContain("subcategory==category-pokemon");
|
|
211
|
+
expect(filters).toContain("price>=100");
|
|
212
|
+
expect(filters).toContain("price<=5000");
|
|
213
|
+
expect(filters).toContain("condition==near-mint");
|
|
214
|
+
expect(filters).toContain("listingType==standard");
|
|
215
|
+
expect(filters).toContain("availableQuantity>0");
|
|
216
|
+
expect(filters).toContain("averageRating>=3");
|
|
217
|
+
expect(filters).toContain("status==published");
|
|
218
|
+
// status is always last
|
|
219
|
+
expect(filters.split(",").at(-1)).toBe("status==published");
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
// ---------------------------------------------------------------------------
|
|
223
|
+
// Sorting
|
|
224
|
+
// ---------------------------------------------------------------------------
|
|
225
|
+
describe("SearchRepository.search — sort", () => {
|
|
226
|
+
it("defaults to sort: createdAt, order: asc when no sort specified", async () => {
|
|
227
|
+
await repo.search({});
|
|
228
|
+
const q = captureSieveQuery();
|
|
229
|
+
expect(q.sort).toBe("createdAt");
|
|
230
|
+
expect(q.order).toBe("asc");
|
|
231
|
+
});
|
|
232
|
+
it("ascending sort: sort='price', no leading dash → order: asc", async () => {
|
|
233
|
+
await repo.search({ sort: "price" });
|
|
234
|
+
const q = captureSieveQuery();
|
|
235
|
+
expect(q.sort).toBe("price");
|
|
236
|
+
expect(q.order).toBe("asc");
|
|
237
|
+
});
|
|
238
|
+
it("descending sort: sort='-price' → order: desc, field: price", async () => {
|
|
239
|
+
await repo.search({ sort: "-price" });
|
|
240
|
+
const q = captureSieveQuery();
|
|
241
|
+
expect(q.sort).toBe("price");
|
|
242
|
+
expect(q.order).toBe("desc");
|
|
243
|
+
});
|
|
244
|
+
it("descending sort: sort='-createdAt' → order: desc, field: createdAt", async () => {
|
|
245
|
+
await repo.search({ sort: "-createdAt" });
|
|
246
|
+
const q = captureSieveQuery();
|
|
247
|
+
expect(q.sort).toBe("createdAt");
|
|
248
|
+
expect(q.order).toBe("desc");
|
|
249
|
+
});
|
|
250
|
+
it("ascending sort: sort='averageRating' → order: asc, field: averageRating", async () => {
|
|
251
|
+
await repo.search({ sort: "averageRating" });
|
|
252
|
+
const q = captureSieveQuery();
|
|
253
|
+
expect(q.sort).toBe("averageRating");
|
|
254
|
+
expect(q.order).toBe("asc");
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
// ---------------------------------------------------------------------------
|
|
258
|
+
// Pagination
|
|
259
|
+
// ---------------------------------------------------------------------------
|
|
260
|
+
describe("SearchRepository.search — pagination", () => {
|
|
261
|
+
it("defaults to page: 1 when not provided", async () => {
|
|
262
|
+
await repo.search({});
|
|
263
|
+
const q = captureSieveQuery();
|
|
264
|
+
expect(q.page).toBe(1);
|
|
265
|
+
});
|
|
266
|
+
it("defaults to perPage: 24 when pageSize not provided", async () => {
|
|
267
|
+
await repo.search({});
|
|
268
|
+
const q = captureSieveQuery();
|
|
269
|
+
expect(q.perPage).toBe(24);
|
|
270
|
+
});
|
|
271
|
+
it("forwards custom page and pageSize", async () => {
|
|
272
|
+
await repo.search({ page: 3, pageSize: 12 });
|
|
273
|
+
const q = captureSieveQuery();
|
|
274
|
+
expect(q.page).toBe(3);
|
|
275
|
+
expect(q.perPage).toBe(12);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
// ---------------------------------------------------------------------------
|
|
279
|
+
// Response shape
|
|
280
|
+
// ---------------------------------------------------------------------------
|
|
281
|
+
describe("SearchRepository.search — response shape", () => {
|
|
282
|
+
it("maps PagedResult to SearchResponse correctly", async () => {
|
|
283
|
+
mockFindAll.mockResolvedValue({
|
|
284
|
+
data: [{ id: "p-1", title: "Charizard" }],
|
|
285
|
+
total: 1,
|
|
286
|
+
page: 1,
|
|
287
|
+
perPage: 24,
|
|
288
|
+
totalPages: 1,
|
|
289
|
+
});
|
|
290
|
+
const result = await repo.search({ q: "charizard" });
|
|
291
|
+
expect(result.items).toHaveLength(1);
|
|
292
|
+
expect(result.total).toBe(1);
|
|
293
|
+
expect(result.page).toBe(1);
|
|
294
|
+
expect(result.pageSize).toBe(24);
|
|
295
|
+
expect(result.totalPages).toBe(1);
|
|
296
|
+
});
|
|
297
|
+
it("hasMore: true when page < totalPages", async () => {
|
|
298
|
+
mockFindAll.mockResolvedValue({
|
|
299
|
+
data: [],
|
|
300
|
+
total: 100,
|
|
301
|
+
page: 1,
|
|
302
|
+
perPage: 24,
|
|
303
|
+
totalPages: 5,
|
|
304
|
+
});
|
|
305
|
+
const result = await repo.search({});
|
|
306
|
+
expect(result.hasMore).toBe(true);
|
|
307
|
+
});
|
|
308
|
+
it("hasMore: false when page == totalPages", async () => {
|
|
309
|
+
mockFindAll.mockResolvedValue({
|
|
310
|
+
data: [],
|
|
311
|
+
total: 24,
|
|
312
|
+
page: 1,
|
|
313
|
+
perPage: 24,
|
|
314
|
+
totalPages: 1,
|
|
315
|
+
});
|
|
316
|
+
const result = await repo.search({});
|
|
317
|
+
expect(result.hasMore).toBe(false);
|
|
318
|
+
});
|
|
319
|
+
it("hasMore: false when page > totalPages (edge case)", async () => {
|
|
320
|
+
mockFindAll.mockResolvedValue({
|
|
321
|
+
data: [],
|
|
322
|
+
total: 0,
|
|
323
|
+
page: 2,
|
|
324
|
+
perPage: 24,
|
|
325
|
+
totalPages: 1,
|
|
326
|
+
});
|
|
327
|
+
const result = await repo.search({});
|
|
328
|
+
expect(result.hasMore).toBe(false);
|
|
329
|
+
});
|
|
330
|
+
it("q is empty string in response when no q provided", async () => {
|
|
331
|
+
const result = await repo.search({});
|
|
332
|
+
expect(result.q).toBe("");
|
|
333
|
+
});
|
|
334
|
+
it("q reflects the search term in response", async () => {
|
|
335
|
+
const result = await repo.search({ q: "pokemon" });
|
|
336
|
+
expect(result.q).toBe("pokemon");
|
|
337
|
+
});
|
|
338
|
+
it("returns empty items array when no results", async () => {
|
|
339
|
+
mockFindAll.mockResolvedValue(makePagedResult());
|
|
340
|
+
const result = await repo.search({ q: "nonexistent-product" });
|
|
341
|
+
expect(result.items).toEqual([]);
|
|
342
|
+
expect(result.total).toBe(0);
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
// ---------------------------------------------------------------------------
|
|
346
|
+
// Filter string format
|
|
347
|
+
// ---------------------------------------------------------------------------
|
|
348
|
+
describe("SearchRepository.search — filter string format", () => {
|
|
349
|
+
it("joins multiple filters with commas", async () => {
|
|
350
|
+
await repo.search({ q: "test", category: "cat-1" });
|
|
351
|
+
const filters = captureFilters();
|
|
352
|
+
const parts = filters.split(",");
|
|
353
|
+
expect(parts.length).toBeGreaterThan(1);
|
|
354
|
+
// No empty segments (no stray commas)
|
|
355
|
+
expect(parts.every((p) => p.length > 0)).toBe(true);
|
|
356
|
+
});
|
|
357
|
+
it("single active filter + status produces exactly 2 comma-separated parts", async () => {
|
|
358
|
+
await repo.search({ category: "cat-1" });
|
|
359
|
+
const filters = captureFilters();
|
|
360
|
+
const parts = filters.split(",");
|
|
361
|
+
expect(parts).toHaveLength(2);
|
|
362
|
+
expect(parts[0]).toBe("category==cat-1");
|
|
363
|
+
expect(parts[1]).toBe("status==published");
|
|
364
|
+
});
|
|
365
|
+
it("empty query produces filter string with only status==published", async () => {
|
|
366
|
+
await repo.search({});
|
|
367
|
+
expect(captureFilters()).toBe("status==published");
|
|
368
|
+
});
|
|
369
|
+
});
|
|
@@ -12,6 +12,6 @@
|
|
|
12
12
|
* export { sellerCouponsGET as GET } from "@mohasinac/feat-seller";
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
|
-
export declare const GET: (request: Request, context
|
|
15
|
+
export declare const GET: (request: Request, context?: {
|
|
16
16
|
params: Promise<Record<string, string>>;
|
|
17
|
-
}) => Promise<Response>;
|
|
17
|
+
} | undefined) => Promise<Response>;
|
|
@@ -12,6 +12,6 @@
|
|
|
12
12
|
* export { sellerOffersGET as GET } from "@mohasinac/feat-seller";
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
|
-
export declare const GET: (request: Request, context
|
|
15
|
+
export declare const GET: (request: Request, context?: {
|
|
16
16
|
params: Promise<Record<string, string>>;
|
|
17
|
-
}) => Promise<Response>;
|
|
17
|
+
} | undefined) => Promise<Response>;
|
|
@@ -12,6 +12,6 @@
|
|
|
12
12
|
* export { sellerProductsGET as GET } from "@mohasinac/feat-seller";
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
|
-
export declare const GET: (request: Request, context
|
|
15
|
+
export declare const GET: (request: Request, context?: {
|
|
16
16
|
params: Promise<Record<string, string>>;
|
|
17
|
-
}) => Promise<Response>;
|
|
17
|
+
} | undefined) => Promise<Response>;
|
|
@@ -12,6 +12,6 @@
|
|
|
12
12
|
* export { sellerStoreGET as GET } from "@mohasinac/feat-seller";
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
|
-
export declare const GET: (request: Request, context
|
|
15
|
+
export declare const GET: (request: Request, context?: {
|
|
16
16
|
params: Promise<Record<string, string>>;
|
|
17
|
-
}) => Promise<Response>;
|
|
17
|
+
} | undefined) => Promise<Response>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|