mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 02:48:38 -04:00
useSuggestions started with channels: [] and reset to that on every keystroke, and the normalizer treats an empty list as "the server found none". So the global search dropdown showed a "Channels: No results" row on focus before anything was typed, and on every keystroke through the debounce and the request. Because that row counts as a result, the SearchBox's own "Searching…" state never appeared. The channel, domain, author and subject groups now start as null, meaning not fetched; an empty list only ever comes from the server. The count summary tolerates the null. Tests render the hook and check no Channels group exists before a search or while the request is pending, and that the "No results" row and real rows still appear after the response. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
105 lines
3.2 KiB
JavaScript
105 lines
3.2 KiB
JavaScript
import React from 'react';
|
|
import {act, render, screen} from '../test-utils';
|
|
import {useSearchSuggestions} from './Search';
|
|
import {TagsContext} from '../Tags';
|
|
import {tagsContextFixture} from '../test-fixtures';
|
|
import {
|
|
searchEstimateFiles, searchEstimateMap, searchEstimateOthers, searchEstimateZims, searchSuggestions,
|
|
} from '../api';
|
|
|
|
// The global search dropdown's groups are built from useSuggestions. A "Channels: No results" row
|
|
// may only appear once the suggestion request has come back empty, never before the user has
|
|
// typed, and never while the request is pending.
|
|
|
|
jest.mock('../api', () => ({
|
|
...jest.requireActual('../api'),
|
|
searchSuggestions: jest.fn(),
|
|
searchEstimateFiles: jest.fn(),
|
|
searchEstimateMap: jest.fn(),
|
|
searchEstimateOthers: jest.fn(),
|
|
searchEstimateZims: jest.fn(),
|
|
}));
|
|
|
|
const DEBOUNCE = 500;
|
|
const pending = () => new Promise(() => {
|
|
});
|
|
|
|
let hook;
|
|
|
|
function Probe() {
|
|
hook = useSearchSuggestions('', [], false);
|
|
return <pre data-testid='results'>{JSON.stringify(hook.suggestionsResults)}</pre>;
|
|
}
|
|
|
|
const results = () => JSON.parse(screen.getByTestId('results').textContent);
|
|
|
|
const renderProbe = () => render(<Probe/>, {
|
|
contexts: [[TagsContext, tagsContextFixture({fuzzyMatchTagsByName: () => []})]],
|
|
});
|
|
|
|
beforeEach(() => {
|
|
jest.useFakeTimers();
|
|
searchEstimateFiles.mockReturnValue(pending());
|
|
searchEstimateMap.mockReturnValue(pending());
|
|
searchEstimateOthers.mockReturnValue(pending());
|
|
searchEstimateZims.mockReturnValue(pending());
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.useRealTimers();
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
test('no Channels group before anything has been searched', () => {
|
|
searchSuggestions.mockReturnValue(pending());
|
|
renderProbe();
|
|
expect(results().channels).toBeUndefined();
|
|
});
|
|
|
|
test('no Channels group while the suggestion request is pending', () => {
|
|
searchSuggestions.mockReturnValue(pending());
|
|
renderProbe();
|
|
act(() => {
|
|
hook.setSearchStr('foo');
|
|
});
|
|
expect(results().channels).toBeUndefined();
|
|
|
|
act(() => {
|
|
jest.advanceTimersByTime(DEBOUNCE);
|
|
});
|
|
expect(searchSuggestions).toHaveBeenCalledWith('foo');
|
|
expect(results().channels).toBeUndefined();
|
|
expect(hook.loading).toBe(true);
|
|
});
|
|
|
|
test('a Channels "No results" row once the server said there are none', async () => {
|
|
let resolve;
|
|
searchSuggestions.mockReturnValue(new Promise(res => resolve = res));
|
|
renderProbe();
|
|
act(() => {
|
|
hook.setSearchStr('foo');
|
|
});
|
|
act(() => {
|
|
jest.advanceTimersByTime(DEBOUNCE);
|
|
});
|
|
await act(async () => {
|
|
resolve({channels: [], domains: [], authors: [], subjects: []});
|
|
});
|
|
expect(results().channels.results).toEqual([{title: 'No results'}]);
|
|
});
|
|
|
|
test('Channels rows once the server found some', async () => {
|
|
let resolve;
|
|
searchSuggestions.mockReturnValue(new Promise(res => resolve = res));
|
|
renderProbe();
|
|
act(() => {
|
|
hook.setSearchStr('foo');
|
|
});
|
|
act(() => {
|
|
jest.advanceTimersByTime(DEBOUNCE);
|
|
});
|
|
await act(async () => {
|
|
resolve({channels: [{id: 3, name: 'Food'}], domains: [], authors: [], subjects: []});
|
|
});
|
|
expect(results().channels.results.map(i => i.title)).toEqual(['Food']);
|
|
});
|