import { render, waitFor } from '@testing-library/react'; import omit from 'lodash.omit'; import { ReactElement, Suspense } from 'react'; import { Marker } from './marker'; import { NaverMapContext } from '../contexts/naver-map'; const map = {} as naver.maps.Map; function renderOverlay(overlay: ReactElement) { return render(overlay, { wrapper: ({ children }) => ( {children} ), }); } const mockPosition = { equals: jest.fn(() => false) }; let options = {} as naver.maps.MarkerOptions; const mockMethods = { getMap: jest.fn(), setMap: jest.fn(), getOptions: jest.fn((key: keyof naver.maps.MarkerOptions) => Object.assign({ [key]: options[key] })), setOptions: jest.fn((opt: any) => { Object.assign(options, opt, { position: mockPosition }); }), getPosition: jest.fn(() => mockPosition), setPosition: jest.fn(), }; const mockMarker = jest.fn().mockImplementation((opt) => { Object.assign(options, opt, { position: mockPosition }); return mockMethods; }); describe('', () => { beforeEach(() => { options = {} as naver.maps.MarkerOptions; mockMarker.mockClear(); Object.values(mockMethods).forEach(mock => mock.mockClear()); // @ts-expect-error mocking navermaps client loader window.naver = { maps: { Marker: mockMarker } }; }); it('should currectly handle options without props', async () => { const { rerender, unmount } = renderOverlay(); await waitFor(() => expect(window.naver.maps).toBeTruthy()); expect(mockMethods.setMap).toBeCalledWith(map); expect(mockMethods.setPosition).not.toBeCalled(); expect(mockMethods.setOptions).not.toBeCalled(); const position = {} as naver.maps.Point; rerender(); expect(mockMethods.setPosition).toBeCalledWith(position); unmount(); expect(mockMethods.setMap).toBeCalledWith(null); }); it('should currectly handle options with props', () => { const position = {} as naver.maps.Point; const animation = 0; const icon = ''; const shape = {} as naver.maps.MarkerShape; const title = 'title'; const cursor = ''; const clickable = true; const draggable = true; const visible = true; const zIndex = 0; const { rerender } = renderOverlay(); expect(mockMethods.setMap).toBeCalledWith(map); expect(omit(options, ['position'])).toEqual({ animation, icon, shape, title, cursor, clickable, draggable, visible, zIndex, }); const diffPosition1 = {} as naver.maps.Coord; const diffTitle1 = 'title1'; const sameClickable1 = true; rerender(); expect(mockMethods.setPosition).toBeCalledWith(diffPosition1); expect(mockMethods.setOptions).toBeCalledWith({ title: diffTitle1 }); }); it('should ignore change when uncontrolled props is set', () => { const position = {} as naver.maps.Point; const title = 'title'; const { rerender } = renderOverlay(); const position1 = {} as naver.maps.Coord; const title1 = 'title1'; // position, defaultPosition 어느것이 변경되더라도 position이 변경되지 않아야한다. const prevCallCount = mockMethods.setPosition.mock.calls.length; rerender(); expect(prevCallCount).toBe(mockMethods.setPosition.mock.calls.length); expect(mockMethods.setOptions).toBeCalledWith({ title: title1 }); }); it('should ignore position change when position is equal', () => { const position = {} as naver.maps.Point; const { rerender } = renderOverlay(); const prevCallCount = mockMethods.setPosition.mock.calls.length; mockPosition.equals.mockImplementationOnce(() => true); rerender(); expect(prevCallCount).toBe(mockMethods.setPosition.mock.calls.length); }); });