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('', () => { beforeEach(() => { // This part of the DOM would be rendered in the search results from the server side. // See search.html.erb. // It is where the portal will render. document.body.innerHTML = '
'; setWindowLocation(`https://localhost:3000/`); global.InstantClick = jest.fn(() => ({ on: jest.fn(), off: jest.fn(), preload: jest.fn(), display: jest.fn(), }))(); }); it('should synchronize search forms', async () => { const { getByRole, getAllByRole } = render(); // 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 getByRole('textbox', { name: /search/i }); // 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://localhost:3000/search?q=${searchTerm}`); fireEvent( window, new CustomEvent('syncSearchForms', { detail: { querystring: window.location.search }, }), ); const [desktopSearch, mobileSearch] = await getAllByRole('textbox', { name: /search/i, }); expect(desktopSearch.value).toEqual(searchTerm); expect(mobileSearch.value).toEqual(searchTerm); }); it('should synchronize search forms on a subsequent search', async () => { const { getByRole, getAllByRole } = render(); // 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 getByRole('textbox', { name: /search/i }); // 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://localhost:3000/search?q=${searchTerm}`); fireEvent( window, new CustomEvent('syncSearchForms', { detail: { querystring: window.location.search }, }), ); let [desktopSearch, mobileSearch] = await getAllByRole('textbox', { name: /search/i, }); 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://localhost:3000/search?q=${searchTerm2}`); const oldPortalContainer = document.getElementById( 'mobile-search-container', ); const newPortalContainer = oldPortalContainer.cloneNode(true); // This simulates the search results wiping out the old portal container // and providing a new portal container (different DOM elements). document.body.removeChild(oldPortalContainer); document.body.prepend(newPortalContainer); fireEvent( window, new CustomEvent('syncSearchForms', { detail: { querystring: window.location.search }, }), ); [desktopSearch, mobileSearch] = await getAllByRole('textbox', { name: /search/i, }); expect(desktopSearch.value).toEqual(searchTerm2); expect(mobileSearch.value).toEqual(searchTerm2); }); it('ensure both mobile search form & desktop search form exists', async () => { const { getAllByRole } = render(); setWindowLocation(`https://localhost:3000/search`); // fire click event twice with empty query to mimic clicking search button twice present in header for (let i = 0; i < 2; i += 1) { fireEvent( window, new CustomEvent('syncSearchForms', { detail: { querystring: window.location.search }, }), ); } const forms = await getAllByRole('textbox', { name: /search/i, }); expect(forms.length).toEqual(2); }); });