From c568e721f4d898c9abcd9a940341f27240ed43f6 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 26 May 2021 21:11:35 +0200 Subject: [PATCH] test(plugins/search): complete SearchBarNext coverage Signed-off-by: Camila Belo Signed-off-by: Eric Peterson --- .../SearchBarNext/SearchBarNext.test.tsx | 122 ++++++++++++++++-- .../SearchBarNext/SearchBarNext.tsx | 46 +++---- .../SearchFilterNext.test.tsx | 8 +- 3 files changed, 137 insertions(+), 39 deletions(-) diff --git a/plugins/search/src/components/SearchBarNext/SearchBarNext.test.tsx b/plugins/search/src/components/SearchBarNext/SearchBarNext.test.tsx index f29cc53b71..a5075c5593 100644 --- a/plugins/search/src/components/SearchBarNext/SearchBarNext.test.tsx +++ b/plugins/search/src/components/SearchBarNext/SearchBarNext.test.tsx @@ -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('', () => { - const _alphaPerformSearch = jest.fn(); - +describe('SearchBarNext', () => { const initialState = { term: '', pageCursor: '', @@ -36,24 +35,119 @@ describe('', () => { 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( , ); - expect( - getByRole('textbox', { name: 'search backstage' }), - ).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByRole('textbox', { name })).toBeInTheDocument(); + }); + }); + + it('Renders based on initial search', async () => { + render( + + + , + ); + + await waitFor(() => { + expect(screen.getByRole('textbox', { name })).toHaveValue(term); + }); + }); + + it('Updates term state when text is entered', async () => { + render( + + + , + ); + + 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( + + + , + ); + + 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( + + + , + ); + + 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 }), + ); }); }); diff --git a/plugins/search/src/components/SearchBarNext/SearchBarNext.tsx b/plugins/search/src/components/SearchBarNext/SearchBarNext.tsx index 014e3d6ee4..b223e6c2cd 100644 --- a/plugins/search/src/components/SearchBarNext/SearchBarNext.tsx +++ b/plugins/search/src/components/SearchBarNext/SearchBarNext.tsx @@ -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(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) => { + setValue(e.target.value); }; - const handleClearSearchBar = () => { - setTerm(''); - }; + const handleClear = () => setValue(''); return ( - - - - + + + + } /> - + diff --git a/plugins/search/src/components/SearchFilterNext/SearchFilterNext.test.tsx b/plugins/search/src/components/SearchFilterNext/SearchFilterNext.test.tsx index ed9c0ecd74..1a35bf54d4 100644 --- a/plugins/search/src/components/SearchFilterNext/SearchFilterNext.test.tsx +++ b/plugins/search/src/components/SearchFilterNext/SearchFilterNext.test.tsx @@ -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 }) =>
{props.name}
;