Skip to content
This repository was archived by the owner on Dec 30, 2022. It is now read-only.

Commit f436d31

Browse files
authored
feat(useInstantSearch): expose status & error (#3645)
<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. --> **Summary** <!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? Are there any linked issues? --> Introduces `status` and `error` in the response of `useInstantSearch`, as well as a new option on `useInstantSearch` to indicate errors in the search lifecycle should be caught. built on top of algolia/instantsearch#5127 **Result** <!-- Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes UI. --> ```jsx function Status() { const { status, error } = useInstantSearch({ catchError: true }); return ( <> <span>Search status: {status}</span> {error && <span>a search error occurred: {error.message}</span>} </> ); } ``` FX-1769
1 parent 980ad70 commit f436d31

File tree

15 files changed

+175
-34
lines changed

15 files changed

+175
-34
lines changed

examples/hooks-e-commerce/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
},
99
"dependencies": {
1010
"algoliasearch": "4.11.0",
11-
"instantsearch.js": "4.46.1",
11+
"instantsearch.js": "4.47.0",
1212
"react": "18.1.0",
1313
"react-compound-slider": "3.4.0",
1414
"react-dom": "18.1.0",

examples/hooks-react-native/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"algoliasearch": "4.12.1",
1515
"expo": "~44.0.0",
1616
"expo-status-bar": "~1.2.0",
17-
"instantsearch.js": "4.46.1",
17+
"instantsearch.js": "4.47.0",
1818
"react": "17.0.1",
1919
"react-dom": "17.0.1",
2020
"react-instantsearch-hooks": "6.35.0",

examples/hooks/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
},
99
"dependencies": {
1010
"algoliasearch": "4.11.0",
11-
"instantsearch.js": "4.46.1",
11+
"instantsearch.js": "4.47.0",
1212
"react": "18.1.0",
1313
"react-dom": "18.1.0",
1414
"react-instantsearch-hooks-web": "6.35.0"

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@
168168
},
169169
{
170170
"path": "packages/react-instantsearch-hooks-web/dist/umd/ReactInstantSearchHooksDOM.min.js",
171-
"maxSize": "49.75 kB"
171+
"maxSize": "50 kB"
172172
},
173173
{
174174
"path": "packages/react-instantsearch-dom/dist/umd/ReactInstantSearchDOM.min.js",

packages/react-instantsearch-hooks-server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
},
4747
"dependencies": {
4848
"@babel/runtime": "^7.1.2",
49-
"instantsearch.js": "^4.46.1",
49+
"instantsearch.js": "^4.47.0",
5050
"react-instantsearch-hooks": "6.35.0"
5151
},
5252
"peerDependencies": {

packages/react-instantsearch-hooks-web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
},
4848
"dependencies": {
4949
"@babel/runtime": "^7.1.2",
50-
"instantsearch.js": "^4.46.1",
50+
"instantsearch.js": "^4.47.0",
5151
"react-instantsearch-hooks": "6.35.0"
5252
},
5353
"peerDependencies": {

packages/react-instantsearch-hooks/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"dependencies": {
4949
"@babel/runtime": "^7.1.2",
5050
"algoliasearch-helper": "^3.11.1",
51-
"instantsearch.js": "^4.46.1",
51+
"instantsearch.js": "^4.47.0",
5252
"use-sync-external-store": "^1.0.0"
5353
},
5454
"peerDependencies": {

packages/react-instantsearch-hooks/src/hooks/__tests__/useConnector.test.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,8 @@ describe('useConnector', () => {
384384
searchMetadata: {
385385
isSearchStalled: false,
386386
},
387+
status: 'idle',
388+
error: undefined,
387389
});
388390
});
389391

packages/react-instantsearch-hooks/src/hooks/__tests__/useInstantSearch.test.tsx

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { createSearchClient } from '../../../../../test/mock';
99
import {
1010
createInstantSearchTestWrapper,
1111
InstantSearchHooksTestWrapper,
12+
wait,
1213
} from '../../../../../test/utils';
1314
import { useInstantSearch } from '../useInstantSearch';
1415

