docbrown/app/javascript/Search/__tests__/SearchFormSync.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

126 lines
4.8 KiB
JavaScript

import { h } from 'preact';
import { fireEvent, render } from '@testing-library/preact';
import { SearchFormSync } from '../SearchFormSync';
function setWindowLocation(url = '') {
delete window.location; // Inspired from https://www.benmvp.com/blog/mocking-window-location-methods-jest-jsdom/
window.location = new URL(url);
}
// a11y tests are not required for this component as it's job is to provide data to other components.
// There is nothing UI related about this component.
describe('<SearchFormSync />', () => {
// For some reason when document.body is used for renders, we need to clear out the rendered markup in it.
// My guess is that Preact testing library handles this internally when using the default container to render in.
beforeEach(() => {
setWindowLocation(`https://locahost:3000/`);
// The body is being cleared out because we are using it as the root element for the tests.
// Typically using the document.body as the root for rendering of components in tests is not necessary,
// but in the case of this component, it renders a portal, and this seemed to be the only way to get these
// tests to render portals.
document.body.innerHTML = '';
global.InstantClick = jest.fn(() => ({
on: jest.fn(),
off: jest.fn(),
preload: jest.fn(),
display: jest.fn(),
}))();
});
it('should synchronize search forms', async () => {
const { findByLabelText, findAllByLabelText } = render(<SearchFormSync />, {
container: document.body,
});
// Only one input is rendered at this point because the synchSearchForms custom event is what
// tells us that there is a new search form to sync with the existing one.
const searchInput = await findByLabelText('search');
// Because window.location has no search term in it's URL
expect(searchInput.value).toEqual('');
// https://www.theatlantic.com/technology/archive/2012/09/here-it-is-the-best-word-ever/262348/
const searchTerm = 'diphthong';
// simulates a search result returned which contains the server side rendered search form for mobile only.
setWindowLocation(`https://locahost:3000/search?q=${searchTerm}`);
// This part of the DOM would be rendered in the search results from the server side.
// See search.html.erb.
document.body.innerHTML =
'<div id="mobile-search-container"><form></form></div>';
fireEvent(
window,
new CustomEvent('syncSearchForms', {
detail: { querystring: window.location.search },
}),
);
const [desktopSearch, mobileSearch] = await findAllByLabelText('search');
expect(desktopSearch.value).toEqual(searchTerm);
expect(mobileSearch.value).toEqual(searchTerm);
});
it('should synchronize search forms on a subsequent search', async () => {
const { findByLabelText, findAllByLabelText } = render(<SearchFormSync />, {
container: document.body,
});
// Only one input is rendered at this point because the synchSearchForms custom event is what
// tells us that there is a new search form to sync with the existing one.
const searchInput = await findByLabelText('search');
// Because window.location has no search term in it's URL
expect(searchInput.value).toEqual('');
// https://www.theatlantic.com/technology/archive/2012/09/here-it-is-the-best-word-ever/262348/
const searchTerm = 'diphthong';
// simulates a search result returned which contains the server side rendered search form for mobile only.
setWindowLocation(`https://locahost:3000/search?q=${searchTerm}`);
// This part of the DOM would be rendered in the search results from the server side.
// See search.html.erb.
document.body.innerHTML =
'<div id="mobile-search-container"><form></form></div>';
fireEvent(
window,
new CustomEvent('syncSearchForms', {
detail: { querystring: window.location.search },
}),
);
let [desktopSearch, mobileSearch] = await findAllByLabelText('search');
expect(desktopSearch.value).toEqual(searchTerm);
expect(mobileSearch.value).toEqual(searchTerm);
const searchTerm2 = 'diphthong2';
// simulates a search result returned which contains the server side rendered search form for mobile only.
setWindowLocation(`https://locahost:3000/search?q=${searchTerm2}`);
// This part of the DOM would be rendered in the search results from the server side.
// See search.html.erb.
document.body.innerHTML =
'<div id="mobile-search-container"><form></form></div>';
fireEvent(
window,
new CustomEvent('syncSearchForms', {
detail: { querystring: window.location.search },
}),
);
[desktopSearch, mobileSearch] = await findAllByLabelText('search');
expect(desktopSearch.value).toEqual(searchTerm2);
expect(mobileSearch.value).toEqual(searchTerm2);
});
});