diff --git a/__tests__/atomWithLocation_spec.tsx b/__tests__/atomWithLocation_spec.tsx index 194065b..3a26cb4 100644 --- a/__tests__/atomWithLocation_spec.tsx +++ b/__tests__/atomWithLocation_spec.tsx @@ -1,12 +1,52 @@ import { useAtom } from 'jotai'; import React, { StrictMode } from 'react'; -import { act, render } from '@testing-library/react'; +import { render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { atomWithLocation } from '../src/index'; +function assertPathNameAndHistoryLength( + expectedPathname: string, + expectedHistoryLength: number, +) { + expect(window.location.pathname).toEqual(expectedPathname); + expect(window.history.length).toEqual(expectedHistoryLength); +} + +async function assertStartState( + startTestHistoryLength: number, + findByText: any, +) { + await findByText('current pathname in atomWithLocation: /'); + assertPathNameAndHistoryLength('/', startTestHistoryLength); +} + +function clickButtonAndAssertTemplate(localFindByText: any) { + return async function clickButtonAndAssert( + target: `button${number}` | 'back' | 'buttonWithReplace' | 'buttonWithPush', + historyLength: number, + targetPathName?: string, + ) { + let expectedPathname: string = '/'; + if (target === 'buttonWithReplace') { + expectedPathname = '/123'; + } else if (target === 'buttonWithPush') { + expectedPathname = '/234'; + } else if (target.startsWith('button')) { + expectedPathname = `/${target.slice(-1)}`; + } else if (target === 'back' && targetPathName) { + expectedPathname = targetPathName; + } + await userEvent.click(await localFindByText(target)); + await localFindByText( + `current pathname in atomWithLocation: ${expectedPathname}`, + ); + assertPathNameAndHistoryLength(expectedPathname, historyLength); + }; +} + describe('atomWithLocation', () => { beforeEach(() => { - window.history.replaceState(null, '', '/'); + window.history.pushState(null, '', '/'); }); it('can replace state', async () => { @@ -37,25 +77,18 @@ describe('atomWithLocation', () => { ); }; - const { findByText, getByText } = render( + const { findByText } = render( , ); - await findByText('current pathname in atomWithLocation: /'); - expect(window.location.pathname).toEqual('/'); - expect(window.history.length).toEqual(1); - - await userEvent.click(getByText('button1')); - - await findByText('current pathname in atomWithLocation: /1'); - expect(window.location.pathname).toEqual('/1'); - expect(window.history.length).toEqual(1); + const clickButtonAndAssert = clickButtonAndAssertTemplate(findByText); + const startHistoryLength = window.history.length; + assertStartState(startHistoryLength, findByText); - await userEvent.click(getByText('button2')); - expect(window.location.pathname).toEqual('/2'); - expect(window.history.length).toEqual(1); + await clickButtonAndAssert('button1', startHistoryLength); + await clickButtonAndAssert('button2', startHistoryLength); }); it('can push state', async () => { @@ -86,36 +119,22 @@ describe('atomWithLocation', () => { ); }; - const { findByText, getByText } = render( + const { findByText } = render( , ); - await findByText('current pathname in atomWithLocation: /'); - expect(window.location.pathname).toEqual('/'); - expect(window.history.length).toEqual(1); - - await userEvent.click(getByText('button1')); - - await findByText('current pathname in atomWithLocation: /1'); - expect(window.location.pathname).toEqual('/1'); - expect(window.history.length).toEqual(2); - - await userEvent.click(getByText('button2')); + const clickButtonAndAssert = clickButtonAndAssertTemplate(findByText); + const startHistoryLength = window.history.length; + assertStartState(startHistoryLength, findByText); - await findByText('current pathname in atomWithLocation: /2'); - expect(window.location.pathname).toEqual('/2'); - expect(window.history.length).toEqual(3); - - await userEvent.click(getByText('back')); - - await findByText('current pathname in atomWithLocation: /1'); - expect(window.location.pathname).toEqual('/1'); - expect(window.history.length).toEqual(3); + await clickButtonAndAssert('button1', startHistoryLength + 1); + await clickButtonAndAssert('button2', startHistoryLength + 2); + await clickButtonAndAssert('back', startHistoryLength + 2, '/1'); }); - it('can override atomOptions', async () => { + it('can override atomOptions, from replace=false to replace=true', async () => { const locationAtom = atomWithLocation({ replace: false }); const Navigation = () => { @@ -128,71 +147,100 @@ describe('atomWithLocation', () => { ); }; - const { findByText, getByText } = render( + const { findByText } = render( , ); - const previousTestHistoryLength = 3; + const clickButtonAndAssert = clickButtonAndAssertTemplate(findByText); + const startHistoryLength = window.history.length; - await act(async () => { - window.history.pushState(null, '', '/'); - }); + assertStartState(startHistoryLength, findByText); - await findByText('current pathname in atomWithLocation: /'); - expect(window.location.pathname).toEqual('/'); - expect(window.history.length).toEqual(previousTestHistoryLength); + await clickButtonAndAssert('buttonWithPush', startHistoryLength + 1); + await clickButtonAndAssert('buttonWithReplace', startHistoryLength + 1); + await clickButtonAndAssert('back', startHistoryLength + 1, '/'); - await userEvent.click(getByText('button1')); - - await findByText('current pathname in atomWithLocation: /123'); - expect(window.location.pathname).toEqual('/123'); - expect(window.history.length).toEqual(previousTestHistoryLength + 1); - - await userEvent.click(getByText('button2')); + // This click overwrites the history entry we + // went back from. The history length remains the same. + await clickButtonAndAssert('buttonWithPush', startHistoryLength + 1); - await findByText('current pathname in atomWithLocation: /234'); - expect(window.location.pathname).toEqual('/234'); - expect(window.history.length).toEqual(previousTestHistoryLength + 1); + // The second click adds a new history entry, which now increments the history length. + await clickButtonAndAssert('buttonWithPush', startHistoryLength + 2); + }); - await userEvent.click(getByText('back')); + it('can override atomOptions, from replace=true to replace=false', async () => { + const locationAtom = atomWithLocation({ replace: true }); - await findByText('current pathname in atomWithLocation: /'); - expect(window.location.pathname).toEqual('/'); - expect(window.history.length).toEqual(previousTestHistoryLength + 1); + const Navigation = () => { + const [location, setLocation] = useAtom(locationAtom); + return ( + <> +
current pathname in atomWithLocation: {location.pathname}
+ + + + + ); + }; - // The first click overwrites the history entry we - // went back from. The history length remains the same. - await userEvent.click(getByText('button1')); + const { findByText } = render( + + + , + ); - // The second click adds a new history entry, which now increments the history length. - await userEvent.click(getByText('button1')); + const clickButtonAndAssert = clickButtonAndAssertTemplate(findByText); + const startTestHistoryLength = window.history.length; + assertStartState(startTestHistoryLength, findByText); - await findByText('current pathname in atomWithLocation: /123'); - expect(window.location.pathname).toEqual('/123'); - expect(window.history.length).toEqual(previousTestHistoryLength + 2); + await clickButtonAndAssert('buttonWithReplace', startTestHistoryLength); + await clickButtonAndAssert('buttonWithPush', startTestHistoryLength + 1); + await clickButtonAndAssert('back', startTestHistoryLength + 1, '/123'); + await clickButtonAndAssert('buttonWithReplace', startTestHistoryLength + 1); + await clickButtonAndAssert('buttonWithPush', startTestHistoryLength + 1); + await clickButtonAndAssert('buttonWithPush', startTestHistoryLength + 2); }); });