import { createRoot } from 'react-dom/client'; import { act } from 'react'; import apiFetch from '@wordpress/api-fetch'; import { useBulkQuotes, type UseBulkQuotesReturn } from '../features/orders/hooks/useBulkQuotes'; jest.mock( '@wordpress/api-fetch', () => jest.fn() ); jest.mock( '../shared/sentry', () => ( { addBreadcrumb: jest.fn(), captureException: jest.fn(), withSpan: ( _name: string, _op: string, fn: () => unknown ) => fn(), } ) ); const mockedApiFetch = apiFetch as unknown as jest.Mock; ( globalThis as any ).IS_REACT_ACT_ENVIRONMENT = true; function deferred< T >() { let resolve!: ( value: T ) => void; const promise = new Promise< T >( ( r ) => ( resolve = r ) ); return { promise, resolve }; } const quotesFor = ( ...refs: string[] ) => ( { quotes: refs.map( ( ref ) => ( { ref, price: { gross: 370 } } ) ), } ); function renderHook() { const result: { current: UseBulkQuotesReturn | null } = { current: null }; function Probe() { result.current = useBulkQuotes(); return null; } const root = createRoot( document.createElement( 'div' ) ); act( () => root.render( ) ); return { result, unmount: () => act( () => root.unmount() ) }; } describe( 'useBulkQuotes', () => { afterEach( () => mockedApiFetch.mockReset() ); it( 'keeps the latest selection when an older response arrives last', async () => { const twoOrders = deferred< unknown >(); const threeOrders = deferred< unknown >(); mockedApiFetch .mockReturnValueOnce( twoOrders.promise ) .mockReturnValueOnce( threeOrders.promise ); const { result, unmount } = renderHook(); let olderResult: unknown; await act( async () => { const older = result.current!.fetchBulkQuotes( [] ); result.current!.fetchBulkQuotes( [] ); threeOrders.resolve( quotesFor( '323', '316', '289' ) ); await Promise.resolve(); twoOrders.resolve( quotesFor( '323', '316' ) ); olderResult = await older; } ); expect( olderResult ).toBeNull(); expect( result.current!.quotes.map( ( q: any ) => q.ref ) ).toEqual( [ '323', '316', '289' ] ); expect( result.current!.loading ).toBe( false ); unmount(); } ); it( 'stays loading until the latest request finishes', async () => { const first = deferred< unknown >(); const second = deferred< unknown >(); mockedApiFetch.mockReturnValueOnce( first.promise ).mockReturnValueOnce( second.promise ); const { result, unmount } = renderHook(); let pending!: Promise< unknown >; await act( async () => { result.current!.fetchBulkQuotes( [] ); pending = result.current!.fetchBulkQuotes( [] ); first.resolve( quotesFor( '1' ) ); await Promise.resolve(); } ); expect( result.current!.loading ).toBe( true ); await act( async () => { second.resolve( quotesFor( '1', '2' ) ); await pending; } ); expect( result.current!.loading ).toBe( false ); expect( result.current!.quotes ).toHaveLength( 2 ); unmount(); } ); } );