refactor: add edit modal tests (#191)
* update drawer layout and container logic * add tests and docstrings for EditModal components * typo fix and merge conflict * v1.4.35
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@edx/frontend-app-gradebook",
|
||||
"version": "1.4.34",
|
||||
"version": "1.4.35",
|
||||
"description": "edx editable gradebook-ui to manipulate grade overrides on subsections",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
26
src/components/GradesTab/EditModal/HistoryHeader.jsx
Normal file
26
src/components/GradesTab/EditModal/HistoryHeader.jsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/**
|
||||
* HistoryHeader
|
||||
* simple display container for an individual history table header
|
||||
* @param {string} id - header id
|
||||
* @param {string} label - header label
|
||||
* @param {string} value - header value
|
||||
*/
|
||||
const HistoryHeader = ({ id, label, value }) => (
|
||||
<div>
|
||||
<div className={`grade-history-header grade-history-${id}`}>{label}: </div>
|
||||
<div>{value}</div>
|
||||
</div>
|
||||
);
|
||||
HistoryHeader.defaultProps = {
|
||||
value: null,
|
||||
};
|
||||
HistoryHeader.propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
};
|
||||
|
||||
export default HistoryHeader;
|
||||
17
src/components/GradesTab/EditModal/HistoryHeader.test.jsx
Normal file
17
src/components/GradesTab/EditModal/HistoryHeader.test.jsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import HistoryHeader from './HistoryHeader';
|
||||
|
||||
describe('HistoryHeader', () => {
|
||||
const props = {
|
||||
id: 'water',
|
||||
label: 'Brita',
|
||||
value: 'hydration',
|
||||
};
|
||||
describe('Component', () => {
|
||||
test('snapshot', () => {
|
||||
expect(shallow(<HistoryHeader {...props} />)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -3,22 +3,13 @@ import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
import HistoryHeader from './HistoryHeader';
|
||||
|
||||
const HistoryHeader = ({ id, label, value }) => (
|
||||
<div>
|
||||
<div className={`grade-history-header grade-history-${id}`}>{label}: </div>
|
||||
<div>{value}</div>
|
||||
</div>
|
||||
);
|
||||
HistoryHeader.defaultProps = {
|
||||
value: null,
|
||||
};
|
||||
HistoryHeader.propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
};
|
||||
|
||||
/**
|
||||
* <ModalHeaders />
|
||||
* Provides a list of HistoryHeaders for the student name, assignment,
|
||||
* original grade, and current override grade.
|
||||
*/
|
||||
export const ModalHeaders = ({
|
||||
modalState,
|
||||
originalGrade,
|
||||
@@ -62,7 +53,6 @@ ModalHeaders.propTypes = {
|
||||
};
|
||||
|
||||
export const mapStateToProps = (state) => ({
|
||||
editUpdateData: selectors.app.editUpdateData(state),
|
||||
modalState: {
|
||||
assignmentName: selectors.app.modalState.assignmentName(state),
|
||||
updateUserName: selectors.app.modalState.updateUserName(state),
|
||||
|
||||
94
src/components/GradesTab/EditModal/ModalHeaders.test.jsx
Normal file
94
src/components/GradesTab/EditModal/ModalHeaders.test.jsx
Normal file
@@ -0,0 +1,94 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
|
||||
import {
|
||||
ModalHeaders,
|
||||
mapStateToProps,
|
||||
} from './ModalHeaders';
|
||||
|
||||
jest.mock('./HistoryHeader', () => 'HistoryHeader');
|
||||
|
||||
jest.mock('data/selectors', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
app: {
|
||||
editUpdateData: jest.fn(state => ({ editUpdateData: state })),
|
||||
modalState: {
|
||||
assignmentName: jest.fn(state => ({ assignmentName: state })),
|
||||
updateUserName: jest.fn(state => ({ updateUserName: state })),
|
||||
},
|
||||
},
|
||||
grades: {
|
||||
gradeOverrideCurrentEarnedGradedOverride: jest.fn(state => ({ currentGrade: state })),
|
||||
gradeOriginalEarnedGraded: jest.fn(state => ({ originalGrade: state })),
|
||||
},
|
||||
},
|
||||
}));
|
||||
describe('ModalHeaders', () => {
|
||||
let el;
|
||||
const props = {
|
||||
currentGrade: 2,
|
||||
originalGrade: 20,
|
||||
modalState: {
|
||||
assignmentName: 'Qwerty',
|
||||
updateUserName: 'Uiop',
|
||||
},
|
||||
};
|
||||
|
||||
describe('Component', () => {
|
||||
describe('snapshots', () => {
|
||||
beforeEach(() => {
|
||||
});
|
||||
describe('gradeOverrideHistoryError is and empty and open is true', () => {
|
||||
test('modal open and StatusAlert showing', () => {
|
||||
el = shallow(<ModalHeaders {...props} />);
|
||||
expect(el).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
describe('gradeOverrideHistoryError is empty and open is false', () => {
|
||||
test('modal closed and StatusAlert closed', () => {
|
||||
el = shallow(
|
||||
<ModalHeaders {...props} open={false} gradeOverrideHistoryError="" />,
|
||||
);
|
||||
expect(el).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapStateToProps', () => {
|
||||
const testState = { he: 'lives in a', pineapple: 'under the sea' };
|
||||
let mapped;
|
||||
beforeEach(() => {
|
||||
mapped = mapStateToProps(testState);
|
||||
});
|
||||
describe('modalState', () => {
|
||||
test('assignmentName from app.modalState.assignmentName', () => {
|
||||
expect(
|
||||
mapped.modalState.assignmentName,
|
||||
).toEqual(selectors.app.modalState.assignmentName(testState));
|
||||
});
|
||||
test('updateUserName from app.modalState.updateUserName', () => {
|
||||
expect(
|
||||
mapped.modalState.updateUserName,
|
||||
).toEqual(selectors.app.modalState.updateUserName(testState));
|
||||
});
|
||||
});
|
||||
describe('originalGrade', () => {
|
||||
test('from grades.gradeOverrideCurrentEarnedGradedOverride', () => {
|
||||
expect(mapped.currentGrade).toEqual(
|
||||
selectors.grades.gradeOverrideCurrentEarnedGradedOverride(testState),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('originalGrade', () => {
|
||||
test('from grades.gradeOriginalEarnedGrades', () => {
|
||||
expect(mapped.originalGrade).toEqual(
|
||||
selectors.grades.gradeOriginalEarnedGraded(testState),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -8,6 +8,11 @@ import { Form } from '@edx/paragon';
|
||||
import selectors from 'data/selectors';
|
||||
import actions from 'data/actions';
|
||||
|
||||
/**
|
||||
* <AdjustedGradeInput />
|
||||
* Input control for adjusting the grade of a unit
|
||||
* displays an "/ ${possibleGrade} if there is one in the data model.
|
||||
*/
|
||||
export class AdjustedGradeInput extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import actions from 'data/actions';
|
||||
import selectors from 'data/selectors';
|
||||
|
||||
import {
|
||||
AdjustedGradeInput,
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
} from './AdjustedGradeInput';
|
||||
|
||||
jest.mock('@edx/paragon', () => ({
|
||||
Form: { Control: () => 'Form.Control' },
|
||||
}));
|
||||
jest.mock('data/selectors', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
root: {
|
||||
editModalPossibleGrade: jest.fn(state => ({ updateUserName: state })),
|
||||
},
|
||||
app: {
|
||||
modalState: { adjustedGradeValue: jest.fn(state => ({ adjustedGradeValue: state })) },
|
||||
},
|
||||
},
|
||||
}));
|
||||
jest.mock('data/actions', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
app: { setModalState: jest.fn() },
|
||||
},
|
||||
}));
|
||||
describe('AdjustedGradeInput', () => {
|
||||
let el;
|
||||
let props = {
|
||||
value: 1,
|
||||
possibleGrade: 5,
|
||||
};
|
||||
beforeEach(() => {
|
||||
props = {
|
||||
...props,
|
||||
setModalState: jest.fn(),
|
||||
};
|
||||
});
|
||||
describe('Component', () => {
|
||||
beforeEach(() => {
|
||||
el = shallow(<AdjustedGradeInput {...props} />);
|
||||
});
|
||||
describe('snapshots', () => {
|
||||
test('displays input control and "out of possible grade" label', () => {
|
||||
el.instance().onChange = jest.fn().mockName('this.onChange');
|
||||
expect(el.instance().render()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
describe('behavior', () => {
|
||||
describe('onChange', () => {
|
||||
it('calls props.setModalState event target value', () => {
|
||||
const value = 42;
|
||||
el.instance().onChange({ target: { value } });
|
||||
expect(props.setModalState).toHaveBeenCalledWith({
|
||||
adjustedGradeValue: value,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapStateToProps', () => {
|
||||
const testState = { like: 'no one', ever: 'was' };
|
||||
let mapped;
|
||||
beforeEach(() => {
|
||||
mapped = mapStateToProps(testState);
|
||||
});
|
||||
describe('modalState', () => {
|
||||
test('possibleGrade from root.editModalPossibleGrade', () => {
|
||||
expect(
|
||||
mapped.possibleGrade,
|
||||
).toEqual(selectors.root.editModalPossibleGrade(testState));
|
||||
});
|
||||
test('updateUserName from app.modalState.updateUserName', () => {
|
||||
expect(
|
||||
mapped.value,
|
||||
).toEqual(selectors.app.modalState.adjustedGradeValue(testState));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('mapDispatchToProps', () => {
|
||||
test('setModalState from actions.app.setModalState', () => {
|
||||
expect(mapDispatchToProps.setModalState).toEqual(actions.app.setModalState);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -7,6 +7,10 @@ import { Form } from '@edx/paragon';
|
||||
import selectors from 'data/selectors';
|
||||
import actions from 'data/actions';
|
||||
|
||||
/**
|
||||
* <ReasonInput />
|
||||
* Input control for the "reason for change" field in the Edit modal.
|
||||
*/
|
||||
export class ReasonInput extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import actions from 'data/actions';
|
||||
import selectors from 'data/selectors';
|
||||
|
||||
import {
|
||||
ReasonInput,
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
} from './ReasonInput';
|
||||
|
||||
jest.mock('@edx/paragon', () => ({
|
||||
Form: { Control: () => 'Form.Control' },
|
||||
}));
|
||||
jest.mock('data/selectors', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
app: {
|
||||
modalState: { reasonForChange: jest.fn(state => ({ reasonForChange: state })) },
|
||||
},
|
||||
},
|
||||
}));
|
||||
jest.mock('data/actions', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
app: { setModalState: jest.fn() },
|
||||
},
|
||||
}));
|
||||
describe('ReasonInput', () => {
|
||||
let el;
|
||||
let props = {
|
||||
value: 'did not answer the question',
|
||||
};
|
||||
beforeEach(() => {
|
||||
props = {
|
||||
...props,
|
||||
setModalState: jest.fn(),
|
||||
};
|
||||
});
|
||||
describe('Component', () => {
|
||||
beforeEach(() => {
|
||||
el = shallow(<ReasonInput {...props} />, { disableLifecycleMethods: true });
|
||||
});
|
||||
describe('snapshots', () => {
|
||||
test('displays reason for change input control', () => {
|
||||
el.instance().onChange = jest.fn().mockName('this.onChange');
|
||||
expect(el.instance().render()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
describe('behavior', () => {
|
||||
describe('onChange', () => {
|
||||
it('calls props.setModalState event target value', () => {
|
||||
const value = 42;
|
||||
el.instance().onChange({ target: { value } });
|
||||
expect(props.setModalState).toHaveBeenCalledWith({
|
||||
reasonForChange: value,
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('componentDidMount', () => {
|
||||
it('focuses the input ref', () => {
|
||||
const focus = jest.fn();
|
||||
expect(el.instance().ref).toEqual({ current: null });
|
||||
el.instance().ref.current = { focus };
|
||||
el.instance().componentDidMount();
|
||||
expect(el.instance().ref.current.focus).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapStateToProps', () => {
|
||||
const testState = { to: { catchThem: 'my real test', trainThem: 'my cause!' } };
|
||||
let mapped;
|
||||
beforeEach(() => {
|
||||
mapped = mapStateToProps(testState);
|
||||
});
|
||||
describe('modalState', () => {
|
||||
test('value from app.modalState.reasonForChange', () => {
|
||||
expect(mapped.value).toEqual(selectors.app.modalState.reasonForChange(testState));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('mapDispatchToProps', () => {
|
||||
test('setModalState from actions.app.setModalState', () => {
|
||||
expect(mapDispatchToProps.setModalState).toEqual(actions.app.setModalState);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`AdjustedGradeInput Component snapshots displays input control and "out of possible grade" label 1`] = `
|
||||
<span>
|
||||
<Control
|
||||
name="adjustedGradeValue"
|
||||
onChange={[MockFunction this.onChange]}
|
||||
type="text"
|
||||
value={1}
|
||||
/>
|
||||
/ 5
|
||||
</span>
|
||||
`;
|
||||
@@ -0,0 +1,10 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ReasonInput Component snapshots displays reason for change input control 1`] = `
|
||||
<Control
|
||||
name="reasonForChange"
|
||||
onChange={[MockFunction this.onChange]}
|
||||
type="text"
|
||||
value="did not answer the question"
|
||||
/>
|
||||
`;
|
||||
@@ -0,0 +1,47 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`OverrideTable Component snapshots basic snapshot shows a row for each entry and one editable row 1`] = `
|
||||
<Table
|
||||
columns={
|
||||
Array [
|
||||
Object {
|
||||
"key": "date",
|
||||
"label": "Date",
|
||||
},
|
||||
Object {
|
||||
"key": "grader",
|
||||
"label": "Grader",
|
||||
},
|
||||
Object {
|
||||
"key": "reason",
|
||||
"label": "Reason",
|
||||
},
|
||||
Object {
|
||||
"key": "adjustedGrade",
|
||||
"label": "Adjusted grade",
|
||||
},
|
||||
]
|
||||
}
|
||||
data={
|
||||
Array [
|
||||
Object {
|
||||
"adjustedGrade": 0,
|
||||
"date": "yesterday",
|
||||
"grader": "me",
|
||||
"reason": "you ate my sandwich",
|
||||
},
|
||||
Object {
|
||||
"adjustedGrade": 20,
|
||||
"date": "today",
|
||||
"grader": "me",
|
||||
"reason": "you brought me a new sandwich",
|
||||
},
|
||||
Object {
|
||||
"adjustedGrade": <AdjustedGradeInput />,
|
||||
"date": "todaaaaaay",
|
||||
"reason": <ReasonInput />,
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
`;
|
||||
@@ -16,6 +16,11 @@ const GRADE_OVERRIDE_HISTORY_COLUMNS = [
|
||||
{ label: 'Adjusted grade', key: 'adjustedGrade' },
|
||||
];
|
||||
|
||||
/**
|
||||
* <OverrideTable />
|
||||
* Table containing previous grade override entries, and an "edit" row
|
||||
* with todays date, an AdjustedGradeInput and a ReasonInput
|
||||
*/
|
||||
export const OverrideTable = ({
|
||||
hide,
|
||||
gradeOverrides,
|
||||
@@ -42,6 +47,7 @@ OverrideTable.defaultProps = {
|
||||
gradeOverrides: [],
|
||||
};
|
||||
OverrideTable.propTypes = {
|
||||
// redux
|
||||
gradeOverrides: PropTypes.arrayOf(PropTypes.shape({
|
||||
date: PropTypes.string,
|
||||
grader: PropTypes.string,
|
||||
|
||||
81
src/components/GradesTab/EditModal/OverrideTable/test.jsx
Normal file
81
src/components/GradesTab/EditModal/OverrideTable/test.jsx
Normal file
@@ -0,0 +1,81 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
|
||||
import {
|
||||
OverrideTable,
|
||||
mapStateToProps,
|
||||
} from '.';
|
||||
|
||||
jest.mock('@edx/paragon', () => ({ Table: () => 'Table' }));
|
||||
jest.mock('./ReasonInput', () => 'ReasonInput');
|
||||
jest.mock('./AdjustedGradeInput', () => 'AdjustedGradeInput');
|
||||
|
||||
jest.mock('data/selectors', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
app: {
|
||||
modalState: {
|
||||
todaysDate: jest.fn(state => ({ todaysDate: state })),
|
||||
},
|
||||
},
|
||||
grades: {
|
||||
hasOverrideErrors: jest.fn(state => ({ hasOverrideErrors: state })),
|
||||
gradeOverrides: jest.fn(state => ({ gradeOverrides: state })),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
describe('OverrideTable', () => {
|
||||
const props = {
|
||||
gradeOverrides: [
|
||||
{
|
||||
date: 'yesterday',
|
||||
grader: 'me',
|
||||
reason: 'you ate my sandwich',
|
||||
adjustedGrade: 0,
|
||||
},
|
||||
{
|
||||
date: 'today',
|
||||
grader: 'me',
|
||||
reason: 'you brought me a new sandwich',
|
||||
adjustedGrade: 20,
|
||||
},
|
||||
],
|
||||
hide: false,
|
||||
todaysDate: 'todaaaaaay',
|
||||
};
|
||||
|
||||
describe('Component', () => {
|
||||
describe('snapshots', () => {
|
||||
it('returns null if hide is true', () => {
|
||||
expect(shallow(<OverrideTable {...props} hide />)).toEqual({});
|
||||
});
|
||||
describe('basic snapshot', () => {
|
||||
test('shows a row for each entry and one editable row', () => {
|
||||
expect(shallow(<OverrideTable {...props} />)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapStateToProps', () => {
|
||||
const testState = { I: 'wanna', be: 'the', very: 'best' };
|
||||
let mapped;
|
||||
beforeEach(() => {
|
||||
mapped = mapStateToProps(testState);
|
||||
});
|
||||
describe('modalState', () => {
|
||||
test('hide from grades.hasOverrideErrors', () => {
|
||||
expect(mapped.hide).toEqual(selectors.grades.hasOverrideErrors(testState));
|
||||
});
|
||||
test('gradeOverrides from grades.gradeOverrides', () => {
|
||||
expect(mapped.gradeOverrides).toEqual(selectors.grades.gradeOverrides(testState));
|
||||
});
|
||||
test('todaysData from app.modalState.todaysDate', () => {
|
||||
expect(mapped.todaysDate).toEqual(selectors.app.modalState.todaysDate(testState));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`HistoryHeader Component snapshot 1`] = `
|
||||
<div>
|
||||
<div
|
||||
className="grade-history-header grade-history-water"
|
||||
>
|
||||
Brita
|
||||
:
|
||||
</div>
|
||||
<div>
|
||||
hydration
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,51 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ModalHeaders Component snapshots gradeOverrideHistoryError is and empty and open is true modal open and StatusAlert showing 1`] = `
|
||||
<div>
|
||||
<HistoryHeader
|
||||
id="assignment"
|
||||
label="Assignment"
|
||||
value="Qwerty"
|
||||
/>
|
||||
<HistoryHeader
|
||||
id="student"
|
||||
label="Student"
|
||||
value="Uiop"
|
||||
/>
|
||||
<HistoryHeader
|
||||
id="original-grade"
|
||||
label="Original Grade"
|
||||
value={20}
|
||||
/>
|
||||
<HistoryHeader
|
||||
id="current-grade"
|
||||
label="Current Grade"
|
||||
value={2}
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ModalHeaders Component snapshots gradeOverrideHistoryError is empty and open is false modal closed and StatusAlert closed 1`] = `
|
||||
<div>
|
||||
<HistoryHeader
|
||||
id="assignment"
|
||||
label="Assignment"
|
||||
value="Qwerty"
|
||||
/>
|
||||
<HistoryHeader
|
||||
id="student"
|
||||
label="Student"
|
||||
value="Uiop"
|
||||
/>
|
||||
<HistoryHeader
|
||||
id="original-grade"
|
||||
label="Original Grade"
|
||||
value={20}
|
||||
/>
|
||||
<HistoryHeader
|
||||
id="current-grade"
|
||||
label="Current Grade"
|
||||
value={2}
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,75 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`EditMoal Component snapshots gradeOverrideHistoryError is and empty and open is true modal open and StatusAlert showing 1`] = `
|
||||
<Modal
|
||||
body={
|
||||
<div>
|
||||
<ModalHeaders />
|
||||
<StatusAlert
|
||||
alertType="danger"
|
||||
dialog="Weve been trying to contact you regarding..."
|
||||
dismissible={false}
|
||||
open={true}
|
||||
/>
|
||||
<OverrideTable />
|
||||
<div>
|
||||
Showing most recent actions (max 5). To see more, please contact support.
|
||||
</div>
|
||||
<div>
|
||||
Note: Once you save, your changes will be visible to students.
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
buttons={
|
||||
Array [
|
||||
<Button
|
||||
onClick={[MockFunction this.handleAdjustedGradeClick]}
|
||||
variant="primary"
|
||||
>
|
||||
Save Grade
|
||||
</Button>,
|
||||
]
|
||||
}
|
||||
closeText="Cancel"
|
||||
onClose={[MockFunction this.closeAssignmentModal]}
|
||||
open={true}
|
||||
title="Edit Grades"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`EditMoal Component snapshots gradeOverrideHistoryError is empty and open is false modal closed and StatusAlert closed 1`] = `
|
||||
<Modal
|
||||
body={
|
||||
<div>
|
||||
<ModalHeaders />
|
||||
<StatusAlert
|
||||
alertType="danger"
|
||||
dialog=""
|
||||
dismissible={false}
|
||||
open={false}
|
||||
/>
|
||||
<OverrideTable />
|
||||
<div>
|
||||
Showing most recent actions (max 5). To see more, please contact support.
|
||||
</div>
|
||||
<div>
|
||||
Note: Once you save, your changes will be visible to students.
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
buttons={
|
||||
Array [
|
||||
<Button
|
||||
onClick={[MockFunction this.handleAdjustedGradeClick]}
|
||||
variant="primary"
|
||||
>
|
||||
Save Grade
|
||||
</Button>,
|
||||
]
|
||||
}
|
||||
closeText="Cancel"
|
||||
onClose={[MockFunction this.closeAssignmentModal]}
|
||||
open={false}
|
||||
title="Edit Grades"
|
||||
/>
|
||||
`;
|
||||
@@ -16,6 +16,15 @@ import thunkActions from 'data/thunkActions';
|
||||
import OverrideTable from './OverrideTable';
|
||||
import ModalHeaders from './ModalHeaders';
|
||||
|
||||
/**
|
||||
* <EditModal />
|
||||
* Wrapper component for the modal that allows editing the grade for an individual
|
||||
* unit, for a given student.
|
||||
* Provides a StatusAlert with override fetch errors if any are found, an OverrideTable
|
||||
* (with appropriate headers) for managing the actual override, and a submit button for
|
||||
* adjusting the grade.
|
||||
* (also provides a close button that clears the modal state)
|
||||
*/
|
||||
export class EditModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
132
src/components/GradesTab/EditModal/test.jsx
Normal file
132
src/components/GradesTab/EditModal/test.jsx
Normal file
@@ -0,0 +1,132 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import actions from 'data/actions';
|
||||
import selectors from 'data/selectors';
|
||||
import thunkActions from 'data/thunkActions';
|
||||
|
||||
import {
|
||||
EditModal,
|
||||
mapDispatchToProps,
|
||||
mapStateToProps,
|
||||
} from '.';
|
||||
|
||||
jest.mock('./OverrideTable', () => 'OverrideTable');
|
||||
jest.mock('./ModalHeaders', () => 'ModalHeaders');
|
||||
jest.mock('@edx/paragon', () => ({
|
||||
Button: () => 'Button',
|
||||
Modal: () => 'Modal',
|
||||
StatusAlert: () => 'StatusAlert',
|
||||
}));
|
||||
jest.mock('data/actions', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
app: { closeModal: jest.fn() },
|
||||
grades: { doneViewingAssignment: jest.fn() },
|
||||
},
|
||||
}));
|
||||
jest.mock('data/thunkActions', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
grades: { updateGrades: jest.fn() },
|
||||
},
|
||||
}));
|
||||
jest.mock('data/selectors', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
app: {
|
||||
modalState: {
|
||||
open: jest.fn(state => ({ isModalOpen: state })),
|
||||
},
|
||||
},
|
||||
grades: {
|
||||
gradeOverrideHistoryError: jest.fn(state => ({ overrideHistoryError: state })),
|
||||
},
|
||||
},
|
||||
}));
|
||||
describe('EditMoal', () => {
|
||||
let props;
|
||||
beforeEach(() => {
|
||||
props = {
|
||||
gradeOverrideHistoryError: 'Weve been trying to contact you regarding...',
|
||||
open: true,
|
||||
closeModal: jest.fn(),
|
||||
doneViewingAssignment: jest.fn(),
|
||||
updateGrades: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('Component', () => {
|
||||
describe('behavior', () => {
|
||||
let el;
|
||||
beforeEach(() => {
|
||||
el = shallow(<EditModal {...props} />);
|
||||
});
|
||||
describe('closeAssignmentModal', () => {
|
||||
it('calls props.doneViewingAssignment and props.closeModal', () => {
|
||||
el.instance().closeAssignmentModal();
|
||||
expect(props.doneViewingAssignment).toHaveBeenCalledWith();
|
||||
expect(props.closeModal).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
describe('handleAdjustedGradeClick', () => {
|
||||
it('calls props.updateGardes and this.closeAssignmentModal', () => {
|
||||
el.instance().closeAssignmentModal = jest.fn();
|
||||
el.instance().handleAdjustedGradeClick();
|
||||
expect(props.updateGrades).toHaveBeenCalledWith();
|
||||
expect(el.instance().closeAssignmentModal).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('snapshots', () => {
|
||||
let el;
|
||||
beforeEach(() => {
|
||||
el = shallow(<EditModal {...props} />);
|
||||
el.instance().closeAssignmentModal = jest.fn().mockName('this.closeAssignmentModal');
|
||||
el.instance().handleAdjustedGradeClick = jest.fn().mockName(
|
||||
'this.handleAdjustedGradeClick',
|
||||
);
|
||||
});
|
||||
describe('gradeOverrideHistoryError is and empty and open is true', () => {
|
||||
test('modal open and StatusAlert showing', () => {
|
||||
expect(el.instance().render()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
describe('gradeOverrideHistoryError is empty and open is false', () => {
|
||||
test('modal closed and StatusAlert closed', () => {
|
||||
el.setProps({ open: false, gradeOverrideHistoryError: '' });
|
||||
expect(el.instance().render()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapStateToProps', () => {
|
||||
const testState = { martha: 'why did you say that name?!' };
|
||||
let mapped;
|
||||
beforeEach(() => {
|
||||
mapped = mapStateToProps(testState);
|
||||
});
|
||||
test('gradeOverrideHistoryError from grades.gradeOverrideHistoryError', () => {
|
||||
expect(
|
||||
mapped.gradeOverrideHistoryError,
|
||||
).toEqual(selectors.grades.gradeOverrideHistoryError(testState));
|
||||
});
|
||||
test('open from app.modalState.open', () => {
|
||||
expect(mapped.open).toEqual(selectors.app.modalState.open(testState));
|
||||
});
|
||||
});
|
||||
describe('mapDispatchToProps', () => {
|
||||
test('closeModal from actions.app.closeModal', () => {
|
||||
expect(mapDispatchToProps.closeModal).toEqual(actions.app.closeModal);
|
||||
});
|
||||
test('doneViewingAssignemtn from actions.grades.doneViewingAssignment', () => {
|
||||
expect(
|
||||
mapDispatchToProps.doneViewingAssignment,
|
||||
).toEqual(actions.grades.doneViewingAssignment);
|
||||
});
|
||||
test('updateGrades from thunkActions.grades.updateGrades', () => {
|
||||
expect(mapDispatchToProps.updateGrades).toEqual(thunkActions.grades.updateGrades);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -109,6 +109,8 @@ export default StrictDict({
|
||||
courseGradeFilterValidity,
|
||||
courseGradeLimits,
|
||||
editUpdateData,
|
||||
isFilterMenuClosed,
|
||||
isFilterMenuOpening,
|
||||
...simpleSelectors,
|
||||
modalState: StrictDict(modalSelectors),
|
||||
filterMenu: StrictDict({
|
||||
|
||||
Reference in New Issue
Block a user