* Admin-configurable display locale * Add i18n-js and namespacing * Basic tests and clean up * A few test adjustments * Update vendor cache * Fix a few tests * Fix a few tests * Update app/views/articles/_actions.html.erb Co-authored-by: Michael Kohl <citizen428@dev.to> * Update app/views/articles/_comments_actions.html.erb Co-authored-by: Michael Kohl <citizen428@dev.to> * Update app/views/articles/_single_story.html.erb Co-authored-by: Michael Kohl <citizen428@dev.to> * Update app/views/articles/_single_story.html.erb Co-authored-by: Michael Kohl <citizen428@dev.to> * Update app/views/comments/_comment_header.html.erb Co-authored-by: Michael Kohl <citizen428@dev.to> * Update app/views/layouts/_sidebar_tags.html.erb Co-authored-by: Michael Kohl <citizen428@dev.to> * Update app/views/listings/index.html.erb Co-authored-by: Michael Kohl <citizen428@dev.to> * Update spec/system/homepage/user_visits_homepage_articles_spec.rb Co-authored-by: Michael Kohl <citizen428@dev.to> * Update spec/system/user/view_user_index_spec.rb Co-authored-by: Michael Kohl <citizen428@dev.to> * Alphabetical locale page * Add activerecord custom validation error translations * Add i18n to webpacker * Fix a few tests * Adjust error messages * Add i18n-tasks * Adjust JS to get working with jest * Adjust the way translations are pulled in * Adjust jest tests * Remove time localization * Remove superfluous public js * Add basic tests for i18n application controller * Remove unnecessary content Co-authored-by: Michael Kohl <citizen428@dev.to>
146 lines
4 KiB
JavaScript
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),
|
|
);
|
|
});
|
|
});
|