import React from 'react'; import { render, screen, waitFor } from '@testing-library/react'; import { EVENTS, UnleashClient } from 'unleash-proxy-client'; import FlagProvider from './FlagProvider'; import useFlagsStatus from './useFlagsStatus'; import { act } from 'react-dom/test-utils'; import useFlag from './useFlag'; import { useFlagContext } from './useFlagContext'; import useVariant from './useVariant'; const fetchMock = vi.fn(async () => { return Promise.resolve({ ok: true, status: 200, headers: new Headers({}), json: () => { return Promise.resolve({ toggles: [ { name: 'test-flag', enabled: true, variant: { name: 'A', payload: { type: 'string', value: 'A' }, enabled: true, }, }, ], }); }, }); }); test('should render toggles', async () => { const client = new UnleashClient({ url: 'http://localhost:4242/api/frontend', appName: 'test', clientKey: 'test', fetch: fetchMock, }); const TestComponent = () => { const { flagsReady } = useFlagsStatus(); const state = useFlag('test-flag'); const variant = useVariant('test-flag'); return ( <>
{flagsReady.toString()}
{state.toString()}
{JSON.stringify(variant)}
); }; const ui = ( ); const { rerender } = render(ui); // Before client initialization expect(fetchMock).not.toHaveBeenCalled(); expect(screen.getByTestId('ready')).toHaveTextContent('false'); expect(screen.getByTestId('state')).toHaveTextContent('false'); expect(screen.getByTestId('variant')).toHaveTextContent('false'); // Wait for client initialization await act( () => new Promise((resolve) => { client.on(EVENTS.READY, () => { setTimeout(resolve, 1); }); }) ); // After client initialization expect(fetchMock).toHaveBeenCalled(); rerender(ui); expect(screen.getByTestId('ready')).toHaveTextContent('true'); expect(screen.getByTestId('state')).toHaveTextContent('true'); expect(screen.getByTestId('variant')).toHaveTextContent( '{"name":"A","payload":{"type":"string","value":"A"},"enabled":true,"feature_enabled":true}' ); }); test('should be ready from the start if bootstrapped', () => { const Component = React.memo(() => { const { flagsReady } = useFlagContext(); return <>{flagsReady ? 'ready' : ''}; }); render( ); expect(screen.getByText('ready')).toBeInTheDocument(); }); test('should immediately return value if boostrapped', () => { const Component = () => { const enabled = useFlag('test-flag'); return <>{enabled ? 'enabled' : ''}; }; render( ); expect(screen.queryByText('enabled')).toBeInTheDocument(); }); test('should render limited times when bootstrapped', async () => { let renders = 0; const config = { url: 'http://localhost:4242/api/frontend', appName: 'test', clientKey: 'test', bootstrap: [ { name: 'test-flag', enabled: true, variant: { name: 'A', enabled: true, payload: { type: 'string', value: 'A' }, }, impressionData: false, }, ], fetch: fetchMock, }; const client = new UnleashClient(config); const Component = () => { const enabled = useFlag('test-flag'); const { flagsReady } = useFlagContext(); renders += 1; return ( <> {flagsReady ? 'flagsReady' : ''} {enabled ? 'enabled' : ''} ); }; render( ); expect(screen.queryByText('enabled')).toBeInTheDocument(); expect(screen.queryByText('flagsReady')).toBeInTheDocument(); expect(renders).toBe(1); // Wait for client initialization await act( () => new Promise((resolve) => { client.on(EVENTS.READY, () => { setTimeout(resolve, 1); }); }) ); expect(renders).toBe(1); }); test('should resolve values before setting flagsReady', async () => { const client = new UnleashClient({ url: 'http://localhost:4242/api/frontend', appName: 'test', clientKey: 'test', fetch: fetchMock, }); let renders = 0; const Component = () => { const enabled = useFlag('test-flag'); const { flagsReady } = useFlagContext(); renders += 1; return ( <> {flagsReady ? 'flagsReady' : ''} {enabled ? 'enabled' : ''} ); }; const ui = ( ); render(ui); expect(renders).toBe(1); expect(screen.queryByText('flagsReady')).not.toBeInTheDocument(); expect(screen.queryByText('enabled')).not.toBeInTheDocument(); await waitFor(() => { expect(screen.queryByText('enabled')).toBeInTheDocument(); expect(screen.queryByText('flagsReady')).toBeNull(); expect(renders).toBe(2); }); await waitFor(() => { expect(screen.queryByText('flagsReady')).toBeInTheDocument(); expect(screen.queryByText('enabled')).toBeInTheDocument(); expect(renders).toBe(3); }); });