mirror of
https://github.com/SomboChea/ui
synced 2026-01-19 01:25:51 +07:00
Search Component - Replaced class by func. comp (#339)
This commit is contained in:
committed by
GitHub
parent
09b831a40d
commit
6ba721446b
@@ -1,272 +1,147 @@
|
||||
import React from 'react';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
|
||||
import { mount, shallow } from '../../utils/test-enzyme';
|
||||
import { render, fireEvent, waitForElement } from '../../utils/test-react-testing-library';
|
||||
import api from '../../utils/api';
|
||||
|
||||
import Search from './Search';
|
||||
|
||||
const SEARCH_FILE_PATH = './Search';
|
||||
const API_FILE_PATH = '../../utils/calls';
|
||||
const URL_FILE_PATH = '../../utils/url';
|
||||
/* eslint-disable verdaccio/jsx-spread */
|
||||
const ComponentToBeRendered: React.FC = () => (
|
||||
<Router>
|
||||
<Search />
|
||||
</Router>
|
||||
);
|
||||
|
||||
// Global mocks
|
||||
const event = {
|
||||
stopPropagation: jest.fn(),
|
||||
};
|
||||
window.location.assign = jest.fn();
|
||||
|
||||
describe('<Search /> component test', () => {
|
||||
let routerWrapper;
|
||||
let wrapper;
|
||||
describe('<Search /> component', () => {
|
||||
beforeEach(() => {
|
||||
routerWrapper = mount(
|
||||
<BrowserRouter>
|
||||
<Search />
|
||||
</BrowserRouter>
|
||||
jest.resetModules();
|
||||
jest.resetAllMocks();
|
||||
jest.spyOn(api, 'request').mockImplementation(() =>
|
||||
Promise.resolve([
|
||||
{
|
||||
name: '@verdaccio/types',
|
||||
version: '8.4.2',
|
||||
},
|
||||
{
|
||||
name: 'verdaccio',
|
||||
version: '4.3.5',
|
||||
},
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
test('should load the component in default state', () => {
|
||||
expect(routerWrapper.html()).toMatchSnapshot();
|
||||
const { container } = render(<ComponentToBeRendered />);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('handleSearch: when user type package name in search component, show suggestions', async () => {
|
||||
const { getByPlaceholderText, getAllByText } = render(<ComponentToBeRendered />);
|
||||
|
||||
const autoCompleteInput = getByPlaceholderText('Search Packages');
|
||||
|
||||
fireEvent.focus(autoCompleteInput);
|
||||
fireEvent.change(autoCompleteInput, { target: { value: 'verdaccio' } });
|
||||
|
||||
expect(autoCompleteInput).toHaveAttribute('value', 'verdaccio');
|
||||
|
||||
const suggestionsElements = await waitForElement(() => getAllByText('verdaccio', { exact: true }));
|
||||
|
||||
expect(suggestionsElements).toHaveLength(2);
|
||||
expect(api.request).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('onBlur: should cancel all search requests', async () => {
|
||||
const Search = require(SEARCH_FILE_PATH).Search;
|
||||
const { getByPlaceholderText, getByRole, getAllByText } = render(<ComponentToBeRendered />);
|
||||
|
||||
const routerWrapper = shallow(
|
||||
<BrowserRouter>
|
||||
<Search />
|
||||
</BrowserRouter>
|
||||
);
|
||||
const autoCompleteInput = getByPlaceholderText('Search Packages');
|
||||
|
||||
wrapper = routerWrapper.find(Search).dive();
|
||||
const { handleOnBlur, requestList, setState } = wrapper.instance();
|
||||
const spyCancelAllSearchRequests = jest.spyOn(wrapper.instance(), 'cancelAllSearchRequests');
|
||||
setState({ search: 'verdaccio' });
|
||||
fireEvent.focus(autoCompleteInput);
|
||||
fireEvent.change(autoCompleteInput, { target: { value: 'verdaccio' } });
|
||||
expect(autoCompleteInput).toHaveAttribute('value', 'verdaccio');
|
||||
|
||||
const request = {
|
||||
abort: jest.fn(),
|
||||
};
|
||||
// adds a request for AbortController
|
||||
wrapper.instance().requestList = [request];
|
||||
const suggestionsElements = await waitForElement(() => getAllByText('verdaccio', { exact: true }));
|
||||
expect(suggestionsElements).toHaveLength(2);
|
||||
expect(api.request).toHaveBeenCalledTimes(1);
|
||||
|
||||
handleOnBlur(event);
|
||||
|
||||
expect(request.abort).toHaveBeenCalled();
|
||||
expect(event.stopPropagation).toHaveBeenCalled();
|
||||
expect(wrapper.state('error')).toBeFalsy();
|
||||
expect(wrapper.state('loaded')).toBeFalsy();
|
||||
expect(wrapper.state('loading')).toBeFalsy();
|
||||
expect(spyCancelAllSearchRequests).toHaveBeenCalled();
|
||||
expect(requestList).toEqual([]);
|
||||
fireEvent.blur(autoCompleteInput);
|
||||
const listBoxElement = await waitForElement(() => getByRole('listbox'));
|
||||
expect(listBoxElement).toBeEmpty();
|
||||
});
|
||||
|
||||
test('handleSearch: when user type package name in search component and set loading to true', () => {
|
||||
const Search = require(SEARCH_FILE_PATH).Search;
|
||||
test('handleSearch: cancel all search requests when there is no value in search component with type method', async () => {
|
||||
const { getByPlaceholderText, getByRole } = render(<ComponentToBeRendered />);
|
||||
|
||||
const routerWrapper = shallow(
|
||||
<BrowserRouter>
|
||||
<Search />
|
||||
</BrowserRouter>
|
||||
);
|
||||
const autoCompleteInput = getByPlaceholderText('Search Packages');
|
||||
|
||||
wrapper = routerWrapper.find(Search).dive();
|
||||
|
||||
const { handleSearch } = wrapper.instance();
|
||||
const newValue = 'verdaccio';
|
||||
|
||||
handleSearch(event, { newValue, method: 'type' });
|
||||
|
||||
expect(event.stopPropagation).toHaveBeenCalled();
|
||||
expect(wrapper.state('error')).toBeFalsy();
|
||||
expect(wrapper.state('loaded')).toBeFalsy();
|
||||
expect(wrapper.state('loading')).toBeTruthy();
|
||||
expect(wrapper.state('search')).toEqual(newValue);
|
||||
fireEvent.focus(autoCompleteInput);
|
||||
fireEvent.change(autoCompleteInput, { target: { value: ' ', method: 'type' } });
|
||||
expect(autoCompleteInput).toHaveAttribute('value', '');
|
||||
const listBoxElement = await waitForElement(() => getByRole('listbox'));
|
||||
expect(listBoxElement).toBeEmpty();
|
||||
expect(api.request).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test('handleSearch: cancel all search requests when there is no value in search component with type method', () => {
|
||||
const Search = require(SEARCH_FILE_PATH).Search;
|
||||
test('handleSearch: when method is not type method', async () => {
|
||||
const { getByPlaceholderText, getByRole } = render(<ComponentToBeRendered />);
|
||||
|
||||
const routerWrapper = shallow(
|
||||
<BrowserRouter>
|
||||
<Search />
|
||||
</BrowserRouter>
|
||||
);
|
||||
const autoCompleteInput = getByPlaceholderText('Search Packages');
|
||||
|
||||
wrapper = routerWrapper.find(Search).dive();
|
||||
|
||||
const { handleSearch, requestList } = wrapper.instance();
|
||||
const spy = jest.spyOn(wrapper.instance(), 'cancelAllSearchRequests');
|
||||
const newValue = '';
|
||||
|
||||
handleSearch(event, { newValue, method: 'type' });
|
||||
|
||||
expect(event.stopPropagation).toHaveBeenCalled();
|
||||
expect(wrapper.state('error')).toBeFalsy();
|
||||
expect(wrapper.state('loaded')).toBeFalsy();
|
||||
expect(wrapper.state('loading')).toBeTruthy();
|
||||
expect(wrapper.state('search')).toEqual(newValue);
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(requestList).toEqual([]);
|
||||
fireEvent.focus(autoCompleteInput);
|
||||
fireEvent.change(autoCompleteInput, { target: { value: ' ', method: 'click' } });
|
||||
expect(autoCompleteInput).toHaveAttribute('value', '');
|
||||
const listBoxElement = await waitForElement(() => getByRole('listbox'));
|
||||
expect(listBoxElement).toBeEmpty();
|
||||
expect(api.request).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test('handleSearch: when method is not type method', () => {
|
||||
const Search = require(SEARCH_FILE_PATH).Search;
|
||||
test('handleSearch: loading is been displayed', async () => {
|
||||
const { getByPlaceholderText, getByRole, getByText } = render(<ComponentToBeRendered />);
|
||||
const autoCompleteInput = getByPlaceholderText('Search Packages');
|
||||
|
||||
const routerWrapper = shallow(
|
||||
<BrowserRouter>
|
||||
<Search />
|
||||
</BrowserRouter>
|
||||
);
|
||||
fireEvent.focus(autoCompleteInput);
|
||||
fireEvent.change(autoCompleteInput, { target: { value: 'verdaccio' } });
|
||||
expect(autoCompleteInput).toHaveAttribute('value', 'verdaccio');
|
||||
|
||||
wrapper = routerWrapper.find(Search).dive();
|
||||
|
||||
const { handleSearch } = wrapper.instance();
|
||||
const newValue = '';
|
||||
|
||||
handleSearch(event, { newValue, method: 'click' });
|
||||
|
||||
expect(event.stopPropagation).toHaveBeenCalled();
|
||||
expect(wrapper.state('error')).toBeFalsy();
|
||||
expect(wrapper.state('loaded')).toBeFalsy();
|
||||
expect(wrapper.state('loading')).toBeFalsy();
|
||||
expect(wrapper.state('search')).toEqual(newValue);
|
||||
const loadingElement = await waitForElement(() => getByText('Loading...'));
|
||||
expect(loadingElement).toBeTruthy();
|
||||
});
|
||||
|
||||
test('handlePackagesClearRequested: should clear suggestions', () => {
|
||||
const Search = require(SEARCH_FILE_PATH).Search;
|
||||
test('handlePackagesClearRequested: should clear suggestions', async () => {
|
||||
const { getByPlaceholderText, getAllByText, getByRole } = render(<ComponentToBeRendered />);
|
||||
const autoCompleteInput = getByPlaceholderText('Search Packages');
|
||||
|
||||
const routerWrapper = shallow(
|
||||
<BrowserRouter>
|
||||
<Search />
|
||||
</BrowserRouter>
|
||||
);
|
||||
fireEvent.focus(autoCompleteInput);
|
||||
fireEvent.change(autoCompleteInput, { target: { value: 'verdaccio' } });
|
||||
expect(autoCompleteInput).toHaveAttribute('value', 'verdaccio');
|
||||
|
||||
wrapper = routerWrapper.find(Search).dive();
|
||||
const suggestionsElements = await waitForElement(() => getAllByText('verdaccio', { exact: true }));
|
||||
expect(suggestionsElements).toHaveLength(2);
|
||||
|
||||
const { handlePackagesClearRequested } = wrapper.instance();
|
||||
fireEvent.change(autoCompleteInput, { target: { value: ' ' } });
|
||||
const listBoxElement = await waitForElement(() => getByRole('listbox'));
|
||||
expect(listBoxElement).toBeEmpty();
|
||||
|
||||
handlePackagesClearRequested();
|
||||
|
||||
expect(wrapper.state('suggestions')).toEqual([]);
|
||||
expect(api.request).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
describe('<Search /> component: mocks specific tests ', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
jest.doMock('lodash/debounce', () => {
|
||||
return function debounceMock(fn) {
|
||||
return fn;
|
||||
};
|
||||
});
|
||||
});
|
||||
test('handleClickSearch: should change the window location on click or return key', async () => {
|
||||
const { getByPlaceholderText, getAllByText, getByRole } = render(<ComponentToBeRendered />);
|
||||
const autoCompleteInput = getByPlaceholderText('Search Packages');
|
||||
|
||||
test('handleFetchPackages: should load the packages from API', async () => {
|
||||
const apiResponse = [{ name: 'verdaccio' }, { name: 'verdaccio-htpasswd' }];
|
||||
const suggestions = [{ name: 'verdaccio' }, { name: 'verdaccio-htpasswd' }];
|
||||
fireEvent.focus(autoCompleteInput);
|
||||
fireEvent.change(autoCompleteInput, { target: { value: 'verdaccio' } });
|
||||
expect(autoCompleteInput).toHaveAttribute('value', 'verdaccio');
|
||||
|
||||
jest.doMock(API_FILE_PATH, () => ({
|
||||
callSearch(url: string) {
|
||||
return Promise.resolve(apiResponse);
|
||||
},
|
||||
}));
|
||||
const suggestionsElements = await waitForElement(() => getAllByText('verdaccio', { exact: true }));
|
||||
expect(suggestionsElements).toHaveLength(2);
|
||||
|
||||
const Search = require(SEARCH_FILE_PATH).Search;
|
||||
|
||||
const routerWrapper = shallow(
|
||||
<BrowserRouter>
|
||||
<Search />
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
wrapper = routerWrapper.find(Search).dive();
|
||||
wrapper.setState({ search: 'verdaccio' });
|
||||
const { handleFetchPackages } = wrapper.instance();
|
||||
|
||||
await handleFetchPackages({ value: 'verdaccio' });
|
||||
|
||||
expect(wrapper.state('suggestions')).toEqual(suggestions);
|
||||
expect(wrapper.state('error')).toBeFalsy();
|
||||
expect(wrapper.state('loaded')).toBeTruthy();
|
||||
expect(wrapper.state('loading')).toBeFalsy();
|
||||
});
|
||||
|
||||
test('handleFetchPackages: when browser cancel a request', async () => {
|
||||
const apiResponse = { name: 'AbortError' };
|
||||
|
||||
jest.doMock(API_FILE_PATH, () => ({ callSearch: jest.fn(() => Promise.reject(apiResponse)) }));
|
||||
|
||||
const Search = require(SEARCH_FILE_PATH).Search;
|
||||
|
||||
const routerWrapper = shallow(
|
||||
<BrowserRouter>
|
||||
<Search />
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
wrapper = routerWrapper.find(Search).dive();
|
||||
|
||||
const { handleFetchPackages, setState } = wrapper.instance();
|
||||
setState({ search: 'verdaccio' });
|
||||
await handleFetchPackages({ value: 'verdaccio' });
|
||||
|
||||
expect(wrapper.state('error')).toBeFalsy();
|
||||
expect(wrapper.state('loaded')).toBeFalsy();
|
||||
expect(wrapper.state('loading')).toBeFalsy();
|
||||
});
|
||||
|
||||
test('handleFetchPackages: when API server failed request', async () => {
|
||||
const apiResponse = { name: 'BAD_REQUEST' };
|
||||
|
||||
jest.doMock(API_FILE_PATH, () => ({
|
||||
callSearch(url) {
|
||||
return Promise.reject(apiResponse);
|
||||
},
|
||||
}));
|
||||
|
||||
const Search = require(SEARCH_FILE_PATH).Search;
|
||||
const routerWrapper = shallow(
|
||||
<BrowserRouter>
|
||||
<Search />
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
wrapper = routerWrapper.find(Search).dive();
|
||||
wrapper.setState({ search: 'verdaccio' });
|
||||
const { handleFetchPackages } = wrapper.instance();
|
||||
|
||||
await handleFetchPackages({ value: 'verdaccio' });
|
||||
|
||||
expect(wrapper.state('error')).toBeTruthy();
|
||||
expect(wrapper.state('loaded')).toBeFalsy();
|
||||
expect(wrapper.state('loading')).toBeFalsy();
|
||||
});
|
||||
|
||||
test('handleClickSearch: should change the window location on click or return key', () => {
|
||||
const getDetailPageURL = jest.fn(() => 'detail/page/url');
|
||||
jest.doMock(URL_FILE_PATH, () => ({ getDetailPageURL }));
|
||||
|
||||
const suggestionValue = [];
|
||||
const Search = require(SEARCH_FILE_PATH).Search;
|
||||
const pushHandler = jest.fn();
|
||||
const routerWrapper = shallow(
|
||||
<BrowserRouter>
|
||||
<Search history={{ push: pushHandler }} />
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
wrapper = routerWrapper.find(Search).dive();
|
||||
const { handleClickSearch } = wrapper.instance();
|
||||
|
||||
// click
|
||||
handleClickSearch(event, { suggestionValue, method: 'click' });
|
||||
expect(event.stopPropagation).toHaveBeenCalled();
|
||||
expect(pushHandler).toHaveBeenCalledTimes(1);
|
||||
|
||||
// return key
|
||||
handleClickSearch(event, { suggestionValue, method: 'enter' });
|
||||
expect(event.stopPropagation).toHaveBeenCalled();
|
||||
expect(pushHandler).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
// click on the second suggestion
|
||||
fireEvent.click(suggestionsElements[1]);
|
||||
const listBoxElement = await waitForElement(() => getByRole('listbox'));
|
||||
// when the page redirects, the list box should be empty again
|
||||
expect(listBoxElement).toBeEmpty();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user