import React, {useContext} from 'react'; import {act, render, screen} from '@testing-library/react'; import {initialize} from '@googlemaps/jest-mocks'; import '@testing-library/jest-dom'; // FIXME: this should no longer be needed with the next version of @googlemaps/jest-mocks import {importLibraryMock} from '../../libraries/__mocks__/lib/import-library-mock'; import { APIProvider, APIProviderContext, APIProviderContextValue } from '../api-provider'; import {ApiParams} from '../../libraries/google-maps-api-loader'; import {useApiIsLoaded} from '../../hooks/use-api-is-loaded'; import {APILoadingStatus} from '../../libraries/api-loading-status'; const apiLoadSpy = jest.fn(); const apiUnloadSpy = jest.fn(); const ContextSpyComponent = () => { const context = useContext(APIProviderContext); ContextSpyComponent.spy(context); return <>; }; ContextSpyComponent.spy = jest.fn(); let triggerMapsApiLoaded: () => void; jest.mock('../../libraries/google-maps-api-loader', () => { class GoogleMapsApiLoader { static async load( params: ApiParams, onLoadingStatusChange: (s: APILoadingStatus) => void ): Promise { apiLoadSpy(params); onLoadingStatusChange(APILoadingStatus.LOADING); google.maps.importLibrary = importLibraryMock; return new Promise( resolve => (triggerMapsApiLoaded = () => { resolve(); onLoadingStatusChange(APILoadingStatus.LOADED); }) ); } static unload() { apiUnloadSpy(); } } return {__esModule: true, GoogleMapsApiLoader}; }); beforeEach(() => { initialize(); jest.clearAllMocks(); }); test('passes parameters to GoogleMapsAPILoader', () => { render( ); expect(apiLoadSpy.mock.lastCall[0]).toMatchObject({ key: 'apikey', libraries: 'places,marker', v: 'beta', language: 'en', region: 'us', authReferrerPolicy: 'origin' }); }); test('passes parameters to GoogleMapsAPILoader', () => { render(); const actual = apiLoadSpy.mock.lastCall[0]; expect(Object.keys(actual)).toMatchObject(['key']); }); test('renders inner components', async () => { const LoadingStatus = () => { const mapsLoaded = useApiIsLoaded(); return {mapsLoaded ? 'loaded' : 'not loaded'}; }; render( ); expect(screen.getByText('not loaded')).toBeInTheDocument(); await act(() => triggerMapsApiLoaded()); expect(screen.getByText('loaded')).toBeInTheDocument(); }); test('provides context values', async () => { render( ); const contextSpy = ContextSpyComponent.spy; expect(contextSpy).toHaveBeenCalled(); let actualContext: APIProviderContextValue = contextSpy.mock.lastCall[0]; expect(actualContext.status).toEqual(APILoadingStatus.LOADING); expect(actualContext.mapInstances).toEqual({}); contextSpy.mockReset(); await act(() => triggerMapsApiLoaded()); expect(contextSpy).toHaveBeenCalled(); actualContext = contextSpy.mock.lastCall[0]; expect(actualContext.status).toBe(APILoadingStatus.LOADED); }); test('map instance management: add, access and remove', async () => { render( ); const contextSpy = ContextSpyComponent.spy; let actualContext: APIProviderContextValue = contextSpy.mock.lastCall[0]; const map1 = new google.maps.Map(null as unknown as HTMLElement); const map2 = new google.maps.Map(null as unknown as HTMLElement); contextSpy.mockReset(); await act(() => { actualContext.addMapInstance(map1, 'map-id-1'); actualContext.addMapInstance(map2, 'map-id-2'); }); expect(contextSpy).toHaveBeenCalled(); actualContext = contextSpy.mock.lastCall[0]; expect(actualContext.mapInstances['map-id-1']).toBe(map1); expect(actualContext.mapInstances['map-id-2']).toBe(map2); contextSpy.mockReset(); await act(() => { actualContext.removeMapInstance('map-id-1'); }); actualContext = contextSpy.mock.lastCall[0]; expect(actualContext.mapInstances).toEqual({'map-id-2': map2}); });