feat: update lock/unlock logistic (#38)
* feat: update lock/unlock logistic * chore: disable submit grade on lock pending * chore: update mock for contested lock * chore: update set lock success response * chore: add failure reducer/action for set lock
This commit is contained in:
@@ -94,7 +94,7 @@ export class StartGradingButton extends React.Component {
|
||||
variant="primary"
|
||||
iconAfter={args.iconAfter}
|
||||
onClick={this.handleClick}
|
||||
disabled={this.props.isPending}
|
||||
disabled={this.props.gradeIsPending || this.props.lockIsPending}
|
||||
>
|
||||
<FormattedMessage {...args.label} />
|
||||
</Button>
|
||||
@@ -119,11 +119,13 @@ StartGradingButton.propTypes = {
|
||||
gradingStatus: PropTypes.string.isRequired,
|
||||
startGrading: PropTypes.func.isRequired,
|
||||
stopGrading: PropTypes.func.isRequired,
|
||||
isPending: PropTypes.bool.isRequired,
|
||||
gradeIsPending: PropTypes.bool.isRequired,
|
||||
lockIsPending: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export const mapStateToProps = (state) => ({
|
||||
isPending: selectors.requests.isPending(state, { requestKey: RequestKeys.submitGrade }),
|
||||
gradeIsPending: selectors.requests.isPending(state, { requestKey: RequestKeys.submitGrade }),
|
||||
lockIsPending: selectors.requests.isPending(state, { requestKey: RequestKeys.setLock }),
|
||||
gradeStatus: selectors.grading.selected.gradeStatus(state),
|
||||
gradingStatus: selectors.grading.selected.gradingStatus(state),
|
||||
});
|
||||
|
||||
@@ -36,7 +36,8 @@ let el;
|
||||
describe('StartGradingButton component', () => {
|
||||
describe('component', () => {
|
||||
const props = {
|
||||
isPending: false,
|
||||
gradeIsPending: false,
|
||||
lockIsPending: false,
|
||||
};
|
||||
beforeEach(() => {
|
||||
props.startGrading = jest.fn().mockName('this.props.startGrading');
|
||||
@@ -69,9 +70,14 @@ describe('StartGradingButton component', () => {
|
||||
test('snapshot: ungraded (startGrading callback)', () => {
|
||||
expect(mockedEl(statuses.ungraded).instance().render()).toMatchSnapshot();
|
||||
});
|
||||
test('snapshot: pending (disabled)', () => {
|
||||
test('snapshot: grade pending (disabled)', () => {
|
||||
el = mockedEl(statuses.ungraded);
|
||||
el.setProps({ isPending: true });
|
||||
el.setProps({ gradeIsPending: true });
|
||||
expect(el.instance().render()).toMatchSnapshot();
|
||||
});
|
||||
test('snapshot: lock pending (disabled)', () => {
|
||||
el = mockedEl(statuses.ungraded);
|
||||
el.setProps({ lockIsPending: true });
|
||||
expect(el.instance().render()).toMatchSnapshot();
|
||||
});
|
||||
test('snapshot: graded, confirmOverride (startGrading callback)', () => {
|
||||
@@ -92,14 +98,22 @@ describe('StartGradingButton component', () => {
|
||||
beforeEach(() => {
|
||||
mapped = mapStateToProps(testState);
|
||||
});
|
||||
test('isPending loads from requests.isPending(submitGrade)', () => {
|
||||
expect(mapped.isPending).toEqual(
|
||||
test('gradeIsPending loads from requests.gradeIsPending(submitGrade)', () => {
|
||||
expect(mapped.gradeIsPending).toEqual(
|
||||
selectors.requests.isPending(
|
||||
testState,
|
||||
{ requestKey: RequestKeys.submitGrade },
|
||||
),
|
||||
);
|
||||
});
|
||||
test('lockIsPending loads from requests.lockIsPending(setLock)', () => {
|
||||
expect(mapped.lockIsPending).toEqual(
|
||||
selectors.requests.isPending(
|
||||
testState,
|
||||
{ requestKey: RequestKeys.setLock },
|
||||
),
|
||||
);
|
||||
});
|
||||
test('gradeStatus loads from grading.selected.gradeStatus', () => {
|
||||
expect(mapped.gradeStatus).toEqual(selectors.grading.selected.gradeStatus(testState));
|
||||
});
|
||||
|
||||
@@ -1,5 +1,33 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`StartGradingButton component component snapshotes snapshot: grade pending (disabled) 1`] = `
|
||||
<React.Fragment>
|
||||
<Button
|
||||
disabled={true}
|
||||
iconAfter={[MockFunction icons.Highlight]}
|
||||
onClick={[MockFunction this.handleClick]}
|
||||
variant="primary"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Start grading"
|
||||
description="Review pane button text to start grading"
|
||||
id="ora-grading.ReviewActions.StartGradingButton.startGrading"
|
||||
/>
|
||||
</Button>
|
||||
<OverrideGradeConfirmModal
|
||||
isOpen={false}
|
||||
onCancel={[MockFunction this.hideConfirmOverrideGrade]}
|
||||
onConfirm={[MockFunction this.confirmOverrideGrade]}
|
||||
/>
|
||||
<StopGradingConfirmModal
|
||||
isOpen={false}
|
||||
isOverride={false}
|
||||
onCancel={[MockFunction this.hideConfirmStopGrading]}
|
||||
onConfirm={[MockFunction this.confirmStopGrading]}
|
||||
/>
|
||||
</React.Fragment>
|
||||
`;
|
||||
|
||||
exports[`StartGradingButton component component snapshotes snapshot: graded, confirmOverride (startGrading callback) 1`] = `
|
||||
<React.Fragment>
|
||||
<Button
|
||||
@@ -56,9 +84,7 @@ exports[`StartGradingButton component component snapshotes snapshot: inProgress,
|
||||
</React.Fragment>
|
||||
`;
|
||||
|
||||
exports[`StartGradingButton component component snapshotes snapshot: locked (null) 1`] = `null`;
|
||||
|
||||
exports[`StartGradingButton component component snapshotes snapshot: pending (disabled) 1`] = `
|
||||
exports[`StartGradingButton component component snapshotes snapshot: lock pending (disabled) 1`] = `
|
||||
<React.Fragment>
|
||||
<Button
|
||||
disabled={true}
|
||||
@@ -86,6 +112,8 @@ exports[`StartGradingButton component component snapshotes snapshot: pending (di
|
||||
</React.Fragment>
|
||||
`;
|
||||
|
||||
exports[`StartGradingButton component component snapshotes snapshot: locked (null) 1`] = `null`;
|
||||
|
||||
exports[`StartGradingButton component component snapshotes snapshot: ungraded (startGrading callback) 1`] = `
|
||||
<React.Fragment>
|
||||
<Button
|
||||
|
||||
65
src/containers/ReviewModal/ReviewErrors/LockErrors.jsx
Normal file
65
src/containers/ReviewModal/ReviewErrors/LockErrors.jsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { selectors } from 'data/redux';
|
||||
import { RequestKeys, ErrorStatuses } from 'data/constants/requests';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
import ReviewError from './ReviewError';
|
||||
|
||||
/**
|
||||
* <LockErrors />
|
||||
*/
|
||||
export class LockErrors extends React.Component {
|
||||
get errorProp() {
|
||||
if (this.errorStatus === ErrorStatuses.forbidden) {
|
||||
return {
|
||||
heading: messages.errorLockContestedHeading,
|
||||
message: messages.errorLockContested,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
heading: messages.errorLockBadRequestHeading,
|
||||
message: messages.errorLockBadRequest,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.props.isFailed) { return null; }
|
||||
const { heading, message } = this.errorProp;
|
||||
return (
|
||||
<ReviewError
|
||||
key="lockFailed"
|
||||
headingMessage={heading}
|
||||
>
|
||||
<FormattedMessage {...message} />
|
||||
</ReviewError>
|
||||
);
|
||||
}
|
||||
}
|
||||
LockErrors.defaultProps = {
|
||||
errorStatus: undefined,
|
||||
};
|
||||
LockErrors.propTypes = {
|
||||
// redux
|
||||
isFailed: PropTypes.bool.isRequired,
|
||||
errorStatus: PropTypes.number,
|
||||
};
|
||||
|
||||
export const mapStateToProps = (state) => ({
|
||||
isFailed: selectors.requests.isFailed(state, {
|
||||
requestKey: RequestKeys.setLock,
|
||||
}),
|
||||
errorStatus: selectors.requests.errorStatus(state, {
|
||||
requestKey: RequestKeys.setLock,
|
||||
}),
|
||||
});
|
||||
|
||||
export const mapDispatchToProps = {};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(LockErrors);
|
||||
62
src/containers/ReviewModal/ReviewErrors/LockErrors.test.jsx
Normal file
62
src/containers/ReviewModal/ReviewErrors/LockErrors.test.jsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { selectors } from 'data/redux';
|
||||
import { ErrorStatuses, RequestKeys } from 'data/constants/requests';
|
||||
|
||||
import {
|
||||
LockErrors,
|
||||
mapStateToProps,
|
||||
} from './LockErrors';
|
||||
|
||||
jest.mock('data/redux', () => ({
|
||||
selectors: {
|
||||
requests: {
|
||||
errorStatus: (...args) => ({ errorStatus: args }),
|
||||
isFailed: (...args) => ({ isFailed: args }),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
let el;
|
||||
jest.mock('./ReviewError', () => 'ReviewError');
|
||||
|
||||
const requestKey = RequestKeys.setLock;
|
||||
|
||||
describe('LockErrors component', () => {
|
||||
const props = {
|
||||
isFailed: true,
|
||||
};
|
||||
describe('component', () => {
|
||||
beforeEach(() => {
|
||||
el = shallow(<LockErrors {...props} />);
|
||||
el.instance().dismissError = jest.fn().mockName('this.dismissError');
|
||||
});
|
||||
describe('snapshots', () => {
|
||||
test('no failure', () => {
|
||||
el.setProps({ isFailed: false });
|
||||
expect(el.instance().render()).toMatchSnapshot();
|
||||
});
|
||||
test('snapshot: error with bad request', () => {
|
||||
el.setProps({ errorStatus: ErrorStatuses.badRequest });
|
||||
expect(el.instance().render()).toMatchSnapshot();
|
||||
});
|
||||
test('snapshot: error with conflicted lock', () => {
|
||||
el.setProps({ errorStatus: ErrorStatuses.forbidden });
|
||||
expect(el.instance().render()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('mapStateToProps', () => {
|
||||
let mapped;
|
||||
const testState = { some: 'test-state' };
|
||||
beforeEach(() => {
|
||||
mapped = mapStateToProps(testState);
|
||||
});
|
||||
test('errorStatus loads from requests.errorStatus(setLock)', () => {
|
||||
expect(mapped.errorStatus).toEqual(
|
||||
selectors.requests.errorStatus(testState, { requestKey }),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -44,6 +44,9 @@ const ReviewError = ({
|
||||
</Alert>
|
||||
);
|
||||
};
|
||||
ReviewError.defaultProps = {
|
||||
actions: {},
|
||||
};
|
||||
ReviewError.propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
cancel: PropTypes.shape({
|
||||
@@ -54,7 +57,7 @@ ReviewError.propTypes = {
|
||||
onClick: PropTypes.func,
|
||||
message: messageShape,
|
||||
}),
|
||||
}).isRequired,
|
||||
}),
|
||||
headingMessage: messageShape.isRequired,
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`LockErrors component component snapshots no failure 1`] = `null`;
|
||||
|
||||
exports[`LockErrors component component snapshots snapshot: error with bad request 1`] = `
|
||||
<ReviewError
|
||||
headingMessage={
|
||||
Object {
|
||||
"defaultMessage": "Invalid request. Please check your input.",
|
||||
"description": "Error lock request for missing params",
|
||||
"id": "ora-grading.ReviewModal.errorLockBadRequestHeading",
|
||||
}
|
||||
}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Invalid request. Please check your input."
|
||||
description="Error lock request for missing params"
|
||||
id="ora-grading.ReviewModal.errorLockBadRequest"
|
||||
/>
|
||||
</ReviewError>
|
||||
`;
|
||||
|
||||
exports[`LockErrors component component snapshots snapshot: error with conflicted lock 1`] = `
|
||||
<ReviewError
|
||||
headingMessage={
|
||||
Object {
|
||||
"defaultMessage": "Invalid request. Please check your input.",
|
||||
"description": "Error lock request for missing params",
|
||||
"id": "ora-grading.ReviewModal.errorLockBadRequestHeading",
|
||||
}
|
||||
}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Invalid request. Please check your input."
|
||||
description="Error lock request for missing params"
|
||||
id="ora-grading.ReviewModal.errorLockBadRequest"
|
||||
/>
|
||||
</ReviewError>
|
||||
`;
|
||||
@@ -4,5 +4,6 @@ exports[`ReviewErrors component component snapshot: no failure 1`] = `
|
||||
<Fragment>
|
||||
<FetchErrors />
|
||||
<SubmitErrors />
|
||||
<LockErrors />
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
import FetchErrors from './FetchErrors';
|
||||
import LockErrors from './LockErrors';
|
||||
import SubmitErrors from './SubmitErrors';
|
||||
|
||||
/**
|
||||
@@ -10,6 +11,7 @@ export const ReviewErrors = () => (
|
||||
<>
|
||||
<FetchErrors />
|
||||
<SubmitErrors />
|
||||
<LockErrors />
|
||||
</>
|
||||
);
|
||||
ReviewErrors.defaultProps = {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { ReviewErrors } from '.';
|
||||
|
||||
jest.mock('./FetchErrors', () => 'FetchErrors');
|
||||
jest.mock('./SubmitErrors', () => 'SubmitErrors');
|
||||
jest.mock('./LockErrors', () => 'LockErrors');
|
||||
|
||||
describe('ReviewErrors component', () => {
|
||||
describe('component', () => {
|
||||
|
||||
@@ -47,7 +47,26 @@ const messages = defineMessages({
|
||||
defaultMessage: 'It looks like someone else got here first! Your grade submission has been rejected',
|
||||
description: 'Error Submitting Grade content',
|
||||
},
|
||||
|
||||
errorLockContestedHeading: {
|
||||
id: 'ora-grading.ReviewModal.errorLockContestedHeading',
|
||||
defaultMessage: 'The lock owned by another user',
|
||||
description: 'Error lock by someone else',
|
||||
},
|
||||
errorLockContested: {
|
||||
id: 'ora-grading.ReviewModal.errorLockContested',
|
||||
defaultMessage: 'The lock owned by another user',
|
||||
description: 'Error lock by someone else',
|
||||
},
|
||||
errorLockBadRequestHeading: {
|
||||
id: 'ora-grading.ReviewModal.errorLockBadRequestHeading',
|
||||
defaultMessage: 'Invalid request. Please check your input.',
|
||||
description: 'Error lock request for missing params',
|
||||
},
|
||||
errorLockBadRequest: {
|
||||
id: 'ora-grading.ReviewModal.errorLockBadRequest',
|
||||
defaultMessage: 'Invalid request. Please check your input.',
|
||||
description: 'Error lock request for missing params',
|
||||
},
|
||||
});
|
||||
|
||||
export default StrictDict(messages);
|
||||
|
||||
@@ -47,6 +47,7 @@ exports[`Rubric Container snapshot is grading 1`] = `
|
||||
disabledStates={
|
||||
Array [
|
||||
"pending",
|
||||
"complete",
|
||||
]
|
||||
}
|
||||
labels={
|
||||
@@ -75,6 +76,82 @@ exports[`Rubric Container snapshot is grading 1`] = `
|
||||
</Card>
|
||||
`;
|
||||
|
||||
exports[`Rubric Container snapshot is grading, lock is pending 1`] = `
|
||||
<Card
|
||||
className="grading-rubric-card"
|
||||
>
|
||||
<Card.Body
|
||||
className="grading-rubric-body"
|
||||
>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
defaultMessage="Rubric"
|
||||
description="Rubric interface label"
|
||||
id="ora-grading.Rubric.rubric"
|
||||
/>
|
||||
</h3>
|
||||
<hr
|
||||
className="m-2.5"
|
||||
/>
|
||||
<CriterionContainer
|
||||
isGrading={true}
|
||||
orderNum={1}
|
||||
/>
|
||||
<CriterionContainer
|
||||
isGrading={true}
|
||||
orderNum={2}
|
||||
/>
|
||||
<CriterionContainer
|
||||
isGrading={true}
|
||||
orderNum={3}
|
||||
/>
|
||||
<CriterionContainer
|
||||
isGrading={true}
|
||||
orderNum={4}
|
||||
/>
|
||||
<CriterionContainer
|
||||
isGrading={true}
|
||||
orderNum={5}
|
||||
/>
|
||||
<hr />
|
||||
<RubricFeedback />
|
||||
</Card.Body>
|
||||
<div
|
||||
className="grading-rubric-footer"
|
||||
>
|
||||
<StatefulButton
|
||||
disabledStates={
|
||||
Array [
|
||||
"pending",
|
||||
"complete",
|
||||
]
|
||||
}
|
||||
labels={
|
||||
Object {
|
||||
"complete": <FormattedMessage
|
||||
defaultMessage="Grade Submitted"
|
||||
description="Submit Grade button text after successful submission"
|
||||
id="ora-grading.Rubric.gradeSubmitted"
|
||||
/>,
|
||||
"default": <FormattedMessage
|
||||
defaultMessage="Submit grade"
|
||||
description="Submit Grade button text"
|
||||
id="ora-grading.Rubric.submitGrade"
|
||||
/>,
|
||||
"pending": <FormattedMessage
|
||||
defaultMessage="Submitting grade"
|
||||
description="Submit Grade button text while submitting"
|
||||
id="ora-grading.Rubric.submittingGrade"
|
||||
/>,
|
||||
}
|
||||
}
|
||||
onClick={[MockFunction this.submitGradeHandler]}
|
||||
state="pending"
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
`;
|
||||
|
||||
exports[`Rubric Container snapshot is grading, submit pending 1`] = `
|
||||
<Card
|
||||
className="grading-rubric-card"
|
||||
@@ -122,6 +199,7 @@ exports[`Rubric Container snapshot is grading, submit pending 1`] = `
|
||||
disabledStates={
|
||||
Array [
|
||||
"pending",
|
||||
"complete",
|
||||
]
|
||||
}
|
||||
labels={
|
||||
@@ -240,6 +318,7 @@ exports[`Rubric Container snapshot submit completed 1`] = `
|
||||
disabledStates={
|
||||
Array [
|
||||
"pending",
|
||||
"complete",
|
||||
]
|
||||
}
|
||||
labels={
|
||||
|
||||
@@ -33,7 +33,7 @@ export class Rubric extends React.Component {
|
||||
}
|
||||
|
||||
get submitButtonState() {
|
||||
if (this.props.isPending) {
|
||||
if (this.props.gradeIsPending || this.props.lockIsPending) {
|
||||
return ButtonStates.pending;
|
||||
}
|
||||
if (this.props.isCompleted) {
|
||||
@@ -68,7 +68,7 @@ export class Rubric extends React.Component {
|
||||
<StatefulButton
|
||||
onClick={this.submitGradeHandler}
|
||||
state={this.submitButtonState}
|
||||
disabledStates={[ButtonStates.pending]}
|
||||
disabledStates={[ButtonStates.pending, ButtonStates.complete]}
|
||||
labels={{
|
||||
[ButtonStates.default]: <FormattedMessage {...messages.submitGrade} />,
|
||||
[ButtonStates.pending]: <FormattedMessage {...messages.submittingGrade} />,
|
||||
@@ -87,17 +87,17 @@ Rubric.defaultProps = {
|
||||
Rubric.propTypes = {
|
||||
isCompleted: PropTypes.bool.isRequired,
|
||||
isGrading: PropTypes.bool.isRequired,
|
||||
isPending: PropTypes.bool.isRequired,
|
||||
gradeIsPending: PropTypes.bool.isRequired,
|
||||
lockIsPending: PropTypes.bool.isRequired,
|
||||
criteriaIndices: PropTypes.arrayOf(PropTypes.number),
|
||||
submitGrade: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const requestKey = RequestKeys.submitGrade;
|
||||
|
||||
export const mapStateToProps = (state) => ({
|
||||
isCompleted: selectors.requests.isCompleted(state, { requestKey }),
|
||||
isCompleted: selectors.requests.isCompleted(state, { requestKey: RequestKeys.submitGrade }),
|
||||
isGrading: selectors.grading.selected.isGrading(state),
|
||||
isPending: selectors.requests.isPending(state, { requestKey }),
|
||||
gradeIsPending: selectors.requests.isPending(state, { requestKey: RequestKeys.submitGrade }),
|
||||
lockIsPending: selectors.requests.isPending(state, { requestKey: RequestKeys.setLock }),
|
||||
criteriaIndices: selectors.app.rubric.criteriaIndices(state),
|
||||
});
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { selectors, thunkActions } from 'data/redux';
|
||||
import { RequestKeys } from 'data/constants/requests';
|
||||
import { Rubric, mapStateToProps, mapDispatchToProps } from '.';
|
||||
|
||||
jest.mock('containers/CriterionContainer', () => 'CriterionContainer');
|
||||
@@ -36,7 +37,8 @@ jest.mock('data/redux', () => ({
|
||||
describe('Rubric Container', () => {
|
||||
const props = {
|
||||
isCompleted: false,
|
||||
isPending: false,
|
||||
gradeIsPending: false,
|
||||
lockIsPending: false,
|
||||
isGrading: true,
|
||||
criteriaIndices: [1, 2, 3, 4, 5],
|
||||
submitGrade: jest.fn().mockName('this.props.submitGrade'),
|
||||
@@ -60,7 +62,11 @@ describe('Rubric Container', () => {
|
||||
expect(el.instance().render()).toMatchSnapshot();
|
||||
});
|
||||
test('is grading, submit pending', () => {
|
||||
el.setProps({ isPending: true });
|
||||
el.setProps({ gradeIsPending: true });
|
||||
expect(el.instance().render()).toMatchSnapshot();
|
||||
});
|
||||
test('is grading, lock is pending', () => {
|
||||
el.setProps({ lockIsPending: true });
|
||||
expect(el.instance().render()).toMatchSnapshot();
|
||||
});
|
||||
test('submit completed', () => {
|
||||
@@ -111,6 +117,16 @@ describe('Rubric Container', () => {
|
||||
test('isGrading from selectors.grading.selected.isGrading', () => {
|
||||
expect(mapped.isGrading).toEqual(selectors.grading.selected.isGrading(testState));
|
||||
});
|
||||
test('gradeIsPending from selectors.requests.isPending(submitGrade)', () => {
|
||||
expect(mapped.gradeIsPending).toEqual(
|
||||
selectors.requests.isPending(testState, { requestKey: RequestKeys.submitGrade }),
|
||||
);
|
||||
});
|
||||
test('lockIsPending from selectors.requests.isPending(setLock)', () => {
|
||||
expect(mapped.lockIsPending).toEqual(selectors.requests.isPending(
|
||||
testState, { requestKey: RequestKeys.setLock },
|
||||
));
|
||||
});
|
||||
test('criteriaIndices from selectors.app.rubric.criteriaIndices', () => {
|
||||
expect(mapped.criteriaIndices).toEqual(
|
||||
selectors.app.rubric.criteriaIndices(testState),
|
||||
|
||||
@@ -166,6 +166,10 @@ const grading = createSlice({
|
||||
gradingData,
|
||||
};
|
||||
},
|
||||
failSetLock: (state, { payload }) => ({
|
||||
...state,
|
||||
current: { ...state.current, lockStatus: payload.lockStatus },
|
||||
}),
|
||||
setRubricFeedback: (state, { payload }) => (
|
||||
updateGradingData(state, { overallFeedback: payload })
|
||||
),
|
||||
|
||||
@@ -72,6 +72,11 @@ export const startGrading = () => (dispatch, getState) => {
|
||||
}
|
||||
dispatch(actions.grading.startGrading({ ...response, gradeData }));
|
||||
},
|
||||
onFailure: (error) => {
|
||||
if (error.response.status === ErrorStatuses.forbidden) {
|
||||
dispatch(actions.grading.failSetLock(error.response.data));
|
||||
}
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
@@ -87,6 +92,11 @@ export const cancelGrading = () => (dispatch, getState) => {
|
||||
onSuccess: () => {
|
||||
dispatch(module.stopGrading());
|
||||
},
|
||||
onFailure: (error) => {
|
||||
if (error.response.status === ErrorStatuses.forbidden) {
|
||||
dispatch(actions.grading.failSetLock(error.response.data));
|
||||
}
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
|
||||
@@ -67,6 +67,21 @@ export const genTestUtils = ({ dispatch }) => {
|
||||
},
|
||||
),
|
||||
}),
|
||||
setLock: StrictDict({
|
||||
start: mockStart(RequestKeys.setLock),
|
||||
success: () => {
|
||||
dispatch(actions.requests.completeRequest({
|
||||
requestKey: RequestKeys.setLock,
|
||||
response: {
|
||||
lockStatus: lockStatuses.inProgress,
|
||||
},
|
||||
}));
|
||||
},
|
||||
badRequestError: mockError(RequestKeys.setLock, ErrorStatuses.badRequest),
|
||||
contestedLockError: mockError(RequestKeys.setLock, ErrorStatuses.forbidden, {
|
||||
lockStatus: lockStatuses.locked,
|
||||
}),
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user