docbrown/app/javascript/Search/__tests__/Search.test.jsx
2023-10-19 12:59:54 -04:00

146 lines
4 KiB
JavaScript

import { h } from 'preact';
import { render, fireEvent, waitFor } from '@testing-library/preact';
import { userEvent } from '@testing-library/user-event';
import { axe } from 'jest-axe';
import { Search } from '../Search';
import { locale } from '../../utilities/locale';
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 { getByRole } = render(<Search {...props} />);
const searchInput = getByRole('textbox', { name: /search/i });
expect(searchInput.value).toEqual('fish');
expect(searchInput.getAttribute('placeholder')).toEqual(`${locale('core.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 { getByRole, findByRole } = render(<Search {...props} />);
let searchInput = getByRole('textbox', { name: /search/i });
expect(searchInput.value).toEqual('fish');
fireEvent.change(searchInput, { target: { value: 'hello' } });
searchInput = await findByRole('textbox', { name: /search/i });
expect(searchInput.value).toEqual('hello');
});
it('should set the search term', async () => {
const props = {
searchTerm: '',
setSearchTerm: jest.fn(),
};
const { getByRole } = render(<Search {...props} />);
const searchInput = getByRole('textbox', { name: /search/i });
expect(searchInput.value).toEqual('');
userEvent.type(searchInput, 'hello');
waitFor(() => {
expect(searchInput.value).toEqual('hello');
expect(props.setSearchTerm).toHaveBeenCalledWith('hello');
});
});
it('should submit the search form', async () => {
const props = {
searchTerm: '',
setSearchTerm: jest.fn(),
onSubmitSearch: jest.fn(),
};
const { getByRole, findByRole } = render(<Search {...props} />);
let searchInput = getByRole('textbox', { name: /search/i });
expect(searchInput.value).toEqual('');
userEvent.type(searchInput, 'hello');
fireEvent.submit(getByRole('search'));
searchInput = await findByRole('textbox', { name: /search/i });
waitFor(() => {
expect(searchInput.value).toEqual('hello');
expect(props.onSubmitSearch).toHaveBeenCalledWith('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),
);
});
});