From 5c889df9be9d60b65aa9a8ff81ce2c37a6ea1c52 Mon Sep 17 00:00:00 2001 From: Mateusz Kwasniewski Date: Mon, 4 Dec 2023 15:47:53 +0100 Subject: [PATCH] test: persistent table state (#5529) --- frontend/package.json | 2 +- .../hooks/usePersistentTableState.test.tsx | 156 ++++++++++++++++++ frontend/src/utils/testRenderer.tsx | 16 +- 3 files changed, 168 insertions(+), 6 deletions(-) create mode 100644 frontend/src/hooks/usePersistentTableState.test.tsx diff --git a/frontend/package.json b/frontend/package.json index 91d440c32af3..72dadda57907 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -17,7 +17,7 @@ "start:demo": "UNLEASH_BASE_PATH=/demo/ UNLEASH_API=https://app.unleash-hosted.com/ yarn run start", "test": "NODE_OPTIONS=\"${NODE_OPTIONS} --no-experimental-fetch\" vitest run", "test:snapshot": "NODE_OPTIONS=\"${NODE_OPTIONS} --no-experimental-fetch\" yarn test -u", - "test:watch": "NODE_OPTIONS=\"${NODE_OPTIONS} --no-experimental-fetch\" vitest watch", + "test:watch": "NODE_OPTIONS=\"${NODE_OPTIONS} --no-experimental-fetch\" vitest watch usePersistentTable", "lint": "biome lint src --apply", "lint:check": "biome check src", "fmt": "biome format src --write", diff --git a/frontend/src/hooks/usePersistentTableState.test.tsx b/frontend/src/hooks/usePersistentTableState.test.tsx new file mode 100644 index 000000000000..8590351758a7 --- /dev/null +++ b/frontend/src/hooks/usePersistentTableState.test.tsx @@ -0,0 +1,156 @@ +import { render } from 'utils/testRenderer'; +import React from 'react'; +import { screen, waitFor } from '@testing-library/react'; +import { usePersistentTableState } from './usePersistentTableState'; +import { Route, Routes } from 'react-router-dom'; +import { createLocalStorage } from '../utils/createLocalStorage'; +import { NumberParam, StringParam } from 'use-query-params'; + +type TestComponentProps = { + keyName: string; + queryParamsDefinition: Record; +}; + +function TestComponent({ keyName, queryParamsDefinition }: TestComponentProps) { + const [tableState, setTableState] = usePersistentTableState( + keyName, + queryParamsDefinition, + ); + + return ( + + + + {tableState.query} + + + + + } + /> + + ); +} + +describe('usePersistentTableState', () => { + it('initializes correctly from URL', async () => { + createLocalStorage('testKey', {}); + + render( + , + { route: '/my-url?query=initialUrl' }, + ); + + expect(screen.getByTestId('state-value').textContent).toBe( + 'initialUrl', + ); + expect(window.location.href).toContain('my-url?query=initialUrl'); + }); + + it('initializes correctly from localStorage', async () => { + createLocalStorage('testKey', {}).setValue({ query: 'initialStorage' }); + + render( + , + { route: '/my-url' }, + ); + + expect(screen.getByTestId('state-value').textContent).toBe( + 'initialStorage', + ); + expect(window.location.href).toContain('my-url?query=initialStorage'); + }); + + it('initializes correctly from localStorage and URL', async () => { + createLocalStorage('testKey', {}).setValue({ query: 'initialStorage' }); + + render( + , + { route: '/my-url?query=initialUrl' }, + ); + + expect(screen.getByTestId('state-value').textContent).toBe( + 'initialUrl', + ); + expect(window.location.href).toContain('my-url?query=initialUrl'); + }); + + it('partially updates the state on button click', async () => { + createLocalStorage('testKey', {}).setValue({ + query: 'before', + other: 'other', + }); + + render( + , + { route: '/my-url' }, + ); + + expect(screen.getByTestId('state-value').textContent).toBe('before'); + + screen.getByText('Update State').click(); + + expect(screen.getByTestId('state-value').textContent).toBe('after'); + expect(window.location.href).toContain( + 'my-url?query=after&other=other', + ); + + await waitFor(() => { + const { value } = createLocalStorage('testKey', {}); + expect(value).toStrictEqual({ query: 'after', other: 'other' }); + }); + }); + + it('omits offset in local storage', async () => { + createLocalStorage('testKey', {}).setValue({ query: 'before' }); + + render( + , + { route: '/my-url' }, + ); + + screen.getByText('Update Offset').click(); + screen.getByText('Update State').click(); + + expect(window.location.href).toContain('my-url?query=after&offset=20'); + + await waitFor(() => { + const { value } = createLocalStorage('testKey', {}); + expect(value).toStrictEqual({ query: 'after' }); + }); + }); +}); diff --git a/frontend/src/utils/testRenderer.tsx b/frontend/src/utils/testRenderer.tsx index f4722f68dd84..daa203b89f05 100644 --- a/frontend/src/utils/testRenderer.tsx +++ b/frontend/src/utils/testRenderer.tsx @@ -7,6 +7,8 @@ import { IPermission } from 'interfaces/user'; import { AnnouncerProvider } from 'component/common/Announcer/AnnouncerProvider/AnnouncerProvider'; import { AccessProviderMock } from 'component/providers/AccessProvider/AccessProviderMock'; import { UIProviderContainer } from '../component/providers/UIProvider/UIProviderContainer'; +import { ReactRouter6Adapter } from 'use-query-params/adapters/react-router-6'; +import { QueryParamProvider } from 'use-query-params'; export const render = ( ui: JSX.Element, @@ -27,11 +29,15 @@ export const render = ( value={{ provider: () => new Map(), dedupingInterval: 0 }} > - - - {children} - - + + + + + {children} + + + +