From 108ca4e681f8d195d5e927af962f7087622a4f9a Mon Sep 17 00:00:00 2001 From: Braden MacDonald Date: Fri, 13 Sep 2024 13:48:38 -0700 Subject: [PATCH 1/9] fix: a11y - missing 'alt' text for Problem Editor IconButton --- .../EditorContainer/{messages.js => messages.ts} | 0 .../SelectTypeWrapper/__snapshots__/index.test.jsx.snap | 1 + .../SelectTypeModal/SelectTypeWrapper/index.jsx | 8 +++++--- .../SelectTypeModal/SelectTypeWrapper/index.test.jsx | 2 +- .../SelectTypeWrapper/{messages.js => messages.ts} | 0 .../SelectTypeModal/__snapshots__/index.test.jsx.snap | 6 +++--- 6 files changed, 10 insertions(+), 7 deletions(-) rename src/editors/containers/EditorContainer/{messages.js => messages.ts} (100%) rename src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/{messages.js => messages.ts} (100%) diff --git a/src/editors/containers/EditorContainer/messages.js b/src/editors/containers/EditorContainer/messages.ts similarity index 100% rename from src/editors/containers/EditorContainer/messages.js rename to src/editors/containers/EditorContainer/messages.ts diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/index.test.jsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/index.test.jsx.snap index 6c9bc201a1..b63009f321 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/index.test.jsx.snap +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/index.test.jsx.snap @@ -17,6 +17,7 @@ exports[`SelectTypeWrapper snapshot 1`] = ` className="pgn__modal-close-container" > diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/index.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/index.jsx index f747783f5a..e452967172 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/index.jsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/index.jsx @@ -1,11 +1,12 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { injectIntl, FormattedMessage } from '@edx/frontend-platform/i18n'; +import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; import { Icon, ModalDialog, IconButton } from '@openedx/paragon'; import { Close } from '@openedx/paragon/icons'; import SelectTypeFooter from './SelectTypeFooter'; import * as hooks from '../../../../EditorContainer/hooks'; +import ecMessages from '../../../../EditorContainer/messages'; import messages from './messages'; const SelectTypeWrapper = ({ @@ -14,6 +15,7 @@ const SelectTypeWrapper = ({ selected, }) => { const handleCancel = hooks.handleCancel({ onClose }); + const intl = useIntl(); return (
@@ -51,5 +54,4 @@ SelectTypeWrapper.propTypes = { onClose: PropTypes.func, }; -export const SelectTypeWrapperInternal = SelectTypeWrapper; // For testing only -export default injectIntl(SelectTypeWrapper); +export default SelectTypeWrapper; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/index.test.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/index.test.jsx index ec2e3a51a6..8ac7456052 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/index.test.jsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/index.test.jsx @@ -2,7 +2,7 @@ import 'CourseAuthoring/editors/setupEditorTest'; import React from 'react'; import { shallow } from '@edx/react-unit-test-utils'; import { IconButton } from '@openedx/paragon'; -import { SelectTypeWrapperInternal as SelectTypeWrapper } from '.'; +import SelectTypeWrapper from '.'; import { handleCancel } from '../../../../EditorContainer/hooks'; jest.mock('../../../../EditorContainer/hooks', () => ({ diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/messages.js b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/messages.ts similarity index 100% rename from src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/messages.js rename to src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/messages.ts diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/__snapshots__/index.test.jsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/__snapshots__/index.test.jsx.snap index 51f08eada8..df6280502b 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/__snapshots__/index.test.jsx.snap +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/__snapshots__/index.test.jsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`SelectTypeModal snapshot 1`] = ` - @@ -13,7 +13,7 @@ exports[`SelectTypeModal snapshot 1`] = ` direction="horizontal" gap={4} > - @@ -22,5 +22,5 @@ exports[`SelectTypeModal snapshot 1`] = ` /> - + `; From 986c100ac256dba3e78fc489f7d2272bd684aabc Mon Sep 17 00:00:00 2001 From: Braden MacDonald Date: Fri, 13 Sep 2024 14:00:05 -0700 Subject: [PATCH 2/9] fix: warning in component - missing key prop in list --- src/custom.d.ts | 5 ++++ .../content/ProblemTypeSelect.test.jsx | 2 +- ...emTypeSelect.jsx => ProblemTypeSelect.tsx} | 18 ++++++------- .../ProblemTypeSelect.test.jsx.snap | 25 +++++++++++++++++++ .../data/constants/{problem.js => problem.ts} | 18 ++++++------- .../utils/{StrictDict.js => StrictDict.ts} | 2 +- 6 files changed, 50 insertions(+), 20 deletions(-) rename src/editors/containers/ProblemEditor/components/SelectTypeModal/content/{ProblemTypeSelect.jsx => ProblemTypeSelect.tsx} (79%) rename src/editors/data/constants/{problem.js => problem.ts} (98%) rename src/editors/utils/{StrictDict.js => StrictDict.ts} (82%) diff --git a/src/custom.d.ts b/src/custom.d.ts index 2b94311838..63c5b2cf57 100644 --- a/src/custom.d.ts +++ b/src/custom.d.ts @@ -3,6 +3,11 @@ declare module '*.svg' { export default content; } +declare module '*.png' { + const content: string; + export default content; +} + declare module '*.json' { const value: any; export default value; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.test.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.test.jsx index 7482f843ef..3d59d4315e 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.test.jsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.test.jsx @@ -2,7 +2,7 @@ import 'CourseAuthoring/editors/setupEditorTest'; import React from 'react'; import { shallow } from '@edx/react-unit-test-utils'; import { ProblemTypeKeys } from '../../../../../data/constants/problem'; -import { ProblemTypeSelectInternal as ProblemTypeSelect } from './ProblemTypeSelect'; +import ProblemTypeSelect from './ProblemTypeSelect'; describe('ProblemTypeSelect', () => { const props = { diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.tsx similarity index 79% rename from src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.jsx rename to src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.tsx index e58d731af2..d0805cf207 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.jsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.tsx @@ -1,14 +1,18 @@ import React from 'react'; -import PropTypes from 'prop-types'; import { Button, Container } from '@openedx/paragon'; -import { FormattedMessage, injectIntl } from '@edx/frontend-platform/i18n'; +import { FormattedMessage } from '@edx/frontend-platform/i18n'; // SelectableBox in paragon has a bug where you can't change selection. So we override it import SelectableBox from '../../../../../sharedComponents/SelectableBox'; import { ProblemTypes, ProblemTypeKeys, AdvanceProblemKeys } from '../../../../../data/constants/problem'; import messages from './messages'; -const ProblemTypeSelect = ({ +interface Props { + selected: string; + setSelected: (selected: string) => void; +} + +const ProblemTypeSelect: React.FC = ({ selected, setSelected, }) => { @@ -30,6 +34,7 @@ const ProblemTypeSelect = ({ @@ -45,10 +50,5 @@ const ProblemTypeSelect = ({ ); }; -ProblemTypeSelect.propTypes = { - selected: PropTypes.string.isRequired, - setSelected: PropTypes.func.isRequired, -}; -export const ProblemTypeSelectInternal = ProblemTypeSelect; // For testing only -export default injectIntl(ProblemTypeSelect); +export default ProblemTypeSelect; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.jsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.jsx.snap index 157708524f..9e562bad14 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.jsx.snap +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.jsx.snap @@ -23,6 +23,7 @@ exports[`ProblemTypeSelect snapshot DROPDOWN 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="multiplechoiceresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -38,6 +39,7 @@ exports[`ProblemTypeSelect snapshot DROPDOWN 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="choiceresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -53,6 +55,7 @@ exports[`ProblemTypeSelect snapshot DROPDOWN 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="optionresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -68,6 +71,7 @@ exports[`ProblemTypeSelect snapshot DROPDOWN 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="numericalresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -83,6 +87,7 @@ exports[`ProblemTypeSelect snapshot DROPDOWN 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="stringresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -128,6 +133,7 @@ exports[`ProblemTypeSelect snapshot MULTISELECT 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="multiplechoiceresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -143,6 +149,7 @@ exports[`ProblemTypeSelect snapshot MULTISELECT 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="choiceresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -158,6 +165,7 @@ exports[`ProblemTypeSelect snapshot MULTISELECT 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="optionresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -173,6 +181,7 @@ exports[`ProblemTypeSelect snapshot MULTISELECT 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="numericalresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -188,6 +197,7 @@ exports[`ProblemTypeSelect snapshot MULTISELECT 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="stringresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -233,6 +243,7 @@ exports[`ProblemTypeSelect snapshot NUMERIC 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="multiplechoiceresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -248,6 +259,7 @@ exports[`ProblemTypeSelect snapshot NUMERIC 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="choiceresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -263,6 +275,7 @@ exports[`ProblemTypeSelect snapshot NUMERIC 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="optionresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -278,6 +291,7 @@ exports[`ProblemTypeSelect snapshot NUMERIC 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="numericalresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -293,6 +307,7 @@ exports[`ProblemTypeSelect snapshot NUMERIC 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="stringresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -338,6 +353,7 @@ exports[`ProblemTypeSelect snapshot SINGLESELECT 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="multiplechoiceresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -353,6 +369,7 @@ exports[`ProblemTypeSelect snapshot SINGLESELECT 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="choiceresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -368,6 +385,7 @@ exports[`ProblemTypeSelect snapshot SINGLESELECT 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="optionresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -383,6 +401,7 @@ exports[`ProblemTypeSelect snapshot SINGLESELECT 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="numericalresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -398,6 +417,7 @@ exports[`ProblemTypeSelect snapshot SINGLESELECT 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="stringresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -443,6 +463,7 @@ exports[`ProblemTypeSelect snapshot TEXTINPUT 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="multiplechoiceresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -458,6 +479,7 @@ exports[`ProblemTypeSelect snapshot TEXTINPUT 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="choiceresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -473,6 +495,7 @@ exports[`ProblemTypeSelect snapshot TEXTINPUT 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="optionresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -488,6 +511,7 @@ exports[`ProblemTypeSelect snapshot TEXTINPUT 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="numericalresponse" onClick={[Function]} onFocus={[Function]} type="radio" @@ -503,6 +527,7 @@ exports[`ProblemTypeSelect snapshot TEXTINPUT 1`] = ` inputHidden={true} isIndeterminate={false} isInvalid={false} + key="stringresponse" onClick={[Function]} onFocus={[Function]} type="radio" diff --git a/src/editors/data/constants/problem.js b/src/editors/data/constants/problem.ts similarity index 98% rename from src/editors/data/constants/problem.js rename to src/editors/data/constants/problem.ts index 5dcc8558cc..3b5cca8381 100644 --- a/src/editors/data/constants/problem.js +++ b/src/editors/data/constants/problem.ts @@ -14,7 +14,7 @@ export const ProblemTypeKeys = StrictDict({ NUMERIC: 'numericalresponse', TEXTINPUT: 'stringresponse', ADVANCED: 'advanced', -}); +} as const); export const ProblemTypes = StrictDict({ [ProblemTypeKeys.SINGLESELECT]: { @@ -84,7 +84,7 @@ export const AdvanceProblemKeys = StrictDict({ IMAGE: 'imageresponse', FORMULA: 'formularesponse', PROBLEMWITHHINT: 'problemwithhint', -}); +} as const); export const AdvanceProblems = StrictDict({ [AdvanceProblemKeys.BLANK]: { @@ -122,7 +122,7 @@ export const AdvanceProblems = StrictDict({ status: 'Not supported', template: advancedOlxTemplates.problemWithHint, }, -}); +} as const); export const ShowAnswerTypesKeys = StrictDict({ ALWAYS: 'always', @@ -137,7 +137,7 @@ export const ShowAnswerTypesKeys = StrictDict({ AFTER_ALL_ATTEMPTS: 'after_all_attempts', AFTER_ALL_ATTEMPTS_OR_CORRECT: 'after_all_attempts_or_correct', ATTEMPTED_NO_PAST_DUE: 'attempted_no_past_due', -}); +} as const); export const ShowAnswerTypes = StrictDict({ [ShowAnswerTypesKeys.ALWAYS]: { @@ -188,14 +188,14 @@ export const ShowAnswerTypes = StrictDict({ id: 'authoring.problemeditor.settings.showanswertype.attempted_no_past_due', defaultMessage: 'Attempted', }, -}); +} as const); export const RandomizationTypesKeys = StrictDict({ NEVER: 'never', ALWAYS: 'always', ONRESET: 'onreset', PERSTUDENT: 'per_student', -}); +} as const); export const RandomizationTypes = StrictDict({ [RandomizationTypesKeys.ALWAYS]: { @@ -214,9 +214,9 @@ export const RandomizationTypes = StrictDict({ id: 'authoring.problemeditor.settings.RandomizationTypes.perstudent', defaultMessage: 'Per Student', }, -}); +} as const); -export const RichTextProblems = [ProblemTypeKeys.SINGLESELECT, ProblemTypeKeys.MULTISELECT]; +export const RichTextProblems = [ProblemTypeKeys.SINGLESELECT, ProblemTypeKeys.MULTISELECT] as const; export const settingsOlxAttributes = [ '@_display_name', @@ -226,4 +226,4 @@ export const settingsOlxAttributes = [ '@_show_reset_button', '@_submission_wait_seconds', '@_attempts_before_showanswer_button', -]; +] as const; diff --git a/src/editors/utils/StrictDict.js b/src/editors/utils/StrictDict.ts similarity index 82% rename from src/editors/utils/StrictDict.js rename to src/editors/utils/StrictDict.ts index d73ac811da..c7b69c161a 100644 --- a/src/editors/utils/StrictDict.js +++ b/src/editors/utils/StrictDict.ts @@ -19,6 +19,6 @@ const strictGet = (target, name) => { return undefined; }; -const StrictDict = (dict) => new Proxy(dict, { get: strictGet }); +const StrictDict = >(dict: T) => new Proxy(dict, { get: strictGet }) as T; export default StrictDict; From 217c7f38a7c90e1cb73f6a85587b79048d6c9f66 Mon Sep 17 00:00:00 2001 From: Braden MacDonald Date: Fri, 13 Sep 2024 14:22:35 -0700 Subject: [PATCH 3/9] fix: warning: `problemType` required in `ProblemEditor`, but is `null` --- ...ndex.test.jsx.snap => index.test.tsx.snap} | 0 .../{index.test.jsx => index.test.tsx} | 3 -- .../ProblemEditor/{index.jsx => index.tsx} | 38 +++++++++---------- src/editors/data/constants/problem.ts | 1 + src/editors/data/redux/index.js | 2 +- 5 files changed, 20 insertions(+), 24 deletions(-) rename src/editors/containers/ProblemEditor/__snapshots__/{index.test.jsx.snap => index.test.tsx.snap} (100%) rename src/editors/containers/ProblemEditor/{index.test.jsx => index.test.tsx} (98%) rename src/editors/containers/ProblemEditor/{index.jsx => index.tsx} (72%) diff --git a/src/editors/containers/ProblemEditor/__snapshots__/index.test.jsx.snap b/src/editors/containers/ProblemEditor/__snapshots__/index.test.tsx.snap similarity index 100% rename from src/editors/containers/ProblemEditor/__snapshots__/index.test.jsx.snap rename to src/editors/containers/ProblemEditor/__snapshots__/index.test.tsx.snap diff --git a/src/editors/containers/ProblemEditor/index.test.jsx b/src/editors/containers/ProblemEditor/index.test.tsx similarity index 98% rename from src/editors/containers/ProblemEditor/index.test.jsx rename to src/editors/containers/ProblemEditor/index.test.tsx index f6866b56a6..ef31cdaac5 100644 --- a/src/editors/containers/ProblemEditor/index.test.jsx +++ b/src/editors/containers/ProblemEditor/index.test.tsx @@ -65,7 +65,6 @@ describe('ProblemEditor', () => { const wrapper = shallow(); @@ -75,7 +74,6 @@ describe('ProblemEditor', () => { const wrapper = shallow(); expect(wrapper.instance.findByType('SelectTypeModal')).toHaveLength(1); @@ -85,7 +83,6 @@ describe('ProblemEditor', () => { {...props} problemType="multiplechoiceresponse" blockFinished - studioViewFinished advancedSettingsFinished />); expect(wrapper.instance.findByType('EditProblemView')).toHaveLength(1); diff --git a/src/editors/containers/ProblemEditor/index.jsx b/src/editors/containers/ProblemEditor/index.tsx similarity index 72% rename from src/editors/containers/ProblemEditor/index.jsx rename to src/editors/containers/ProblemEditor/index.tsx index 5f342ad1e4..b281481f29 100644 --- a/src/editors/containers/ProblemEditor/index.jsx +++ b/src/editors/containers/ProblemEditor/index.tsx @@ -1,17 +1,30 @@ import React from 'react'; import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; import { Spinner } from '@openedx/paragon'; -import { injectIntl, FormattedMessage } from '@edx/frontend-platform/i18n'; +import { FormattedMessage } from '@edx/frontend-platform/i18n'; import SelectTypeModal from './components/SelectTypeModal'; import EditProblemView from './components/EditProblemView'; import { selectors, thunkActions } from '../../data/redux'; import { RequestKeys } from '../../data/constants/requests'; import messages from './messages'; +import { ProblemType } from '../../data/constants/problem'; -const ProblemEditor = ({ +interface Props { + onClose: () => void | null; + returnFunction?: () => (result: any) => void | null; + // redux + advancedSettingsFinished: boolean; + blockFinished: boolean; + blockFailed: boolean; + /** null if this is a new problem */ + problemType: ProblemType | null; + initializeProblemEditor: (blockValue: any) => void; + blockValue: Record; +} + +const ProblemEditor: React.FC = ({ onClose, - returnFunction, + returnFunction = null, // Redux problemType, blockFinished, @@ -52,21 +65,6 @@ const ProblemEditor = ({ return (); }; -ProblemEditor.defaultProps = { - returnFunction: null, -}; -ProblemEditor.propTypes = { - onClose: PropTypes.func.isRequired, - returnFunction: PropTypes.func, - // redux - advancedSettingsFinished: PropTypes.bool.isRequired, - blockFinished: PropTypes.bool.isRequired, - blockFailed: PropTypes.bool.isRequired, - problemType: PropTypes.string.isRequired, - initializeProblemEditor: PropTypes.func.isRequired, - blockValue: PropTypes.objectOf(PropTypes.shape({})).isRequired, -}; - export const mapStateToProps = (state) => ({ blockFinished: selectors.requests.isFinished(state, { requestKey: RequestKeys.fetchBlock }), blockFailed: selectors.requests.isFailed(state, { requestKey: RequestKeys.fetchBlock }), @@ -80,4 +78,4 @@ export const mapDispatchToProps = { }; export const ProblemEditorInternal = ProblemEditor; // For testing only -export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(ProblemEditor)); +export default connect(mapStateToProps, mapDispatchToProps)(ProblemEditor); diff --git a/src/editors/data/constants/problem.ts b/src/editors/data/constants/problem.ts index 3b5cca8381..539e59cbc1 100644 --- a/src/editors/data/constants/problem.ts +++ b/src/editors/data/constants/problem.ts @@ -15,6 +15,7 @@ export const ProblemTypeKeys = StrictDict({ TEXTINPUT: 'stringresponse', ADVANCED: 'advanced', } as const); +export type ProblemType = typeof ProblemTypeKeys[keyof typeof ProblemTypeKeys]; export const ProblemTypes = StrictDict({ [ProblemTypeKeys.SINGLESELECT]: { diff --git a/src/editors/data/redux/index.js b/src/editors/data/redux/index.js index 84e5648bda..e231759a92 100644 --- a/src/editors/data/redux/index.js +++ b/src/editors/data/redux/index.js @@ -20,7 +20,7 @@ const modules = { const moduleProps = (propName) => Object.keys(modules).reduce( (obj, moduleKey) => ({ ...obj, [moduleKey]: modules[moduleKey][propName] }), - {}, + /** @type {Record} */({}), ); const rootReducer = combineReducers(moduleProps('reducer')); From ad10865987bf59647dda632fb7592bca34c281e1 Mon Sep 17 00:00:00 2001 From: Braden MacDonald Date: Fri, 13 Sep 2024 14:39:12 -0700 Subject: [PATCH 4/9] fix: warning: The prop `onClose` marked as required in `SelectTypeModal` --- src/editors/{Editor.jsx => Editor.tsx} | 42 +++++++------------ src/editors/EditorComponent.ts | 6 +++ .../SelectTypeModal/{index.jsx => index.tsx} | 11 +++-- .../containers/ProblemEditor/index.tsx | 5 +-- ...upportedEditors.js => supportedEditors.ts} | 2 +- 5 files changed, 30 insertions(+), 36 deletions(-) rename src/editors/{Editor.jsx => Editor.tsx} (61%) create mode 100644 src/editors/EditorComponent.ts rename src/editors/containers/ProblemEditor/components/SelectTypeModal/{index.jsx => index.tsx} (89%) rename src/editors/{supportedEditors.js => supportedEditors.ts} (98%) diff --git a/src/editors/Editor.jsx b/src/editors/Editor.tsx similarity index 61% rename from src/editors/Editor.jsx rename to src/editors/Editor.tsx index 044c773f26..ae9c68ef46 100644 --- a/src/editors/Editor.jsx +++ b/src/editors/Editor.tsx @@ -1,21 +1,29 @@ import React from 'react'; import { useDispatch } from 'react-redux'; -import PropTypes from 'prop-types'; import { FormattedMessage } from '@edx/frontend-platform/i18n'; import messages from './messages'; import * as hooks from './hooks'; import supportedEditors from './supportedEditors'; +import type { EditorComponent } from './EditorComponent'; -const Editor = ({ - learningContextId, +export interface Props extends EditorComponent { + blockType: string; + blockId?: string | null; + learningContextId?: string | null; + lmsEndpointUrl?: string | null; + studioEndpointUrl?: string | null; +} + +const Editor: React.FC = ({ + learningContextId = null, blockType, - blockId, - lmsEndpointUrl, - studioEndpointUrl, - onClose, - returnFunction, + blockId = null, + lmsEndpointUrl = null, + studioEndpointUrl = null, + onClose = null, + returnFunction = null, }) => { const dispatch = useDispatch(); hooks.initializeApp({ @@ -46,23 +54,5 @@ const Editor = ({ ); }; -Editor.defaultProps = { - blockId: null, - learningContextId: null, - lmsEndpointUrl: null, - onClose: null, - returnFunction: null, - studioEndpointUrl: null, -}; - -Editor.propTypes = { - blockId: PropTypes.string, - blockType: PropTypes.string.isRequired, - learningContextId: PropTypes.string, - lmsEndpointUrl: PropTypes.string, - onClose: PropTypes.func, - returnFunction: PropTypes.func, - studioEndpointUrl: PropTypes.string, -}; export default Editor; diff --git a/src/editors/EditorComponent.ts b/src/editors/EditorComponent.ts new file mode 100644 index 0000000000..e670ff6f5d --- /dev/null +++ b/src/editors/EditorComponent.ts @@ -0,0 +1,6 @@ +/** Shared interface that all Editor components (like ProblemEditor) adhere to */ +export interface EditorComponent { + onClose: (() => void) | null; + // TODO: get a better type for the 'result' here + returnFunction?: (() => (result: any) => void) | null; +} diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.tsx similarity index 89% rename from src/editors/containers/ProblemEditor/components/SelectTypeModal/index.jsx rename to src/editors/containers/ProblemEditor/components/SelectTypeModal/index.tsx index 828dc4be05..21fa829236 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.jsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import PropTypes from 'prop-types'; import { Row, Stack } from '@openedx/paragon'; import ProblemTypeSelect from './content/ProblemTypeSelect'; @@ -9,7 +8,11 @@ import SelectTypeWrapper from './SelectTypeWrapper'; import * as hooks from './hooks'; import { AdvanceProblemKeys } from '../../../../data/constants/problem'; -const SelectTypeModal = ({ +interface Props { + onClose: (() => void) | null; +} + +const SelectTypeModal: React.FC = ({ onClose, }) => { const { selected, setSelected } = hooks.selectHooks(); @@ -29,8 +32,4 @@ const SelectTypeModal = ({ ); }; -SelectTypeModal.propTypes = { - onClose: PropTypes.func.isRequired, -}; - export default SelectTypeModal; diff --git a/src/editors/containers/ProblemEditor/index.tsx b/src/editors/containers/ProblemEditor/index.tsx index b281481f29..293b7da6ac 100644 --- a/src/editors/containers/ProblemEditor/index.tsx +++ b/src/editors/containers/ProblemEditor/index.tsx @@ -8,10 +8,9 @@ import { selectors, thunkActions } from '../../data/redux'; import { RequestKeys } from '../../data/constants/requests'; import messages from './messages'; import { ProblemType } from '../../data/constants/problem'; +import type { EditorComponent } from '../../EditorComponent'; -interface Props { - onClose: () => void | null; - returnFunction?: () => (result: any) => void | null; +export interface Props extends EditorComponent { // redux advancedSettingsFinished: boolean; blockFinished: boolean; diff --git a/src/editors/supportedEditors.js b/src/editors/supportedEditors.ts similarity index 98% rename from src/editors/supportedEditors.js rename to src/editors/supportedEditors.ts index 82d9c568a7..71d0bad737 100644 --- a/src/editors/supportedEditors.js +++ b/src/editors/supportedEditors.ts @@ -15,6 +15,6 @@ const supportedEditors = { [blockTypes.video_upload]: VideoUploadEditor, // ADDED_EDITORS GO BELOW [blockTypes.game]: GameEditor, -}; +} as const; export default supportedEditors; From 30bcff4aa301e11f6ecade8e4e39e552d4f15f31 Mon Sep 17 00:00:00 2001 From: Braden MacDonald Date: Fri, 13 Sep 2024 14:42:03 -0700 Subject: [PATCH 5/9] fix: warning: prop `name` is marked as required in `ForwardRef(_c)` --- .../components/SelectTypeModal/content/ProblemTypeSelect.tsx | 1 + .../content/__snapshots__/ProblemTypeSelect.test.jsx.snap | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.tsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.tsx index d0805cf207..8639f30fc6 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.tsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.tsx @@ -23,6 +23,7 @@ const ProblemTypeSelect: React.FC = ({ return ( Date: Sat, 14 Sep 2024 13:01:22 -0700 Subject: [PATCH 6/9] fix: warning: props `alt`, `id`, and `key` are required --- ...ct.test.jsx => AdvanceTypeSelect.test.tsx} | 22 +- ...ceTypeSelect.jsx => AdvanceTypeSelect.tsx} | 49 +- ...x.snap => AdvanceTypeSelect.test.tsx.snap} | 434 ++++++------------ .../content/{messages.js => messages.ts} | 5 + src/editors/data/constants/problem.ts | 1 + src/editors/setupEditorTest.js | 3 +- 6 files changed, 183 insertions(+), 331 deletions(-) rename src/editors/containers/ProblemEditor/components/SelectTypeModal/content/{AdvanceTypeSelect.test.jsx => AdvanceTypeSelect.test.tsx} (68%) rename src/editors/containers/ProblemEditor/components/SelectTypeModal/content/{AdvanceTypeSelect.jsx => AdvanceTypeSelect.tsx} (77%) rename src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/{AdvanceTypeSelect.test.jsx.snap => AdvanceTypeSelect.test.tsx.snap} (86%) rename src/editors/containers/ProblemEditor/components/SelectTypeModal/content/{messages.js => messages.ts} (94%) diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.test.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.test.tsx similarity index 68% rename from src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.test.jsx rename to src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.test.tsx index 978b35e7c5..09d0e40e39 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.test.jsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.test.tsx @@ -1,16 +1,11 @@ import 'CourseAuthoring/editors/setupEditorTest'; -import React from 'react'; import { shallow } from '@edx/react-unit-test-utils'; -import { formatMessage } from '../../../../../testUtils'; -import * as module from './AdvanceTypeSelect'; - -const AdvanceTypeSelect = module.AdvanceTypeSelectInternal; +import AdvanceTypeSelect from './AdvanceTypeSelect'; describe('AdvanceTypeSelect', () => { const props = { - intl: { formatMessage }, - selected: 'blankadvanced', + selected: 'blankadvanced' as const, setSelected: jest.fn().mockName('setSelect'), }; describe('snapshots', () => { @@ -29,11 +24,6 @@ describe('AdvanceTypeSelect', () => { shallow().snapshot, ).toMatchSnapshot(); }); - test('snapshots: renders as expected with problemType is drag_and_drop', () => { - expect( - shallow().snapshot, - ).toMatchSnapshot(); - }); test('snapshots: renders as expected with problemType is formularesponse', () => { expect( shallow().snapshot, @@ -44,14 +34,14 @@ describe('AdvanceTypeSelect', () => { shallow().snapshot, ).toMatchSnapshot(); }); - test('snapshots: renders as expected with problemType is jsinput_response', () => { + test('snapshots: renders as expected with problemType is jsinputresponse', () => { expect( - shallow().snapshot, + shallow().snapshot, ).toMatchSnapshot(); }); - test('snapshots: renders as expected with problemType is problem_with_hint', () => { + test('snapshots: renders as expected with problemType is problemwithhint', () => { expect( - shallow().snapshot, + shallow().snapshot, ).toMatchSnapshot(); }); }); diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.tsx similarity index 77% rename from src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.jsx rename to src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.tsx index d60061ddd1..cddba79870 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.jsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import PropTypes from 'prop-types'; import { Form, @@ -12,22 +11,36 @@ import { Col, } from '@openedx/paragon'; import { ArrowBack } from '@openedx/paragon/icons'; -import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n'; -import { AdvanceProblems, ProblemTypeKeys } from '../../../../../data/constants/problem'; +import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; +import { + AdvancedProblemType, + AdvanceProblems, + ProblemType, + ProblemTypeKeys, +} from '../../../../../data/constants/problem'; import messages from './messages'; -const AdvanceTypeSelect = ({ - selected, +interface Props { + selected: AdvancedProblemType | null; + setSelected: React.Dispatch; +} + +const AdvanceTypeSelect: React.FC = ({ + selected = null, setSelected, - // injected - intl, }) => { + const intl = useIntl(); const handleChange = e => { setSelected(e.target.value); }; return ( - setSelected(ProblemTypeKeys.SINGLESELECT)} /> + setSelected(ProblemTypeKeys.SINGLESELECT)} + /> @@ -43,7 +56,7 @@ const AdvanceTypeSelect = ({ {Object.entries(AdvanceProblems).map(([type, data]) => { if (data.status !== '') { return ( - + {intl.formatMessage(messages.advanceProblemTypeLabel, { problemType: data.title })} @@ -51,7 +64,7 @@ const AdvanceTypeSelect = ({ +
{intl.formatMessage(messages.supportStatusTooltipMessage, { supportStatus: data.status.replace(' ', '_') })}
@@ -66,7 +79,7 @@ const AdvanceTypeSelect = ({ ); } return ( - + {intl.formatMessage(messages.advanceProblemTypeLabel, { problemType: data.title })} @@ -86,16 +99,4 @@ const AdvanceTypeSelect = ({ ); }; -AdvanceTypeSelect.defaultProps = { - selected: null, -}; - -AdvanceTypeSelect.propTypes = { - selected: PropTypes.string, - setSelected: PropTypes.func.isRequired, - // injected - intl: intlShape.isRequired, -}; - -export const AdvanceTypeSelectInternal = AdvanceTypeSelect; // For testing only -export default injectIntl(AdvanceTypeSelect); +export default AdvanceTypeSelect; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/AdvanceTypeSelect.test.jsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/AdvanceTypeSelect.test.tsx.snap similarity index 86% rename from src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/AdvanceTypeSelect.test.jsx.snap rename to src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/AdvanceTypeSelect.test.tsx.snap index 79a7990579..73f572377d 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/AdvanceTypeSelect.test.jsx.snap +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/AdvanceTypeSelect.test.tsx.snap @@ -13,6 +13,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with default className="border-primary-100 border-bottom py-3 pl-2.5 pr-4" > @@ -36,6 +37,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with default > +
@@ -91,6 +96,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with default +
@@ -146,6 +155,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with default +
@@ -190,6 +202,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with default +
@@ -271,6 +287,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem className="border-primary-100 border-bottom py-3 pl-2.5 pr-4" > @@ -294,6 +311,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem > +
@@ -349,6 +370,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem +
@@ -404,6 +429,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem +
@@ -448,6 +476,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem +
@@ -529,6 +561,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem className="border-primary-100 border-bottom py-3 pl-2.5 pr-4" > @@ -552,6 +585,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem > +
@@ -607,6 +644,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem +
@@ -662,6 +703,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem +
@@ -706,6 +750,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem -
- {supportStatus, select, - Provisional {Provisionally supported tools might lack the robustness of functionality - that your courses require. edX does not have control over the quality of the software, - or of the content that can be provided using these tools. - - - - Test these tools thoroughly before using them in your course, especially in graded - sections. Complete documentstion might not be available for provisionally supported - tools, or documentation might be available from sources other than edX.} - Not_supported {Tools with no support are not maintained by edX, and might be deprecated - in the future. They are not recommened for use in courses due to non-compliance with one - or more of the base requirements, such as testing, accessibility, internationalization, - and documentation.} - other { } - } -
- - } - placement="right" - > -
- Not supported -
-
-
- - - - - - -`; - -exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is drag_and_drop 1`] = ` - - - - - - - - - - - - - - Blank problem - - - - - - Circuit schematic builder - - - -
- {supportStatus, select, - Provisional {Provisionally supported tools might lack the robustness of functionality - that your courses require. edX does not have control over the quality of the software, - or of the content that can be provided using these tools. - - - - Test these tools thoroughly before using them in your course, especially in graded - sections. Complete documentstion might not be available for provisionally supported - tools, or documentation might be available from sources other than edX.} - Not_supported {Tools with no support are not maintained by edX, and might be deprecated - in the future. They are not recommened for use in courses due to non-compliance with one - or more of the base requirements, such as testing, accessibility, internationalization, - and documentation.} - other { } - } -
- - } - placement="right" - > -
- Not supported -
-
-
- - - Custom JavaScript display and grading - - - - - - Custom Python-evaluated input - - - -
- {supportStatus, select, - Provisional {Provisionally supported tools might lack the robustness of functionality - that your courses require. edX does not have control over the quality of the software, - or of the content that can be provided using these tools. - - - - Test these tools thoroughly before using them in your course, especially in graded - sections. Complete documentstion might not be available for provisionally supported - tools, or documentation might be available from sources other than edX.} - Not_supported {Tools with no support are not maintained by edX, and might be deprecated - in the future. They are not recommened for use in courses due to non-compliance with one - or more of the base requirements, such as testing, accessibility, internationalization, - and documentation.} - other { } - } -
- - } - placement="right" - > -
- Provisional -
-
-
- - - Image mapped input - - - -
- {supportStatus, select, - Provisional {Provisionally supported tools might lack the robustness of functionality - that your courses require. edX does not have control over the quality of the software, - or of the content that can be provided using these tools. - - - - Test these tools thoroughly before using them in your course, especially in graded - sections. Complete documentstion might not be available for provisionally supported - tools, or documentation might be available from sources other than edX.} - Not_supported {Tools with no support are not maintained by edX, and might be deprecated - in the future. They are not recommened for use in courses due to non-compliance with one - or more of the base requirements, such as testing, accessibility, internationalization, - and documentation.} - other { } - } -
- - } - placement="right" - > -
- Not supported -
-
-
- - - Math expression input - - - - - - Problem with adaptive hint - - - +
@@ -1045,6 +835,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem className="border-primary-100 border-bottom py-3 pl-2.5 pr-4" > @@ -1068,6 +859,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem > +
@@ -1123,6 +918,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem +
@@ -1178,6 +977,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem +
@@ -1222,6 +1024,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem +
@@ -1303,6 +1109,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem className="border-primary-100 border-bottom py-3 pl-2.5 pr-4" > @@ -1326,6 +1133,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem > +
@@ -1381,6 +1192,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem +
@@ -1436,6 +1251,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem +
@@ -1480,6 +1298,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem +
@@ -1548,7 +1370,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem `; -exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is jsinput_response 1`] = ` +exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is jsinputresponse 1`] = ` @@ -1580,10 +1403,11 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem className="px-4" name="advanceTypes" onChange={[Function]} - value="jsinput_response" + value="jsinputresponse" > +
@@ -1639,6 +1466,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem +
@@ -1694,6 +1525,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem +
@@ -1738,6 +1572,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem +
@@ -1806,7 +1644,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem `; -exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is problem_with_hint 1`] = ` +exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is problemwithhint 1`] = ` @@ -1838,10 +1677,11 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem className="px-4" name="advanceTypes" onChange={[Function]} - value="problem_with_hint" + value="problemwithhint" > +
@@ -1897,6 +1740,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem +
@@ -1952,6 +1799,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem +
@@ -1996,6 +1846,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem +
diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/messages.js b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/messages.ts similarity index 94% rename from src/editors/containers/ProblemEditor/components/SelectTypeModal/content/messages.js rename to src/editors/containers/ProblemEditor/components/SelectTypeModal/content/messages.ts index 508d665f15..66873921de 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/messages.js +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/messages.ts @@ -12,6 +12,11 @@ const messages = defineMessages({ defaultMessage: 'Advanced problems', description: 'Title for advanced problem menu', }, + advanceMenuGoBack: { + id: 'authoring.problemEditor.advanceProblem.menu.goBack', + defaultMessage: 'Go back', + description: 'Return to the previous menu that shows basic problem types', + }, advanceProblemTypeLabel: { id: 'authoring.problemEditor.advanceProblem.problemType.label', defaultMessage: '{problemType}', diff --git a/src/editors/data/constants/problem.ts b/src/editors/data/constants/problem.ts index 539e59cbc1..edbc13d95c 100644 --- a/src/editors/data/constants/problem.ts +++ b/src/editors/data/constants/problem.ts @@ -86,6 +86,7 @@ export const AdvanceProblemKeys = StrictDict({ FORMULA: 'formularesponse', PROBLEMWITHHINT: 'problemwithhint', } as const); +export type AdvancedProblemType = typeof AdvanceProblemKeys[keyof typeof AdvanceProblemKeys]; export const AdvanceProblems = StrictDict({ [AdvanceProblemKeys.BLANK]: { diff --git a/src/editors/setupEditorTest.js b/src/editors/setupEditorTest.js index 47df9429a2..0bd2d75ca6 100644 --- a/src/editors/setupEditorTest.js +++ b/src/editors/setupEditorTest.js @@ -1,5 +1,6 @@ // These additional mocks and setup are required for some tests in src/editors/ // and are imported on an as-needed basis. +import { formatMessage as mockFormatMessage } from './testUtils'; // eslint-disable-next-line import/no-extraneous-dependencies import 'jest-canvas-mock'; @@ -8,7 +9,7 @@ jest.mock('@edx/frontend-platform/i18n', () => { const PropTypes = jest.requireActual('prop-types'); return { ...i18n, - useIntl: () => ({ formatMessage: (m) => m.defaultMessage }), + useIntl: () => ({ formatMessage: mockFormatMessage }), intlShape: PropTypes.shape({ formatMessage: PropTypes.func, }), From 64be1777e9584fc9a7545478bb8492a1600926bf Mon Sep 17 00:00:00 2001 From: Braden MacDonald Date: Mon, 16 Sep 2024 14:07:59 -0700 Subject: [PATCH 7/9] test: improve test coverage of SelectTypeModal, refactor some code --- .../SelectTypeWrapper/SelectTypeFooter.jsx | 102 ++++++++---------- .../SelectTypeFooter.test.jsx | 17 +-- .../__snapshots__/index.test.jsx.snap | 2 +- .../__snapshots__/index.test.jsx.snap | 26 ----- .../content/ProblemTypeSelect.tsx | 12 ++- .../ProblemTypeSelect.test.jsx.snap | 25 ----- .../components/SelectTypeModal/hooks.js | 22 +--- .../components/SelectTypeModal/hooks.test.js | 43 ++------ .../components/SelectTypeModal/index.test.jsx | 22 ---- .../components/SelectTypeModal/index.test.tsx | 47 ++++++++ .../components/SelectTypeModal/index.tsx | 13 ++- src/editors/setupEditorTest.js | 9 ++ src/testUtils.tsx | 3 +- 13 files changed, 132 insertions(+), 211 deletions(-) delete mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/__snapshots__/index.test.jsx.snap delete mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/index.test.jsx create mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/index.test.tsx diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.jsx index 733f87a1a2..00c2e6bfa1 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.jsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.jsx @@ -1,13 +1,12 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; - +import { useDispatch, useSelector } from 'react-redux'; +import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; import { ActionRow, Button, ModalDialog, } from '@openedx/paragon'; -import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import messages from './messages'; import * as hooks from '../hooks'; @@ -16,68 +15,55 @@ import { actions, selectors } from '../../../../../data/redux'; const SelectTypeFooter = ({ onCancel, selected, - // redux - defaultSettings, - updateField, - setBlockTitle, - // injected, - intl, -}) => ( -
- - - - - - - -
-); +}) => { + const intl = useIntl(); + const defaultSettings = useSelector(selectors.problem.defaultSettings); + const dispatch = useDispatch(); + const updateField = React.useCallback((data) => dispatch(actions.problem.updateField(data)), [dispatch]); + const setBlockTitle = React.useCallback((title) => dispatch(actions.app.setBlockTitle(title)), [dispatch]); + return ( +
+ + + + + + + +
+ ); +}; SelectTypeFooter.defaultProps = { selected: null, }; SelectTypeFooter.propTypes = { - defaultSettings: PropTypes.shape({ - maxAttempts: PropTypes.number, - rerandomize: PropTypes.string, - showResetButton: PropTypes.bool, - showanswer: PropTypes.string, - }).isRequired, + // defaultSettings: PropTypes.shape({ + // maxAttempts: PropTypes.number, + // rerandomize: PropTypes.string, + // showResetButton: PropTypes.bool, + // showanswer: PropTypes.string, + // }).isRequired, onCancel: PropTypes.func.isRequired, selected: PropTypes.string, - updateField: PropTypes.func.isRequired, - setBlockTitle: PropTypes.func.isRequired, - // injected - intl: intlShape.isRequired, -}; - -export const mapStateToProps = (state) => ({ - defaultSettings: selectors.problem.defaultSettings(state), -}); - -export const mapDispatchToProps = { - updateField: actions.problem.updateField, - setBlockTitle: actions.app.setBlockTitle, }; -export const SelectTypeFooterInternal = SelectTypeFooter; // For testing only -export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(SelectTypeFooter)); +export default SelectTypeFooter; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.test.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.test.jsx index c00cd02d48..d0795c36ba 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.test.jsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.test.jsx @@ -1,14 +1,10 @@ import 'CourseAuthoring/editors/setupEditorTest'; -import React from 'react'; import { shallow } from '@edx/react-unit-test-utils'; import { Button } from '@openedx/paragon'; import { formatMessage } from '../../../../../testUtils'; -import * as module from './SelectTypeFooter'; +import SelectTypeFooter from './SelectTypeFooter'; import * as hooks from '../hooks'; -import { actions } from '../../../../../data/redux'; - -const SelectTypeFooter = module.SelectTypeFooterInternal; jest.mock('../hooks', () => ({ onSelect: jest.fn().mockName('onSelect'), @@ -46,15 +42,4 @@ describe('SelectTypeFooter', () => { .toEqual(expected); }); }); - - describe('mapStateToProps', () => { - test('is empty', () => { - expect(module.mapDispatchToProps.defaultSettings).toEqual(actions.problem.defaultSettings); - }); - }); - describe('mapDispatchToProps', () => { - test('loads updateField from problem.updateField actions', () => { - expect(module.mapDispatchToProps.updateField).toEqual(actions.problem.updateField); - }); - }); }); diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/index.test.jsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/index.test.jsx.snap index b63009f321..fb228f3205 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/index.test.jsx.snap +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/index.test.jsx.snap @@ -31,7 +31,7 @@ exports[`SelectTypeWrapper snapshot 1`] = ` test child -
diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/__snapshots__/index.test.jsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/__snapshots__/index.test.jsx.snap deleted file mode 100644 index df6280502b..0000000000 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/__snapshots__/index.test.jsx.snap +++ /dev/null @@ -1,26 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`SelectTypeModal snapshot 1`] = ` - - - - - - - - -`; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.tsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.tsx index 8639f30fc6..cd38dd8f0d 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.tsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.tsx @@ -4,12 +4,18 @@ import { FormattedMessage } from '@edx/frontend-platform/i18n'; // SelectableBox in paragon has a bug where you can't change selection. So we override it import SelectableBox from '../../../../../sharedComponents/SelectableBox'; -import { ProblemTypes, ProblemTypeKeys, AdvanceProblemKeys } from '../../../../../data/constants/problem'; +import { + ProblemTypes, + ProblemTypeKeys, + AdvanceProblemKeys, + AdvancedProblemType, + ProblemType, +} from '../../../../../data/constants/problem'; import messages from './messages'; interface Props { selected: string; - setSelected: (selected: string) => void; + setSelected: (selected: ProblemType | AdvancedProblemType) => void; } const ProblemTypeSelect: React.FC = ({ @@ -18,7 +24,7 @@ const ProblemTypeSelect: React.FC = ({ }) => { const handleChange = e => setSelected(e.target.value); const handleClick = () => setSelected(AdvanceProblemKeys.BLANK); - const settings = { 'aria-label': 'checkbox', type: 'radio' }; + const settings = { type: 'radio' }; return ( diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.jsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.jsx.snap index a2a31b31e4..f21b392688 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.jsx.snap +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.jsx.snap @@ -17,7 +17,6 @@ exports[`ProblemTypeSelect snapshot DROPDOWN 1`] = ` value="optionresponse" > useState(val), -}); - -export const selectHooks = () => { - const [selected, setSelected] = module.state.selected(ProblemTypeKeys.SINGLESELECT); - return { - selected, - setSelected, - }; -}; - export const onSelect = ({ selected, updateField, diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.test.js b/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.test.js index e0582b5fb2..0c7f987f4c 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.test.js +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.test.js @@ -1,11 +1,6 @@ /* eslint-disable prefer-destructuring */ import React from 'react'; -import { MockUseState } from '../../../../testUtils'; -// This 'module' self-import hack enables mocking during tests. -// See src/editors/decisions/0005-internal-editor-testability-decisions.md. The whole approach to how hooks are tested -// should be re-thought and cleaned up to avoid this pattern. -// eslint-disable-next-line import/no-self-import -import * as module from './hooks'; +import * as hooks from './hooks'; import { AdvanceProblems, ProblemTypeKeys, ProblemTypes } from '../../../../data/constants/problem'; import { getDataFromOlx } from '../../../../data/redux/thunkActions/problem'; @@ -15,7 +10,6 @@ jest.mock('react', () => ({ useEffect: jest.fn(), })); -const state = new MockUseState(module); const mockUpdateField = jest.fn().mockName('updateField'); const mockSelected = 'multiplechoiceresponse'; const mockAdvancedSelected = 'circuitschematic'; @@ -28,35 +22,14 @@ const mockDefaultSettings = { showanswer: 'always', }; -let hook; - describe('SelectTypeModal hooks', () => { - beforeEach(() => { - state.mock(); - }); afterEach(() => { - state.restore(); jest.clearAllMocks(); }); - describe('selectHooks', () => { - beforeEach(() => { - hook = module.selectHooks(); - }); - test('selected defaults to SINGLESELECT', () => { - expect(hook.selected).toEqual(ProblemTypeKeys.SINGLESELECT); - }); - test('setSelected sets state as expected', () => { - const expectedArg = 'neWvAl'; - state.mockVal(state.keys.selected, 'mOcKvAl'); - hook.setSelected(expectedArg); - expect(state.setState.selected).toHaveBeenCalledWith(expectedArg); - }); - }); - describe('onSelect', () => { test('updateField is called with selected templated if selected is an Advanced Problem', () => { - module.onSelect({ + hooks.onSelect({ selected: mockAdvancedSelected, updateField: mockUpdateField, setBlockTitle: mocksetBlockTitle, @@ -68,7 +41,7 @@ describe('SelectTypeModal hooks', () => { expect(mocksetBlockTitle).toHaveBeenCalledWith(AdvanceProblems[mockAdvancedSelected].title); }); test('updateField is called with selected on visual propblems', () => { - module.onSelect({ + hooks.onSelect({ selected: mockSelected, updateField: mockUpdateField, setBlockTitle: mocksetBlockTitle, @@ -106,7 +79,7 @@ describe('SelectTypeModal hooks', () => { describe('SINGLESELECT', () => { beforeEach(() => { - module.useArrowNav(ProblemTypeKeys.SINGLESELECT, mockSetSelected); + hooks.useArrowNav(ProblemTypeKeys.SINGLESELECT, mockSetSelected); [cb, prereqs] = React.useEffect.mock.calls[0]; cb(); }); @@ -125,7 +98,7 @@ describe('SelectTypeModal hooks', () => { }); describe('MULTISELECT', () => { beforeEach(() => { - module.useArrowNav(ProblemTypeKeys.MULTISELECT, mockSetSelected); + hooks.useArrowNav(ProblemTypeKeys.MULTISELECT, mockSetSelected); [cb, prereqs] = React.useEffect.mock.calls[0]; cb(); }); @@ -144,7 +117,7 @@ describe('SelectTypeModal hooks', () => { }); describe('DROPDOWN', () => { beforeEach(() => { - module.useArrowNav(ProblemTypeKeys.DROPDOWN, mockSetSelected); + hooks.useArrowNav(ProblemTypeKeys.DROPDOWN, mockSetSelected); [cb, prereqs] = React.useEffect.mock.calls[0]; cb(); }); @@ -163,7 +136,7 @@ describe('SelectTypeModal hooks', () => { }); describe('NUMERIC', () => { beforeEach(() => { - module.useArrowNav(ProblemTypeKeys.NUMERIC, mockSetSelected); + hooks.useArrowNav(ProblemTypeKeys.NUMERIC, mockSetSelected); [cb, prereqs] = React.useEffect.mock.calls[0]; cb(); }); @@ -182,7 +155,7 @@ describe('SelectTypeModal hooks', () => { }); describe('TEXTINPUT', () => { beforeEach(() => { - module.useArrowNav(ProblemTypeKeys.TEXTINPUT, mockSetSelected); + hooks.useArrowNav(ProblemTypeKeys.TEXTINPUT, mockSetSelected); [cb, prereqs] = React.useEffect.mock.calls[0]; cb(); }); diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.test.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.test.jsx deleted file mode 100644 index 4574c1b799..0000000000 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.test.jsx +++ /dev/null @@ -1,22 +0,0 @@ -import 'CourseAuthoring/editors/setupEditorTest'; -import React from 'react'; -import { shallow } from '@edx/react-unit-test-utils'; -import SelectTypeModal from '.'; - -jest.mock('./hooks', () => ({ - selectHooks: jest.fn(() => ({ - selected: 'mOcKsELEcted', - setSelected: jest.fn().mockName('setSelected'), - })), - useArrowNav: jest.fn().mockName('useArrowNav'), -})); - -describe('SelectTypeModal', () => { - const props = { - onClose: jest.fn(), - }; - - test('snapshot', () => { - expect(shallow().snapshot).toMatchSnapshot(); - }); -}); diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.test.tsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.test.tsx new file mode 100644 index 0000000000..9be7578c5f --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.test.tsx @@ -0,0 +1,47 @@ +import { Provider } from 'react-redux'; +import { + fireEvent, + render, + screen, + initializeMocks, +} from '../../../../../testUtils'; +import editorStore from '../../../../data/store'; +import * as hooks from './hooks'; +import SelectTypeModal from '.'; + +describe('SelectTypeModal', () => { + beforeEach(() => { + initializeMocks(); + }); + test('it can select a basic problem type', async () => { + const mockClose = jest.fn(); + 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(); + + // First we see the menu of problem types: + expect(await screen.findByRole('button', { name: 'Numerical input' })).toBeInTheDocument(); + // And the "Advanced" types are not yet listed: + expect(screen.queryByRole('radio', { name: 'Custom JavaScript display and grading' })).not.toBeInTheDocument(); + + // Before we select a problem type, try viewing the advanced types and then going back: + const advancedButton = await screen.findByRole('button', { name: 'Advanced problem types' }); + fireEvent.click(advancedButton); + + // Now we see the advanced types: + await screen.findByRole('radio', { name: 'Custom JavaScript display and grading' }); + expect(screen.queryByRole('button', { name: 'Numerical input' })).not.toBeInTheDocument(); + + const goBackButton = screen.getByRole('button', { name: 'Go back' }); + fireEvent.click(goBackButton); + + const numericalInputBtn = await screen.findByRole('button', { name: 'Numerical input' }); + fireEvent.click(numericalInputBtn); + + // Now we save our selection: + const selectBtn = screen.getByRole('button', { name: 'Select' }); + fireEvent.click(selectBtn); + expect(mockSelect).toHaveBeenLastCalledWith(expect.objectContaining({ selected: 'numericalresponse' })); + }); +}); diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.tsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.tsx index 21fa829236..4e7a4c7173 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.tsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.tsx @@ -6,7 +6,12 @@ import Preview from './content/Preview'; import AdvanceTypeSelect from './content/AdvanceTypeSelect'; import SelectTypeWrapper from './SelectTypeWrapper'; import * as hooks from './hooks'; -import { AdvanceProblemKeys } from '../../../../data/constants/problem'; +import { + AdvancedProblemType, + AdvanceProblemKeys, + ProblemType, + ProblemTypeKeys, +} from '../../../../data/constants/problem'; interface Props { onClose: (() => void) | null; @@ -15,18 +20,18 @@ interface Props { const SelectTypeModal: React.FC = ({ onClose, }) => { - const { selected, setSelected } = hooks.selectHooks(); + const [selected, setSelected] = React.useState(ProblemTypeKeys.SINGLESELECT); hooks.useArrowNav(selected, setSelected); return ( - {(!Object.values(AdvanceProblemKeys).includes(selected)) ? ( + {(!Object.values(AdvanceProblemKeys).includes(selected as any)) ? ( - ) : } + ) : } ); diff --git a/src/editors/setupEditorTest.js b/src/editors/setupEditorTest.js index 0bd2d75ca6..88129bd9a9 100644 --- a/src/editors/setupEditorTest.js +++ b/src/editors/setupEditorTest.js @@ -1,5 +1,14 @@ // These additional mocks and setup are required for some tests in src/editors/ // and are imported on an as-needed basis. + +// ///////////////////////////////////////////////////////////////////////////// +// TODO: tests using this 'setupEditorTest', shallow rendering, and snapshots +// should be replaced with modern tests that use src/testUtils.ts and +// @testing-library/react. See +// src/editors/containers/ProblemEditor/components/SelectTypeModal/index.test.tsx +// for an example of an editor test in the new format. +// ///////////////////////////////////////////////////////////////////////////// + import { formatMessage as mockFormatMessage } from './testUtils'; // eslint-disable-next-line import/no-extraneous-dependencies import 'jest-canvas-mock'; diff --git a/src/testUtils.tsx b/src/testUtils.tsx index 283e341f48..7481797621 100644 --- a/src/testUtils.tsx +++ b/src/testUtils.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { AxiosError } from 'axios'; import { jest } from '@jest/globals'; +import type { Store } from 'redux'; import { initializeMockApp } from '@edx/frontend-platform'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; import { IntlProvider } from '@edx/frontend-platform/i18n'; @@ -25,7 +26,7 @@ import { ToastContext, type ToastContextData } from './generic/toast-context'; import initializeReduxStore from './store'; /** @deprecated Use React Query and/or regular React Context instead of redux */ -let reduxStore; +let reduxStore: Store; let queryClient; let axiosMock: MockAdapter; From 8b5a4c68dbb02c16df8aa3d59544389329bf3bc8 Mon Sep 17 00:00:00 2001 From: Braden MacDonald Date: Mon, 16 Sep 2024 17:18:56 -0700 Subject: [PATCH 8/9] test: improve test coverage --- src/editors/Editor.tsx | 16 ++++++++-------- .../content/AdvanceTypeSelect.tsx | 4 ++-- ...elect.test.jsx => ProblemTypeSelect.test.tsx} | 3 +-- .../content/ProblemTypeSelect.tsx | 2 +- ....jsx.snap => ProblemTypeSelect.test.tsx.snap} | 0 .../components/SelectTypeModal/index.tsx | 6 +++--- src/editors/data/constants/problem.ts | 4 ++++ 7 files changed, 19 insertions(+), 16 deletions(-) rename src/editors/containers/ProblemEditor/components/SelectTypeModal/content/{ProblemTypeSelect.test.jsx => ProblemTypeSelect.test.tsx} (96%) rename src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/{ProblemTypeSelect.test.jsx.snap => ProblemTypeSelect.test.tsx.snap} (100%) diff --git a/src/editors/Editor.tsx b/src/editors/Editor.tsx index ae9c68ef46..cc42647f56 100644 --- a/src/editors/Editor.tsx +++ b/src/editors/Editor.tsx @@ -10,18 +10,18 @@ import type { EditorComponent } from './EditorComponent'; export interface Props extends EditorComponent { blockType: string; - blockId?: string | null; - learningContextId?: string | null; - lmsEndpointUrl?: string | null; - studioEndpointUrl?: string | null; + blockId: string | null; + learningContextId: string | null; + lmsEndpointUrl: string | null; + studioEndpointUrl: string | null; } const Editor: React.FC = ({ - learningContextId = null, + learningContextId, blockType, - blockId = null, - lmsEndpointUrl = null, - studioEndpointUrl = null, + blockId, + lmsEndpointUrl, + studioEndpointUrl, onClose = null, returnFunction = null, }) => { diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.tsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.tsx index cddba79870..2add431b27 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.tsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.tsx @@ -21,12 +21,12 @@ import { import messages from './messages'; interface Props { - selected: AdvancedProblemType | null; + selected: AdvancedProblemType; setSelected: React.Dispatch; } const AdvanceTypeSelect: React.FC = ({ - selected = null, + selected, setSelected, }) => { const intl = useIntl(); diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.test.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.test.tsx similarity index 96% rename from src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.test.jsx rename to src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.test.tsx index 3d59d4315e..e7d433c92d 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.test.jsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.test.tsx @@ -1,12 +1,11 @@ import 'CourseAuthoring/editors/setupEditorTest'; -import React from 'react'; + import { shallow } from '@edx/react-unit-test-utils'; import { ProblemTypeKeys } from '../../../../../data/constants/problem'; import ProblemTypeSelect from './ProblemTypeSelect'; describe('ProblemTypeSelect', () => { const props = { - selected: null, setSelected: jest.fn(), }; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.tsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.tsx index cd38dd8f0d..a87f329042 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.tsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.tsx @@ -14,7 +14,7 @@ import { import messages from './messages'; interface Props { - selected: string; + selected: ProblemType; setSelected: (selected: ProblemType | AdvancedProblemType) => void; } diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.jsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.tsx.snap similarity index 100% rename from src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.jsx.snap rename to src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.tsx.snap diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.tsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.tsx index 4e7a4c7173..fbb17fad43 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.tsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.tsx @@ -8,7 +8,7 @@ import SelectTypeWrapper from './SelectTypeWrapper'; import * as hooks from './hooks'; import { AdvancedProblemType, - AdvanceProblemKeys, + isAdvancedProblemType, ProblemType, ProblemTypeKeys, } from '../../../../data/constants/problem'; @@ -26,12 +26,12 @@ const SelectTypeModal: React.FC = ({ return ( - {(!Object.values(AdvanceProblemKeys).includes(selected as any)) ? ( + {(!isAdvancedProblemType(selected)) ? ( - ) : } + ) : } ); diff --git a/src/editors/data/constants/problem.ts b/src/editors/data/constants/problem.ts index edbc13d95c..e0cb91d593 100644 --- a/src/editors/data/constants/problem.ts +++ b/src/editors/data/constants/problem.ts @@ -88,6 +88,10 @@ export const AdvanceProblemKeys = StrictDict({ } as const); export type AdvancedProblemType = typeof AdvanceProblemKeys[keyof typeof AdvanceProblemKeys]; +export function isAdvancedProblemType(pt: ProblemType | AdvancedProblemType): pt is AdvancedProblemType { + return Object.values(AdvanceProblemKeys).includes(pt as any); +} + export const AdvanceProblems = StrictDict({ [AdvanceProblemKeys.BLANK]: { title: 'Blank problem', From 2a2879d51fe2e0bcd69fab056081cf8e94bc73fd Mon Sep 17 00:00:00 2001 From: Braden MacDonald Date: Wed, 18 Sep 2024 09:52:09 -0700 Subject: [PATCH 9/9] chore: delete commented code --- .../SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.jsx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.jsx index 00c2e6bfa1..cd41940bb3 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.jsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.jsx @@ -56,12 +56,6 @@ SelectTypeFooter.defaultProps = { }; SelectTypeFooter.propTypes = { - // defaultSettings: PropTypes.shape({ - // maxAttempts: PropTypes.number, - // rerandomize: PropTypes.string, - // showResetButton: PropTypes.bool, - // showanswer: PropTypes.string, - // }).isRequired, onCancel: PropTypes.func.isRequired, selected: PropTypes.string, };