Skip to content

Commit

Permalink
Merge pull request #163 from openedx/bw/documentation
Browse files Browse the repository at this point in the history
fix: feedback only criteria in readonly assessment
  • Loading branch information
Ben Warzeski authored Jan 5, 2024
2 parents 0f5be69 + 0263fcc commit e4e1acf
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const AssessmentCriteria = ({ criteria, overallFeedback, stepLabel }) => {
<>
{criteriaConfig.map((rubricCriterion, i) => {
const { selectedOption, feedback } = criteria[i];
const option = rubricCriterion.options[selectedOption];
const option = rubricCriterion.options[selectedOption] || {};
const commentHeader = stepLabel
? formatMessage(messages.stepComments, { step: stepLabel })
: null;
Expand Down
129 changes: 121 additions & 8 deletions src/hooks/assessment.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// import React from 'react';
import React from 'react';
import { when } from 'jest-when';

import { getEffects } from '@edx/react-unit-test-utils';

import { stepNames } from 'constants/index';

import * as reduxHooks from 'data/redux/hooks';
Expand All @@ -13,21 +15,26 @@ import * as exported from './assessment';
const { hooks } = exported;

jest.mock('data/redux/hooks', () => ({
useCriterionOption: jest.fn(),
useSetCriterionOption: jest.fn(),
useSetShowTrainingError: jest.fn(),
useCriterionFeedback: jest.fn(),
useSetCriterionFeedback: jest.fn(),
useCriterionOption: jest.fn(),
useFormFields: jest.fn(),
useOverallFeedbackValue: jest.fn(),
useResetAssessment: jest.fn(),
useSetCriterionFeedback: jest.fn(),
useSetCriterionOption: jest.fn(),
useSetFormFields: jest.fn(),
useSetOverallFeedback: jest.fn(),
useFormFields: jest.fn(),
useSetResponse: jest.fn(),
useSetShowTrainingError: jest.fn(),
}));

jest.mock('data/services/lms/hooks/actions', () => ({
}));
jest.mock('data/services/lms/hooks/selectors', () => ({
useCriteriaConfig: jest.fn(),
useStepInfo: jest.fn(),
useEmptyRubric: jest.fn(),
useResponseData: jest.fn(),
}));
jest.mock('./routing', () => ({
useViewStep: jest.fn(),
Expand All @@ -51,12 +58,27 @@ const testStepInfo = {
expectedRubricSelections: [1, 2, 3],
},
};
const testResponse = { test: 'response' };
when(lmsSelectors.useResponseData).calledWith().mockReturnValue(testResponse);
const testEmptyRubric = { test: 'empty rubric' };
when(lmsSelectors.useEmptyRubric).calledWith().mockReturnValue(testEmptyRubric);
const setCriterionFeedback = jest.fn();
when(reduxHooks.useSetCriterionFeedback).calledWith().mockReturnValue(setCriterionFeedback);
const setFormFields = jest.fn();
when(reduxHooks.useSetFormFields).calledWith().mockReturnValue(setFormFields);
const setOverallFeedback = jest.fn();
when(reduxHooks.useSetOverallFeedback).calledWith().mockReturnValue(setOverallFeedback);
const setResponse = jest.fn();
when(reduxHooks.useSetResponse).calledWith().mockReturnValue(setResponse);
const reset = jest.fn();
when(reduxHooks.useResetAssessment).calledWith().mockReturnValue(reset);

describe('Assessment hooks', () => {
beforeEach(() => {
jest.clearAllMocks();
});

describe('useCheckTrainingSelection', () => {
describe('useIsTrainingSelectionValid', () => {
const prepHook = ({ assessment = testAssessment, stepInfo = testStepInfo } = {}) => {
when(reduxHooks.useFormFields).calledWith().mockReturnValueOnce(assessment);
when(lmsSelectors.useStepInfo).calledWith().mockReturnValueOnce(stepInfo);
Expand Down Expand Up @@ -96,14 +118,39 @@ describe('Assessment hooks', () => {
prepHook();
expect(out).toEqual(true);
});

it('returns false if any of the selected options to not match expected values', () => {
prepHook({ studentTraining: { expectedRubricSelections: [1, 2, 4] } });
expect(out).toEqual(true);
});
});
});
describe('useInitializeAssessment', () => {
const prepHook = () => {
out = hooks.useInitializeAssessment();
};
describe('behavior', () => {
it('loads response, empty rubric, and setters for response and formFields from hooks', () => {
prepHook();
expect(lmsSelectors.useEmptyRubric).toHaveBeenCalledWith();
expect(lmsSelectors.useResponseData).toHaveBeenCalledWith();
expect(reduxHooks.useSetFormFields).toHaveBeenCalledWith();
expect(reduxHooks.useSetResponse).toHaveBeenCalledWith();
});
it('calls setResponse with response on first load', () => {
prepHook();
const [cb] = getEffects([], React);
cb();
expect(setResponse).toHaveBeenCalledWith(testResponse);
});
});
describe('output', () => {
it('returns a static callback that sets form fields to empty rubric', () => {
prepHook();
expect(out.useCallback.prereqs).toEqual([]);
out.useCallback.cb();
expect(setFormFields).toHaveBeenCalledWith(testEmptyRubric);
});
});
});
describe('useIsCriterionFeedbackInvalid', () => {
const prepHook = ({ viewStep, criteriaConfig }) => {
Expand Down Expand Up @@ -134,8 +181,46 @@ describe('Assessment hooks', () => {
});
});
describe('useOverallFeedbackFormFields', () => {
const prepHook = () => {
when(reduxHooks.useOverallFeedbackValue).calledWith().mockReturnValueOnce(testValue);
out = hooks.useOverallFeedbackFormFields();
};
describe('behavior', () => {
it('loads value and setter from hooks', () => {
prepHook();
expect(reduxHooks.useOverallFeedbackValue).toHaveBeenCalledWith();
expect(reduxHooks.useSetOverallFeedback).toHaveBeenCalledWith();
});
});
describe('output', () => {
it('returns value and setFeedback event handler', () => {
prepHook();
expect(out.value).toEqual(testValue);
out.onChange({ target: { value: testValue } });
expect(setOverallFeedback).toHaveBeenCalledWith(testValue);
});
});
});
describe('useResetAssessment', () => {
const prepHook = () => {
out = hooks.useResetAssessment();
};
describe('behavior', () => {
it('loads value and setter from hooks', () => {
prepHook();
expect(reduxHooks.useResetAssessment).toHaveBeenCalledWith();
expect(reduxHooks.useSetFormFields).toHaveBeenCalledWith();
expect(lmsSelectors.useEmptyRubric).toHaveBeenCalledWith();
});
});
describe('output', () => {
it('returns value and setFeedback event handler', () => {
prepHook();
out();
expect(reset).toHaveBeenCalled();
expect(setFormFields).toHaveBeenCalledWith(testEmptyRubric);
});
});
});
describe('useTrainingOptionValidity', () => {
const prepHook = ({ value, stepInfo, criterionIndex = 1 }) => {
Expand Down Expand Up @@ -174,7 +259,35 @@ describe('Assessment hooks', () => {
});

describe('useCriterionFeedbackFormFields', () => {
const criterionIndex = 3;
const mockIsInvalid = (args) => ({ isInvalid: args });
let spy;
const prepHook = () => {
when(reduxHooks.useCriterionFeedback).calledWith(criterionIndex).mockReturnValueOnce(testValue);
when(reduxHooks.useSetCriterionFeedback).calledWith(criterionIndex).mockReturnValueOnce(setCriterionFeedback);
spy = jest.spyOn(hooks, 'useIsCriterionFeedbackInvalid');
when(spy).calledWith().mockReturnValueOnce(mockIsInvalid);
out = hooks.useCriterionFeedbackFormFields(criterionIndex);
};
describe('behavior', () => {
it('loads value, validity, and setter from hooks', () => {
prepHook();
expect(reduxHooks.useCriterionFeedback).toHaveBeenCalledWith(criterionIndex);
expect(reduxHooks.useSetCriterionFeedback).toHaveBeenCalledWith(criterionIndex);
expect(hooks.useIsCriterionFeedbackInvalid).toHaveBeenCalledWith();
});
});
describe('output', () => {
it('returns value and setFeedback event handler', () => {
prepHook();
expect(out.value).toEqual(testValue);
expect(out.isInvalid).toEqual(mockIsInvalid({ value: testValue, criterionIndex }));
out.onChange({ target: { value: testValue } });
expect(setCriterionFeedback).toHaveBeenCalledWith(testValue);
});
});
});

describe('useCriterionOptionFormFields', () => {
const hook = hooks.useCriterionOptionFormFields;
let spy;
Expand Down

0 comments on commit e4e1acf

Please sign in to comment.