test(plugins/search): complete SearchBarNext coverage
Signed-off-by: Camila Belo <camilaibs@gmail.com> Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
committed by
Eric Peterson
parent
51e2b40cbb
commit
c568e721f4
@@ -15,7 +15,8 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { screen, render, waitFor, act } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { useApi } from '@backstage/core';
|
||||
|
||||
import { SearchContextProvider } from '../SearchContext';
|
||||
@@ -23,12 +24,10 @@ import { SearchBarNext } from './SearchBarNext';
|
||||
|
||||
jest.mock('@backstage/core', () => ({
|
||||
...jest.requireActual('@backstage/core'),
|
||||
useApi: jest.fn(),
|
||||
useApi: jest.fn().mockReturnValue({}),
|
||||
}));
|
||||
|
||||
describe('<SearchBarNext />', () => {
|
||||
const _alphaPerformSearch = jest.fn();
|
||||
|
||||
describe('SearchBarNext', () => {
|
||||
const initialState = {
|
||||
term: '',
|
||||
pageCursor: '',
|
||||
@@ -36,24 +35,119 @@ describe('<SearchBarNext />', () => {
|
||||
types: ['*'],
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
_alphaPerformSearch.mockResolvedValue([]);
|
||||
(useApi as jest.Mock).mockReturnValue({ _alphaPerformSearch });
|
||||
});
|
||||
const name = 'Search term';
|
||||
const term = 'term';
|
||||
|
||||
const _alphaPerformSearch = jest.fn().mockResolvedValue({});
|
||||
(useApi as jest.Mock).mockReturnValue({ _alphaPerformSearch });
|
||||
|
||||
afterAll(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('renders without exploding', async () => {
|
||||
const { getByRole } = await renderInTestApp(
|
||||
it('Renders without exploding', async () => {
|
||||
render(
|
||||
<SearchContextProvider initialState={initialState}>
|
||||
<SearchBarNext />
|
||||
</SearchContextProvider>,
|
||||
);
|
||||
|
||||
expect(
|
||||
getByRole('textbox', { name: 'search backstage' }),
|
||||
).toBeInTheDocument();
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('textbox', { name })).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('Renders based on initial search', async () => {
|
||||
render(
|
||||
<SearchContextProvider initialState={{ ...initialState, term }}>
|
||||
<SearchBarNext />
|
||||
</SearchContextProvider>,
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('textbox', { name })).toHaveValue(term);
|
||||
});
|
||||
});
|
||||
|
||||
it('Updates term state when text is entered', async () => {
|
||||
render(
|
||||
<SearchContextProvider initialState={initialState}>
|
||||
<SearchBarNext />
|
||||
</SearchContextProvider>,
|
||||
);
|
||||
|
||||
const textbox = screen.getByRole('textbox', { name });
|
||||
|
||||
const value = 'value';
|
||||
|
||||
userEvent.type(textbox, value);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(textbox).toHaveValue(value);
|
||||
});
|
||||
|
||||
expect(_alphaPerformSearch).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({ term: value }),
|
||||
);
|
||||
});
|
||||
|
||||
it('Clear button clears term state', async () => {
|
||||
render(
|
||||
<SearchContextProvider initialState={{ ...initialState, term }}>
|
||||
<SearchBarNext />
|
||||
</SearchContextProvider>,
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('textbox', { name })).toHaveValue(term);
|
||||
});
|
||||
|
||||
userEvent.click(screen.getByRole('button', { name: 'Clear term' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('textbox', { name })).toHaveValue('');
|
||||
});
|
||||
|
||||
expect(_alphaPerformSearch).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({ term: '' }),
|
||||
);
|
||||
});
|
||||
|
||||
it('Adheres to provided debounceTime', async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const debounceTime = 600;
|
||||
|
||||
render(
|
||||
<SearchContextProvider initialState={initialState}>
|
||||
<SearchBarNext debounceTime={debounceTime} />
|
||||
</SearchContextProvider>,
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('textbox', { name })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const textbox = screen.getByRole('textbox', { name });
|
||||
|
||||
const value = 'value';
|
||||
|
||||
userEvent.type(textbox, value);
|
||||
|
||||
expect(_alphaPerformSearch).not.toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({ term: value }),
|
||||
);
|
||||
|
||||
act(() => {
|
||||
jest.advanceTimersByTime(debounceTime);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(textbox).toHaveValue(value);
|
||||
});
|
||||
|
||||
expect(_alphaPerformSearch).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({ term: value }),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,17 +14,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import React, { ChangeEvent, useState } from 'react';
|
||||
import { useDebounce } from 'react-use';
|
||||
import { Paper, InputBase, IconButton, makeStyles } from '@material-ui/core';
|
||||
import {
|
||||
Theme,
|
||||
Paper,
|
||||
InputBase,
|
||||
InputAdornment,
|
||||
IconButton,
|
||||
makeStyles,
|
||||
} from '@material-ui/core';
|
||||
import SearchIcon from '@material-ui/icons/Search';
|
||||
import ClearButton from '@material-ui/icons/Clear';
|
||||
|
||||
import { useSearch } from '../SearchContext';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
root: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
padding: theme.spacing(0, 0, 0, 1.5),
|
||||
},
|
||||
input: {
|
||||
flex: 1,
|
||||
@@ -40,36 +49,29 @@ export const SearchBarNext = ({ debounceTime = 0 }: Props) => {
|
||||
const { term, setTerm } = useSearch();
|
||||
const [value, setValue] = useState<string>(term);
|
||||
|
||||
useDebounce(
|
||||
() => {
|
||||
setTerm(value);
|
||||
},
|
||||
debounceTime,
|
||||
[value],
|
||||
);
|
||||
useDebounce(() => setTerm(value), debounceTime, [value]);
|
||||
|
||||
const handleSearch = (event: React.ChangeEvent | React.FormEvent) => {
|
||||
event.preventDefault();
|
||||
setValue((event.target as HTMLInputElement).value as string);
|
||||
const handleSearch = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setValue(e.target.value);
|
||||
};
|
||||
|
||||
const handleClearSearchBar = () => {
|
||||
setTerm('');
|
||||
};
|
||||
const handleClear = () => setValue('');
|
||||
|
||||
return (
|
||||
<Paper component="form" onSubmit={handleSearch} className={classes.root}>
|
||||
<IconButton disabled type="submit" aria-label="search">
|
||||
<SearchIcon />
|
||||
</IconButton>
|
||||
<Paper component="form" className={classes.root}>
|
||||
<InputBase
|
||||
className={classes.input}
|
||||
placeholder="Search in Backstage"
|
||||
value={value}
|
||||
onChange={handleSearch}
|
||||
inputProps={{ 'aria-label': 'search backstage' }}
|
||||
inputProps={{ 'aria-label': 'Search term' }}
|
||||
startAdornment={
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon />
|
||||
</InputAdornment>
|
||||
}
|
||||
/>
|
||||
<IconButton aria-label="search" onClick={handleClearSearchBar}>
|
||||
<IconButton aria-label="Clear term" onClick={handleClear}>
|
||||
<ClearButton />
|
||||
</IconButton>
|
||||
</Paper>
|
||||
|
||||
@@ -24,9 +24,7 @@ import { SearchContextProvider } from '../SearchContext';
|
||||
|
||||
jest.mock('@backstage/core', () => ({
|
||||
...jest.requireActual('@backstage/core'),
|
||||
useApi: jest.fn().mockReturnValue({
|
||||
_alphaPerformSearch: jest.fn().mockResolvedValue({}),
|
||||
}),
|
||||
useApi: jest.fn().mockReturnValue({}),
|
||||
}));
|
||||
|
||||
describe('SearchFilterNext', () => {
|
||||
@@ -44,6 +42,10 @@ describe('SearchFilterNext', () => {
|
||||
const _alphaPerformSearch = jest.fn().mockResolvedValue({});
|
||||
(useApi as jest.Mock).mockReturnValue({ _alphaPerformSearch });
|
||||
|
||||
afterAll(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('Check that element was rendered and received props', async () => {
|
||||
const CustomFilter = (props: { name: string }) => <h6>{props.name}</h6>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user