Skip to content

Commit

Permalink
test: persistent table state (#5529)
Browse files Browse the repository at this point in the history
  • Loading branch information
kwasniew authored Dec 4, 2023
1 parent d1984b2 commit 5c889df
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 6 deletions.
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
156 changes: 156 additions & 0 deletions frontend/src/hooks/usePersistentTableState.test.tsx
Original file line number Diff line number Diff line change
@@ -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<string, any>;
};

function TestComponent({ keyName, queryParamsDefinition }: TestComponentProps) {
const [tableState, setTableState] = usePersistentTableState(
keyName,
queryParamsDefinition,
);

return (
<Routes>
<Route
path={'/my-url'}
element={
<div>
<span data-testid='state-value'>
{tableState.query}
</span>
<button
type='button'
onClick={() => setTableState({ query: 'after' })}
>
Update State
</button>
<button
type='button'
onClick={() => setTableState({ offset: 20 })}
>
Update Offset
</button>
</div>
}
/>
</Routes>
);
}

describe('usePersistentTableState', () => {
it('initializes correctly from URL', async () => {
createLocalStorage('testKey', {});

render(
<TestComponent
keyName='testKey'
queryParamsDefinition={{ query: StringParam }}
/>,
{ 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(
<TestComponent
keyName='testKey'
queryParamsDefinition={{ query: StringParam }}
/>,
{ 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(
<TestComponent
keyName='testKey'
queryParamsDefinition={{ query: StringParam }}
/>,
{ 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(
<TestComponent
keyName='testKey'
queryParamsDefinition={{
query: StringParam,
other: StringParam,
}}
/>,
{ 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(
<TestComponent
keyName='testKey'
queryParamsDefinition={{
query: StringParam,
offset: NumberParam,
}}
/>,
{ 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' });
});
});
});
16 changes: 11 additions & 5 deletions frontend/src/utils/testRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -27,11 +29,15 @@ export const render = (
value={{ provider: () => new Map(), dedupingInterval: 0 }}
>
<AccessProviderMock permissions={permissions}>
<ThemeProvider>
<AnnouncerProvider>
<BrowserRouter>{children}</BrowserRouter>
</AnnouncerProvider>
</ThemeProvider>
<BrowserRouter>
<QueryParamProvider adapter={ReactRouter6Adapter}>
<ThemeProvider>
<AnnouncerProvider>
{children}
</AnnouncerProvider>
</ThemeProvider>
</QueryParamProvider>
</BrowserRouter>
</AccessProviderMock>
</SWRConfig>
</UIProviderContainer>
Expand Down

0 comments on commit 5c889df

Please sign in to comment.