skip the very first search on opening the app
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-search-react': patch
|
||||
---
|
||||
|
||||
Skip the very first empty search when going to the landing page
|
||||
@@ -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();
|
||||
|
||||
@@ -264,8 +264,8 @@ export const searchTranslationRef: TranslationRef<
|
||||
readonly 'searchType.tabs.allTitle': 'All';
|
||||
readonly 'searchType.allResults': 'All Results';
|
||||
readonly 'searchType.accordion.collapse': 'Collapse';
|
||||
readonly 'searchType.accordion.allTitle': 'All';
|
||||
readonly 'searchType.accordion.numberOfResults': '{{number}} results';
|
||||
readonly 'searchType.accordion.allTitle': 'All';
|
||||
readonly 'sidebarSearchModal.title': 'Search';
|
||||
}
|
||||
>;
|
||||
|
||||
@@ -46,12 +46,7 @@ describe('<HomePageSearchBar/>', () => {
|
||||
},
|
||||
);
|
||||
|
||||
expect(searchApiMock.query).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ term: '' }),
|
||||
{
|
||||
signal: expect.any(AbortSignal),
|
||||
},
|
||||
);
|
||||
expect(searchApiMock.query).not.toHaveBeenCalled();
|
||||
|
||||
await userEvent.type(screen.getByLabelText('Search'), 'term{enter}');
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { screen } from '@testing-library/react';
|
||||
import { screen, waitFor } from '@testing-library/react';
|
||||
import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { configApiRef } from '@backstage/core-plugin-api';
|
||||
@@ -63,7 +63,6 @@ describe('SearchModal', () => {
|
||||
);
|
||||
|
||||
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
||||
expect(searchApiMock.query).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('Should use parent search context if defined', async () => {
|
||||
@@ -106,15 +105,21 @@ describe('SearchModal', () => {
|
||||
);
|
||||
|
||||
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
||||
expect(searchApiMock.query).toHaveBeenCalledWith(
|
||||
{
|
||||
term: '',
|
||||
filters: {},
|
||||
types: [],
|
||||
pageCursor: undefined,
|
||||
},
|
||||
{ signal: expect.any(AbortSignal) },
|
||||
);
|
||||
|
||||
const input = screen.getByLabelText<HTMLInputElement>('Search');
|
||||
await userEvent.type(input, 'text');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(searchApiMock.query).toHaveBeenCalledWith(
|
||||
{
|
||||
term: 'text',
|
||||
filters: {},
|
||||
types: [],
|
||||
pageCursor: undefined,
|
||||
},
|
||||
{ signal: expect.any(AbortSignal) },
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('Should render a custom Modal correctly', async () => {
|
||||
@@ -146,7 +151,6 @@ describe('SearchModal', () => {
|
||||
},
|
||||
);
|
||||
|
||||
expect(searchApiMock.query).toHaveBeenCalledTimes(1);
|
||||
await userEvent.keyboard('{Escape}');
|
||||
expect(toggleModal).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user