mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	test: persistent table state (#5529)
This commit is contained in:
		
							parent
							
								
									d1984b2447
								
							
						
					
					
						commit
						5c889df9be
					
				@ -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",
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										156
									
								
								frontend/src/hooks/usePersistentTableState.test.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								frontend/src/hooks/usePersistentTableState.test.tsx
									
									
									
									
									
										Normal file
									
								
							@ -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' });
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
@ -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 }}
 | 
			
		||||
            >
 | 
			
		||||
                <AccessProviderMock permissions={permissions}>
 | 
			
		||||
                    <BrowserRouter>
 | 
			
		||||
                        <QueryParamProvider adapter={ReactRouter6Adapter}>
 | 
			
		||||
                            <ThemeProvider>
 | 
			
		||||
                                <AnnouncerProvider>
 | 
			
		||||
                            <BrowserRouter>{children}</BrowserRouter>
 | 
			
		||||
                                    {children}
 | 
			
		||||
                                </AnnouncerProvider>
 | 
			
		||||
                            </ThemeProvider>
 | 
			
		||||
                        </QueryParamProvider>
 | 
			
		||||
                    </BrowserRouter>
 | 
			
		||||
                </AccessProviderMock>
 | 
			
		||||
            </SWRConfig>
 | 
			
		||||
        </UIProviderContainer>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user