docbrown/app/javascript/Search/__tests__/Search.test.jsx
Nick Taylor df31a94f2e
Prep work to sync mobile search in #10424 (#11525)
* Prep work to sync mobile search in #10424

* Added a comment about the custom search event.

* Refactor to fix already defined error caused by const and InstantClick.

* Moved <SearchFormSync /> out of the pack file.

* Fixed broken tests.

* Renamed getInitialSearchTerm utility function to getSearchTermFromUrl

* Added some API docs to getSearchTermFromUrl

* Fixed a typo.

* Added some more API docs.

* Switched to a custom event so a custom payload can be passed.

* Added some API docs.

* Fixed bad destructuring statement.

* wip for some more tests.

* Refactored getSearchTermFromUrl to use URLSearchParams

* lazy loaded state for search term initial value.

* test broken still. Need to think on it.

* filterXSS is now set up in testSetup.js

* Fixed tests.

* Added the @utilities alias to Storybooks webpack config.

* Almost 100% coverage with two useful tests.

* Added some comments explaining document.body usage in the tests.

* Fixed issue where search attemps to get results on first load.

* Small refactor for setting the window.location in tests.

* Clarified an explanation in a comment.
2020-11-30 06:13:06 -05:00

163 lines
4.3 KiB
JavaScript

import { h } from 'preact';
import { render, fireEvent } from '@testing-library/preact';
import { axe } from 'jest-axe';
import { Search } from '../Search';
describe('<Search />', () => {
beforeEach(() => {
global.filterXSS = jest.fn();
global.InstantClick = jest.fn(() => ({
on: jest.fn(),
off: jest.fn(),
preload: jest.fn(),
display: jest.fn(),
}))();
global.instantClick = jest.fn(() => ({}))();
});
it('should have no a11y violations', async () => {
const props = {
searchTerm: 'fish',
setSearchTerm: jest.fn(),
};
const { container } = render(<Search {...props} />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it('should have a search textbox', () => {
const props = {
searchTerm: 'fish',
setSearchTerm: jest.fn(),
};
const { getByLabelText } = render(<Search {...props} />);
const searchInput = getByLabelText(/search/i);
expect(searchInput.value).toEqual('fish');
expect(searchInput.getAttribute('placeholder')).toEqual('Search...');
expect(searchInput.getAttribute('autocomplete')).toEqual('off');
});
it('should contain text the user entered in the search textbox', async () => {
const props = {
searchTerm: 'fish',
setSearchTerm: jest.fn(),
};
const { getByLabelText, findByLabelText } = render(<Search {...props} />);
let searchInput = getByLabelText(/search/i);
expect(searchInput.value).toEqual('fish');
// user.type doesn't work in the case of
// search as the current implementation is relying on keydown
// events
fireEvent.keyDown(searchInput, {
key: 'Enter',
keyCode: 13,
which: 13,
target: { value: 'hello' },
});
searchInput = await findByLabelText(/search/i);
expect(searchInput.value).toEqual('hello');
});
it('should set the search term', async () => {
const props = {
searchTerm: '',
setSearchTerm: jest.fn(),
};
const { getByLabelText } = render(<Search {...props} />);
let searchInput = getByLabelText(/search/i);
expect(searchInput.value).toEqual('');
// user.type doesn't work in the case of
// search as the current implementation is relying on keydown
// events
fireEvent.keyDown(searchInput, {
key: 'Enter',
keyCode: 13,
which: 13,
target: { value: 'hello' },
});
expect(searchInput.value).toEqual('hello');
expect(props.setSearchTerm).toHaveBeenCalledWith('hello');
});
it('should submit the search form', async () => {
jest.spyOn(Search.prototype, 'search');
const props = {
searchTerm: '',
setSearchTerm: jest.fn(),
};
const { getByLabelText, findByLabelText } = render(<Search {...props} />);
let searchInput = getByLabelText(/search/i);
expect(searchInput.value).toEqual('');
// user.type doesn't work in the case of
// search as the current implementation is relying on keydown
// events
fireEvent.keyDown(searchInput, {
key: 'Enter',
keyCode: 13,
which: 13,
target: { value: 'hello' },
});
searchInput = await findByLabelText(/search/i);
expect(searchInput.value).toEqual('hello');
expect(Search.prototype.search).toHaveBeenCalledWith('Enter', 'hello');
});
it('should be listening for history state changes', async () => {
// This is an implementation detail, but I want to make sure that this
// listener is registered as it affects the UI.
jest.spyOn(window, 'addEventListener');
const props = {
searchTerm: '',
setSearchTerm: jest.fn(),
};
render(<Search {...props} />);
expect(window.addEventListener).toHaveBeenNthCalledWith(
1,
'popstate',
expect.any(Function),
);
});
it('should stop listening for history state changes when the component is destroyed', async () => {
// This is an implementation detail, but I want to make sure that this
// listener is unregistered as it affects the UI.
jest.spyOn(window, 'removeEventListener');
const props = {
searchTerm: '',
setSearchTerm: jest.fn(),
};
const { unmount } = render(<Search {...props} />);
unmount();
expect(window.removeEventListener).toHaveBeenNthCalledWith(
1,
'popstate',
expect.any(Function),
);
});
});