diff --git a/src/course-unit/add-component/AddComponent.jsx b/src/course-unit/add-component/AddComponent.jsx index 1ec73e7522..70962a7ac6 100644 --- a/src/course-unit/add-component/AddComponent.jsx +++ b/src/course-unit/add-component/AddComponent.jsx @@ -37,12 +37,12 @@ const AddComponent = ({ blockId, handleCreateNewCourseXBlock }) => { useEventListener('message', receiveMessage); - const onComponentSelectionSubmit = () => { + const onComponentSelectionSubmit = useCallback(() => { sendMessageToIframe(messageTypes.addSelectedComponentsToBank, { selectedComponents }); closeSelectLibraryContentModal(); - }; + }, [selectedComponents]); - const handleLibraryV2Selection = (selection) => { + const handleLibraryV2Selection = useCallback((selection) => { handleCreateNewCourseXBlock({ type: COMPONENT_TYPES.libraryV2, category: selection.blockType, @@ -50,7 +50,7 @@ const AddComponent = ({ blockId, handleCreateNewCourseXBlock }) => { libraryContentKey: selection.usageKey, }); closeAddLibraryContentModal(); - }; + }, []); const handleCreateNewXBlock = (type, moduleName) => { switch (type) { diff --git a/src/course-unit/add-component/AddComponent.test.jsx b/src/course-unit/add-component/AddComponent.test.jsx index 9cc27acf55..c3b3ffc3e4 100644 --- a/src/course-unit/add-component/AddComponent.test.jsx +++ b/src/course-unit/add-component/AddComponent.test.jsx @@ -1,6 +1,6 @@ import MockAdapter from 'axios-mock-adapter'; import { - render, waitFor, within, + act, render, screen, waitFor, within, } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; @@ -17,25 +17,53 @@ import { courseSectionVerticalMock } from '../__mocks__'; import { COMPONENT_TYPES } from '../../generic/block-type-utils/constants'; import AddComponent from './AddComponent'; import messages from './messages'; +import { IframeProvider } from '../context/iFrameContext'; +import { messageTypes } from '../constants'; let store; let axiosMock; const blockId = '123'; const handleCreateNewCourseXBlockMock = jest.fn(); +const usageKey = 'lb:Axim:TEST:html:571fe018-f3ce-45c9-8f53-5dafcb422fddest-usage-key' -// Mock ComponentPicker to call onComponentSelected on load +// Mock ComponentPicker to call onComponentSelected on click jest.mock('../../library-authoring/component-picker', () => ({ - ComponentPicker: (props) => props.onComponentSelected({ usageKey: 'test-usage-key', blockType: 'html' }), + ComponentPicker: (props) => { + const onClick = () => { + if (props.componentPickerMode === 'single') { + props.onComponentSelected({ + usageKey, + blockType: 'html', + }); + } else { + props.onChangeComponentSelection([{ + usageKey, + blockType: 'html', + }]); + } + } + return ; + }, +})); + +const mockSendMessageToIframe = jest.fn(); +jest.mock('../context/hooks', () => ({ + useIframe: () => ({ + sendMessageToIframe: mockSendMessageToIframe, + }), })); const renderComponent = (props) => render( - + + + , ); @@ -413,19 +441,67 @@ describe('', () => { }); it('shows library picker on clicking v2 library content btn', async () => { - const { findByRole } = renderComponent(); - const libBtn = await findByRole('button', { + renderComponent(); + const libBtn = await screen.findByRole('button', { name: new RegExp(`${messages.buttonText.defaultMessage} Library content`, 'i'), }); - userEvent.click(libBtn); + + // click dummy button to execute onComponentSelected prop. + const dummyBtn = await screen.findByRole('button', { name: 'Dummy button' }); + userEvent.click(dummyBtn); + expect(handleCreateNewCourseXBlockMock).toHaveBeenCalled(); expect(handleCreateNewCourseXBlockMock).toHaveBeenCalledWith({ type: COMPONENT_TYPES.libraryV2, parentLocator: '123', category: 'html', - libraryContentKey: 'test-usage-key', + libraryContentKey: usageKey, + }); + }); + + it('closes library component picker on close', async () => { + renderComponent(); + const libBtn = await screen.findByRole('button', { + name: new RegExp(`${messages.buttonText.defaultMessage} Library content`, 'i'), }); + userEvent.click(libBtn); + + expect(screen.queryByRole('button', { name: 'Dummy button' })).toBeInTheDocument(); + // click dummy button to execute onComponentSelected prop. + const closeBtn = await screen.findByRole('button', { name: 'Close' }); + userEvent.click(closeBtn); + + expect(screen.queryByRole('button', { name: 'Dummy button' })).not.toBeInTheDocument(); + }); + + it('shows component picker on window message', async () => { + renderComponent(); + const message = { + data: { + type: messageTypes.showMultipleComponentPicker, + }, + }; + // Dispatch showMultipleComponentPicker message event to open the picker modal. + act(() => { + window.dispatchEvent(new MessageEvent('message', message)); + }); + + // click dummy button to execute onChangeComponentSelection prop. + const dummyBtn = await screen.findByRole('button', { name: 'Dummy button' }); + userEvent.click(dummyBtn); + + const submitBtn = await screen.findByRole('button', { name: 'Add selected components' }); + userEvent.click(submitBtn); + + expect(mockSendMessageToIframe).toHaveBeenCalledWith( + messageTypes.addSelectedComponentsToBank, { + selectedComponents: [{ + blockType: "html", + usageKey, + }], + } + ); }); describe('component support label', () => {