Merge pull request #32080 from backstage/freben/search-first

This commit is contained in:
Fredrik Adelöw
2025-12-15 19:44:09 +01:00
committed by GitHub
7 changed files with 66 additions and 40 deletions
@@ -69,7 +69,7 @@ describe('SearchPagination', () => {
expect(screen.getByText('Results per page:')).toBeInTheDocument();
expect(screen.getByText('25')).toBeInTheDocument();
expect(screen.getByText('1-25')).toBeInTheDocument();
expect(screen.getByLabelText('Next page')).toBeEnabled();
expect(screen.getByLabelText('Next page')).toBeDisabled();
expect(screen.getByLabelText('Previous page')).toBeDisabled();
});
@@ -176,6 +176,12 @@ describe('SearchPagination', () => {
});
it('Set page limit in the context', async () => {
const initialState = {
term: 'a',
types: [],
filters: {},
};
await renderInTestApp(
<TestApiProvider
apis={[
@@ -183,7 +189,7 @@ describe('SearchPagination', () => {
[configApiRef, configApiMock],
]}
>
<SearchContextProvider>
<SearchContextProvider initialState={initialState}>
<SearchPagination />
</SearchContextProvider>
</TestApiProvider>,
@@ -205,7 +211,7 @@ describe('SearchPagination', () => {
it('Set page cursor in the context', async () => {
const initialState = {
term: '',
term: 'a',
types: [],
filters: {},
pageCursor: 'MQ==', // page: 1
@@ -253,7 +259,7 @@ describe('SearchPagination', () => {
it('Resets page cursor when page limit changes', async () => {
const initialState = {
term: '',
term: 'a',
types: [],
filters: {},
pageCursor: 'Mg==', // page: 2
@@ -280,9 +286,7 @@ describe('SearchPagination', () => {
pageCursor: undefined,
pageLimit: 10,
}),
{
signal: expect.any(AbortSignal),
},
{ signal: expect.any(AbortSignal) },
);
});
});
@@ -66,7 +66,7 @@ describe('SearchResultGroup', () => {
});
it('Renders without exploding', async () => {
query.mockResolvedValueOnce({
query.mockResolvedValue({
results,
});
@@ -96,7 +96,7 @@ describe('SearchResultGroup', () => {
});
it('Renders search results from context', async () => {
query.mockResolvedValueOnce({
query.mockResolvedValue({
results,
});
@@ -107,7 +107,9 @@ describe('SearchResultGroup', () => {
[analyticsApiRef, analyticsApiMock],
]}
>
<SearchContextProvider>
<SearchContextProvider
initialState={{ term: '', filters: {}, types: ['techdocs'] }}
>
<SearchResultGroup
icon={<DocsIcon titleAccess="Docs icon" />}
title="Documentation"
@@ -128,7 +130,7 @@ describe('SearchResultGroup', () => {
});
it('Renders search results using extensions', async () => {
query.mockResolvedValueOnce({
query.mockResolvedValue({
results,
});
@@ -166,7 +168,7 @@ describe('SearchResultGroup', () => {
});
it('Defines a default link', async () => {
query.mockResolvedValueOnce({
query.mockResolvedValue({
results,
});
@@ -190,7 +192,7 @@ describe('SearchResultGroup', () => {
});
it('Defines a default render result item', async () => {
query.mockResolvedValueOnce({
query.mockResolvedValue({
results,
});
@@ -221,6 +223,10 @@ describe('SearchResultGroup', () => {
});
it('Could be customized with no results text', async () => {
query.mockResolvedValue({
results: [],
});
await renderInTestApp(
<TestApiProvider
apis={[
@@ -242,7 +248,7 @@ describe('SearchResultGroup', () => {
});
it('Could be customized with filters', async () => {
query.mockResolvedValueOnce({
query.mockResolvedValue({
results,
});
@@ -272,7 +278,7 @@ describe('SearchResultGroup', () => {
});
it('Could have a text search filter field', async () => {
query.mockResolvedValueOnce({
query.mockResolvedValue({
results,
});
@@ -323,7 +329,7 @@ describe('SearchResultGroup', () => {
});
it('Could have a select search filter field', async () => {
query.mockResolvedValueOnce({
query.mockResolvedValue({
results,
});
@@ -376,7 +382,7 @@ describe('SearchResultGroup', () => {
});
it('Shows a progress bar when loading results', async () => {
query.mockReturnValueOnce(new Promise(() => {}));
query.mockReturnValue(new Promise(() => {}));
await renderInTestApp(
<TestApiProvider
apis={[
@@ -398,7 +404,7 @@ describe('SearchResultGroup', () => {
});
it('Does not render result group if no results returned and disableRenderingWithNoResults prop is provided', async () => {
query.mockResolvedValueOnce({ results: [] });
query.mockResolvedValue({ results: [] });
await renderInTestApp(
<TestApiProvider
apis={[
@@ -421,7 +427,7 @@ describe('SearchResultGroup', () => {
});
it('Should render custom component when no results returned', async () => {
query.mockResolvedValueOnce({ results: [] });
query.mockResolvedValue({ results: [] });
await renderInTestApp(
<TestApiProvider
apis={[
@@ -444,7 +450,7 @@ describe('SearchResultGroup', () => {
});
it('Shows an error panel when results rendering fails', async () => {
query.mockRejectedValueOnce(new Error());
query.mockRejectedValue(new Error());
await renderInTestApp(
<TestApiProvider
apis={[
@@ -130,12 +130,24 @@ const useSearchContextValue = (
const [pageCursor, setPageCursor] = useState<string | undefined>(
initialValue.pageCursor,
);
const isFirstEmptyMount = useRef(true);
const prevTerm = usePrevious(term);
const prevFilters = usePrevious(filters);
const abortControllerRef = useRef<AbortController | null>(null);
const result = useAsync(async () => {
const result = useAsync(async (): Promise<SearchResultSet> => {
if (isFirstEmptyMount.current) {
if (!term && !types.length && !Object.keys(filters).length) {
return {
results: [],
numberOfResults: 0,
};
}
isFirstEmptyMount.current = false;
}
// Here we cancel the previous request before making a new one
if (abortControllerRef.current) {
abortControllerRef.current.abort();