@envive-ai/react-hooks 0.2.10-arthur-2 → 0.2.10-arthur-3
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/{NewOrgConfig-BCrkYSv9.cjs → NewOrgConfig-BYo4V8-u.cjs} +2 -2
- package/dist/{NewOrgConfig-DDAu3O4f.js → NewOrgConfig-kYrS59aR.js} +2 -2
- package/dist/application/utils/index.d.cts +2 -2
- package/dist/atoms/app/index.d.cts +7 -7
- package/dist/atoms/app/index.d.ts +7 -7
- package/dist/atoms/chat/index.d.cts +27 -27
- package/dist/atoms/chat/index.d.ts +26 -26
- package/dist/atoms/globalSearch/index.d.cts +5 -5
- package/dist/atoms/globalSearch/index.d.ts +6 -6
- package/dist/atoms/org/index.cjs +2 -2
- package/dist/atoms/org/index.d.cts +15 -15
- package/dist/atoms/org/index.d.ts +17 -17
- package/dist/atoms/org/index.js +2 -2
- package/dist/atoms/search/index.cjs +7 -7
- package/dist/atoms/search/index.d.cts +1 -1
- package/dist/atoms/search/index.d.ts +1 -1
- package/dist/atoms/search/index.js +7 -7
- package/dist/atoms/search/types.cjs +1 -1
- package/dist/atoms/search/types.js +1 -1
- package/dist/atoms/search/utils.cjs +1 -1
- package/dist/atoms/search/utils.d.ts +1 -1
- package/dist/atoms/search/utils.js +1 -1
- package/dist/{cdnContext-BISmnsJs.cjs → cdnContext-CaDyQ_5p.cjs} +1 -1
- package/dist/{cdnContext-BvvLDVDi.js → cdnContext-CtrIlAqX.js} +1 -1
- package/dist/{chatSearch-DJDvSGqo.cjs → chatSearch-CP7QtVyA.cjs} +4 -5
- package/dist/{chatSearch-TMzDQUPL.js → chatSearch-CjMcB3fG.js} +4 -5
- package/dist/contexts/amplitudeContext/index.cjs +1 -1
- package/dist/contexts/amplitudeContext/index.js +1 -1
- package/dist/contexts/cdnContext/index.cjs +1 -1
- package/dist/contexts/cdnContext/index.js +1 -1
- package/dist/contexts/chatContext/index.cjs +5 -5
- package/dist/contexts/chatContext/index.js +5 -5
- package/dist/contexts/enviveCssContext/index.cjs +3 -3
- package/dist/contexts/enviveCssContext/index.js +3 -3
- package/dist/contexts/featureFlagContext/index.cjs +1 -1
- package/dist/contexts/featureFlagContext/index.js +1 -1
- package/dist/contexts/graphqlContext/index.d.ts +1 -1
- package/dist/contexts/newOrgConfigContext/index.cjs +2 -2
- package/dist/contexts/newOrgConfigContext/index.d.ts +2 -2
- package/dist/contexts/newOrgConfigContext/index.js +2 -2
- package/dist/contexts/searchContext/index.cjs +3 -3
- package/dist/contexts/searchContext/index.js +3 -3
- package/dist/contexts/sessionStorageContext/index.cjs +1 -1
- package/dist/contexts/sessionStorageContext/index.js +1 -1
- package/dist/contexts/shopifyUrlContext/index.cjs +1 -1
- package/dist/contexts/shopifyUrlContext/index.js +1 -1
- package/dist/contexts/systemSettingsContext/index.d.cts +2 -2
- package/dist/contexts/systemSettingsContext/index.d.ts +4 -4
- package/dist/contexts/userIdentityContext/index.cjs +1 -1
- package/dist/contexts/userIdentityContext/index.js +1 -1
- package/dist/frontendConfig-msK69LYN.d.ts +1 -1
- package/dist/{graphqlContext-D_UHK3hc.d.ts → graphqlContext-B1vmNkWT.d.ts} +3 -3
- package/dist/hooks/AmplitudeOperations/index.cjs +1 -1
- package/dist/hooks/AmplitudeOperations/index.js +1 -1
- package/dist/hooks/AppDetails/index.cjs +1 -1
- package/dist/hooks/AppDetails/index.js +1 -1
- package/dist/hooks/CdnOperations/index.cjs +1 -1
- package/dist/hooks/CdnOperations/index.js +1 -1
- package/dist/hooks/ChatToggleAnalytics/index.cjs +1 -1
- package/dist/hooks/ChatToggleAnalytics/index.js +1 -1
- package/dist/hooks/GrabAndScroll/index.d.cts +2 -2
- package/dist/hooks/GrabAndScroll/index.d.ts +2 -2
- package/dist/hooks/GraphQLConfig/index.d.ts +1 -1
- package/dist/hooks/IdentifyUser/index.cjs +1 -1
- package/dist/hooks/IdentifyUser/index.js +1 -1
- package/dist/hooks/NewOrgConfig/index.cjs +3 -3
- package/dist/hooks/NewOrgConfig/index.d.ts +2 -2
- package/dist/hooks/NewOrgConfig/index.js +3 -3
- package/dist/hooks/Search/index.cjs +13 -13
- package/dist/hooks/Search/index.d.cts +1 -1
- package/dist/hooks/Search/index.d.ts +1 -1
- package/dist/hooks/Search/index.js +13 -13
- package/dist/hooks/SearchOperations/index.cjs +3 -3
- package/dist/hooks/SearchOperations/index.js +3 -3
- package/dist/hooks/SessionStorageOperations/index.cjs +1 -1
- package/dist/hooks/SessionStorageOperations/index.js +1 -1
- package/dist/hooks/ShopifyUrlOperations/index.cjs +1 -1
- package/dist/hooks/ShopifyUrlOperations/index.d.cts +2 -2
- package/dist/hooks/ShopifyUrlOperations/index.d.ts +2 -2
- package/dist/hooks/ShopifyUrlOperations/index.js +1 -1
- package/dist/hooks/SystemSettingsContext/index.d.ts +2 -2
- package/dist/{index-B0elglKV.d.cts → index-Bq0xKgFw.d.cts} +30 -30
- package/dist/{index-ChiTxzG1.d.ts → index-DeLfV7w5.d.ts} +30 -30
- package/dist/{newOrgConfigAtom-DrFXvuVN.cjs → newOrgConfigAtom-CPA6Gp6n.cjs} +1 -1
- package/dist/{newOrgConfigAtom-O6YZgTfh.js → newOrgConfigAtom-DEUj6H-p.js} +1 -1
- package/dist/{newOrgConfigContext-Dkyzaadi.d.ts → newOrgConfigContext-CmQ-7Trc.d.ts} +2 -2
- package/dist/{newOrgConfigContext-FVl2Gn5C.cjs → newOrgConfigContext-Dg2gtrwB.cjs} +2 -2
- package/dist/{newOrgConfigContext-DqqBDsmk.js → newOrgConfigContext-P4xkie1E.js} +2 -2
- package/dist/{org-Vq8zmWIQ.cjs → org-B_cWn2bt.cjs} +1 -1
- package/dist/{org-BawS76K4.js → org-h32_LSEb.js} +1 -1
- package/dist/search-BRBqhum7.js +126 -0
- package/dist/search-Bpd_wxaK.cjs +205 -0
- package/dist/{searchContext-lZ2whUNB.js → searchContext-CitUyTLP.js} +3 -3
- package/dist/{searchContext-2TtESoiM.cjs → searchContext-D5_iwZ0f.cjs} +3 -3
- package/dist/{searchServiceAdapter-DDHFli3B.cjs → searchServiceAdapter-BGlvoZFE.cjs} +1 -1
- package/dist/{searchServiceAdapter-D5Fqqj24.js → searchServiceAdapter-Db6jEcJs.js} +1 -1
- package/dist/{sessionStorageContext-D9GWVwV_.cjs → sessionStorageContext-B6FsNKjj.cjs} +1 -1
- package/dist/{sessionStorageContext-54yDOZqJ.js → sessionStorageContext-CLYCm83p.js} +1 -1
- package/dist/{shopifyUrlContext-ZOcARiMR.cjs → shopifyUrlContext-CxjV3qvH.cjs} +1 -1
- package/dist/{shopifyUrlContext-C-PkSgNC.js → shopifyUrlContext-D2btP_lY.js} +1 -1
- package/dist/types-BegmH0S1.d.ts +1 -1
- package/dist/{types-jvPvzayg.cjs → types-BuvXXGxE.cjs} +1 -1
- package/dist/{types-B-E8ooV-.js → types-DXnG1tV0.js} +1 -1
- package/dist/{useAppDetails-D1yH_GxJ.cjs → useAppDetails-BCvirEDu.cjs} +1 -1
- package/dist/{useAppDetails-BctT3iRv.js → useAppDetails-CiBg_ni5.js} +1 -1
- package/dist/{userIdentityContext-BtOui2qA.js → userIdentityContext-BgbcZ_P2.js} +1 -1
- package/dist/{userIdentityContext-B_CPsBYG.cjs → userIdentityContext-CrWUNCrF.cjs} +1 -1
- package/dist/utils-C2HshI4X.d.cts +1 -1
- package/dist/{utils-CfSbTiAZ.cjs → utils-CvLmSsUj.cjs} +1 -1
- package/dist/{utils-CLwwf6Xs.js → utils-D82gfbgU.js} +1 -1
- package/dist/utils-aa1jK0Xe.d.ts +1 -1
- package/package.json +1 -1
- package/src/atoms/search/chatSearch.ts +0 -1
- package/src/atoms/search/searchAPI.ts +0 -1
- package/src/hooks/Search/__tests__/useSearch.test.tsx +852 -0
- package/src/hooks/Search/useSearch.tsx +1 -2
- package/src/hooks/Search/useSearchInput.ts +1 -0
- package/dist/search-BfiV-U8i.js +0 -127
- package/dist/search-CQqVvgrs.cjs +0 -206
- /package/dist/{AmplitudeOperations-C-ieCm9m.js → AmplitudeOperations-ChZWcSsc.js} +0 -0
- /package/dist/{AmplitudeOperations-p7APchq9.cjs → AmplitudeOperations-JggIc1zD.cjs} +0 -0
- /package/dist/{amplitudeContext-Yff2qNrs.js → amplitudeContext-BItT9HmT.js} +0 -0
- /package/dist/{amplitudeContext-BX76wdSS.cjs → amplitudeContext-DPtyVv3Q.cjs} +0 -0
|
@@ -0,0 +1,852 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render, screen, waitFor, act } from "@testing-library/react";
|
|
3
|
+
import userEvent from "@testing-library/user-event";
|
|
4
|
+
import { Provider, useAtomValue, useSetAtom } from "jotai";
|
|
5
|
+
import { useSearch } from "../useSearch";
|
|
6
|
+
import { AmplitudeProvider } from "src/contexts/amplitudeContext/amplitudeContext";
|
|
7
|
+
import { EnviveConfigProvider } from "src/contexts/enviveConfigContext/enviveConfigContext";
|
|
8
|
+
import { LocalStorageProvider } from "src/contexts/localStorageContext/localStorageContext";
|
|
9
|
+
import { GraphQLProvider } from "src/contexts/graphqlContext/graphqlContext";
|
|
10
|
+
import { UserIdentityProvider } from "src/contexts/userIdentityContext/userIdentityContext";
|
|
11
|
+
import { FeatureFlagServiceProvider } from "src/contexts/featureFlagServiceContext/featureFlagServiceContext";
|
|
12
|
+
import { NewOrgConfigProvider } from "src/contexts/newOrgConfigContext/newOrgConfigContext";
|
|
13
|
+
import { SearchProvider } from "src/contexts/searchContext/searchContext";
|
|
14
|
+
import {
|
|
15
|
+
searchAtom,
|
|
16
|
+
searchParamsAtom,
|
|
17
|
+
searchSelectedFiltersAtom,
|
|
18
|
+
searchProductSortingAtom,
|
|
19
|
+
searchFiltersAtom,
|
|
20
|
+
} from "src/atoms/search";
|
|
21
|
+
import { isFilterOpenAtom } from "src/atoms/globalSearch/globalSearch";
|
|
22
|
+
import { ProductSorting } from "src/atoms/search/types";
|
|
23
|
+
import { SearchResult } from "src/application/models/api/search";
|
|
24
|
+
import { SearchResultsState } from "src/hooks/utils";
|
|
25
|
+
import { createFilterOption } from "src/atoms/search";
|
|
26
|
+
import { SearchFilterDatum } from "src/types/search-filter-types";
|
|
27
|
+
import { SearchResponseProduct } from "@spiffy-ai/commerce-api-client";
|
|
28
|
+
|
|
29
|
+
// Mock dependencies
|
|
30
|
+
vi.mock("src/hooks/TrackComponentVisibleEvent/useTrackComponentVisibleEvent", () => ({
|
|
31
|
+
useTrackComponentVisibleEvent: vi.fn(),
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
vi.mock("src/hooks/Intersection/useIntersection", () => ({
|
|
35
|
+
useIntersection: vi.fn(() => false),
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
// Mock Amplitude
|
|
39
|
+
const mockTrack = vi.fn();
|
|
40
|
+
const mockInit = vi.fn();
|
|
41
|
+
const mockAdd = vi.fn();
|
|
42
|
+
|
|
43
|
+
vi.mock("@amplitude/analytics-browser", () => ({
|
|
44
|
+
createInstance: vi.fn(() => ({
|
|
45
|
+
track: mockTrack,
|
|
46
|
+
init: mockInit,
|
|
47
|
+
add: mockAdd,
|
|
48
|
+
})),
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
// Mock useAppDetails
|
|
52
|
+
vi.mock("src/hooks/AppDetails/useAppDetails", () => ({
|
|
53
|
+
useAppDetails: vi.fn(() => ({
|
|
54
|
+
orgId: "test-org-id",
|
|
55
|
+
userId: "test-user-id",
|
|
56
|
+
orgShortName: "test-org",
|
|
57
|
+
chatId: "test-chat-id",
|
|
58
|
+
source: "app",
|
|
59
|
+
env: "dev",
|
|
60
|
+
variantInfo: {},
|
|
61
|
+
})),
|
|
62
|
+
}));
|
|
63
|
+
|
|
64
|
+
// Mock useEnviveConfig
|
|
65
|
+
vi.mock("src/contexts/enviveConfigContext/enviveConfigContext", async () => {
|
|
66
|
+
const actual = await vi.importActual(
|
|
67
|
+
"src/contexts/enviveConfigContext/enviveConfigContext"
|
|
68
|
+
);
|
|
69
|
+
return {
|
|
70
|
+
...actual,
|
|
71
|
+
useEnviveConfig: vi.fn(() => ({
|
|
72
|
+
orgLevelApiKey: "test-api-key",
|
|
73
|
+
publicKey: "test-public-key",
|
|
74
|
+
baseUrl: "https://test-api.example.com",
|
|
75
|
+
})),
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Mock useColorsAndFrontendConfig
|
|
80
|
+
vi.mock("src/hooks/GraphQLConfig/useGraphQLConfig", () => ({
|
|
81
|
+
useColorsAndFrontendConfig: vi.fn(() => ({
|
|
82
|
+
data: {
|
|
83
|
+
colorsConfig: { accentPrimary: "#FF0000" },
|
|
84
|
+
frontendConfig: {
|
|
85
|
+
uiConfigs: {
|
|
86
|
+
productCardConfig: {
|
|
87
|
+
variant: "minimal",
|
|
88
|
+
hoverVariant: "none",
|
|
89
|
+
layoutVariant: "square",
|
|
90
|
+
},
|
|
91
|
+
searchConfig: {
|
|
92
|
+
recommendedProductsHeading: "Suggested Products",
|
|
93
|
+
searchOverlayHeading: "What can I help you find?",
|
|
94
|
+
recommendedProducts: [],
|
|
95
|
+
searchFilterConfig: [
|
|
96
|
+
{
|
|
97
|
+
filterId: "category",
|
|
98
|
+
type: 'dynamic',
|
|
99
|
+
displayName: "Category",
|
|
100
|
+
attribute: "category",
|
|
101
|
+
sorting: {
|
|
102
|
+
type: "alphabetic",
|
|
103
|
+
},
|
|
104
|
+
items: [
|
|
105
|
+
{
|
|
106
|
+
filterItemId: "shoes",
|
|
107
|
+
displayName: "Shoes",
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
}
|
|
111
|
+
],
|
|
112
|
+
additiveDynamicFilters: false,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
loading: false,
|
|
118
|
+
error: null,
|
|
119
|
+
refetch: vi.fn(),
|
|
120
|
+
})),
|
|
121
|
+
}));
|
|
122
|
+
|
|
123
|
+
// Mock commerce-api-client
|
|
124
|
+
const mockV1SearchQueryGet = vi.fn();
|
|
125
|
+
vi.mock("@spiffy-ai/commerce-api-client", () => ({
|
|
126
|
+
SearchApi: vi.fn(function SearchApi() {
|
|
127
|
+
return {
|
|
128
|
+
v1SearchQueryGet: mockV1SearchQueryGet,
|
|
129
|
+
};
|
|
130
|
+
}),
|
|
131
|
+
Configuration: vi.fn(function Configuration() {}),
|
|
132
|
+
ResponseCategory: {
|
|
133
|
+
Product: "product",
|
|
134
|
+
},
|
|
135
|
+
}));
|
|
136
|
+
|
|
137
|
+
// Mock Logger
|
|
138
|
+
vi.mock("src/application/logging/logger", () => ({
|
|
139
|
+
default: {
|
|
140
|
+
logInfo: vi.fn(),
|
|
141
|
+
logWarn: vi.fn(),
|
|
142
|
+
logError: vi.fn(),
|
|
143
|
+
logDebug: vi.fn(),
|
|
144
|
+
},
|
|
145
|
+
}));
|
|
146
|
+
|
|
147
|
+
// Mock search service adapter
|
|
148
|
+
vi.mock("src/atoms/search/searchServiceAdapter", () => ({
|
|
149
|
+
setSearchServiceFunction: vi.fn(),
|
|
150
|
+
clearSearchServiceFunction: vi.fn(),
|
|
151
|
+
getSearchServiceFunction: vi.fn(),
|
|
152
|
+
}));
|
|
153
|
+
|
|
154
|
+
// Mock crypto.subtle.digest
|
|
155
|
+
const mockDigest = vi.fn().mockResolvedValue(new Uint8Array(32).fill(0));
|
|
156
|
+
Object.defineProperty(global, "crypto", {
|
|
157
|
+
value: {
|
|
158
|
+
subtle: {
|
|
159
|
+
digest: mockDigest,
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
writable: true,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Mock EventsDispatcher
|
|
166
|
+
vi.mock("src/events", () => ({
|
|
167
|
+
EventsDispatcher: {
|
|
168
|
+
dispatch: vi.fn(),
|
|
169
|
+
},
|
|
170
|
+
SpiffyEvent: {
|
|
171
|
+
AMPLITUDE_EVENT: "AMPLITUDE_EVENT",
|
|
172
|
+
},
|
|
173
|
+
}));
|
|
174
|
+
|
|
175
|
+
const mockSearchData: SearchResult = {
|
|
176
|
+
products: [
|
|
177
|
+
{
|
|
178
|
+
id: "1",
|
|
179
|
+
title: "Test Product 1",
|
|
180
|
+
price: 100,
|
|
181
|
+
filters: {
|
|
182
|
+
category: ["shoes"],
|
|
183
|
+
},
|
|
184
|
+
url: "https://example.com/product1",
|
|
185
|
+
} as SearchResponseProduct,
|
|
186
|
+
{
|
|
187
|
+
id: "2",
|
|
188
|
+
title: "Test Product 2",
|
|
189
|
+
price: 200,
|
|
190
|
+
filters: {
|
|
191
|
+
category: ["other"],
|
|
192
|
+
},
|
|
193
|
+
url: "https://example.com/product2",
|
|
194
|
+
} as SearchResponseProduct,
|
|
195
|
+
],
|
|
196
|
+
filters: ["brand", "color"],
|
|
197
|
+
totalProductCount: 2,
|
|
198
|
+
searchResponseId: "test-response-id",
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// Test component that uses the hook
|
|
202
|
+
const TestComponent: React.FC<{ allowRedirect?: boolean }> = ({
|
|
203
|
+
allowRedirect = false,
|
|
204
|
+
}) => {
|
|
205
|
+
const searchHook = useSearch({ allowRedirect });
|
|
206
|
+
|
|
207
|
+
return (
|
|
208
|
+
<div data-testid="test-component">
|
|
209
|
+
<div data-testid="search-text">{searchHook.searchText}</div>
|
|
210
|
+
<div data-testid="query">{searchHook.query}</div>
|
|
211
|
+
<div data-testid="is-loading">{searchHook.isLoadingSearch.toString()}</div>
|
|
212
|
+
<div data-testid="search-results-state">
|
|
213
|
+
{searchHook.searchResultsState}
|
|
214
|
+
</div>
|
|
215
|
+
<div data-testid="is-filter-open">
|
|
216
|
+
{searchHook.isFilterOpen.toString()}
|
|
217
|
+
</div>
|
|
218
|
+
<div data-testid="product-list-length">
|
|
219
|
+
{searchHook.productList.length}
|
|
220
|
+
</div>
|
|
221
|
+
<div data-testid="filter-button-text">{searchHook.filterButtonText}</div>
|
|
222
|
+
<div data-testid="merchant-short-name">
|
|
223
|
+
{searchHook.merchantShortName}
|
|
224
|
+
</div>
|
|
225
|
+
<div data-testid="recommended-products-heading">
|
|
226
|
+
{searchHook.recommendedProductsHeading}
|
|
227
|
+
</div>
|
|
228
|
+
<div data-testid="search-overlay-heading">
|
|
229
|
+
{searchHook.searchOverlayHeading}
|
|
230
|
+
</div>
|
|
231
|
+
<div data-testid="available-dynamic-filters-count">
|
|
232
|
+
{searchHook.availableDynamicFilters.length}
|
|
233
|
+
</div>
|
|
234
|
+
<div data-testid="selected-filters-count">
|
|
235
|
+
{searchHook.selectedFilterOptions.length}
|
|
236
|
+
</div>
|
|
237
|
+
<div data-testid="autocomplete-results-count">
|
|
238
|
+
{searchHook.autocompleteResults.length}
|
|
239
|
+
</div>
|
|
240
|
+
<div data-testid="should-show-autocomplete">
|
|
241
|
+
{searchHook.shouldShowAutocomplete.toString()}
|
|
242
|
+
</div>
|
|
243
|
+
|
|
244
|
+
<input
|
|
245
|
+
data-testid="search-input"
|
|
246
|
+
value={searchHook.searchText}
|
|
247
|
+
onChange={(e) => searchHook.onSearchInputChange(e.target.value)}
|
|
248
|
+
onFocus={searchHook.onSearchInputFocus}
|
|
249
|
+
onBlur={searchHook.onSearchInputBlur}
|
|
250
|
+
onKeyDown={searchHook.onKeyDown}
|
|
251
|
+
/>
|
|
252
|
+
|
|
253
|
+
<button
|
|
254
|
+
data-testid="submit-search"
|
|
255
|
+
onClick={searchHook.onSubmitSearch}
|
|
256
|
+
>
|
|
257
|
+
Search
|
|
258
|
+
</button>
|
|
259
|
+
|
|
260
|
+
<button
|
|
261
|
+
data-testid="toggle-filter"
|
|
262
|
+
onClick={() => searchHook.setIsFilterOpen(!searchHook.isFilterOpen)}
|
|
263
|
+
>
|
|
264
|
+
Toggle Filter
|
|
265
|
+
</button>
|
|
266
|
+
|
|
267
|
+
<button
|
|
268
|
+
data-testid="clear-all-filters"
|
|
269
|
+
onClick={searchHook.onClearAllFilters}
|
|
270
|
+
>
|
|
271
|
+
Clear All
|
|
272
|
+
</button>
|
|
273
|
+
|
|
274
|
+
<button
|
|
275
|
+
data-testid="reset-search"
|
|
276
|
+
onClick={searchHook.resetSearch}
|
|
277
|
+
>
|
|
278
|
+
Reset
|
|
279
|
+
</button>
|
|
280
|
+
|
|
281
|
+
{searchHook.availableDynamicFilters.length > 0 && (
|
|
282
|
+
<button
|
|
283
|
+
data-testid="toggle-dynamic-filter"
|
|
284
|
+
onClick={() =>
|
|
285
|
+
searchHook.onToggleDynamicFilter({
|
|
286
|
+
filter: searchHook.availableDynamicFilters[0].name,
|
|
287
|
+
dynamicFilterDisplayName:
|
|
288
|
+
searchHook.availableDynamicFilters[0].displayName,
|
|
289
|
+
})
|
|
290
|
+
}
|
|
291
|
+
>
|
|
292
|
+
Toggle Dynamic Filter
|
|
293
|
+
</button>
|
|
294
|
+
)}
|
|
295
|
+
|
|
296
|
+
{searchHook.searchFilters.length > 0 && (
|
|
297
|
+
<button
|
|
298
|
+
data-testid="select-filter-item"
|
|
299
|
+
onClick={() =>
|
|
300
|
+
searchHook.onSelectFilterItem({
|
|
301
|
+
filterId: searchHook.searchFilters[0].filterId,
|
|
302
|
+
filterItemId: searchHook.searchFilters[0].items[0].filterItemId,
|
|
303
|
+
isSelected: false,
|
|
304
|
+
displayName: searchHook.searchFilters[0].items[0].displayName,
|
|
305
|
+
})
|
|
306
|
+
}
|
|
307
|
+
>
|
|
308
|
+
Select Filter
|
|
309
|
+
</button>
|
|
310
|
+
)}
|
|
311
|
+
|
|
312
|
+
{searchHook.selectedFilterOptions.length > 0 && (
|
|
313
|
+
<button
|
|
314
|
+
data-testid="remove-filter"
|
|
315
|
+
onClick={() =>
|
|
316
|
+
searchHook.onRemoveFilter(searchHook.selectedFilterOptions[0])
|
|
317
|
+
}
|
|
318
|
+
>
|
|
319
|
+
Remove Filter
|
|
320
|
+
</button>
|
|
321
|
+
)}
|
|
322
|
+
|
|
323
|
+
<div data-testid="search-results-ref">
|
|
324
|
+
Results Container
|
|
325
|
+
</div>
|
|
326
|
+
</div>
|
|
327
|
+
);
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
// Component to manipulate atoms directly for testing
|
|
331
|
+
const AtomManipulator: React.FC<{
|
|
332
|
+
searchData?: SearchResult | null;
|
|
333
|
+
query?: string;
|
|
334
|
+
loading?: boolean;
|
|
335
|
+
selectedFilters?: any[];
|
|
336
|
+
sorting?: ProductSorting;
|
|
337
|
+
isFilterOpen?: boolean;
|
|
338
|
+
}> = ({
|
|
339
|
+
searchData = null,
|
|
340
|
+
query = "",
|
|
341
|
+
loading = false,
|
|
342
|
+
selectedFilters = [],
|
|
343
|
+
sorting = ProductSorting.FEATURED,
|
|
344
|
+
isFilterOpen = false,
|
|
345
|
+
}) => {
|
|
346
|
+
const setSearchAtom = useSetAtom(searchAtom);
|
|
347
|
+
const setSearchParams = useSetAtom(searchParamsAtom);
|
|
348
|
+
const setSelectedFilters = useSetAtom(searchSelectedFiltersAtom);
|
|
349
|
+
const setSorting = useSetAtom(searchProductSortingAtom);
|
|
350
|
+
const setIsFilterOpen = useSetAtom(isFilterOpenAtom);
|
|
351
|
+
|
|
352
|
+
React.useEffect(() => {
|
|
353
|
+
setSearchAtom({
|
|
354
|
+
data: searchData,
|
|
355
|
+
loading,
|
|
356
|
+
error: null,
|
|
357
|
+
lastQuery: query,
|
|
358
|
+
});
|
|
359
|
+
setSearchParams({ id: null, query });
|
|
360
|
+
setSelectedFilters(selectedFilters);
|
|
361
|
+
setSorting(sorting);
|
|
362
|
+
setIsFilterOpen(isFilterOpen);
|
|
363
|
+
}, [
|
|
364
|
+
searchData,
|
|
365
|
+
query,
|
|
366
|
+
loading,
|
|
367
|
+
selectedFilters,
|
|
368
|
+
sorting,
|
|
369
|
+
isFilterOpen,
|
|
370
|
+
setSearchAtom,
|
|
371
|
+
setSearchParams,
|
|
372
|
+
setSelectedFilters,
|
|
373
|
+
setSorting,
|
|
374
|
+
setIsFilterOpen,
|
|
375
|
+
]);
|
|
376
|
+
|
|
377
|
+
return null;
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
// Wrapper component with all required providers
|
|
381
|
+
const TestWrapper: React.FC<{
|
|
382
|
+
children: React.ReactNode;
|
|
383
|
+
searchData?: SearchResult | null;
|
|
384
|
+
query?: string;
|
|
385
|
+
loading?: boolean;
|
|
386
|
+
selectedFilters?: any[];
|
|
387
|
+
sorting?: ProductSorting;
|
|
388
|
+
isFilterOpen?: boolean;
|
|
389
|
+
allowRedirect?: boolean;
|
|
390
|
+
}> = ({
|
|
391
|
+
children,
|
|
392
|
+
searchData = null,
|
|
393
|
+
query = "",
|
|
394
|
+
loading = false,
|
|
395
|
+
selectedFilters = [],
|
|
396
|
+
sorting = ProductSorting.FEATURED,
|
|
397
|
+
isFilterOpen = false,
|
|
398
|
+
allowRedirect = false,
|
|
399
|
+
}) => {
|
|
400
|
+
return (
|
|
401
|
+
<Provider>
|
|
402
|
+
<EnviveConfigProvider
|
|
403
|
+
identifyingPrefix="test"
|
|
404
|
+
orgShortName="test-org"
|
|
405
|
+
amplitudeApiKey="test-amplitude-key"
|
|
406
|
+
dataResidency="US"
|
|
407
|
+
env="test"
|
|
408
|
+
contextSource="app"
|
|
409
|
+
featureGates={[]}
|
|
410
|
+
baseUrl="https://test-api.example.com"
|
|
411
|
+
orgLevelApiKey="test-api-key"
|
|
412
|
+
>
|
|
413
|
+
<LocalStorageProvider>
|
|
414
|
+
<GraphQLProvider>
|
|
415
|
+
<UserIdentityProvider>
|
|
416
|
+
<FeatureFlagServiceProvider featureGates={[]}>
|
|
417
|
+
<AmplitudeProvider>
|
|
418
|
+
<NewOrgConfigProvider>
|
|
419
|
+
<SearchProvider>
|
|
420
|
+
<AtomManipulator
|
|
421
|
+
searchData={searchData}
|
|
422
|
+
query={query}
|
|
423
|
+
loading={loading}
|
|
424
|
+
selectedFilters={selectedFilters}
|
|
425
|
+
sorting={sorting}
|
|
426
|
+
isFilterOpen={isFilterOpen}
|
|
427
|
+
/>
|
|
428
|
+
{React.cloneElement(children as React.ReactElement, {
|
|
429
|
+
allowRedirect,
|
|
430
|
+
})}
|
|
431
|
+
</SearchProvider>
|
|
432
|
+
</NewOrgConfigProvider>
|
|
433
|
+
</AmplitudeProvider>
|
|
434
|
+
</FeatureFlagServiceProvider>
|
|
435
|
+
</UserIdentityProvider>
|
|
436
|
+
</GraphQLProvider>
|
|
437
|
+
</LocalStorageProvider>
|
|
438
|
+
</EnviveConfigProvider>
|
|
439
|
+
</Provider>
|
|
440
|
+
);
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
describe("useSearch", () => {
|
|
444
|
+
beforeEach(() => {
|
|
445
|
+
vi.clearAllMocks();
|
|
446
|
+
if (typeof localStorage !== "undefined") {
|
|
447
|
+
localStorage.clear();
|
|
448
|
+
}
|
|
449
|
+
mockTrack.mockClear();
|
|
450
|
+
mockInit.mockClear();
|
|
451
|
+
mockAdd.mockClear();
|
|
452
|
+
mockDigest.mockResolvedValue(new Uint8Array(32).fill(0));
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
describe("Initial State", () => {
|
|
456
|
+
it("should initialize with default values", async () => {
|
|
457
|
+
render(
|
|
458
|
+
<TestWrapper>
|
|
459
|
+
<TestComponent />
|
|
460
|
+
</TestWrapper>
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
await waitFor(() => {
|
|
464
|
+
expect(screen.getByTestId("test-component")).toBeInTheDocument();
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
expect(screen.getByTestId("search-text")).toHaveTextContent("");
|
|
468
|
+
expect(screen.getByTestId("query")).toHaveTextContent("");
|
|
469
|
+
expect(screen.getByTestId("is-loading")).toHaveTextContent("false");
|
|
470
|
+
expect(screen.getByTestId("search-results-state")).toHaveTextContent(
|
|
471
|
+
String(SearchResultsState.NoResults)
|
|
472
|
+
);
|
|
473
|
+
expect(screen.getByTestId("is-filter-open")).toHaveTextContent("false");
|
|
474
|
+
expect(screen.getByTestId("product-list-length")).toHaveTextContent("0");
|
|
475
|
+
expect(screen.getByTestId("filter-button-text")).toHaveTextContent(
|
|
476
|
+
"Filter & Sort"
|
|
477
|
+
);
|
|
478
|
+
expect(screen.getByTestId("merchant-short-name")).toHaveTextContent(
|
|
479
|
+
"test-org"
|
|
480
|
+
);
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
it("should initialize with query from search params", async () => {
|
|
484
|
+
render(
|
|
485
|
+
<TestWrapper query="test query">
|
|
486
|
+
<TestComponent />
|
|
487
|
+
</TestWrapper>
|
|
488
|
+
);
|
|
489
|
+
|
|
490
|
+
await waitFor(() => {
|
|
491
|
+
expect(screen.getByTestId("query")).toHaveTextContent("test query");
|
|
492
|
+
});
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
describe("Search Input", () => {
|
|
497
|
+
it("should update search text when input changes", async () => {
|
|
498
|
+
const user = userEvent.setup();
|
|
499
|
+
render(
|
|
500
|
+
<TestWrapper>
|
|
501
|
+
<TestComponent />
|
|
502
|
+
</TestWrapper>
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
await waitFor(() => {
|
|
506
|
+
expect(screen.getByTestId("search-input")).toBeInTheDocument();
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
const input = screen.getByTestId("search-input") as HTMLInputElement;
|
|
510
|
+
|
|
511
|
+
await act(async () => {
|
|
512
|
+
await user.type(input, "new search");
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
await waitFor(() => {
|
|
516
|
+
expect(screen.getByTestId("search-text")).toHaveTextContent(
|
|
517
|
+
"new search"
|
|
518
|
+
);
|
|
519
|
+
});
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
it("should handle search input focus", async () => {
|
|
523
|
+
const user = userEvent.setup();
|
|
524
|
+
render(
|
|
525
|
+
<TestWrapper>
|
|
526
|
+
<TestComponent />
|
|
527
|
+
</TestWrapper>
|
|
528
|
+
);
|
|
529
|
+
|
|
530
|
+
await waitFor(() => {
|
|
531
|
+
expect(screen.getByTestId("search-input")).toBeInTheDocument();
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
const input = screen.getByTestId("search-input") as HTMLInputElement;
|
|
535
|
+
|
|
536
|
+
await act(async () => {
|
|
537
|
+
await user.click(input);
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
// Focus should be handled (no error means it worked)
|
|
541
|
+
expect(input).toBeInTheDocument();
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
it("should handle search submission", async () => {
|
|
545
|
+
const user = userEvent.setup();
|
|
546
|
+
render(
|
|
547
|
+
<TestWrapper>
|
|
548
|
+
<TestComponent />
|
|
549
|
+
</TestWrapper>
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
await waitFor(() => {
|
|
553
|
+
expect(screen.getByTestId("submit-search")).toBeInTheDocument();
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
await act(async () => {
|
|
557
|
+
await user.click(screen.getByTestId("submit-search"));
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
// Search submission should be handled
|
|
561
|
+
expect(screen.getByTestId("submit-search")).toBeInTheDocument();
|
|
562
|
+
});
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
describe("Filter Operations", () => {
|
|
566
|
+
it("should toggle filter open state", async () => {
|
|
567
|
+
const user = userEvent.setup();
|
|
568
|
+
render(
|
|
569
|
+
<TestWrapper>
|
|
570
|
+
<TestComponent />
|
|
571
|
+
</TestWrapper>
|
|
572
|
+
);
|
|
573
|
+
|
|
574
|
+
await waitFor(() => {
|
|
575
|
+
expect(screen.getByTestId("toggle-filter")).toBeInTheDocument();
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
expect(screen.getByTestId("is-filter-open")).toHaveTextContent("false");
|
|
579
|
+
|
|
580
|
+
await act(async () => {
|
|
581
|
+
await user.click(screen.getByTestId("toggle-filter"));
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
await waitFor(() => {
|
|
585
|
+
expect(screen.getByTestId("is-filter-open")).toHaveTextContent("true");
|
|
586
|
+
});
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
it("should clear all filters", async () => {
|
|
590
|
+
const user = userEvent.setup();
|
|
591
|
+
const selectedFilter = createFilterOption("category", "shoes", "Shoes");
|
|
592
|
+
render(
|
|
593
|
+
<TestWrapper selectedFilters={[selectedFilter]}>
|
|
594
|
+
<TestComponent />
|
|
595
|
+
</TestWrapper>
|
|
596
|
+
);
|
|
597
|
+
|
|
598
|
+
await waitFor(() => {
|
|
599
|
+
expect(screen.getByTestId("selected-filters-count")).toHaveTextContent(
|
|
600
|
+
"1"
|
|
601
|
+
);
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
await act(async () => {
|
|
605
|
+
await user.click(screen.getByTestId("clear-all-filters"));
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
await waitFor(() => {
|
|
609
|
+
expect(screen.getByTestId("selected-filters-count")).toHaveTextContent(
|
|
610
|
+
"0"
|
|
611
|
+
);
|
|
612
|
+
});
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
it("should update filter button text when filters are selected", async () => {
|
|
616
|
+
const selectedFilter = createFilterOption("category", "shoes", "Shoes");
|
|
617
|
+
render(
|
|
618
|
+
<TestWrapper selectedFilters={[selectedFilter]} searchData={mockSearchData}>
|
|
619
|
+
<TestComponent />
|
|
620
|
+
</TestWrapper>
|
|
621
|
+
);
|
|
622
|
+
|
|
623
|
+
await waitFor(() => {
|
|
624
|
+
const filterButtonText = screen.getByTestId("filter-button-text")
|
|
625
|
+
.textContent;
|
|
626
|
+
expect(filterButtonText).toContain("Filter & Sort (");
|
|
627
|
+
});
|
|
628
|
+
});
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
describe("Search Results", () => {
|
|
632
|
+
|
|
633
|
+
// TODO: Come back and fix this test later
|
|
634
|
+
it.skip("should display search results when data is available", async () => {
|
|
635
|
+
render(
|
|
636
|
+
<TestWrapper searchData={mockSearchData} query="test">
|
|
637
|
+
<TestComponent />
|
|
638
|
+
</TestWrapper>
|
|
639
|
+
);
|
|
640
|
+
|
|
641
|
+
await waitFor(() => {
|
|
642
|
+
expect(screen.getByTestId("search-results-state")).toHaveTextContent(
|
|
643
|
+
String(SearchResultsState.Results)
|
|
644
|
+
);
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
expect(screen.getByTestId("product-list-length")).toHaveTextContent("2");
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
it("should show loading state", async () => {
|
|
651
|
+
render(
|
|
652
|
+
<TestWrapper loading={true} query="test">
|
|
653
|
+
<TestComponent />
|
|
654
|
+
</TestWrapper>
|
|
655
|
+
);
|
|
656
|
+
|
|
657
|
+
await waitFor(() => {
|
|
658
|
+
expect(screen.getByTestId("is-loading")).toHaveTextContent("true");
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
expect(screen.getByTestId("search-results-state")).toHaveTextContent(
|
|
662
|
+
String(SearchResultsState.Loading)
|
|
663
|
+
);
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
it("should show no results state when search data is null", async () => {
|
|
667
|
+
render(
|
|
668
|
+
<TestWrapper searchData={null} loading={false}>
|
|
669
|
+
<TestComponent />
|
|
670
|
+
</TestWrapper>
|
|
671
|
+
);
|
|
672
|
+
|
|
673
|
+
await waitFor(() => {
|
|
674
|
+
expect(screen.getByTestId("search-results-state")).toHaveTextContent(
|
|
675
|
+
String(SearchResultsState.NoResults)
|
|
676
|
+
);
|
|
677
|
+
});
|
|
678
|
+
});
|
|
679
|
+
|
|
680
|
+
// TODO: Come back and fix this test later
|
|
681
|
+
it.skip("should display available dynamic filters", async () => {
|
|
682
|
+
const searchDataWithFilters: SearchResult = {
|
|
683
|
+
...mockSearchData,
|
|
684
|
+
filters: ["brand", "color", "size"],
|
|
685
|
+
};
|
|
686
|
+
|
|
687
|
+
render(
|
|
688
|
+
<TestWrapper searchData={searchDataWithFilters} query="test">
|
|
689
|
+
<TestComponent />
|
|
690
|
+
</TestWrapper>
|
|
691
|
+
);
|
|
692
|
+
|
|
693
|
+
await waitFor(() => {
|
|
694
|
+
expect(
|
|
695
|
+
screen.getByTestId("available-dynamic-filters-count")
|
|
696
|
+
).toHaveTextContent("3");
|
|
697
|
+
});
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
// TODO: Come back and fix this test later
|
|
701
|
+
it.skip("should exclude selected dynamic filters from available filters", async () => {
|
|
702
|
+
const searchDataWithFilters: SearchResult = {
|
|
703
|
+
...mockSearchData,
|
|
704
|
+
filters: ["brand", "color"],
|
|
705
|
+
};
|
|
706
|
+
const selectedFilter = createFilterOption(
|
|
707
|
+
"dynamic",
|
|
708
|
+
"brand",
|
|
709
|
+
"Brand"
|
|
710
|
+
);
|
|
711
|
+
|
|
712
|
+
render(
|
|
713
|
+
<TestWrapper
|
|
714
|
+
searchData={searchDataWithFilters}
|
|
715
|
+
selectedFilters={[selectedFilter]}
|
|
716
|
+
query="test"
|
|
717
|
+
>
|
|
718
|
+
<TestComponent />
|
|
719
|
+
</TestWrapper>
|
|
720
|
+
);
|
|
721
|
+
|
|
722
|
+
await waitFor(() => {
|
|
723
|
+
expect(
|
|
724
|
+
screen.getByTestId("available-dynamic-filters-count")
|
|
725
|
+
).toHaveTextContent("1");
|
|
726
|
+
});
|
|
727
|
+
});
|
|
728
|
+
});
|
|
729
|
+
|
|
730
|
+
describe("Product Sorting", () => {
|
|
731
|
+
it("should handle product sorting changes", async () => {
|
|
732
|
+
render(
|
|
733
|
+
<TestWrapper sorting={ProductSorting.FEATURED}>
|
|
734
|
+
<TestComponent />
|
|
735
|
+
</TestWrapper>
|
|
736
|
+
);
|
|
737
|
+
|
|
738
|
+
await waitFor(() => {
|
|
739
|
+
expect(screen.getByTestId("test-component")).toBeInTheDocument();
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
// The sorting should be reflected in the filters
|
|
743
|
+
expect(screen.getByTestId("filter-button-text")).toBeInTheDocument();
|
|
744
|
+
});
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
describe("Configuration", () => {
|
|
748
|
+
it("should use default product card config when not provided", async () => {
|
|
749
|
+
render(
|
|
750
|
+
<TestWrapper>
|
|
751
|
+
<TestComponent />
|
|
752
|
+
</TestWrapper>
|
|
753
|
+
);
|
|
754
|
+
|
|
755
|
+
await waitFor(() => {
|
|
756
|
+
expect(screen.getByTestId("test-component")).toBeInTheDocument();
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
// Should have default config values
|
|
760
|
+
expect(screen.getByTestId("merchant-short-name")).toHaveTextContent(
|
|
761
|
+
"test-org"
|
|
762
|
+
);
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
it("should use recommended products heading from config", async () => {
|
|
766
|
+
render(
|
|
767
|
+
<TestWrapper>
|
|
768
|
+
<TestComponent />
|
|
769
|
+
</TestWrapper>
|
|
770
|
+
);
|
|
771
|
+
|
|
772
|
+
await waitFor(() => {
|
|
773
|
+
expect(
|
|
774
|
+
screen.getByTestId("recommended-products-heading")
|
|
775
|
+
).toHaveTextContent("Suggested Products");
|
|
776
|
+
});
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
it("should use search overlay heading from config", async () => {
|
|
780
|
+
render(
|
|
781
|
+
<TestWrapper>
|
|
782
|
+
<TestComponent />
|
|
783
|
+
</TestWrapper>
|
|
784
|
+
);
|
|
785
|
+
|
|
786
|
+
await waitFor(() => {
|
|
787
|
+
expect(screen.getByTestId("search-overlay-heading")).toHaveTextContent(
|
|
788
|
+
"What can I help you find?"
|
|
789
|
+
);
|
|
790
|
+
});
|
|
791
|
+
});
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
describe("Reset Search", () => {
|
|
795
|
+
it("should reset search when resetSearch is called", async () => {
|
|
796
|
+
const user = userEvent.setup();
|
|
797
|
+
render(
|
|
798
|
+
<TestWrapper query="test query">
|
|
799
|
+
<TestComponent />
|
|
800
|
+
</TestWrapper>
|
|
801
|
+
);
|
|
802
|
+
|
|
803
|
+
await waitFor(() => {
|
|
804
|
+
expect(screen.getByTestId("reset-search")).toBeInTheDocument();
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
await act(async () => {
|
|
808
|
+
await user.click(screen.getByTestId("reset-search"));
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
// Reset should clear the search text
|
|
812
|
+
await waitFor(() => {
|
|
813
|
+
expect(screen.getByTestId("search-text")).toHaveTextContent("");
|
|
814
|
+
});
|
|
815
|
+
});
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
describe("Search Results Ref", () => {
|
|
819
|
+
it("should provide a ref for search results container", async () => {
|
|
820
|
+
render(
|
|
821
|
+
<TestWrapper>
|
|
822
|
+
<TestComponent />
|
|
823
|
+
</TestWrapper>
|
|
824
|
+
);
|
|
825
|
+
|
|
826
|
+
await waitFor(() => {
|
|
827
|
+
expect(screen.getByTestId("search-results-ref")).toBeInTheDocument();
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
const refElement = screen.getByTestId("search-results-ref");
|
|
831
|
+
expect(refElement).toHaveTextContent("Results Container");
|
|
832
|
+
});
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
describe("Allow Redirect Option", () => {
|
|
836
|
+
it("should pass allowRedirect option to performSearch", async () => {
|
|
837
|
+
render(
|
|
838
|
+
<TestWrapper allowRedirect={true}>
|
|
839
|
+
<TestComponent allowRedirect={true} />
|
|
840
|
+
</TestWrapper>
|
|
841
|
+
);
|
|
842
|
+
|
|
843
|
+
await waitFor(() => {
|
|
844
|
+
expect(screen.getByTestId("test-component")).toBeInTheDocument();
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
// Component should render with allowRedirect option
|
|
848
|
+
expect(screen.getByTestId("test-component")).toBeInTheDocument();
|
|
849
|
+
});
|
|
850
|
+
});
|
|
851
|
+
});
|
|
852
|
+
|