diff --git a/src/editors/VideoSelector.test.tsx b/src/editors/VideoSelector.test.tsx
index 25b5b2d17..f839bf475 100644
--- a/src/editors/VideoSelector.test.tsx
+++ b/src/editors/VideoSelector.test.tsx
@@ -1,22 +1,9 @@
import React from 'react';
import * as reactRedux from 'react-redux';
-import { Provider } from 'react-redux';
import * as hooks from './hooks';
import VideoSelector from './VideoSelector';
-import { render as baseRender, initializeMocks, screen } from '../testUtils';
-
-import { EditorContextProvider } from './EditorContext';
-import editorStore from './data/store';
-
-const render = (ui) => baseRender(ui, {
- extraWrapper: ({ children }) => (
-
-
- {children}
-
-
- ),
-});
+import editorRender from './editorTestRender';
+import { initializeMocks, screen } from '../testUtils';
const defaultProps = {
blockId: 'block-v1:edX+DemoX+Demo_Course+type@html+block@030e35c4756a4ddc8d40b95fbbfff4d4',
@@ -32,7 +19,7 @@ describe('VideoSelector', () => {
test('renders VideoGallery when loading is false', () => {
jest.spyOn(hooks, 'useInitializeApp').mockReturnValue(false);
- render( );
+ editorRender( );
expect(screen.getByText('Add video to your course')).toBeInTheDocument();
});
@@ -40,7 +27,7 @@ describe('VideoSelector', () => {
// "testing the application components in the way the user would use it"
test('renders nothing when loading is true', () => {
jest.spyOn(hooks, 'useInitializeApp').mockReturnValue(true);
- render( );
+ editorRender( );
expect(screen.queryByText('Add video to your course')).not.toBeInTheDocument();
});
@@ -54,7 +41,7 @@ describe('VideoSelector', () => {
const mockDispatch = jest.fn();
jest.spyOn(reactRedux, 'useDispatch').mockReturnValue(mockDispatch);
jest.spyOn(hooks, 'useInitializeApp');
- render( );
+ editorRender( );
expect(hooks.useInitializeApp).toHaveBeenCalledWith({
dispatch: mockDispatch,
data: initData,
diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswersContainer.test.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswersContainer.test.jsx
deleted file mode 100644
index c52933af2..000000000
--- a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswersContainer.test.jsx
+++ /dev/null
@@ -1,165 +0,0 @@
-/* eslint-disable react/prop-types */
-import 'CourseAuthoring/editors/setupEditorTest';
-import React from 'react';
-import { shallow } from '@edx/react-unit-test-utils';
-import { act, render, waitFor } from '@testing-library/react';
-
-import { actions, selectors } from '../../../../../data/redux';
-
-import { AnswersContainerInternal as AnswersContainer, mapStateToProps, mapDispatchToProps } from './AnswersContainer';
-import { ProblemTypeKeys } from '../../../../../data/constants/problem';
-
-jest.mock('@edx/frontend-platform/i18n', () => ({
- FormattedMessage: ({ defaultMessage }) => (
{defaultMessage}
),
- defineMessages: m => m,
- injectIntl: (args) => args,
- intlShape: {},
- getLocale: jest.fn(),
-}));
-
-jest.mock('./AnswerOption', () => function mockAnswerOption() {
- return MockAnswerOption
;
-});
-
-jest.mock('../../../../../data/redux', () => ({
- actions: {
- problem: {
- updateField: jest.fn().mockName('actions.problem.updateField'),
- addAnswer: jest.fn().mockName('actions.problem.addAnswer'),
- },
- },
- selectors: {
- problem: {
- answers: jest.fn(state => ({ answers: state })),
- },
- },
-}));
-describe('AnswersContainer', () => {
- const props = {
- answers: [],
- updateField: jest.fn(),
- addAnswer: jest.fn(),
- };
- describe('render', () => {
- test('snapshot: renders correct default', () => {
- act(() => {
- expect(shallow( ).snapshot).toMatchSnapshot();
- });
- });
- test('snapshot: renders correctly with answers', () => {
- act(() => {
- expect(shallow(
- ,
- ).snapshot).toMatchSnapshot();
- });
- });
- test('snapshot: numeric problems: answer range/answer select button: empty', () => {
- act(() => {
- const emptyAnswerProps = {
- problemType: ProblemTypeKeys.NUMERIC,
- answers: [],
- updateField: jest.fn(),
- addAnswer: jest.fn(),
- addAnswerRange: jest.fn(),
- };
- expect(shallow(
- ,
- ).snapshot).toMatchSnapshot();
- });
- });
- test('snapshot: numeric problems: answer range/answer select button: Range disables the additon of more adds', () => {
- act(() => {
- const answerRangeProps = {
- problemType: ProblemTypeKeys.NUMERIC,
- answers: [{
- id: 'A',
- title: 'Answer 1',
- correct: true,
- selectedFeedback: 'selected feedback',
- unselectedFeedback: 'unselected feedback',
- isAnswerRange: true,
- }],
- updateField: jest.fn(),
- addAnswer: jest.fn(),
- addAnswerRange: jest.fn(),
- };
- expect(shallow(
- ,
- ).snapshot).toMatchSnapshot();
- });
- });
- test('snapshot: numeric problems: answer range/answer select button: multiple answers disables range.', () => {
- act(() => {
- const answersProps = {
- problemType: ProblemTypeKeys.NUMERIC,
- answers: [{
- id: 'A',
- title: 'Answer 1',
- correct: true,
- selectedFeedback: 'selected feedback',
- unselectedFeedback: 'unselected feedback',
- isAnswerRange: false,
- },
- {
- id: 'B',
- title: 'Answer 1',
- correct: true,
- selectedFeedback: 'selected feedback',
- unselectedFeedback: 'unselected feedback',
- isAnswerRange: false,
- },
- ],
- updateField: jest.fn(),
- addAnswer: jest.fn(),
- addAnswerRange: jest.fn(),
- };
- expect(shallow(
- ,
- ).snapshot).toMatchSnapshot();
- });
- });
-
- test('useAnswerContainer', async () => {
- let container = null;
- await act(async () => {
- const wrapper = render(
- ,
- );
- container = wrapper.container;
- });
-
- await waitFor(() => expect(container.querySelector('button')).toBeTruthy());
- await new Promise(resolve => { setTimeout(resolve, 500); });
-
- expect(props.updateField).toHaveBeenCalledWith(expect.objectContaining({ correctAnswerCount: 2 }));
- });
- });
- describe('mapStateToProps', () => {
- const testState = { A: 'pple', B: 'anana', C: 'ucumber' };
- test('answers from problem.answers', () => {
- expect(
- mapStateToProps(testState).answers,
- ).toEqual(selectors.problem.answers(testState));
- });
- });
- describe('mapDispatchToProps', () => {
- test('updateField from actions.problem.updateField', () => {
- expect(mapDispatchToProps.updateField).toEqual(actions.problem.updateField);
- });
- test('updateField from actions.problem.addAnswer', () => {
- expect(mapDispatchToProps.addAnswer).toEqual(actions.problem.addAnswer);
- });
- });
-});
diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswersContainer.test.tsx b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswersContainer.test.tsx
new file mode 100644
index 000000000..69e9d23e1
--- /dev/null
+++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswersContainer.test.tsx
@@ -0,0 +1,65 @@
+import React from 'react';
+import {
+ render, screen, fireEvent, initializeMocks,
+} from '../../../../../../testUtils';
+import { AnswersContainerInternal as AnswersContainer } from './AnswersContainer';
+import { ProblemTypeKeys } from '../../../../../data/constants/problem';
+
+const { useAnswerContainer } = require('./hooks');
+
+jest.mock('./AnswerOption', () => jest.fn(({ answer }) => AnswerOption-{answer.id}
));
+jest.mock(
+ '../../../../../sharedComponents/Button',
+ () => jest.fn(({ children, ...props }) => {children} ),
+);
+
+jest.mock('./hooks', () => ({
+ useAnswerContainer: jest.fn(),
+ isSingleAnswerProblem: jest.fn(() => false),
+}));
+
+describe('AnswersContainer', () => {
+ const defaultProps = {
+ problemType: 'multiple_choice',
+ answers: [
+ { id: 'a1', isAnswerRange: false },
+ { id: 'a2', isAnswerRange: false },
+ ],
+ addAnswer: jest.fn(),
+ addAnswerRange: jest.fn(),
+ updateField: jest.fn(),
+ };
+
+ beforeEach(() => {
+ initializeMocks();
+ });
+
+ it('renders AnswerOption for each answer', () => {
+ render( );
+ expect(screen.getByText('AnswerOption-a1')).toBeInTheDocument();
+ expect(screen.getByText('AnswerOption-a2')).toBeInTheDocument();
+ });
+
+ it('renders add answer Button for non-NUMERIC problemType and calls addAnswer on click', () => {
+ render( );
+ const button = screen.getByRole('button', { name: 'Add answer' });
+ expect(button).toBeInTheDocument();
+ fireEvent.click(button);
+ expect(defaultProps.addAnswer).toHaveBeenCalled();
+ });
+
+ it('renders Dropdown for NUMERIC problemType', () => {
+ render( );
+ expect(screen.getByRole('button', { name: 'Add answer' })).toBeInTheDocument();
+ expect(screen.getByText('Add answer').closest('.dropdown')).toBeInTheDocument();
+ });
+
+ it('calls useAnswerContainer with correct args', () => {
+ render( );
+ expect(useAnswerContainer).toHaveBeenCalledWith({
+ answers: defaultProps.answers,
+ problemType: defaultProps.problemType,
+ updateField: defaultProps.updateField,
+ });
+ });
+});
diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/__snapshots__/AnswersContainer.test.jsx.snap b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/__snapshots__/AnswersContainer.test.jsx.snap
deleted file mode 100644
index 9977f0dac..000000000
--- a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/__snapshots__/AnswersContainer.test.jsx.snap
+++ /dev/null
@@ -1,238 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`AnswersContainer render snapshot: numeric problems: answer range/answer select button: Range disables the additon of more adds 1`] = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`AnswersContainer render snapshot: numeric problems: answer range/answer select button: empty 1`] = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`AnswersContainer render snapshot: numeric problems: answer range/answer select button: multiple answers disables range. 1`] = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`AnswersContainer render snapshot: renders correct default 1`] = `
-
-
-
-
-
-`;
-
-exports[`AnswersContainer render snapshot: renders correctly with answers 1`] = `
-
-
-
-
-
-
-
-`;
diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeRow.test.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeRow.test.jsx
deleted file mode 100644
index 3902fd965..000000000
--- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeRow.test.jsx
+++ /dev/null
@@ -1,60 +0,0 @@
-import 'CourseAuthoring/editors/setupEditorTest';
-import React from 'react';
-import { shallow } from '@edx/react-unit-test-utils';
-import TypeRow from './TypeRow';
-import { typeRowHooks } from '../hooks';
-
-jest.mock('../hooks', () => ({
- typeRowHooks: jest.fn(),
-}));
-
-describe('TypeRow', () => {
- const typeKey = 'TEXTINPUT';
- const props = {
- answers: [],
- blockTitle: 'bLoCkTiTLE',
- correctAnswerCount: 0,
- typeKey,
- label: 'Text Input Problem',
- selected: true,
- lastRow: false,
- problemType: 'prOBlEMtyPE',
- setBlockTitle: jest.fn().mockName('args.setBlockTitle'),
- updateField: jest.fn().mockName('args.updateField'),
- updateAnswer: jest.fn().mockName('args.updateAnswer'),
- };
-
- const typeRowHooksProps = {
- onClick: jest.fn().mockName('typeRowHooks.onClick'),
- };
-
- typeRowHooks.mockReturnValue(typeRowHooksProps);
-
- describe('behavior', () => {
- it(' calls typeRowHooks when initialized', () => {
- shallow( );
- expect(typeRowHooks).toHaveBeenCalledWith({
- answers: props.answers,
- blockTitle: props.blockTitle,
- correctAnswerCount: props.correctAnswerCount,
- problemType: props.problemType,
- typeKey,
- setBlockTitle: props.setBlockTitle,
- updateField: props.updateField,
- updateAnswer: props.updateAnswer,
- });
- });
- });
-
- describe('snapshot', () => {
- test('snapshot: renders type row setting card', () => {
- expect(shallow( ).snapshot).toMatchSnapshot();
- });
- test('snapshot: renders type row setting card not selected', () => {
- expect(shallow( ).snapshot).toMatchSnapshot();
- });
- test('snapshot: renders type row setting card last row', () => {
- expect(shallow( ).snapshot).toMatchSnapshot();
- });
- });
-});
diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeRow.test.tsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeRow.test.tsx
new file mode 100644
index 000000000..32e887bbd
--- /dev/null
+++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeRow.test.tsx
@@ -0,0 +1,68 @@
+import React from 'react';
+import {
+ render, screen, fireEvent, initializeMocks,
+} from '../../../../../../../testUtils';
+import TypeRow from './TypeRow';
+
+const mockOnClick = jest.fn();
+jest.mock('../hooks', () => ({
+ typeRowHooks: () => ({ onClick: mockOnClick }),
+}));
+
+const defaultProps = {
+ answers: [
+ {
+ correct: true, id: '1', selectedFeedback: 'Good', title: 'A', unselectedFeedback: 'Try again',
+ },
+ {
+ correct: false, id: '2', selectedFeedback: 'No', title: 'B', unselectedFeedback: 'Nope',
+ },
+ ],
+ blockTitle: 'Block Title',
+ correctAnswerCount: 1,
+ typeKey: 'multiple_choice',
+ label: 'Multiple Choice',
+ selected: false,
+ lastRow: false,
+ problemType: 'choice',
+ setBlockTitle: jest.fn(),
+ updateField: jest.fn(),
+ updateAnswer: jest.fn(),
+};
+
+describe('TypeRow Component', () => {
+ beforeEach(() => {
+ initializeMocks();
+ });
+
+ test('renders label and Check icon when not selected', () => {
+ const { container } = render( );
+ expect(screen.getByText('Multiple Choice')).toBeInTheDocument();
+ const icon = container.querySelector('svg');
+ expect(icon).toBeInTheDocument();
+ expect(icon?.parentElement).toHaveClass('text-success');
+ });
+
+ test('calls onClick from typeRowHooks when Button is clicked', () => {
+ render( );
+ const button = screen.getByRole('button');
+ fireEvent.click(button);
+ expect(mockOnClick).toHaveBeenCalled();
+ });
+
+ test('renders with minimal valid props', () => {
+ const minimalProps = {
+ ...defaultProps,
+ answers: [],
+ blockTitle: '',
+ correctAnswerCount: 0,
+ typeKey: 'short_answer',
+ label: 'Short Answer',
+ selected: false,
+ lastRow: false,
+ problemType: 'short',
+ };
+ render( );
+ expect(screen.getByText('Short Answer')).toBeInTheDocument();
+ });
+});
diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/TypeRow.test.jsx.snap b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/TypeRow.test.jsx.snap
deleted file mode 100644
index af70e8dfd..000000000
--- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/TypeRow.test.jsx.snap
+++ /dev/null
@@ -1,82 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`TypeRow snapshot snapshot: renders type row setting card 1`] = `
-
-
-
- Text Input Problem
-
-
-
-
-
-
-
-`;
-
-exports[`TypeRow snapshot snapshot: renders type row setting card last row 1`] = `
-
-
-
- Text Input Problem
-
-
-
-
-
-
-
-`;
-
-exports[`TypeRow snapshot snapshot: renders type row setting card not selected 1`] = `
-
-
-
- Text Input Problem
-
-
-
-
-
-
-
-`;
diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/index.test.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/index.test.jsx
index 5232c7b31..18c58fc53 100644
--- a/src/editors/containers/ProblemEditor/components/EditProblemView/index.test.jsx
+++ b/src/editors/containers/ProblemEditor/components/EditProblemView/index.test.jsx
@@ -1,12 +1,8 @@
import React from 'react';
-import { Provider } from 'react-redux';
-import {
- render as baseRender, screen, fireEvent, initializeMocks,
-} from '../../../../../testUtils';
+import { screen, fireEvent, initializeMocks } from '../../../../../testUtils';
+import editorRender from '../../../../editorTestRender';
import { EditProblemViewInternal, mapStateToProps } from './index';
import { ProblemTypeKeys } from '../../../../data/constants/problem';
-import { EditorContextProvider } from '../../../../EditorContext';
-import editorStore from '../../../../data/store';
import { selectors } from '../../../../data/redux';
const { saveBlock } = require('../../../../hooks');
@@ -44,16 +40,6 @@ jest.mock('./hooks', () => ({
getContent: jest.fn(() => 'content'),
}));
-const render = (ui) => baseRender(ui, {
- extraWrapper: ({ children }) => (
-
-
- {children}
-
-
- ),
-});
-
describe('EditProblemView', () => {
const baseProps = {
problemType: 'standard',
@@ -71,7 +57,7 @@ describe('EditProblemView', () => {
});
it('renders standard problem widgets', () => {
- render( );
+ editorRender( );
expect(screen.getByText('QuestionWidget')).toBeInTheDocument();
expect(screen.getByText('ExplanationWidget')).toBeInTheDocument();
expect(screen.getByText('AnswerWidget')).toBeInTheDocument();
@@ -81,23 +67,23 @@ describe('EditProblemView', () => {
});
it('renders advanced problem with RawEditor', () => {
- render( );
+ editorRender( );
expect(screen.getByText('xml: ')).toBeInTheDocument();
expect(screen.getByText('SettingsWidget')).toBeInTheDocument();
});
it('renders markdown editor with RawEditor', () => {
- render( );
+ editorRender( );
expect(screen.getByText('markdown:## Problem')).toBeInTheDocument();
});
it('shows AlertModal with correct title/body for standard', () => {
- render( );
+ editorRender( );
expect(screen.getAllByText('No correct answer has been specified.').length).toBeGreaterThan(0);
});
it('calls saveBlock when save button is clicked', () => {
- render( );
+ editorRender( );
const saveBtn = screen.getByRole('button', { name: 'Ok' });
fireEvent.click(saveBtn);
expect(saveBlock).toHaveBeenCalled();
@@ -110,7 +96,7 @@ describe('EditProblemView', () => {
openSaveWarningModal: jest.fn(),
closeSaveWarningModal,
});
- render( );
+ editorRender( );
const cancelBtn = screen.getByRole('button', { name: 'Cancel' });
fireEvent.click(cancelBtn);
expect(closeSaveWarningModal).toHaveBeenCalled();
diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/index.test.tsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/index.test.tsx.snap
deleted file mode 100644
index 44c699487..000000000
--- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/index.test.tsx.snap
+++ /dev/null
@@ -1,61 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`SelectTypeWrapper snapshot 1`] = `
-
-
-
-
-
-
-
-
-
-
-
- test child
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/index.test.tsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/index.test.tsx
index 8ac745605..155afb94d 100644
--- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/index.test.tsx
+++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/index.test.tsx
@@ -1,34 +1,85 @@
-import 'CourseAuthoring/editors/setupEditorTest';
import React from 'react';
-import { shallow } from '@edx/react-unit-test-utils';
-import { IconButton } from '@openedx/paragon';
-import SelectTypeWrapper from '.';
-import { handleCancel } from '../../../../EditorContainer/hooks';
-
-jest.mock('../../../../EditorContainer/hooks', () => ({
- handleCancel: jest.fn().mockName('handleCancel'),
-}));
+import {
+ screen, fireEvent, initializeMocks,
+} from '../../../../../../testUtils';
+import editorRender from '../../../../../editorTestRender';
+import SelectTypeWrapper from './index';
+import * as hooks from '../hooks';
describe('SelectTypeWrapper', () => {
- const props = {
- children: (test child ),
- onClose: jest.fn(),
- selected: 'iMAsElecTedValUE',
- };
+ const mockOnClose = jest.fn();
- test('snapshot', () => {
- expect(shallow( ).snapshot).toMatchSnapshot();
+ beforeEach(() => {
+ initializeMocks();
});
- describe('behavior', () => {
- let el;
- beforeEach(() => {
- el = shallow( );
- });
- test('close behavior is linked to modal onClose', () => {
- const expected = handleCancel({ onClose: props.onClose });
- expect(el.instance.findByType(IconButton)[0].props.onClick)
- .toEqual(expected);
- });
+ it('renders component with provided content', () => {
+ editorRender(
+
+ Child Content
+ ,
+ );
+ expect(screen.getByText('Child Content')).toBeInTheDocument();
+ });
+
+ it('calls onClose when close button is clicked', () => {
+ editorRender(
+
+
+ ,
+ );
+ fireEvent.click(screen.getByLabelText('Exit the editor'));
+ expect(mockOnClose).toHaveBeenCalled();
+ });
+
+ it('calls onClose when cancel button is clicked', () => {
+ editorRender(
+
+
+ ,
+ );
+ fireEvent.click(screen.getByRole('button', { name: 'Cancel' }));
+ expect(mockOnClose).toHaveBeenCalled();
+ });
+
+ it('calls hooks.onSelect with correct args when select button is clicked', () => {
+ const onSelectMock = jest.fn();
+ jest.spyOn(hooks, 'onSelect').mockImplementation(onSelectMock);
+
+ editorRender(
+
+
+ ,
+ );
+ fireEvent.click(screen.getByRole('button', { name: 'Select' }));
+ expect(hooks.onSelect).toHaveBeenCalledWith(
+ expect.objectContaining({
+ selected: 'foo',
+ updateField: expect.any(Function),
+ setBlockTitle: expect.any(Function),
+ defaultSettings: expect.any(Object),
+ }),
+ );
+ expect(onSelectMock).toHaveBeenCalled();
+ });
+
+ it('disables select button when selected is empty', () => {
+ editorRender(
+
+
+ ,
+ );
+ const selectBtn = screen.getByRole('button', { name: 'Select' });
+ expect(selectBtn).toBeDisabled();
+ });
+
+ it('enables select button when selected is not empty', () => {
+ editorRender(
+
+
+ ,
+ );
+ const selectBtn = screen.getByRole('button', { name: 'Select' });
+ expect(selectBtn).not.toBeDisabled();
});
});
diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/Preview.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/Preview.jsx
index 7077c18a5..71698b941 100644
--- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/Preview.jsx
+++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/Preview.jsx
@@ -3,17 +3,15 @@ import PropTypes from 'prop-types';
import { Hyperlink, Image, Container } from '@openedx/paragon';
import {
FormattedMessage,
- injectIntl,
- intlShape,
+ useIntl,
} from '@edx/frontend-platform/i18n';
import messages from './messages';
import { ProblemTypes } from '../../../../../data/constants/problem';
const Preview = ({
problemType,
- // injected
- intl,
}) => {
+ const intl = useIntl();
if (problemType === null) {
return null;
}
@@ -48,9 +46,6 @@ Preview.defaultProps = {
Preview.propTypes = {
problemType: PropTypes.string,
- // injected
- intl: intlShape.isRequired,
};
-export const PreviewInternal = Preview; // For testing only
-export default injectIntl(Preview);
+export default Preview;
diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/Preview.test.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/Preview.test.jsx
deleted file mode 100644
index 36cf961fc..000000000
--- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/Preview.test.jsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import 'CourseAuthoring/editors/setupEditorTest';
-import React from 'react';
-import { shallow } from '@edx/react-unit-test-utils';
-
-import { formatMessage } from '../../../../../testUtils';
-import { PreviewInternal as Preview } from './Preview';
-
-describe('Preview', () => {
- const props = {
- intl: { formatMessage },
- problemType: null,
- };
- describe('snapshots', () => {
- test('snapshots: renders as expected with default props', () => {
- expect(
- shallow( ).snapshot,
- ).toMatchSnapshot();
- });
- test('snapshots: renders as expected with problemType is stringresponse', () => {
- expect(
- shallow( ).snapshot,
- ).toMatchSnapshot();
- });
- test('snapshots: renders as expected with problemType is numericalresponse', () => {
- expect(
- shallow( ).snapshot,
- ).toMatchSnapshot();
- });
- test('snapshots: renders as expected with problemType is optionresponse', () => {
- expect(
- shallow( ).snapshot,
- ).toMatchSnapshot();
- });
- test('snapshots: renders as expected with problemType is choiceresponse', () => {
- expect(
- shallow( ).snapshot,
- ).toMatchSnapshot();
- });
- test('snapshots: renders as expected with problemType is multiplechoiceresponse', () => {
- expect(
- shallow( ).snapshot,
- ).toMatchSnapshot();
- });
- });
-});
diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/Preview.test.tsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/Preview.test.tsx
new file mode 100644
index 000000000..acb338435
--- /dev/null
+++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/Preview.test.tsx
@@ -0,0 +1,48 @@
+import React from 'react';
+import { render, screen, initializeMocks } from '../../../../../../testUtils';
+import Preview from './Preview';
+
+// Mock ProblemTypes and messages
+jest.mock('../../../../../data/constants/problem', () => ({
+ ProblemTypes: {
+ example: {
+ title: 'Example Title',
+ preview: 'example.png',
+ previewDescription: 'Example description',
+ helpLink: 'https://help.example.com',
+ },
+ },
+}));
+
+describe('Preview', () => {
+ beforeEach(() => {
+ initializeMocks();
+ });
+
+ it('renders nothing if problemType is null', () => {
+ const { container } = render( );
+ const reduxProviderDiv = container.querySelector('div[data-testid="redux-provider"]');
+ expect(reduxProviderDiv?.innerHTML).toBe('');
+ });
+
+ it('renders preview with correct data for a valid problemType', () => {
+ render( );
+ expect(screen.getByText('Example Title problem')).toBeInTheDocument();
+ expect(screen.getByText('Example description')).toBeInTheDocument();
+ expect(screen.getByRole('img')).toHaveAttribute('src', 'example.png');
+ expect(screen.getByRole('img')).toHaveAttribute('alt', 'A preview illustration of a null problem');
+ expect(screen.getByRole('link', { name: 'Learn more in a new tab' })).toHaveAttribute('href', 'https://help.example.com');
+ });
+
+ it('renders the help link with target="_blank"', () => {
+ render( );
+ const link = screen.getByRole('link', { name: 'Learn more in a new tab' });
+ expect(link).toHaveAttribute('target', '_blank');
+ });
+
+ it('renders the correct title and description', () => {
+ render( );
+ expect(screen.getByText('Example Title problem')).toBeInTheDocument();
+ expect(screen.getByText('Example description')).toBeInTheDocument();
+ });
+});
diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/Preview.test.jsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/Preview.test.jsx.snap
deleted file mode 100644
index 4bd50f084..000000000
--- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/Preview.test.jsx.snap
+++ /dev/null
@@ -1,233 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Preview snapshots snapshots: renders as expected with default props 1`] = `null`;
-
-exports[`Preview snapshots snapshots: renders as expected with problemType is choiceresponse 1`] = `
-
-
- Multi-select problem
-
-
-
- Learners must select all correct answers from a list of possible options.
-
-
-
-
-
-`;
-
-exports[`Preview snapshots snapshots: renders as expected with problemType is multiplechoiceresponse 1`] = `
-
-
- Single select problem
-
-
-
- Learners must select the correct answer from a list of possible options.
-
-
-
-
-
-`;
-
-exports[`Preview snapshots snapshots: renders as expected with problemType is numericalresponse 1`] = `
-
-
- Numerical input problem
-
-
-
- Specify one or more correct numeric answers, submitted in a response field.
-
-
-
-
-
-`;
-
-exports[`Preview snapshots snapshots: renders as expected with problemType is optionresponse 1`] = `
-
-
- Dropdown problem
-
-
-
- Learners must select the correct answer from a list of possible options
-
-
-
-
-
-`;
-
-exports[`Preview snapshots snapshots: renders as expected with problemType is stringresponse 1`] = `
-
-
- Text input problem
-
-
-
- Specify one or more correct text answers, including numbers and special characters, submitted in a response field.
-
-
-
-
-
-`;
diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.test.tsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.test.tsx
index 2cef8c36b..ade0843a0 100644
--- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.test.tsx
+++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.test.tsx
@@ -1,12 +1,9 @@
-import { Provider } from 'react-redux';
import {
fireEvent,
- render,
screen,
initializeMocks,
} from '../../../../../testUtils';
-import editorStore from '../../../../data/store';
-import { EditorContextProvider } from '../../../../EditorContext';
+import editorRender from '../../../../editorTestRender';
import * as hooks from './hooks';
import SelectTypeModal from '.';
@@ -19,12 +16,8 @@ describe('SelectTypeModal', () => {
const mockSelect = jest.fn();
jest.spyOn(hooks, 'onSelect').mockImplementation(mockSelect);
// This is a new-style test, unlike most of the old snapshot-based editor tests.
- render(
-
-
-
-
- ,
+ editorRender(
+ ,
);
// First we see the menu of problem types:
diff --git a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/LicenseWidget/LicenseDisplay.jsx b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/LicenseWidget/LicenseDisplay.jsx
index a67d40607..52f4b3e0a 100644
--- a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/LicenseWidget/LicenseDisplay.jsx
+++ b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/LicenseWidget/LicenseDisplay.jsx
@@ -3,7 +3,6 @@ import PropTypes from 'prop-types';
import {
FormattedMessage,
- injectIntl,
} from '@edx/frontend-platform/i18n';
import {
Stack,
@@ -55,5 +54,4 @@ LicenseDisplay.propTypes = {
licenseDescription: PropTypes.string.isRequired,
};
-export const LicenseDisplayInternal = LicenseDisplay; // For testing only
-export default injectIntl(LicenseDisplay);
+export default LicenseDisplay;
diff --git a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/LicenseWidget/LicenseDisplay.test.jsx b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/LicenseWidget/LicenseDisplay.test.jsx
deleted file mode 100644
index 111169499..000000000
--- a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/LicenseWidget/LicenseDisplay.test.jsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import 'CourseAuthoring/editors/setupEditorTest';
-import React from 'react';
-import { shallow } from '@edx/react-unit-test-utils';
-
-import { LicenseDisplayInternal as LicenseDisplay } from './LicenseDisplay';
-
-jest.mock('react', () => ({
- ...jest.requireActual('react'),
- useContext: jest.fn(() => ({ license: ['error.license', jest.fn().mockName('error.setLicense')] })),
-}));
-
-describe('LicenseDisplay', () => {
- const props = {
- license: 'all-rights-reserved',
- details: {},
- licenseDescription: 'FormattedMessage component with license description',
- level: 'course',
- };
-
- describe('snapshots', () => {
- test('snapshots: renders as expected with default props', () => {
- expect(
- shallow( ).snapshot,
- ).toMatchSnapshot();
- });
- test('snapshots: renders as expected with level set to library', () => {
- expect(
- shallow( ).snapshot,
- ).toMatchSnapshot();
- });
- test('snapshots: renders as expected with level set to block', () => {
- expect(
- shallow( ).snapshot,
- ).toMatchSnapshot();
- });
- test('snapshots: renders as expected with level set to block and license set to select', () => {
- expect(
- shallow( ).snapshot,
- ).toMatchSnapshot();
- });
- test('snapshots: renders as expected with level set to block and license set to Creative Commons', () => {
- expect(
- shallow( ).snapshot,
- ).toMatchSnapshot();
- });
- });
-});
diff --git a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/LicenseWidget/LicenseDisplay.test.tsx b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/LicenseWidget/LicenseDisplay.test.tsx
new file mode 100644
index 000000000..30968f7c8
--- /dev/null
+++ b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/LicenseWidget/LicenseDisplay.test.tsx
@@ -0,0 +1,75 @@
+import React from 'react';
+import { initializeMocks, render, screen } from '../../../../../../../testUtils';
+import LicenseDisplay from './LicenseDisplay';
+
+jest.mock('../../../../../../data/constants/licenses', () => ({
+ LicenseTypes: {
+ select: 'select',
+ creativeCommons: 'creativeCommons',
+ proprietary: 'proprietary',
+ },
+}));
+
+const defaultDetails = {
+ attribution: true,
+ noncommercial: false,
+ noDerivatives: false,
+ shareAlike: false,
+};
+
+describe('LicenseDisplay', () => {
+ beforeEach(() => {
+ initializeMocks();
+ });
+ it('renders nothing if license is select', () => {
+ const { container } = render(
+ ,
+ );
+ const reduxProviderDiv = container.querySelector('div[data-testid="redux-provider"]');
+ expect(reduxProviderDiv?.innerHTML).toBe('');
+ });
+
+ it('renders displaySubsectionTitle and licenseDescription for non-select license', () => {
+ render(
+ ,
+ );
+ expect(screen.getByText('License Display')).toBeInTheDocument();
+ expect(screen.getByText('Proprietary license description')).toBeInTheDocument();
+ });
+
+ it('renders Hyperlink for creativeCommons license', () => {
+ render(
+ ,
+ );
+ const link = screen.getByRole('link', { name: 'View license details in a new tab' });
+ expect(link).toHaveAttribute('href', 'https://creativecommons.org/about');
+ expect(link).toHaveAttribute('target', '_blank');
+ });
+
+ it('does not render Hyperlink for non-creativeCommons license', () => {
+ render(
+ ,
+ );
+ expect(screen.queryByRole('link', { name: 'View Details' })).toBeNull();
+ });
+});
diff --git a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/LicenseWidget/__snapshots__/LicenseDisplay.test.jsx.snap b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/LicenseWidget/__snapshots__/LicenseDisplay.test.jsx.snap
deleted file mode 100644
index 655802d54..000000000
--- a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/LicenseWidget/__snapshots__/LicenseDisplay.test.jsx.snap
+++ /dev/null
@@ -1,130 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`LicenseDisplay snapshots snapshots: renders as expected with default props 1`] = `
-
-
-
-
-
-
-
- FormattedMessage component with license description
-
-
-
-`;
-
-exports[`LicenseDisplay snapshots snapshots: renders as expected with level set to block 1`] = `
-
-
-
-
-
-
-
- FormattedMessage component with license description
-
-
-
-`;
-
-exports[`LicenseDisplay snapshots snapshots: renders as expected with level set to block and license set to Creative Commons 1`] = `
-
-
-
-
-
-
-
- FormattedMessage component with license description
-
-
-
-
-
-
-`;
-
-exports[`LicenseDisplay snapshots snapshots: renders as expected with level set to block and license set to select 1`] = `null`;
-
-exports[`LicenseDisplay snapshots snapshots: renders as expected with level set to library 1`] = `
-
-
-
-
-
-
-
- FormattedMessage component with license description
-
-
-
-`;
diff --git a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/LicenseWidget/__snapshots__/index.test.jsx.snap b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/LicenseWidget/__snapshots__/index.test.jsx.snap
index cfc25e06a..d63bc7705 100644
--- a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/LicenseWidget/__snapshots__/index.test.jsx.snap
+++ b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/LicenseWidget/__snapshots__/index.test.jsx.snap
@@ -34,7 +34,7 @@ exports[`LicenseWidget snapshots snapshots: renders as expected with default pro
level="course"
license="all-rights-reserved"
/>
-
-
- baseRender(ui, {
+ extraWrapper: ({ children }) => (
+
+
+ {children}
+
+
+ ),
+});
+
+export default editorRender;