Skip to content

Commit 40ab49d

Browse files
committed
Handle empty Predict search states
1 parent e1f3647 commit 40ab49d

3 files changed

Lines changed: 64 additions & 25 deletions

File tree

app/components/UI/Predict/views/PredictFeed/PredictFeed.test.tsx

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -698,11 +698,43 @@ describe('PredictFeed', () => {
698698
expect(getByText(/No results found/i)).toBeOnTheScreen();
699699
});
700700

701+
it('does not display no results message before the user enters a query', () => {
702+
mockUsePredictSearchMarketData.mockReturnValue({
703+
marketData: [],
704+
isFetching: false,
705+
error: null,
706+
refetch: jest.fn(),
707+
});
708+
709+
const { getByTestId, queryByText } = render(<PredictFeed />);
710+
711+
fireEvent.press(getByTestId(PredictSearchSelectorsIDs.SEARCH_BUTTON));
712+
713+
expect(queryByText(/No results found/i)).toBeNull();
714+
});
715+
716+
it('does not display search error state before the user enters a query', () => {
717+
mockUsePredictSearchMarketData.mockReturnValue({
718+
marketData: [],
719+
isFetching: false,
720+
error: 'Search error',
721+
refetch: jest.fn(),
722+
});
723+
724+
const { getByTestId, queryByTestId } = render(<PredictFeed />);
725+
726+
fireEvent.press(getByTestId(PredictSearchSelectorsIDs.SEARCH_BUTTON));
727+
728+
expect(
729+
queryByTestId(PredictFeedMockSelectorsIDs.OFFLINE_MOCK),
730+
).toBeNull();
731+
});
732+
701733
it('displays error state in search when fetch fails', () => {
702734
mockUsePredictSearchMarketData.mockReturnValue({
703735
marketData: [],
704736
isFetching: false,
705-
error: new Error('Search error'),
737+
error: 'Search error',
706738
refetch: jest.fn(),
707739
});
708740

app/components/UI/Predict/views/PredictFeed/PredictFeed.tsx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,7 @@ const PredictSearchOverlay: React.FC<PredictSearchOverlayProps> = ({
533533
);
534534

535535
const isSearchLoading = isDebouncing || isFetching;
536+
const hasSearchQuery = debouncedSearchQuery.trim().length > 0;
536537

537538
const renderItem = useCallback(
538539
(info: { item: PredictMarketType; index: number }) => (
@@ -593,17 +594,21 @@ const PredictSearchOverlay: React.FC<PredictSearchOverlayProps> = ({
593594
testID={getPredictFeedSelector.searchSkeleton(3)}
594595
/>
595596
</Box>
596-
) : error ? (
597+
) : error && hasSearchQuery ? (
597598
<PredictOffline onRetry={refetch} />
598599
) : !marketData || marketData.length === 0 ? (
599-
<Box twClassName="flex-1 justify-center items-center p-8">
600-
<Text
601-
variant={TextVariant.BodyMd}
602-
color={TextColor.PrimaryAlternative}
603-
>
604-
{strings('predict.search_no_markets_found', { q: searchQuery })}
605-
</Text>
606-
</Box>
600+
hasSearchQuery ? (
601+
<Box twClassName="flex-1 justify-center items-center p-8">
602+
<Text
603+
variant={TextVariant.BodyMd}
604+
color={TextColor.PrimaryAlternative}
605+
>
606+
{strings('predict.search_no_markets_found', {
607+
q: searchQuery,
608+
})}
609+
</Text>
610+
</Box>
611+
) : null
607612
) : (
608613
<FlashList<PredictMarketType>
609614
data={marketData}

app/components/UI/Predict/views/PredictFeed/PredictFeed.view.test.tsx

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -539,18 +539,19 @@ describe('PredictFeed', () => {
539539
});
540540

541541
describe('search error recovery', () => {
542-
it('shows the offline error state in the search overlay when all market fetch retries fail', async () => {
543-
const getMarketsSpy = jest.spyOn(
542+
it('shows the offline error state in the search overlay when all search retries fail', async () => {
543+
const searchMarketsSpy = jest.spyOn(
544544
Engine.context.PredictController,
545-
'getMarkets',
545+
'searchMarkets',
546546
);
547-
getMarketsSpy.mockRejectedValue(new Error('Network error'));
547+
searchMarketsSpy.mockRejectedValue(new Error('Network error'));
548548

549549
const { getByTestId, findByPlaceholderText, findByTestId } =
550550
renderPredictFeedView();
551551

552552
fireEvent.press(getByTestId(PredictSearchSelectorsIDs.SEARCH_BUTTON));
553-
await findByPlaceholderText(SEARCH_PLACEHOLDER);
553+
const searchInput = await findByPlaceholderText(SEARCH_PLACEHOLDER);
554+
fireEvent.changeText(searchInput, 'bitcoin');
554555

555556
// The hook retries up to 3 times with exponential backoff (~3-5 s total).
556557
// findByTestId waits until the error state appears after all retries exhaust.
@@ -562,42 +563,43 @@ describe('PredictFeed', () => {
562563
),
563564
).toBeOnTheScreen();
564565

565-
getMarketsSpy.mockRestore();
566+
searchMarketsSpy.mockRestore();
566567
});
567568

568-
it('calls getMarkets again when the user presses Retry after an error', async () => {
569-
const getMarketsSpy = jest.spyOn(
569+
it('calls searchMarkets again when the user presses Retry after an error', async () => {
570+
const searchMarketsSpy = jest.spyOn(
570571
Engine.context.PredictController,
571-
'getMarkets',
572+
'searchMarkets',
572573
);
573-
getMarketsSpy.mockRejectedValue(new Error('Network error'));
574+
searchMarketsSpy.mockRejectedValue(new Error('Network error'));
574575

575576
const { getByTestId, findByPlaceholderText, findByTestId, findByText } =
576577
renderPredictFeedView();
577578

578579
fireEvent.press(getByTestId(PredictSearchSelectorsIDs.SEARCH_BUTTON));
579-
await findByPlaceholderText(SEARCH_PLACEHOLDER);
580+
const searchInput = await findByPlaceholderText(SEARCH_PLACEHOLDER);
581+
fireEvent.changeText(searchInput, 'bitcoin');
580582

581583
await findByTestId(
582584
PREDICT_OFFLINE_TEST_IDS.ERROR_STATE,
583585
{},
584586
{ timeout: 10000 },
585587
);
586588

587-
const callCountBeforeRetry = getMarketsSpy.mock.calls.length;
589+
const callCountBeforeRetry = searchMarketsSpy.mock.calls.length;
588590

589591
// Make subsequent calls succeed so the retry completes quickly.
590-
getMarketsSpy.mockResolvedValue({ markets: [], nextCursor: null });
592+
searchMarketsSpy.mockResolvedValue([]);
591593

592594
fireEvent.press(await findByText('Retry'));
593595

594596
await waitFor(() => {
595-
expect(getMarketsSpy.mock.calls.length).toBeGreaterThan(
597+
expect(searchMarketsSpy.mock.calls.length).toBeGreaterThan(
596598
callCountBeforeRetry,
597599
);
598600
});
599601

600-
getMarketsSpy.mockRestore();
602+
searchMarketsSpy.mockRestore();
601603
});
602604
});
603605
});

0 commit comments

Comments
 (0)