diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.jsx index cbe42ee20c..fca62c9619 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.jsx @@ -1,6 +1,5 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; +import { useSelector } from 'react-redux'; import { useIntl, FormattedMessage } from '@edx/frontend-platform/i18n'; import { getConfig } from '@edx/frontend-platform'; @@ -9,27 +8,31 @@ import messages from './messages'; import TinyMceWidget from '../../../../../sharedComponents/TinyMceWidget'; import { prepareEditorRef, replaceStaticWithAsset } from '../../../../../sharedComponents/TinyMceWidget/hooks'; -const ExplanationWidget = ({ - // redux - settings, - learningContextId, - images, - isLibrary, - blockId, -}) => { +const ExplanationWidget = () => { const intl = useIntl(); const { editorRef, refReady, setEditorRef } = prepareEditorRef(); + + // Select state values using useSelector + const settings = useSelector(selectors.problem.settings); + const learningContextId = useSelector(selectors.app.learningContextId); + const images = useSelector(selectors.app.images); + const isLibrary = useSelector(selectors.app.isLibrary); + const blockId = useSelector(selectors.app.blockId); + const initialContent = settings?.solutionExplanation || ''; const newContent = replaceStaticWithAsset({ initialContent, learningContextId, }); const solutionContent = newContent || initialContent; + let staticRootUrl; if (isLibrary) { - staticRootUrl = `${getConfig().STUDIO_BASE_URL }/library_assets/blocks/${ blockId }/`; + staticRootUrl = `${getConfig().STUDIO_BASE_URL}/library_assets/blocks/${blockId}/`; } + if (!refReady) { return null; } + return (
@@ -57,22 +60,4 @@ const ExplanationWidget = ({ ); }; -ExplanationWidget.propTypes = { - // redux - // eslint-disable-next-line - settings: PropTypes.any.isRequired, - learningContextId: PropTypes.string.isRequired, - images: PropTypes.shape({}).isRequired, - isLibrary: PropTypes.bool.isRequired, - blockId: PropTypes.string.isRequired, -}; -export const mapStateToProps = (state) => ({ - settings: selectors.problem.settings(state), - learningContextId: selectors.app.learningContextId(state), - images: selectors.app.images(state), - isLibrary: selectors.app.isLibrary(state), - blockId: selectors.app.blockId(state), -}); - -export const ExplanationWidgetInternal = ExplanationWidget; // For testing only -export default connect(mapStateToProps)(ExplanationWidget); +export default ExplanationWidget; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.test.tsx b/src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.test.tsx index 616484ee81..9aa440d764 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.test.tsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.test.tsx @@ -1,27 +1,8 @@ import React from 'react'; -import { render, screen, initializeMocks } from '@src/testUtils'; -import ExplanationWidget from '.'; - -jest.mock('../../../../../data/redux', () => ({ - __esModule: true, - default: jest.fn(), - selectors: { - problem: { - settings: jest.fn(state => ({ question: state })), - }, - app: { - learningContextId: jest.fn(state => ({ learningContextId: state })), - images: jest.fn(state => ({ images: state })), - isLibrary: jest.fn(state => ({ isLibrary: state })), - blockId: jest.fn(state => ({ blockId: state })), - }, - }, - thunkActions: { - video: { - importTranscript: jest.fn(), - }, - }, -})); +import { screen, initializeMocks } from '@src/testUtils'; +import editorRender from '../../../../../modifiedEditorTestRender'; +import ExplanationWidget from './index'; +import { initializeStore } from '../../../../../data/redux'; jest.mock('../../../../../sharedComponents/TinyMceWidget/hooks', () => ({ ...jest.requireActual('../../../../../sharedComponents/TinyMceWidget/hooks'), @@ -36,19 +17,27 @@ jest.mock('../../../../../sharedComponents/TinyMceWidget', () => ({ default: () =>
TinyMceWidget
, })); -describe('SolutionWidget', () => { - const props = { +const initialState = { + problem: { settings: { solutionExplanation: 'This is my solution' }, + }, + app: { learningContextId: 'course+org+run', images: {}, isLibrary: false, blockId: 'block-v1:Org+TS100+24+type@html+block@12345', - }; + }, +}; + +describe('SolutionWidget', () => { beforeEach(() => { - initializeMocks(); + initializeMocks({ + initializeStore, + initialState, + }); }); test('renders correct default', () => { - render(); + editorRender(, { initialState }); expect(screen.getByText('Explanation')).toBeInTheDocument(); expect(screen.getByText('Provide an explanation for the correct answer')).toBeInTheDocument(); expect(screen.getByText('TinyMceWidget')).toBeInTheDocument(); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.jsx index f8020721a1..e2f5e4674e 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.jsx @@ -1,35 +1,40 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; +import { useSelector } from 'react-redux'; +import { useIntl, FormattedMessage } from '@edx/frontend-platform/i18n'; import { getConfig } from '@edx/frontend-platform'; import { selectors } from '../../../../../data/redux'; import messages from './messages'; import TinyMceWidget from '../../../../../sharedComponents/TinyMceWidget'; -import { prepareEditorRef, replaceStaticWithAsset } from '../../../../../sharedComponents/TinyMceWidget/hooks'; +import { + prepareEditorRef, + replaceStaticWithAsset, +} from '../../../../../sharedComponents/TinyMceWidget/hooks'; -const QuestionWidget = ({ - // redux - question, - learningContextId, - images, - isLibrary, - blockId, -}) => { +const QuestionWidget = () => { const intl = useIntl(); + const question = useSelector(selectors.problem.question); + const learningContextId = useSelector(selectors.app.learningContextId); + const images = useSelector(selectors.app.images); + const isLibrary = useSelector(selectors.app.isLibrary); + const blockId = useSelector(selectors.app.blockId); + const { editorRef, refReady, setEditorRef } = prepareEditorRef(); + const initialContent = question; const newContent = replaceStaticWithAsset({ initialContent, learningContextId, }); const questionContent = newContent || initialContent; + let staticRootUrl; if (isLibrary) { - staticRootUrl = `${getConfig().STUDIO_BASE_URL }/library_assets/blocks/${ blockId }/`; + staticRootUrl = `${getConfig().STUDIO_BASE_URL}/library_assets/blocks/${blockId}/`; } + if (!refReady) { return null; } + return (
@@ -54,21 +59,4 @@ const QuestionWidget = ({ ); }; -QuestionWidget.propTypes = { - // redux - question: PropTypes.string.isRequired, - learningContextId: PropTypes.string.isRequired, - images: PropTypes.shape({}).isRequired, - isLibrary: PropTypes.bool.isRequired, - blockId: PropTypes.string.isRequired, -}; -export const mapStateToProps = (state) => ({ - question: selectors.problem.question(state), - learningContextId: selectors.app.learningContextId(state), - images: selectors.app.images(state), - isLibrary: selectors.app.isLibrary(state), - blockId: selectors.app.blockId(state), -}); - -export const QuestionWidgetInternal = QuestionWidget; // For testing only -export default connect(mapStateToProps)(QuestionWidget); +export default QuestionWidget; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.test.tsx b/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.test.tsx index 886d7351e7..14bac35fa8 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.test.tsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.test.tsx @@ -1,33 +1,8 @@ import React from 'react'; -import { render, screen, initializeMocks } from '@src/testUtils'; -import { formatMessage } from '@src/editors/testUtils'; -import { QuestionWidgetInternal as QuestionWidget } from '.'; - -jest.mock('@src/editors/data/redux', () => ({ - __esModule: true, - default: jest.fn(), - actions: { - problem: { - updateQuestion: jest.fn().mockName('actions.problem.updateQuestion'), - }, - }, - selectors: { - app: { - learningContextId: jest.fn(state => ({ learningContextId: state })), - images: jest.fn(state => ({ images: state })), - isLibrary: jest.fn(state => ({ isLibrary: state })), - blockId: jest.fn(state => ({ blockId: state })), - }, - problem: { - question: jest.fn(state => ({ question: state })), - }, - }, - thunkActions: { - video: { - importTranscript: jest.fn(), - }, - }, -})); +import { screen, initializeMocks } from '@src/testUtils'; +import editorRender from '../../../../../modifiedEditorTestRender'; +import { initializeStore } from '../../../../../data/redux'; +import QuestionWidget from '.'; jest.mock('@src/editors/sharedComponents/TinyMceWidget/hooks', () => ({ ...jest.requireActual('../../../../../sharedComponents/TinyMceWidget/hooks'), @@ -39,23 +14,28 @@ jest.mock('@src/editors/sharedComponents/TinyMceWidget/hooks', () => ({ jest.mock('@src/editors/sharedComponents/TinyMceWidget', () => ('TinyMceWidget')); -describe('QuestionWidget', () => { - const props = { +const initialState = { + problem: { question: 'This is my question', - updateQuestion: jest.fn(), + }, + app: { learningContextId: 'course+org+run', images: {}, isLibrary: false, blockId: '', - // injected - intl: { formatMessage }, - }; + }, +}; + +describe('QuestionWidget', () => { + beforeEach(() => { + initializeMocks({ initialState, initializeStore }); + }); describe('render', () => { beforeEach(() => { initializeMocks(); }); test('renders correct default', () => { - render(); + editorRender(, { initialState }); expect(screen.getByText('Question')).toBeInTheDocument(); }); }); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/index.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/index.jsx index ded9e742c7..82fbdac6e7 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/index.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/index.jsx @@ -1,7 +1,8 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { FormattedMessage } from '@edx/frontend-platform/i18n'; -import { connect } from 'react-redux'; + +import { useDispatch, useSelector } from 'react-redux'; +import { injectIntl, FormattedMessage } from '@edx/frontend-platform/i18n'; import { Button, Collapsible, } from '@openedx/paragon'; @@ -17,44 +18,60 @@ import GroupFeedbackCard from './settingsComponents/GroupFeedback/index'; import SwitchEditorCard from './settingsComponents/SwitchEditorCard'; import messages from './messages'; import { showAdvancedSettingsCards } from './hooks'; - -import './index.scss'; import { ProblemTypeKeys } from '../../../../../data/constants/problem'; import Randomization from './settingsComponents/Randomization'; -// This widget should be connected, grab all settings from store, update them as needed. +import './index.scss'; + const SettingsWidget = ({ problemType, - // redux - answers, - groupFeedbackList, - blockTitle, - correctAnswerCount, - settings, - setBlockTitle, - updateSettings, - updateField, - updateAnswer, - defaultSettings, - images, - isLibrary, - learningContextId, - showMarkdownEditorButton, }) => { + const dispatch = useDispatch(); + const { + groupFeedbackList, + settings, + answers, + blockTitle, + correctAnswerCount, + defaultSettings, + images, + isLibrary, + learningContextId, + showMarkdownEditorButton, + } = useSelector((state) => ({ + groupFeedbackList: selectors.problem.groupFeedbackList(state), + settings: selectors.problem.settings(state), + answers: selectors.problem.answers(state), + blockTitle: selectors.app.blockTitle(state), + correctAnswerCount: selectors.problem.correctAnswerCount(state), + defaultSettings: selectors.problem.defaultSettings(state), + images: selectors.app.images(state), + isLibrary: selectors.app.isLibrary(state), + learningContextId: selectors.app.learningContextId(state), + showMarkdownEditorButton: selectors.app.isMarkdownEditorEnabledForCourse(state) + && selectors.problem.rawMarkdown(state), + })); + const { isAdvancedCardsVisible, showAdvancedCards } = showAdvancedSettingsCards(); + + const setBlockTitle = (title) => dispatch(actions.app.setBlockTitle(title)); + const updateSettings = (newSettings) => dispatch(actions.problem.updateSettings(newSettings)); + const updateField = (fieldName, value) => dispatch(actions.problem.updateField(fieldName, value)); + const updateAnswer = (index, update) => dispatch(actions.problem.updateAnswer(index, update)); + const feedbackCard = () => { - if ([ProblemTypeKeys.MULTISELECT].includes(problemType)) { + if (problemType === ProblemTypeKeys.MULTISELECT) { return ( -
+
+
); } - // eslint-disable-next-line react/jsx-no-useless-fragment - return (<>); + return null; }; return ( @@ -70,17 +87,18 @@ const SettingsWidget = ({ updateAnswer={updateAnswer} />
- {ProblemTypeKeys.NUMERIC === problemType - && ( -
- -
- )} + + {problemType === ProblemTypeKeys.NUMERIC && ( +
+ +
+ )} + {!isLibrary && (
)} +
+ {feedbackCard()} +
@@ -117,6 +136,7 @@ const SettingsWidget = ({
+ {!isLibrary && ( @@ -137,8 +157,7 @@ const SettingsWidget = ({ />
)} - { - problemType === ProblemTypeKeys.ADVANCED && ( + {problemType === ProblemTypeKeys.ADVANCED && (
- ) - } + )} {!isLibrary && (
- +
)}
- { showMarkdownEditorButton - && ( -
- -
+ {showMarkdownEditorButton && ( +
+ +
)} @@ -169,63 +189,8 @@ const SettingsWidget = ({ }; SettingsWidget.propTypes = { - answers: PropTypes.arrayOf(PropTypes.shape({ - correct: PropTypes.bool, - id: PropTypes.string, - selectedFeedback: PropTypes.string, - title: PropTypes.string, - unselectedFeedback: PropTypes.string, - })).isRequired, - groupFeedbackList: PropTypes.arrayOf( - PropTypes.shape( - { - id: PropTypes.number, - feedback: PropTypes.string, - answers: PropTypes.arrayOf(PropTypes.string), - }, - ), - ).isRequired, - blockTitle: PropTypes.string.isRequired, - correctAnswerCount: PropTypes.number.isRequired, problemType: PropTypes.string.isRequired, - setBlockTitle: PropTypes.func.isRequired, - updateAnswer: PropTypes.func.isRequired, - updateField: PropTypes.func.isRequired, - updateSettings: PropTypes.func.isRequired, - defaultSettings: PropTypes.shape({ - maxAttempts: PropTypes.number, - showanswer: PropTypes.string, - showResetButton: PropTypes.bool, - rerandomize: PropTypes.string, - }).isRequired, - images: PropTypes.shape({}).isRequired, - learningContextId: PropTypes.string.isRequired, - isLibrary: PropTypes.bool.isRequired, - // eslint-disable-next-line - settings: PropTypes.any.isRequired, - showMarkdownEditorButton: PropTypes.bool.isRequired, -}; - -const mapStateToProps = (state) => ({ - groupFeedbackList: selectors.problem.groupFeedbackList(state), - settings: selectors.problem.settings(state), - answers: selectors.problem.answers(state), - blockTitle: selectors.app.blockTitle(state), - correctAnswerCount: selectors.problem.correctAnswerCount(state), - defaultSettings: selectors.problem.defaultSettings(state), - images: selectors.app.images(state), - isLibrary: selectors.app.isLibrary(state), - learningContextId: selectors.app.learningContextId(state), - showMarkdownEditorButton: selectors.app.isMarkdownEditorEnabledForCourse(state) - && selectors.problem.rawMarkdown(state), -}); - -export const mapDispatchToProps = { - setBlockTitle: actions.app.setBlockTitle, - updateSettings: actions.problem.updateSettings, - updateField: actions.problem.updateField, - updateAnswer: actions.problem.updateAnswer, }; -export const SettingsWidgetInternal = SettingsWidget; // For testing only -export default connect(mapStateToProps, mapDispatchToProps)(SettingsWidget); +export const SettingsWidgetInternal = SettingsWidget; // For testing +export default injectIntl(SettingsWidget); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/index.test.tsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/index.test.tsx index f74b710a36..2cfc12bddb 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/index.test.tsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/index.test.tsx @@ -5,6 +5,7 @@ import { import * as hooks from './hooks'; import { SettingsWidgetInternal as SettingsWidget } from '.'; import { ProblemTypeKeys } from '../../../../../data/constants/problem'; +// import editorRender from '../../../../../modifiedEditorTestRender'; jest.mock('./settingsComponents/GeneralFeedback', () => 'GeneralFeedback'); jest.mock('./settingsComponents/GroupFeedback', () => 'GroupFeedback'); @@ -17,34 +18,63 @@ jest.mock('./settingsComponents/SwitchEditorCard', () => 'SwitchEditorCard'); jest.mock('./settingsComponents/TimerCard', () => 'TimerCard'); jest.mock('./settingsComponents/TypeCard', () => 'TypeCard'); +jest.mock('../../../../../data/redux', () => ({ + selectors: { + problem: { + groupFeedbackList: jest.fn(() => []), + settings: jest.fn(() => ({ + hints: [], + scoring: 'default', + showAnswer: 'finished', + showResetButton: false, + randomization: 'always', + tolerance: 0.1, + timeBetween: 0, + })), + answers: jest.fn(() => []), + correctAnswerCount: jest.fn(() => 0), + defaultSettings: jest.fn(() => ({ + maxAttempts: 2, + showanswer: 'finished', + showResetButton: false, + rerandomize: 'always', + })), + rawMarkdown: jest.fn(() => '## Sample markdown'), + }, + app: { + blockTitle: jest.fn(() => 'Sample Block Title'), + images: jest.fn(() => ({})), + isLibrary: jest.fn(() => false), + learningContextId: jest.fn(() => 'course+org+run'), + isMarkdownEditorEnabledForCourse: jest.fn(() => true), + }, + }, + actions: { + app: { + setBlockTitle: jest.fn(() => ({ type: 'MOCK_SET_BLOCK_TITLE' })), + }, + problem: { + updateSettings: jest.fn(() => ({ type: 'MOCK_UPDATE_SETTINGS' })), + updateField: jest.fn(() => ({ type: 'MOCK_UPDATE_FIELD' })), + updateAnswer: jest.fn(() => ({ type: 'MOCK_UPDATE_ANSWER' })), + }, + }, +})); + describe('SettingsWidget', () => { const showAdvancedSettingsCardsBaseProps = { isAdvancedCardsVisible: false, showAdvancedCards: jest.fn().mockName('showAdvancedSettingsCards.showAdvancedCards'), setResetTrue: jest.fn().mockName('showAdvancedSettingsCards.setResetTrue'), }; + // const showAdvancedSettingsCardsBaseProps = { + // isAdvancedCardsVisible: false, + // showAdvancedCards: jest.fn(), + // setResetTrue: jest.fn(), + // }; const props = { problemType: ProblemTypeKeys.TEXTINPUT, - settings: {}, - defaultSettings: { - maxAttempts: 2, - showanswer: 'finished', - showResetButton: false, - }, - images: {}, - isLibrary: false, - learningContextId: 'course+org+run', - setBlockTitle: jest.fn().mockName('setBlockTitle'), - blockTitle: '', - updateAnswer: jest.fn().mockName('updateAnswer'), - updateSettings: jest.fn().mockName('updateSettings'), - updateField: jest.fn().mockName('updateField'), - answers: [], - correctAnswerCount: 0, - groupFeedbackList: [], - showMarkdownEditorButton: false, - }; beforeEach(() => { @@ -115,7 +145,6 @@ describe('SettingsWidget', () => { const { container } = render(); expect(screen.queryByText('Show advanced settings')).not.toBeInTheDocument(); expect(container.querySelector('showanswearscard')).not.toBeInTheDocument(); - expect(container.querySelector('resetcard')).not.toBeInTheDocument(); expect(container.querySelector('typecard')).toBeInTheDocument(); expect(container.querySelector('hintscard')).toBeInTheDocument(); }); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ScoringCard.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ScoringCard.jsx index 6b12e552a2..e0e90f2a48 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ScoringCard.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ScoringCard.jsx @@ -1,7 +1,7 @@ import React from 'react'; import isNil from 'lodash/isNil'; import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; +import { useSelector } from 'react-redux'; import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; import { Form, Hyperlink } from '@openedx/paragon'; import { selectors } from '../../../../../../data/redux'; @@ -13,12 +13,14 @@ const ScoringCard = ({ scoring, defaultValue, updateSettings, - // redux - studioEndpointUrl, - learningContextId, - isLibrary, }) => { const intl = useIntl(); + + // Redux state + const studioEndpointUrl = useSelector(selectors.app.studioEndpointUrl); + const learningContextId = useSelector(selectors.app.learningContextId); + const isLibrary = useSelector(selectors.app.isLibrary); + const { handleUnlimitedChange, handleMaxAttemptChange, @@ -92,27 +94,19 @@ const ScoringCard = ({ }; ScoringCard.propTypes = { - // eslint-disable-next-line - scoring: PropTypes.any.isRequired, + scoring: PropTypes.shape({ + weight: PropTypes.number.isRequired, + attempts: PropTypes.shape({ + number: PropTypes.number, + unlimited: PropTypes.bool.isRequired, + }).isRequired, + }).isRequired, updateSettings: PropTypes.func.isRequired, defaultValue: PropTypes.number, - // redux - studioEndpointUrl: PropTypes.string.isRequired, - learningContextId: PropTypes.string, - isLibrary: PropTypes.bool.isRequired, }; ScoringCard.defaultProps = { - learningContextId: null, defaultValue: null, }; -export const mapStateToProps = (state) => ({ - studioEndpointUrl: selectors.app.studioEndpointUrl(state), - learningContextId: selectors.app.learningContextId(state), - isLibrary: selectors.app.isLibrary(state), -}); - -export const mapDispatchToProps = {}; - -export default connect(mapStateToProps, mapDispatchToProps)(ScoringCard); +export default ScoringCard; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ScoringCard.test.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ScoringCard.test.jsx index e5f632a392..1fad5f1e08 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ScoringCard.test.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ScoringCard.test.jsx @@ -1,12 +1,21 @@ import React from 'react'; import { - render, screen, initializeMocks, fireEvent, + screen, initializeMocks, fireEvent, } from '@src/testUtils'; import ScoringCard from './ScoringCard'; -import { selectors } from '../../../../../../data/redux'; +import { selectors, initializeStore } from '../../../../../../data/redux'; +import editorRender from '../../../../../../modifiedEditorTestRender'; const { app } = selectors; +const initialState = { + app: { + studioEndpointUrl: 'studioEndpointUrl', + learningContextId: 'learningContextId', + isLibrary: false, + }, +}; + describe('ScoringCard', () => { const scoring = { weight: 1.5, @@ -24,33 +33,30 @@ describe('ScoringCard', () => { }; beforeEach(() => { - jest.spyOn(app, 'studioEndpointUrl').mockReturnValue('studioEndpointUrl'); - jest.spyOn(app, 'learningContextId').mockReturnValue('learningContextId'); - jest.spyOn(app, 'isLibrary').mockReturnValue(false); - initializeMocks(); + initializeMocks({ initialState, initializeStore }); }); test('render the component', () => { - render(); + editorRender(); expect(screen.getByText('Scoring')).toBeInTheDocument(); }); test('should not render advance settings link when isLibrary is true', () => { jest.spyOn(app, 'isLibrary').mockReturnValue(true); - render(); + editorRender(); fireEvent.click(screen.getByText('Scoring')); expect(screen.queryByText('Set a default value in advanced settings')).not.toBeInTheDocument(); }); test('should render advance settings link when isLibrary is false', () => { jest.spyOn(app, 'isLibrary').mockReturnValue(false); - render(); + editorRender(); fireEvent.click(screen.getByText('Scoring')); expect(screen.getByText('Set a default value in advanced settings')).toBeInTheDocument(); }); test('should call updateSettings when clicking points button', () => { - render(); + editorRender(); fireEvent.click(screen.getByText('Scoring')); const pointsButton = screen.getByRole('spinbutton', { name: 'Points' }); expect(pointsButton).toBeInTheDocument(); @@ -61,7 +67,7 @@ describe('ScoringCard', () => { test('should call updateSettings when clicking attempts button', () => { const scoringUnlimited = { ...scoring, attempts: { unlimited: true, number: 0 } }; - render(); + editorRender(); fireEvent.click(screen.getByText('Scoring')); fireEvent.click(screen.getByText('Attempts')); const attemptsButton = screen.getByRole('spinbutton', { name: 'Points' }); @@ -73,7 +79,7 @@ describe('ScoringCard', () => { test('should display checked checkbox when unlimited is true', () => { const scoringUnlimited = { ...scoring, attempts: { unlimited: true, number: 0 } }; - render(); + editorRender(); fireEvent.click(screen.getByText('Scoring')); const checkbox = screen.getByRole('checkbox', { name: 'Unlimited attempts' }); expect(checkbox).toBeChecked(); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ShowAnswerCard.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ShowAnswerCard.jsx index 414233d53f..34c805007c 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ShowAnswerCard.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ShowAnswerCard.jsx @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; +import { useSelector } from 'react-redux'; +import { injectIntl, FormattedMessage, intlShape } from '@edx/frontend-platform/i18n'; import { Form, Hyperlink } from '@openedx/paragon'; import SettingsOption from '../SettingsOption'; import { ShowAnswerTypes, ShowAnswerTypesKeys } from '../../../../../../data/constants/problem'; @@ -13,12 +13,12 @@ const ShowAnswerCard = ({ showAnswer, updateSettings, defaultValue, - // redux - studioEndpointUrl, - learningContextId, - isLibrary, + intl, }) => { - const intl = useIntl(); + const studioEndpointUrl = useSelector(selectors.app.studioEndpointUrl); + const learningContextId = useSelector(selectors.app.learningContextId); + const isLibrary = useSelector(selectors.app.isLibrary); + const { handleShowAnswerChange, handleAttemptsChange, @@ -50,7 +50,10 @@ const ShowAnswerCard = ({ {Object.values(ShowAnswerTypesKeys).map((answerType) => { let optionDisplayName = ShowAnswerTypes[answerType]; if (answerType === defaultValue) { - optionDisplayName = { ...optionDisplayName, defaultMessage: `${optionDisplayName.defaultMessage} (Default)` }; + optionDisplayName = { + ...optionDisplayName, + defaultMessage: `${optionDisplayName.defaultMessage} (Default)`, + }; } return (