import { renderHook, act } from '@testing-library/react'; import useAnnotatorEvents from '../useAnnotatorEvents'; import { Status } from '../types'; describe('src/elements/common/annotator-context/useAnnotatorEvents', () => { const mockAddListener = jest.fn(); const mockEmit = jest.fn(); const mockRemoveListener = jest.fn(); const getHook = (props: Object = {}) => { const mockEventEmitter = { addListener: mockAddListener, emit: mockEmit, eventNames: jest.fn(), getMaxListeners: jest.fn(), listenerCount: jest.fn(), listeners: jest.fn(), off: jest.fn(), on: jest.fn(), once: jest.fn(), prependListener: jest.fn(), prependOnceListener: jest.fn(), rawListeners: jest.fn(), removeAllListeners: jest.fn(), removeListener: mockRemoveListener, setMaxListeners: jest.fn(), }; return renderHook(() => useAnnotatorEvents({ ...props, eventEmitter: mockEventEmitter })); }; test('should remove all listeneres on cleanup', () => { const mockOnSidebarAnnotationSelected = jest.fn(); const mockOnAnnotationDeleteEnd = jest.fn(); const mockOnAnnotationDeleteStart = jest.fn(); const mockOnAnnotationUpdateEnd = jest.fn(); const mockOnAnnotationUpdateStart = jest.fn(); const mockOnAnnotationReplyAddEnd = jest.fn(); const mockOnAnnotationReplyAddStart = jest.fn(); const mockOnAnnotationReplyDeleteEnd = jest.fn(); const mockOnAnnotationReplyDeleteStart = jest.fn(); const mockOnAnnotationReplyUpdateEnd = jest.fn(); const mockOnAnnotationReplyUpdateStart = jest.fn(); const { unmount } = getHook({ onSidebarAnnotationSelected: mockOnSidebarAnnotationSelected, onAnnotationDeleteEnd: mockOnAnnotationDeleteEnd, onAnnotationDeleteStart: mockOnAnnotationDeleteStart, onAnnotationUpdateEnd: mockOnAnnotationUpdateEnd, onAnnotationUpdateStart: mockOnAnnotationUpdateStart, onAnnotationReplyAddEnd: mockOnAnnotationReplyAddEnd, onAnnotationReplyAddStart: mockOnAnnotationReplyAddStart, onAnnotationReplyDeleteEnd: mockOnAnnotationReplyDeleteEnd, onAnnotationReplyDeleteStart: mockOnAnnotationReplyDeleteStart, onAnnotationReplyUpdateEnd: mockOnAnnotationReplyUpdateEnd, onAnnotationReplyUpdateStart: mockOnAnnotationReplyUpdateStart, }); unmount(); expect(mockRemoveListener).toHaveBeenNthCalledWith( 1, 'annotations_active_set', mockOnSidebarAnnotationSelected, ); expect(mockRemoveListener).toHaveBeenNthCalledWith(2, 'annotations_remove', mockOnAnnotationDeleteEnd); expect(mockRemoveListener).toHaveBeenNthCalledWith(3, 'annotations_remove_start', mockOnAnnotationDeleteStart); expect(mockRemoveListener).toHaveBeenNthCalledWith(4, 'sidebar.annotations_update', mockOnAnnotationUpdateEnd); expect(mockRemoveListener).toHaveBeenNthCalledWith( 5, 'sidebar.annotations_update_start', mockOnAnnotationUpdateStart, ); expect(mockRemoveListener).toHaveBeenNthCalledWith( 6, 'sidebar.annotations_reply_create', mockOnAnnotationReplyAddEnd, ); expect(mockRemoveListener).toHaveBeenNthCalledWith( 7, 'sidebar.annotations_reply_create_start', mockOnAnnotationReplyAddStart, ); expect(mockRemoveListener).toHaveBeenNthCalledWith( 8, 'sidebar.annotations_reply_delete', mockOnAnnotationReplyDeleteEnd, ); expect(mockRemoveListener).toHaveBeenNthCalledWith( 9, 'sidebar.annotations_reply_delete_start', mockOnAnnotationReplyDeleteStart, ); expect(mockRemoveListener).toHaveBeenNthCalledWith( 10, 'sidebar.annotations_reply_update', mockOnAnnotationReplyUpdateEnd, ); expect(mockRemoveListener).toHaveBeenNthCalledWith( 11, 'sidebar.annotations_reply_update_start', mockOnAnnotationReplyUpdateStart, ); }); test('should call onAnnotationDeleteStart when proper event is emitted', () => { const mockAnnotationDeleteStart = jest.fn(); const mockAnnotationId = '123'; mockAddListener.mockImplementation((event: string, callback: (id: string) => void) => { if (event === 'annotations_remove_start') { callback(mockAnnotationId); } }); getHook({ onAnnotationDeleteStart: mockAnnotationDeleteStart }); expect(mockAddListener).toBeCalledWith('annotations_remove_start', mockAnnotationDeleteStart); expect(mockAnnotationDeleteStart).toBeCalledWith(mockAnnotationId); }); test('should call onAnnotationDeleteEnd when proper event is emitted', () => { const mockAnnotationDeleteEnd = jest.fn(); const mockAnnotationId = '123'; mockAddListener.mockImplementation((event: string, callback: (id: string) => void) => { if (event === 'annotations_remove') { callback(mockAnnotationId); } }); getHook({ onAnnotationDeleteEnd: mockAnnotationDeleteEnd }); expect(mockAddListener).toBeCalledWith('annotations_remove', mockAnnotationDeleteEnd); expect(mockAnnotationDeleteEnd).toBeCalledWith(mockAnnotationId); }); test('should call onAnnotationUpdateStart when proper event is emitted', () => { const mockAnnotationUpdateStart = jest.fn(); const mockAnnotation = { id: '123', status: 'resolved' }; mockAddListener.mockImplementation((event: string, callback: (annotation: Object) => void) => { if (event === 'sidebar.annotations_update_start') { callback(mockAnnotation); } }); getHook({ onAnnotationUpdateStart: mockAnnotationUpdateStart }); expect(mockAddListener).toBeCalledWith('sidebar.annotations_update_start', mockAnnotationUpdateStart); expect(mockAnnotationUpdateStart).toBeCalledWith(mockAnnotation); }); test('should call onAnnotationUpdateEnd when proper event is emitted', () => { const mockAnnotationUpdateEnd = jest.fn(); const mockAnnotation = { id: '123', status: 'resolved' }; mockAddListener.mockImplementation((event: string, callback: (annotation: Object) => void) => { if (event === 'sidebar.annotations_update') { callback(mockAnnotation); } }); getHook({ onAnnotationUpdateEnd: mockAnnotationUpdateEnd }); expect(mockAddListener).toBeCalledWith('sidebar.annotations_update', mockAnnotationUpdateEnd); expect(mockAnnotationUpdateEnd).toBeCalledWith(mockAnnotation); }); test('should call onAnnotationReplyAddStart when proper event is emitted', () => { const mockAnnotationReplyAddStart = jest.fn(); const mockEventData = { annotationId: '123', reply: { tagged_message: 'abc' }, requestId: 'comment_456' }; mockAddListener.mockImplementation((event: string, callback: (eventData: Object) => void) => { if (event === 'sidebar.annotations_reply_create_start') { callback(mockEventData); } }); getHook({ onAnnotationReplyAddStart: mockAnnotationReplyAddStart }); expect(mockAddListener).toBeCalledWith('sidebar.annotations_reply_create_start', mockAnnotationReplyAddStart); expect(mockAnnotationReplyAddStart).toBeCalledWith(mockEventData); }); test('should call onAnnotationReplyAddEnd when proper event is emitted', () => { const mockAnnotationReplyAddEnd = jest.fn(); const mockEventData = { annotationId: '123', reply: { id: '456', tagged_message: 'abc' }, requestId: 'comment_456', }; mockAddListener.mockImplementation((event: string, callback: (eventData: Object) => void) => { if (event === 'sidebar.annotations_reply_create') { callback(mockEventData); } }); getHook({ onAnnotationReplyAddEnd: mockAnnotationReplyAddEnd }); expect(mockAddListener).toBeCalledWith('sidebar.annotations_reply_create', mockAnnotationReplyAddEnd); expect(mockAnnotationReplyAddEnd).toBeCalledWith(mockEventData); }); test('should call onAnnotationReplyDeleteStart when proper event is emitted', () => { const mockAnnotationReplyDeleteStart = jest.fn(); const mockEventData = { annotationId: '123', id: '456' }; mockAddListener.mockImplementation((event: string, callback: (eventData: Object) => void) => { if (event === 'sidebar.annotations_reply_delete_start') { callback(mockEventData); } }); getHook({ onAnnotationReplyDeleteStart: mockAnnotationReplyDeleteStart }); expect(mockAddListener).toBeCalledWith( 'sidebar.annotations_reply_delete_start', mockAnnotationReplyDeleteStart, ); expect(mockAnnotationReplyDeleteStart).toBeCalledWith(mockEventData); }); test('should call onAnnotationReplyDeleteEnd when proper event is emitted', () => { const mockAnnotationReplyDeleteEnd = jest.fn(); const mockEventData = { annotationId: '123', id: '456' }; mockAddListener.mockImplementation((event: string, callback: (eventData: Object) => void) => { if (event === 'sidebar.annotations_reply_delete') { callback(mockEventData); } }); getHook({ onAnnotationReplyDeleteEnd: mockAnnotationReplyDeleteEnd }); expect(mockAddListener).toBeCalledWith('sidebar.annotations_reply_delete', mockAnnotationReplyDeleteEnd); expect(mockAnnotationReplyDeleteEnd).toBeCalledWith(mockEventData); }); test('should call onAnnotationReplyUpdateStart when proper event is emitted', () => { const mockAnnotationReplyUpdateStart = jest.fn(); const mockEventData = { annotationId: '123', reply: { id: '123', tagged_message: 'abc' } }; mockAddListener.mockImplementation((event: string, callback: (eventData: Object) => void) => { if (event === 'sidebar.annotations_reply_update_start') { callback(mockEventData); } }); getHook({ onAnnotationReplyUpdateStart: mockAnnotationReplyUpdateStart }); expect(mockAddListener).toBeCalledWith( 'sidebar.annotations_reply_update_start', mockAnnotationReplyUpdateStart, ); expect(mockAnnotationReplyUpdateStart).toBeCalledWith(mockEventData); }); test('should call onAnnotationReplyUpdateEnd when proper event is emitted', () => { const mockAnnotationReplyUpdateEnd = jest.fn(); const mockEventData = { annotationId: '123', reply: { id: '123', tagged_message: 'abc' } }; mockAddListener.mockImplementation((event: string, callback: (eventData: Object) => void) => { if (event === 'sidebar.annotations_reply_update') { callback(mockEventData); } }); getHook({ onAnnotationReplyUpdateEnd: mockAnnotationReplyUpdateEnd }); expect(mockAddListener).toBeCalledWith('sidebar.annotations_reply_update', mockAnnotationReplyUpdateEnd); expect(mockAnnotationReplyUpdateEnd).toBeCalledWith(mockEventData); }); test('should call onSidebarAnnotationSelected when proper event is emitted', () => { const mockOnSidebarAnnotationSelected = jest.fn(); const mockAnnotationId = '123'; mockAddListener.mockImplementation((event: string, callback: (id: string) => void) => { if (event === 'annotations_active_set') { callback(mockAnnotationId); } }); getHook({ onSidebarAnnotationSelected: mockOnSidebarAnnotationSelected }); expect(mockAddListener).toBeCalledWith('annotations_active_set', mockOnSidebarAnnotationSelected); expect(mockOnSidebarAnnotationSelected).toBeCalledWith(mockAnnotationId); }); test('should emit annotation active change event', () => { const annotationId = '123'; const fileVersionId = '456'; const { result } = getHook(); act(() => { result.current.emitAnnotationActiveChangeEvent(annotationId, fileVersionId); }); expect(mockEmit).toBeCalledWith('annotations_active_change', { annotationId, fileVersionId }); }); test('should emit annotation add start event', () => { const annotation = { description: { message: 'New Annotation', }, }; const requestId = 'annotation_123'; const { result } = getHook(); act(() => { result.current.emitAddAnnotationStartEvent(annotation, requestId); }); const expectedAnnotationActionEvent = { annotation, meta: { requestId, status: Status.PENDING }, }; expect(mockEmit).toBeCalledWith('annotations_create', expectedAnnotationActionEvent); }); test('should emit annotation add end event', () => { const annotation = { description: { message: 'New Annotation', }, id: '1234', target: { location: { value: 1, type: 'page', }, shape: { height: 41.66666666666667, type: 'rect', width: 41.66666666666667, x: 20.833333333333336, y: 25, }, type: 'region', }, }; const requestId = 'annotation_123'; const { result } = getHook(); act(() => { result.current.emitAddAnnotationEndEvent(annotation, requestId); }); const expectedAnnotationActionEvent = { annotation, meta: { requestId, status: Status.SUCCESS }, }; expect(mockEmit).toBeCalledWith('annotations_create', expectedAnnotationActionEvent); }); test('should emit annotation delete start event', () => { const { result } = getHook(); act(() => { result.current.emitDeleteAnnotationStartEvent('123'); }); const expectedAnnotationActionEvent = { annotation: { id: '123' }, meta: { status: Status.PENDING }, }; expect(mockEmit).toBeCalledWith('annotations_delete', expectedAnnotationActionEvent); }); test('should emit annotation delete end event', () => { const { result } = getHook(); act(() => { result.current.emitDeleteAnnotationEndEvent('123'); }); const expectedAnnotationActionEvent = { annotation: { id: '123' }, meta: { status: Status.SUCCESS }, }; expect(mockEmit).toBeCalledWith('annotations_delete', expectedAnnotationActionEvent); }); test('should emit annotation update start event', () => { const annotation = { id: '123', status: 'resolved' }; const { result } = getHook(); act(() => { result.current.emitUpdateAnnotationStartEvent(annotation); }); const expectedAnnotationActionEvent = { annotation, meta: { status: Status.PENDING }, }; expect(mockEmit).toBeCalledWith('annotations_update', expectedAnnotationActionEvent); }); test('should emit annotation update end event', () => { const annotation = { id: '123', status: 'resolved' }; const { result } = getHook(); act(() => { result.current.emitUpdateAnnotationEndEvent(annotation); }); const expectedAnnotationActionEvent = { annotation, meta: { status: Status.SUCCESS }, }; expect(mockEmit).toBeCalledWith('annotations_update', expectedAnnotationActionEvent); }); test('should emit annotation reply create start event', () => { const annotationId = '123'; const reply = { tagged_message: 'abc' }; const requestId = 'comment_456'; const { result } = getHook(); act(() => { result.current.emitAddAnnotationReplyStartEvent(reply, annotationId, requestId); }); const expectedAnnotationActionEvent = { annotation: { id: annotationId }, annotationReply: reply, meta: { status: Status.PENDING, requestId }, }; expect(mockEmit).toBeCalledWith('annotations_reply_create', expectedAnnotationActionEvent); }); test('should emit annotation reply create end event', () => { const annotationId = '123'; const reply = { id: '456', tagged_message: 'abc' }; const requestId = 'comment_456'; const { result } = getHook(); act(() => { result.current.emitAddAnnotationReplyEndEvent(reply, annotationId, requestId); }); const expectedAnnotationActionEvent = { annotation: { id: annotationId }, annotationReply: reply, meta: { status: Status.SUCCESS, requestId }, }; expect(mockEmit).toBeCalledWith('annotations_reply_create', expectedAnnotationActionEvent); }); test('should emit annotation reply delete start event', () => { const annotationId = '123'; const replyId = '456'; const { result } = getHook(); act(() => { result.current.emitDeleteAnnotationReplyStartEvent(replyId, annotationId); }); const expectedAnnotationActionEvent = { annotation: { id: annotationId }, annotationReply: { id: replyId }, meta: { status: Status.PENDING }, }; expect(mockEmit).toBeCalledWith('annotations_reply_delete', expectedAnnotationActionEvent); }); test('should emit annotation reply delete end event', () => { const annotationId = '123'; const replyId = '456'; const { result } = getHook(); act(() => { result.current.emitDeleteAnnotationReplyEndEvent(replyId, annotationId); }); const expectedAnnotationActionEvent = { annotation: { id: annotationId }, annotationReply: { id: replyId }, meta: { status: Status.SUCCESS }, }; expect(mockEmit).toBeCalledWith('annotations_reply_delete', expectedAnnotationActionEvent); }); test('should emit annotation reply update start event', () => { const annotationId = '123'; const reply = { id: '456', tagged_message: 'abc' }; const { result } = getHook(); act(() => { result.current.emitUpdateAnnotationReplyStartEvent(reply, annotationId); }); const expectedAnnotationActionEvent = { annotation: { id: annotationId }, annotationReply: reply, meta: { status: Status.PENDING }, }; expect(mockEmit).toBeCalledWith('annotations_reply_update', expectedAnnotationActionEvent); }); test('should emit annotation reply update end event', () => { const annotationId = '123'; const reply = { id: '456', tagged_message: 'abc' }; const { result } = getHook(); act(() => { result.current.emitUpdateAnnotationReplyEndEvent(reply, annotationId); }); const expectedAnnotationActionEvent = { annotation: { id: annotationId }, annotationReply: reply, meta: { status: Status.SUCCESS }, }; expect(mockEmit).toBeCalledWith('annotations_reply_update', expectedAnnotationActionEvent); }); });