@@ -286,4 +287,124 @@ describe('useInstantSearch', () => {
286287
expect(result.current.refresh).toBe(ref);
287288
});
288289
});
290+
291+
describe('status', () => {
292+
test('initial status: idle', () => {
293+
const App = () => (
294+
<InstantSearchHooksTestWrapper>
295+
<SearchBox />
296+
<Status />
297+
</InstantSearchHooksTestWrapper>
298+
);
299+
300+
const { getByTestId } = render(<App />);
301+
302+
expect(getByTestId('status')).toHaveTextContent('idle');
303+
});
304+
305+
test('turns to loading and idle when searching', async () => {
306+
const App = () => (
307+
<InstantSearchHooksTestWrapper
308+
searchClient={createDelayedSearchClient(20)}
309+
>
310+
<SearchBox placeholder="search here" />
311+
<Status />
312+
</InstantSearchHooksTestWrapper>
313+
);
314+
315+
const { getByTestId, getByPlaceholderText } = render(<App />);
316+
317+
expect(getByTestId('status')).toHaveTextContent('idle');
318+
319+
userEvent.type(getByPlaceholderText('search here'), 'hey search');
320+
321+
await waitFor(() => {
322+
expect(getByTestId('status')).toHaveTextContent('loading');
323+
});
324+
325+
await waitFor(() => {
326+
expect(getByTestId('status')).toHaveTextContent('idle');
327+
});
328+
});
329+
330+
test('turns to loading, stalled and idle when searching slowly', async () => {
331+
const App = () => (
332+
<InstantSearchHooksTestWrapper
333+
searchClient={createDelayedSearchClient(300)}
334+
stalledSearchDelay={200}
335+
>
336+
<SearchBox placeholder="search here" />
337+
<Status />
338+
</InstantSearchHooksTestWrapper>
339+
);
340+
341+
const { getByTestId, getByPlaceholderText } = render(<App />);
342+
343+
expect(getByTestId('status')).toHaveTextContent('idle');
344+
345+
userEvent.type(getByPlaceholderText('search here'), 'h');
346+
347+
await waitFor(() => {
348+
expect(getByTestId('status')).toHaveTextContent('loading');
349+
});
350+
351+
await waitFor(() => {
352+
expect(getByTestId('status')).toHaveTextContent('stalled');
353+
});
354+
355+
await waitFor(() => {
356+
expect(getByTestId('status')).toHaveTextContent('idle');
357+
});
358+
});
359+
360+
test('turns to loading and error when searching', async () => {
361+
const searchClient = createSearchClient({});
362+
searchClient.search.mockImplementation(() =>
363+
Promise.reject(new Error('API_ERROR'))
364+
);
365+
366+
const App = () => (
367+
<InstantSearchHooksTestWrapper searchClient={searchClient}>
368+
<SearchBox placeholder="search here" />
369+
{/* has catchError, as the real error can not be asserted upon */}
370+
<Status catchError />
371+
</InstantSearchHooksTestWrapper>
372+
);
373+
374+
const { getByTestId, getByPlaceholderText } = render(<App />);
375+
376+
expect(getByTestId('status')).toHaveTextContent('idle');
377+
expect(getByTestId('error')).toBeEmptyDOMElement();
378+
379+
userEvent.type(getByPlaceholderText('search here'), 'hey search');
380+
381+
await waitFor(() => {
382+
expect(getByTestId('status')).toHaveTextContent('loading');
383+
expect(getByTestId('error')).toBeEmptyDOMElement();
384+
});
385+
386+
await waitFor(() => {
387+
expect(getByTestId('status')).toHaveTextContent('error');
388+
expect(getByTestId('error')).toHaveTextContent('API_ERROR');
389+
});
390+
});
391+
392+
function Status(props) {
393+
const { status, error } = useInstantSearch(props);
394+
395+
return (
396+
<>
397+
<span data-testid="status">{status}</span>
398+
<span data-testid="error">{error?.message}</span>
399+
</>
400+
);
401+
}
402+
403+
function createDelayedSearchClient(timeout: number) {
404+
const searchFn = createSearchClient({}).search!;
405+
return createSearchClient({
406+
search: (requests) => wait(timeout).then(() => searchFn(requests)),
407+
});
408+
}
409+
});
289410
});

packages/react-instantsearch-hooks/src/hooks/useConnector.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,10 @@ export function useConnector<
115115
templatesConfig: search.templatesConfig,
116116
createURL: parentIndex.createURL,
117117
searchMetadata: {
118-
isSearchStalled: search._isSearchStalled,
118+
isSearchStalled: search.status === 'stalled',
119119
},
120+
status: search.status,
121+
error: search.error,
120122
});
121123

122124
return renderState;

0 commit comments

Comments
 (0)