feat: requests redux modules
This commit is contained in:
8
package-lock.json
generated
8
package-lock.json
generated
@@ -3849,6 +3849,14 @@
|
||||
"@testing-library/dom": "^8.0.0"
|
||||
}
|
||||
},
|
||||
"@testing-library/user-event": {
|
||||
"version": "13.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz",
|
||||
"integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.12.5"
|
||||
}
|
||||
},
|
||||
"@tootallnate/once": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
"@fortawesome/react-fontawesome": "^0.1.15",
|
||||
"@redux-beacon/segment": "^1.1.0",
|
||||
"@reduxjs/toolkit": "^1.6.1",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"classnames": "^2.3.1",
|
||||
"core-js": "3.16.2",
|
||||
"dompurify": "^2.3.1",
|
||||
|
||||
@@ -2,10 +2,12 @@ import { StrictDict } from 'utils';
|
||||
|
||||
import app from './app';
|
||||
import grading from './grading';
|
||||
import requests from './requests';
|
||||
import submissions from './submissions';
|
||||
|
||||
export default StrictDict({
|
||||
app,
|
||||
grading,
|
||||
requests,
|
||||
submissions,
|
||||
});
|
||||
|
||||
15
src/data/actions/requests.js
Normal file
15
src/data/actions/requests.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { StrictDict } from 'utils';
|
||||
import { createActionFactory } from './utils';
|
||||
|
||||
export const dataKey = 'requests';
|
||||
const createAction = createActionFactory(dataKey);
|
||||
|
||||
export const startRequest = createAction('startRequest');
|
||||
export const completeRequest = createAction('completeRequest');
|
||||
export const failRequest = createAction('failRequest');
|
||||
|
||||
export default StrictDict({
|
||||
startRequest,
|
||||
completeRequest,
|
||||
failRequest,
|
||||
});
|
||||
18
src/data/actions/requests.test.js
Normal file
18
src/data/actions/requests.test.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import actions, { dataKey } from './requests';
|
||||
import { testAction, testActionTypes } from './testUtils';
|
||||
|
||||
describe('actions', () => {
|
||||
describe('action types', () => {
|
||||
const actionTypes = [
|
||||
actions.startRequest,
|
||||
actions.completeRequest,
|
||||
actions.failRequest,
|
||||
].map(action => action.toString());
|
||||
testActionTypes(actionTypes, dataKey);
|
||||
});
|
||||
describe('actions provided', () => {
|
||||
test('startRequest action', () => testAction(actions.startRequest));
|
||||
test('completeRequest action', () => testAction(actions.completeRequest));
|
||||
test('failRequest action', () => testAction(actions.failRequest));
|
||||
});
|
||||
});
|
||||
18
src/data/constants/requests.js
Normal file
18
src/data/constants/requests.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { StrictDict } from 'utils';
|
||||
|
||||
export const RequestStates = StrictDict({
|
||||
inactive: 'inactive',
|
||||
pending: 'pending',
|
||||
completed: 'completed',
|
||||
failed: 'failed',
|
||||
});
|
||||
|
||||
export const RequestKeys = StrictDict({
|
||||
initialize: 'initialize',
|
||||
fetchSubmission: 'fetchSubmission',
|
||||
fetchSubmissionStatus: 'fetchSubmissionStatus',
|
||||
setLock: 'setLock',
|
||||
prefetchNext: 'prefetchNext',
|
||||
prefetchPrev: 'prefetchPrev',
|
||||
submitGrade: 'submitGrade',
|
||||
});
|
||||
@@ -2,12 +2,14 @@ import { combineReducers } from 'redux';
|
||||
|
||||
import app from './app';
|
||||
import grading from './grading';
|
||||
import requests from './requests';
|
||||
import submissions from './submissions';
|
||||
|
||||
/* istanbul ignore next */
|
||||
const rootReducer = combineReducers({
|
||||
app,
|
||||
grading,
|
||||
requests,
|
||||
submissions,
|
||||
});
|
||||
|
||||
|
||||
41
src/data/reducers/requests.js
Normal file
41
src/data/reducers/requests.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
|
||||
import { RequestStates, RequestKeys } from 'data/constants/requests';
|
||||
import actions from 'data/actions';
|
||||
|
||||
const initialState = {
|
||||
[RequestKeys.initialize]: { status: RequestStates.inactive },
|
||||
[RequestKeys.fetchSubmission]: { status: RequestStates.inactive },
|
||||
[RequestKeys.fetchSubmissionStatus]: { status: RequestStates.inactive },
|
||||
[RequestKeys.setLock]: { status: RequestStates.inactive },
|
||||
[RequestKeys.prefetchNext]: { status: RequestStates.inactive },
|
||||
[RequestKeys.prefetchPrev]: { status: RequestStates.inactive },
|
||||
[RequestKeys.submitGrade]: { status: RequestStates.inactive },
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const app = createReducer(initialState, {
|
||||
[actions.requests.startRequest]: (state, { payload }) => ({
|
||||
...state,
|
||||
[payload]: {
|
||||
status: RequestStates.pending,
|
||||
},
|
||||
}),
|
||||
[actions.requests.completeRequest]: (state, { payload }) => ({
|
||||
...state,
|
||||
[payload.requestKey]: {
|
||||
status: RequestStates.completed,
|
||||
response: payload.response,
|
||||
},
|
||||
}),
|
||||
[actions.requests.failRequest]: (state, { payload }) => ({
|
||||
...state,
|
||||
[payload.requestKey]: {
|
||||
status: RequestStates.failed,
|
||||
error: payload.error,
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
export { initialState };
|
||||
export default app;
|
||||
52
src/data/reducers/requests.test.js
Normal file
52
src/data/reducers/requests.test.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import actions from 'data/actions';
|
||||
import { RequestStates } from 'data/constants/requests';
|
||||
import requests, { initialState } from './requests';
|
||||
|
||||
const testingState = {
|
||||
...initialState,
|
||||
arbitraryField: 'arbitrary',
|
||||
};
|
||||
|
||||
describe('requests reducer', () => {
|
||||
it('has initial state', () => {
|
||||
expect(requests(undefined, {})).toEqual(initialState);
|
||||
});
|
||||
|
||||
const testValue = 'roll for initiative';
|
||||
const testKey = 'test-key';
|
||||
describe('handling actions', () => {
|
||||
describe('requests.startRequest', () => {
|
||||
it('adds a pending status for the given key', () => {
|
||||
expect(requests(
|
||||
testingState,
|
||||
actions.requests.startRequest(testKey),
|
||||
)).toEqual({
|
||||
...testingState,
|
||||
[testKey]: { status: RequestStates.pending },
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('requests.completeRequest', () => {
|
||||
it('adds a completed status with passed response', () => {
|
||||
expect(requests(
|
||||
testingState,
|
||||
actions.requests.completeRequest({ requestKey: testKey, response: testValue }),
|
||||
)).toEqual({
|
||||
...testingState,
|
||||
[testKey]: { status: RequestStates.completed, response: testValue },
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('requests.failRequest', () => {
|
||||
it('adds a failed status with passed error', () => {
|
||||
expect(requests(
|
||||
testingState,
|
||||
actions.requests.failRequest({ requestKey: testKey, error: testValue }),
|
||||
)).toEqual({
|
||||
...testingState,
|
||||
[testKey]: { status: RequestStates.failed, error: testValue },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,19 +1,22 @@
|
||||
import { StrictDict } from 'utils';
|
||||
|
||||
import actions from 'data/actions';
|
||||
import api from 'data/services/lms/api';
|
||||
import { locationId } from 'data/constants/app';
|
||||
import { initializeApp } from './requests';
|
||||
|
||||
/**
|
||||
* initialize the app, loading ora and course metadata from the api, and loading the initial
|
||||
* submission list data.
|
||||
*/
|
||||
export const initialize = () => (dispatch) => (
|
||||
api.initializeApp(locationId).then((response) => {
|
||||
dispatch(actions.app.loadOraMetadata(response.oraMetadata));
|
||||
dispatch(actions.app.loadCourseMetadata(response.courseMetadata));
|
||||
dispatch(actions.submissions.loadList(response.submissions));
|
||||
})
|
||||
);
|
||||
export const initialize = () => (dispatch) => {
|
||||
dispatch(initializeApp({
|
||||
locationId,
|
||||
onSuccess: (response) => {
|
||||
dispatch(actions.app.loadOraMetadata(response.oraMetadata));
|
||||
dispatch(actions.app.loadCourseMetadata(response.courseMetadata));
|
||||
dispatch(actions.submissions.loadList(response.submissions));
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
export default StrictDict({ initialize });
|
||||
|
||||
@@ -1,51 +1,43 @@
|
||||
import api from 'data/services/lms/api';
|
||||
import { locationId } from 'data/constants/app';
|
||||
|
||||
import actions from 'data/actions';
|
||||
import thunkActions from './app';
|
||||
|
||||
jest.mock('data/services/lms/api', () => {
|
||||
const response = {
|
||||
oraMetadata: { some: 'ora-metadata' },
|
||||
courseMetadata: { some: 'course-metadata' },
|
||||
submissions: { some: 'submissions' },
|
||||
};
|
||||
return {
|
||||
response,
|
||||
initializeApp: jest.fn(() => new Promise((resolve) => resolve(response))),
|
||||
};
|
||||
});
|
||||
jest.mock('./requests', () => ({
|
||||
initializeApp: (args) => ({ initializeApp: args }),
|
||||
}));
|
||||
jest.mock('data/constants/app', () => ({
|
||||
locationId: 'fake-location-id',
|
||||
}));
|
||||
jest.mock('data/actions', () => ({
|
||||
app: {
|
||||
loadOraMetadata: (data) => ({ loadOraMetadata: data }),
|
||||
loadCourseMetadata: (data) => ({ loadCourseMetadata: data }),
|
||||
},
|
||||
submissions: {
|
||||
loadList: (data) => ({ loadList: data }),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('app thunkActions', () => {
|
||||
let dispatch;
|
||||
let dispatchedAction;
|
||||
beforeEach(() => {
|
||||
dispatch = jest.fn((action) => ({ dispatch: action }));
|
||||
});
|
||||
describe('initialize', () => {
|
||||
beforeEach(() => {
|
||||
thunkActions.initialize()(dispatch);
|
||||
[[dispatchedAction]] = dispatch.mock.calls;
|
||||
});
|
||||
test('it is called with location id from constants/app', () => {
|
||||
expect(api.initializeApp).toHaveBeenCalledWith(locationId);
|
||||
it('dispatches initializeApp with locationId and onSuccess', () => {
|
||||
expect(dispatchedAction.initializeApp.locationId).toEqual(locationId);
|
||||
expect(typeof dispatchedAction.initializeApp.onSuccess).toEqual('function');
|
||||
});
|
||||
describe('on success', () => {
|
||||
test('loads oraMetadata, courseMetadata and list data', () => {
|
||||
dispatch.mockClear();
|
||||
const response = {
|
||||
oraMetadata: { some: 'ora-metadata' },
|
||||
courseMetadata: { some: 'course-metadata' },
|
||||
submissions: { some: 'submissions' },
|
||||
};
|
||||
dispatchedAction.initializeApp.onSuccess(response);
|
||||
expect(dispatch.mock.calls).toEqual([
|
||||
[actions.app.loadOraMetadata(api.response.oraMetadata)],
|
||||
[actions.app.loadCourseMetadata(api.response.courseMetadata)],
|
||||
[actions.submissions.loadList(api.response.submissions)],
|
||||
[actions.app.loadOraMetadata(response.oraMetadata)],
|
||||
[actions.app.loadCourseMetadata(response.courseMetadata)],
|
||||
[actions.submissions.loadList(response.submissions)],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,32 +1,67 @@
|
||||
import { StrictDict } from 'utils';
|
||||
|
||||
import { RequestKeys } from 'data/constants/requests';
|
||||
import actions from 'data/actions';
|
||||
import selectors from 'data/selectors';
|
||||
import api from 'data/services/lms/api';
|
||||
import { gradingStatuses as statuses } from 'data/services/lms/constants';
|
||||
import * as module from './grading';
|
||||
import requests from './requests';
|
||||
|
||||
/**
|
||||
* Prefetch the "next" submission in the selected queue. Only fetches the response info.
|
||||
*/
|
||||
export const prefetchNext = () => (dispatch, getState) => (
|
||||
api.fetchSubmissionResponse(
|
||||
selectors.grading.next.submissionId(getState()),
|
||||
).then((response) => {
|
||||
dispatch(actions.grading.preloadNext(response));
|
||||
})
|
||||
);
|
||||
export const prefetchNext = () => (dispatch, getState) => {
|
||||
dispatch(requests.fetchSubmissionResponse({
|
||||
requestKey: RequestKeys.prefetchNext,
|
||||
submissionId: selectors.grading.next.submissionId(getState()),
|
||||
onSuccess: (response) => {
|
||||
dispatch(actions.grading.preloadNext(response));
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
* Prefetch the "previous" submission in the selected queue. Only fetches the response info.
|
||||
*/
|
||||
export const prefetchPrev = () => (dispatch, getState) => (
|
||||
api.fetchSubmissionResponse(
|
||||
selectors.grading.prev.submissionId(getState()),
|
||||
).then((response) => {
|
||||
dispatch(actions.grading.preloadPrev(response));
|
||||
})
|
||||
);
|
||||
export const prefetchPrev = () => (dispatch, getState) => {
|
||||
dispatch(requests.fetchSubmissionResponse({
|
||||
requestKey: RequestKeys.prefetchPrev,
|
||||
submissionId: selectors.grading.prev.submissionId(getState()),
|
||||
onSuccess: (response) => {
|
||||
dispatch(actions.grading.preloadPrev(response));
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch the target neighbor submission's status, start grading if in progress,
|
||||
* dispatches load action with the response (injecting submissionId). If hasNeighbor,
|
||||
* also dispatches the prefetchAction to pre-fetch the new neighbor's response.
|
||||
* @param {string} submissionId - target submission id
|
||||
* @param {action} loadAction - redux action/thunkAction to load the submission status
|
||||
* @param {bool} hasNeighbor - is there a new neighbor to be pre-fetched?
|
||||
* @param {action} prefetchAction - redux action/thunkAction to prefetch the new
|
||||
* neighbor's response.
|
||||
*/
|
||||
export const fetchNeighbor = ({
|
||||
submissionId,
|
||||
loadAction,
|
||||
hasNeighbor,
|
||||
prefetchAction,
|
||||
}) => (dispatch) => {
|
||||
dispatch(requests.fetchSubmissionStatus({
|
||||
submissionId,
|
||||
onSuccess: (response) => {
|
||||
if (response.lockStatus === statuses.inProgress) {
|
||||
dispatch(module.startGrading());
|
||||
} else {
|
||||
dispatch(module.stopGrading());
|
||||
}
|
||||
dispatch(loadAction({ ...response, submissionId }));
|
||||
if (hasNeighbor) { dispatch(prefetchAction()); }
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetches the current status for the "next" submission in the selected queue,
|
||||
@@ -34,19 +69,12 @@ export const prefetchPrev = () => (dispatch, getState) => (
|
||||
* If the new index has a next submission available, preload its response.
|
||||
*/
|
||||
export const loadNext = () => (dispatch, getState) => {
|
||||
const nextId = selectors.grading.next.submissionId(getState());
|
||||
return api.fetchSubmissionStatus(nextId).then((response) => {
|
||||
console.log({ loadNext: response });
|
||||
dispatch(actions.grading.loadNext({ ...response, submissionId: nextId }));
|
||||
if (response.lockStatus === statuses.inProgress) {
|
||||
dispatch(module.startGrading());
|
||||
} else {
|
||||
dispatch(actions.app.setGrading(false));
|
||||
}
|
||||
if (selectors.grading.next.doesExist(getState())) {
|
||||
dispatch(module.prefetchNext());
|
||||
}
|
||||
});
|
||||
dispatch(module.fetchNeighbor({
|
||||
loadAction: actions.grading.loadNext,
|
||||
hasNeighbor: selectors.grading.next.doesExist(getState()),
|
||||
prefetchAction: module.prefetchNext,
|
||||
submissionId: selectors.grading.next.submissionId(getState()),
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -55,18 +83,12 @@ export const loadNext = () => (dispatch, getState) => {
|
||||
* If the new index has a previous submission available, preload its response.
|
||||
*/
|
||||
export const loadPrev = () => (dispatch, getState) => {
|
||||
const prevId = selectors.grading.prev.submissionId(getState());
|
||||
return api.fetchSubmissionStatus(prevId).then((response) => {
|
||||
dispatch(actions.grading.loadPrev({ ...response, submissionId: prevId }));
|
||||
if (response.gradeStatus === statuses.inProgress) {
|
||||
dispatch(module.startGrading());
|
||||
} else {
|
||||
dispatch(actions.app.setGrading(false));
|
||||
}
|
||||
if (selectors.grading.prev.doesExist(getState())) {
|
||||
dispatch(module.prefetchPrev());
|
||||
}
|
||||
});
|
||||
dispatch(module.fetchNeighbor({
|
||||
loadAction: actions.grading.loadPrev,
|
||||
hasNeighbor: selectors.grading.prev.doesExist(getState()),
|
||||
prefetchAction: module.prefetchPrev,
|
||||
submissionId: selectors.grading.prev.submissionId(getState()),
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -76,22 +98,23 @@ export const loadPrev = () => (dispatch, getState) => {
|
||||
* @param {string[]} submissionIds - ordered list of submissionIds for selected submissions
|
||||
*/
|
||||
export const loadSelectionForReview = (submissionIds) => (dispatch, getState) => {
|
||||
dispatch(actions.grading.updateSelection(submissionIds));
|
||||
return api.fetchSubmission(
|
||||
selectors.grading.selected.submissionId(getState()),
|
||||
).then((response) => {
|
||||
dispatch(actions.grading.loadSubmission({
|
||||
...response,
|
||||
submissionId: submissionIds[0],
|
||||
}));
|
||||
dispatch(actions.app.setShowReview(true));
|
||||
if (selectors.grading.next.doesExist(getState())) {
|
||||
dispatch(prefetchNext());
|
||||
}
|
||||
if (selectors.grading.prev.doesExist(getState())) {
|
||||
dispatch(prefetchPrev());
|
||||
}
|
||||
});
|
||||
dispatch(requests.fetchSubmission({
|
||||
submissionId: submissionIds[0],
|
||||
onSuccess: (response) => {
|
||||
dispatch(actions.grading.updateSelection(submissionIds));
|
||||
dispatch(actions.grading.loadSubmission({
|
||||
...response,
|
||||
submissionId: submissionIds[0],
|
||||
}));
|
||||
dispatch(actions.app.setShowReview(true));
|
||||
if (selectors.grading.next.doesExist(getState())) {
|
||||
dispatch(module.prefetchNext());
|
||||
}
|
||||
if (selectors.grading.prev.doesExist(getState())) {
|
||||
dispatch(module.prefetchPrev());
|
||||
}
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -102,20 +125,18 @@ export const loadSelectionForReview = (submissionIds) => (dispatch, getState) =>
|
||||
* based on the rubric config.
|
||||
*/
|
||||
export const startGrading = () => (dispatch, getState) => {
|
||||
console.log('start grading');
|
||||
return api.lockSubmission(
|
||||
selectors.grading.selected.submissionId(getState()),
|
||||
).then(() => {
|
||||
console.log('succeed at locking');
|
||||
dispatch(actions.app.setGrading(true));
|
||||
let gradeData = selectors.grading.selected.gradeData(getState());
|
||||
if (gradeData === undefined) {
|
||||
gradeData = selectors.app.emptyGrade(getState());
|
||||
}
|
||||
dispatch(actions.grading.startGrading(gradeData));
|
||||
}).catch((error) => {
|
||||
console.log({ error });
|
||||
});
|
||||
dispatch(requests.setLock({
|
||||
value: true,
|
||||
submissionId: selectors.grading.selected.submissionId(getState()),
|
||||
onSuccess: () => {
|
||||
dispatch(actions.app.setGrading(true));
|
||||
let gradeData = selectors.grading.selected.gradeData(getState());
|
||||
if (!gradeData) {
|
||||
gradeData = selectors.app.emptyGrade(getState());
|
||||
}
|
||||
dispatch(actions.grading.startGrading(gradeData));
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
325
src/data/thunkActions/grading.test.js
Normal file
325
src/data/thunkActions/grading.test.js
Normal file
@@ -0,0 +1,325 @@
|
||||
import { RequestKeys } from 'data/constants/requests';
|
||||
import { gradingStatuses } from 'data/services/lms/constants';
|
||||
import actions from 'data/actions';
|
||||
import selectors from 'data/selectors';
|
||||
import * as thunkActions from './grading';
|
||||
|
||||
jest.mock('./requests', () => ({
|
||||
fetchSubmission: (args) => ({ fetchSubmission: args }),
|
||||
fetchSubmissionResponse: (args) => ({ fetchSubmissionResponse: args }),
|
||||
fetchSubmissionStatus: (args) => ({ fetchSubmissionStatus: args }),
|
||||
setLock: (args) => ({ setLock: args }),
|
||||
submitGrade: (args) => ({ submitGrade: args }),
|
||||
}));
|
||||
|
||||
jest.mock('data/selectors', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
app: {
|
||||
emptyGrade: (state) => ({ emptyGrade: state }),
|
||||
},
|
||||
grading: {
|
||||
prev: {
|
||||
submissionId: (state) => ({ prevSubmissionId: state }),
|
||||
doesExist: jest.fn((state) => ({ prevDoesExist: state })),
|
||||
},
|
||||
next: {
|
||||
submissionId: (state) => ({ prevSubmissionId: state }),
|
||||
doesExist: jest.fn((state) => ({ nextDoesExist: state })),
|
||||
},
|
||||
selected: {
|
||||
submissionId: (state) => ({ selectedSubmissionId: state }),
|
||||
gradeData: jest.fn((state) => ({ gradeData: state })),
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
describe('grading thunkActions', () => {
|
||||
const testState = { some: 'testy-state' };
|
||||
const submissionId = 'test-submission-id';
|
||||
const response = 'test-response';
|
||||
let dispatch;
|
||||
let dispatched;
|
||||
let actionArgs;
|
||||
const getState = () => testState;
|
||||
|
||||
const getDispatched = (calledAction) => {
|
||||
calledAction(dispatch, getState);
|
||||
[[dispatched]] = dispatch.mock.calls;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
dispatch = jest.fn((action) => ({ dispatch: action }));
|
||||
});
|
||||
|
||||
describe('prefetchNext', () => {
|
||||
beforeEach(() => {
|
||||
getDispatched(thunkActions.prefetchNext());
|
||||
actionArgs = dispatched.fetchSubmissionResponse;
|
||||
});
|
||||
it('dispatches fetchSubmissionResponse with prefetchNext key and nextSubmissionId', () => {
|
||||
expect(actionArgs).not.toEqual(undefined);
|
||||
expect(actionArgs.requestKey).toEqual(RequestKeys.prefetchNext);
|
||||
expect(actionArgs.submissionId).toEqual(selectors.grading.prev.submissionId(testState));
|
||||
});
|
||||
describe('on success', () => {
|
||||
test('dispatches preloadNext', () => {
|
||||
dispatch.mockClear();
|
||||
actionArgs.onSuccess(response);
|
||||
expect(dispatch.mock.calls).toEqual([
|
||||
[actions.grading.preloadNext(response)],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('prefetchPrev', () => {
|
||||
beforeEach(() => {
|
||||
getDispatched(thunkActions.prefetchPrev());
|
||||
actionArgs = dispatched.fetchSubmissionResponse;
|
||||
});
|
||||
it('dispatches fetchSubmissionResponse with prefetchPrev key and next submissionId', () => {
|
||||
expect(actionArgs).not.toEqual(undefined);
|
||||
expect(actionArgs.requestKey).toEqual(RequestKeys.prefetchPrev);
|
||||
expect(actionArgs.submissionId).toEqual(selectors.grading.next.submissionId(testState));
|
||||
});
|
||||
describe('on success', () => {
|
||||
test('dispatches preloadPrev', () => {
|
||||
dispatch.mockClear();
|
||||
actionArgs.onSuccess(response);
|
||||
expect(dispatch.mock.calls).toEqual([
|
||||
[actions.grading.preloadPrev(response)],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('fetchNeighbor', () => {
|
||||
let startGrading;
|
||||
let stopGrading;
|
||||
const loadAction = actions.grading.loadNext;
|
||||
const prefetchAction = actions.grading.loadNext;
|
||||
|
||||
const submitAction = (hasNeighbor) => {
|
||||
getDispatched(thunkActions.fetchNeighbor({
|
||||
submissionId,
|
||||
loadAction,
|
||||
hasNeighbor,
|
||||
prefetchAction,
|
||||
}));
|
||||
actionArgs = dispatched.fetchSubmissionStatus;
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
startGrading = thunkActions.startGrading;
|
||||
thunkActions.startGrading = () => 'startGrading';
|
||||
stopGrading = thunkActions.stopGrading;
|
||||
thunkActions.stopGrading = () => 'stopGrading';
|
||||
});
|
||||
afterAll(() => {
|
||||
thunkActions.startGrading = startGrading;
|
||||
thunkActions.stopGrading = stopGrading;
|
||||
});
|
||||
|
||||
it('calls fetchSubmissionStatus with submissionId', () => {
|
||||
submitAction(false);
|
||||
expect(actionArgs).not.toEqual(undefined);
|
||||
expect(actionArgs.submissionId).toEqual(submissionId);
|
||||
});
|
||||
describe('onSuccess', () => {
|
||||
it('dispatches startGrading if lockStatus is in progress', () => {
|
||||
submitAction(false);
|
||||
dispatch.mockClear();
|
||||
actionArgs.onSuccess({ lockStatus: gradingStatuses.inProgress });
|
||||
expect(dispatch.mock.calls[0]).toEqual([thunkActions.startGrading()]);
|
||||
});
|
||||
it('dispatches stopGrading if lockStatus is not in progress', () => {
|
||||
submitAction(false);
|
||||
dispatch.mockClear();
|
||||
actionArgs.onSuccess({ lockStatus: 'other status' });
|
||||
expect(dispatch.mock.calls[0]).toEqual([thunkActions.stopGrading()]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('fetchNeigbor inheritors', () => {
|
||||
let fetchNeighbor;
|
||||
beforeAll(() => {
|
||||
fetchNeighbor = thunkActions.fetchNeighbor;
|
||||
thunkActions.fetchNeighbor = args => ({ fetchNeighbor: args });
|
||||
});
|
||||
afterAll(() => {
|
||||
thunkActions.fetchNeighbor = fetchNeighbor;
|
||||
});
|
||||
describe('loadNext', () => {
|
||||
beforeEach(() => {
|
||||
getDispatched(thunkActions.loadNext());
|
||||
actionArgs = dispatched.fetchNeighbor;
|
||||
});
|
||||
test('dispatches fetchNeighbor', () => {
|
||||
expect(actionArgs).not.toEqual(undefined);
|
||||
});
|
||||
describe('fetchNeighbor args', () => {
|
||||
const selGroup = selectors.grading.next;
|
||||
test('loadAction: actions.grading.loadNext', () => {
|
||||
expect(actionArgs.loadAction).toEqual(actions.grading.loadNext);
|
||||
});
|
||||
test('prefetchAction: module.prefetchNext', () => {
|
||||
expect(actionArgs.prefetchAction).toEqual(thunkActions.prefetchNext);
|
||||
});
|
||||
test('hasNeighbor: selectors.grading.next.doesExist', () => {
|
||||
expect(actionArgs.hasNeighbor).toEqual(selGroup.doesExist(testState));
|
||||
});
|
||||
test('submissionId: selectors.grading.next.submissionId', () => {
|
||||
expect(actionArgs.submissionId).toEqual(selGroup.submissionId(testState));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('loadPrev', () => {
|
||||
beforeEach(() => {
|
||||
getDispatched(thunkActions.loadPrev());
|
||||
actionArgs = dispatched.fetchNeighbor;
|
||||
});
|
||||
test('dispatches fetchNeighbor', () => {
|
||||
expect(actionArgs).not.toEqual(undefined);
|
||||
});
|
||||
describe('fetchNeighbor args', () => {
|
||||
const selGroup = selectors.grading.prev;
|
||||
test('loadAction: actions.grading.loadPrev', () => {
|
||||
expect(actionArgs.loadAction).toEqual(actions.grading.loadPrev);
|
||||
});
|
||||
test('prefetchAction: module.prefetchPrev', () => {
|
||||
expect(actionArgs.prefetchAction).toEqual(thunkActions.prefetchPrev);
|
||||
});
|
||||
test('hasNeighbor: selectors.grading.prev.doesExist', () => {
|
||||
expect(actionArgs.hasNeighbor).toEqual(selGroup.doesExist(testState));
|
||||
});
|
||||
test('submissionId: selectors.grading.prev.submissionId', () => {
|
||||
expect(actionArgs.submissionId).toEqual(selGroup.submissionId(testState));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('loadSelectionForReview', () => {
|
||||
const submissionIds = [
|
||||
'submission-id-0',
|
||||
'submission-id-1',
|
||||
'submission-id-2',
|
||||
'submission-id-3',
|
||||
];
|
||||
let prefetchPrev;
|
||||
let prefetchNext;
|
||||
beforeAll(() => {
|
||||
prefetchNext = thunkActions.prefetchNext;
|
||||
prefetchPrev = thunkActions.prefetchPrev;
|
||||
thunkActions.prefetchNext = () => 'prefetch next';
|
||||
thunkActions.prefetchPrev = () => 'prefetch prev';
|
||||
});
|
||||
afterAll(() => {
|
||||
thunkActions.prefetchNext = prefetchNext;
|
||||
thunkActions.prefetchPrev = prefetchPrev;
|
||||
});
|
||||
beforeEach(() => {
|
||||
getDispatched(thunkActions.loadSelectionForReview(submissionIds));
|
||||
actionArgs = dispatched.fetchSubmission;
|
||||
});
|
||||
it('dispatches fetchSubmission with first submissionId', () => {
|
||||
expect(actionArgs).not.toEqual(undefined);
|
||||
expect(actionArgs.submissionId).toEqual(submissionIds[0]);
|
||||
});
|
||||
describe('onSuccess', () => {
|
||||
beforeEach(() => {
|
||||
dispatch.mockClear();
|
||||
actionArgs.onSuccess(response);
|
||||
});
|
||||
it('dispatches updateSelection with passed submissionIds', () => {
|
||||
expect(dispatch.mock.calls).toContainEqual(
|
||||
[actions.grading.updateSelection(submissionIds)],
|
||||
);
|
||||
});
|
||||
it('dispatches actions.grading.loadSubmission with response and first submission id', () => {
|
||||
expect(dispatch.mock.calls).toContainEqual(
|
||||
[actions.grading.loadSubmission({ ...response, submissionId: submissionIds[0] })],
|
||||
);
|
||||
});
|
||||
it('dispatches app setShowReview(true)', () => {
|
||||
expect(dispatch.mock.calls).toContainEqual(
|
||||
[actions.app.setShowReview(true)],
|
||||
);
|
||||
});
|
||||
it('dispatches prefetchNext iff selectors.grading.next.doesExist', () => {
|
||||
// default configured to be truthy
|
||||
expect(dispatch.mock.calls).toContainEqual(
|
||||
[thunkActions.prefetchNext()],
|
||||
);
|
||||
selectors.grading.next.doesExist.mockReturnValue(false);
|
||||
dispatch.mockClear();
|
||||
actionArgs.onSuccess(response);
|
||||
expect(dispatch.mock.calls).not.toContainEqual(
|
||||
[thunkActions.prefetchNext()],
|
||||
);
|
||||
});
|
||||
it('dispatches prefetchPrev iff selectors.grading.prev.doesExist', () => {
|
||||
// default configured to be truthy
|
||||
expect(dispatch.mock.calls).toContainEqual(
|
||||
[thunkActions.prefetchPrev()],
|
||||
);
|
||||
selectors.grading.prev.doesExist.mockReturnValue(false);
|
||||
dispatch.mockClear();
|
||||
actionArgs.onSuccess(response);
|
||||
expect(dispatch.mock.calls).not.toContainEqual(
|
||||
[thunkActions.prefetchPrev()],
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('startGrading', () => {
|
||||
beforeEach(() => {
|
||||
getDispatched(thunkActions.startGrading());
|
||||
actionArgs = dispatched.setLock;
|
||||
});
|
||||
test('dispatches setLock with selected submissionId and value: true', () => {
|
||||
expect(actionArgs).not.toEqual(undefined);
|
||||
expect(actionArgs.value).toEqual(true);
|
||||
expect(actionArgs.submissionId).toEqual(selectors.grading.selected.submissionId(testState));
|
||||
});
|
||||
describe('onSuccess', () => {
|
||||
beforeEach(() => {
|
||||
dispatch.mockClear();
|
||||
});
|
||||
test('dispatches app.setGrading(true)', () => {
|
||||
actionArgs.onSuccess();
|
||||
expect(dispatch.mock.calls).toContainEqual([actions.app.setGrading(true)]);
|
||||
});
|
||||
test('dispatches startGrading with selected gradeData if truthy', () => {
|
||||
actionArgs.onSuccess();
|
||||
const gradeData = selectors.grading.selected.gradeData(testState);
|
||||
expect(dispatch.mock.calls).toContainEqual([actions.grading.startGrading(gradeData)]);
|
||||
});
|
||||
test('dispatches startGrading with empty grade if selected gradeData is not truthy', () => {
|
||||
const emptyGrade = selectors.app.emptyGrade(testState);
|
||||
selectors.grading.selected.gradeData.mockReturnValueOnce(null);
|
||||
actionArgs.onSuccess();
|
||||
expect(dispatch.mock.calls).toContainEqual([actions.grading.startGrading(emptyGrade)]);
|
||||
|
||||
dispatch.mockClear();
|
||||
selectors.grading.selected.gradeData.mockReturnValueOnce(undefined);
|
||||
actionArgs.onSuccess();
|
||||
expect(dispatch.mock.calls).toContainEqual([actions.grading.startGrading(emptyGrade)]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('stopGrading', () => {
|
||||
it('dispatches grading.clearGrade and app.setGrading(false)', () => {
|
||||
thunkActions.stopGrading()(dispatch);
|
||||
expect(dispatch.mock.calls).toEqual([
|
||||
[actions.grading.clearGrade()],
|
||||
[actions.app.setGrading(false)],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
129
src/data/thunkActions/requests.js
Normal file
129
src/data/thunkActions/requests.js
Normal file
@@ -0,0 +1,129 @@
|
||||
import { StrictDict } from 'utils';
|
||||
|
||||
import { RequestKeys } from 'data/constants/requests';
|
||||
import actions from 'data/actions';
|
||||
import api from 'data/services/lms/api';
|
||||
import * as module from './requests';
|
||||
|
||||
/**
|
||||
* Wrapper around a network request promise, that sends actions to the redux store to
|
||||
* track the state of that promise.
|
||||
* Tracks the promise by requestKey, and sends an action when it is started, succeeds, or
|
||||
* fails. It also accepts onSuccess and onFailure methods to be called with the output
|
||||
* of failure or success of the promise.
|
||||
* @param {string} requestKey - request tracking identifier
|
||||
* @param {Promise} promise - api event promise
|
||||
* @param {[func]} onSuccess - onSuccess method ((response) => { ... })
|
||||
* @param {[func]} onFailure - onFailure method ((error) => { ... })
|
||||
*/
|
||||
export const networkRequest = ({
|
||||
requestKey,
|
||||
promise,
|
||||
onSuccess,
|
||||
onFailure,
|
||||
}) => (dispatch) => {
|
||||
dispatch(actions.requests.startRequest(requestKey));
|
||||
return promise.then((response) => {
|
||||
dispatch(actions.requests.completeRequest({ requestKey, response }));
|
||||
if (onSuccess) { onSuccess(response); }
|
||||
}).catch((error) => {
|
||||
dispatch(actions.requests.failRequest({ requestKey, error }));
|
||||
if (onFailure) { onFailure(error); }
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Tracked initializeApp api method.
|
||||
* Tracked to the `initialize` request key.
|
||||
* @param {string} locationId - ora location id
|
||||
* @param {[func]} onSuccess - onSuccess method ((response) => { ... })
|
||||
* @param {[func]} onFailure - onFailure method ((error) => { ... })
|
||||
*/
|
||||
export const initializeApp = ({ locationId, ...rest }) => (dispatch) => {
|
||||
dispatch(module.networkRequest({
|
||||
requestKey: RequestKeys.initialize,
|
||||
promise: api.initializeApp(locationId),
|
||||
...rest,
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
* Tracked fetchSubmissionResponse api method.
|
||||
* Tracked either prefetchNext or prefetchPrev request key.
|
||||
* @param {string} submissionId - target submission id
|
||||
* @param {[func]} onSuccess - onSuccess method ((response) => { ... })
|
||||
* @param {[func]} onFailure - onFailure method ((error) => { ... })
|
||||
*/
|
||||
export const fetchSubmissionResponse = ({ submissionId, ...rest }) => (dispatch) => {
|
||||
dispatch(module.networkRequest({
|
||||
promise: api.fetchSubmissionResponse(submissionId),
|
||||
...rest,
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
* Tracked fetchSubmissionStatus api method.
|
||||
* Tracked to the `fetchSubmissinStatus` request key.
|
||||
* @param {string} submissionId - target submission id
|
||||
* @param {[func]} onSuccess - onSuccess method ((response) => { ... })
|
||||
* @param {[func]} onFailure - onFailure method ((error) => { ... })
|
||||
*/
|
||||
export const fetchSubmissionStatus = ({ submissionId, ...rest }) => (dispatch) => {
|
||||
dispatch(module.networkRequest({
|
||||
requestKey: RequestKeys.fetchSubmissionStatus,
|
||||
promise: api.fetchSubmissionStatus(submissionId),
|
||||
...rest,
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
* Tracked initializeApp api method. tracked to the `initialize` request key.
|
||||
* @param {string} submissionId - target submission id
|
||||
* @param {[func]} onSuccess - onSuccess method ((response) => { ... })
|
||||
* @param {[func]} onFailure - onFailure method ((error) => { ... })
|
||||
*/
|
||||
export const fetchSubmission = ({ submissionId, ...rest }) => (dispatch) => {
|
||||
dispatch(module.networkRequest({
|
||||
requestKey: RequestKeys.fetchSubmission,
|
||||
promise: api.fetchSubmission(submissionId),
|
||||
...rest,
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
* Tracked initializeApp api method. tracked to the `initialize` request key.
|
||||
* @param {string} submissionId - target submission id
|
||||
* @param {bool} value - requested lock value
|
||||
* @param {[func]} onSuccess - onSuccess method ((response) => { ... })
|
||||
* @param {[func]} onFailure - onFailure method ((error) => { ... })
|
||||
*/
|
||||
export const setLock = ({ submissionId, value, ...rest }) => (dispatch) => {
|
||||
dispatch(module.networkRequest({
|
||||
requestKey: RequestKeys.setLock,
|
||||
promise: api.lockSubmission({ submissionId, value }),
|
||||
...rest,
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
* Tracked initializeApp api method. tracked to the `initialize` request key.
|
||||
* @param {string} submissionId - target submission id
|
||||
* @param {obj} gradeData - grade data object
|
||||
* @param {[func]} onSuccess - onSuccess method ((response) => { ... })
|
||||
* @param {[func]} onFailure - onFailure method ((error) => { ... })
|
||||
*/
|
||||
export const submitGrade = ({ submissionId, gradeData, ...rest }) => (dispatch) => {
|
||||
dispatch(module.networkRequest({
|
||||
requestKey: RequestKeys.submitGrade,
|
||||
promise: api.updateGrade(submissionId, gradeData),
|
||||
...rest,
|
||||
}));
|
||||
};
|
||||
|
||||
export default StrictDict({
|
||||
fetchSubmission,
|
||||
fetchSubmissionResponse,
|
||||
fetchSubmissionStatus,
|
||||
setLock,
|
||||
submitGrade,
|
||||
});
|
||||
181
src/data/thunkActions/requests.test.js
Normal file
181
src/data/thunkActions/requests.test.js
Normal file
@@ -0,0 +1,181 @@
|
||||
import actions from 'data/actions';
|
||||
import { RequestKeys } from 'data/constants/requests';
|
||||
import api from 'data/services/lms/api';
|
||||
import * as requests from './requests';
|
||||
|
||||
jest.mock('data/services/lms/api', () => ({
|
||||
initializeApp: (locationId) => ({ initializeApp: locationId }),
|
||||
fetchSubmissionResponse: (submissionId) => ({ fetchSubmissionResponse: submissionId }),
|
||||
fetchSubmissionStatus: (submissionId) => ({ fetchSubmissionStatus: submissionId }),
|
||||
fetchSubmission: (submissionId) => ({ fetchSubmission: submissionId }),
|
||||
lockSubmission: ({ submissionId, value }) => ({ lockSubmission: { submissionId, value } }),
|
||||
updateGrade: (submissionId, gradeData) => ({ updateGrade: { submissionId, gradeData } }),
|
||||
}));
|
||||
|
||||
let dispatch;
|
||||
let onSuccess;
|
||||
let onFailure;
|
||||
describe('requests thunkActions module', () => {
|
||||
beforeEach(() => {
|
||||
dispatch = jest.fn();
|
||||
onSuccess = jest.fn();
|
||||
onFailure = jest.fn();
|
||||
});
|
||||
|
||||
describe('networkRequest', () => {
|
||||
const requestKey = 'test-request';
|
||||
const testData = { some: 'test data' };
|
||||
let resolveFn;
|
||||
let rejectFn;
|
||||
beforeEach(() => {
|
||||
onSuccess = jest.fn();
|
||||
onFailure = jest.fn();
|
||||
requests.networkRequest({
|
||||
requestKey,
|
||||
promise: new Promise((resolve, reject) => {
|
||||
resolveFn = resolve;
|
||||
rejectFn = reject;
|
||||
}),
|
||||
onSuccess,
|
||||
onFailure,
|
||||
})(dispatch);
|
||||
});
|
||||
test('calls startRequest action with requestKey', async () => {
|
||||
expect(dispatch.mock.calls).toEqual([[actions.requests.startRequest(requestKey)]]);
|
||||
});
|
||||
describe('on success', () => {
|
||||
beforeEach(async () => {
|
||||
await resolveFn(testData);
|
||||
});
|
||||
it('dispatches completeRequest', async () => {
|
||||
expect(dispatch.mock.calls).toEqual([
|
||||
[actions.requests.startRequest(requestKey)],
|
||||
[actions.requests.completeRequest({ requestKey, response: testData })],
|
||||
]);
|
||||
});
|
||||
it('calls onSuccess with response', async () => {
|
||||
expect(onSuccess).toHaveBeenCalledWith(testData);
|
||||
expect(onFailure).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
describe('on failure', () => {
|
||||
beforeEach(async () => {
|
||||
await rejectFn(testData);
|
||||
});
|
||||
test('dispatches completeRequest', async () => {
|
||||
expect(dispatch.mock.calls).toEqual([
|
||||
[actions.requests.startRequest(requestKey)],
|
||||
[actions.requests.failRequest({ requestKey, error: testData })],
|
||||
]);
|
||||
});
|
||||
test('calls onSuccess with response', async () => {
|
||||
expect(onFailure).toHaveBeenCalledWith(testData);
|
||||
expect(onSuccess).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const testNetworkRequestAction = ({
|
||||
action,
|
||||
args,
|
||||
expectedData,
|
||||
expectedString,
|
||||
}) => {
|
||||
let dispatchedAction;
|
||||
beforeEach(() => {
|
||||
action({ ...args, onSuccess, onFailure })(dispatch);
|
||||
[[dispatchedAction]] = dispatch.mock.calls;
|
||||
});
|
||||
it('dispatches networkRequest', () => {
|
||||
expect(dispatchedAction.networkRequest).not.toEqual(undefined);
|
||||
});
|
||||
test('forwards onSuccess and onFailure', () => {
|
||||
expect(dispatchedAction.networkRequest.onSuccess).toEqual(onSuccess);
|
||||
expect(dispatchedAction.networkRequest.onFailure).toEqual(onFailure);
|
||||
});
|
||||
test(expectedString, () => {
|
||||
expect(dispatchedAction.networkRequest).toEqual({
|
||||
...expectedData,
|
||||
onSuccess,
|
||||
onFailure,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
describe('network request actions', () => {
|
||||
const submissionId = 'test-submission-id';
|
||||
const locationId = 'test-location-id';
|
||||
beforeEach(() => {
|
||||
requests.networkRequest = jest.fn(args => ({ networkRequest: args }));
|
||||
});
|
||||
describe('initializeApp', () => {
|
||||
testNetworkRequestAction({
|
||||
action: requests.initializeApp,
|
||||
args: { locationId },
|
||||
expectedString: 'with initialize key, initializeApp promise',
|
||||
expectedData: {
|
||||
requestKey: RequestKeys.initialize,
|
||||
promise: api.initializeApp(locationId),
|
||||
},
|
||||
});
|
||||
});
|
||||
describe('fetchSubmissionResponse', () => {
|
||||
const requestKey = 'test-request-key';
|
||||
testNetworkRequestAction({
|
||||
action: requests.fetchSubmissionResponse,
|
||||
args: { submissionId, requestKey },
|
||||
expectedString: 'with fetchSubmissionResponse promise',
|
||||
expectedData: {
|
||||
requestKey,
|
||||
promise: api.fetchSubmissionResponse(submissionId),
|
||||
},
|
||||
});
|
||||
});
|
||||
describe('fetchSubmissionStatus', () => {
|
||||
testNetworkRequestAction({
|
||||
action: requests.fetchSubmissionStatus,
|
||||
args: { submissionId },
|
||||
expectedString: 'with fetchSubmissionStatus promise',
|
||||
expectedData: {
|
||||
requestKey: RequestKeys.fetchSubmissionStatus,
|
||||
promise: api.fetchSubmissionStatus(submissionId),
|
||||
},
|
||||
});
|
||||
});
|
||||
describe('fetchSubmission', () => {
|
||||
testNetworkRequestAction({
|
||||
action: requests.fetchSubmission,
|
||||
args: { submissionId },
|
||||
expectedString: 'with fetchSubmission promise',
|
||||
expectedData: {
|
||||
requestKey: RequestKeys.fetchSubmission,
|
||||
promise: api.fetchSubmission(submissionId),
|
||||
},
|
||||
});
|
||||
});
|
||||
describe('setLock', () => {
|
||||
const lockValue = 'test-lock-value';
|
||||
testNetworkRequestAction({
|
||||
action: requests.setLock,
|
||||
args: { submissionId, value: lockValue },
|
||||
expectedString: 'with setLock promise',
|
||||
expectedData: {
|
||||
requestKey: RequestKeys.setLock,
|
||||
promise: api.lockSubmission({ submissionId, value: lockValue }),
|
||||
},
|
||||
});
|
||||
});
|
||||
describe('submitGrade', () => {
|
||||
const gradeData = 'test-grade-data';
|
||||
testNetworkRequestAction({
|
||||
action: requests.submitGrade,
|
||||
args: { submissionId, gradeData },
|
||||
expectedString: 'with submitGrade promise',
|
||||
expectedData: {
|
||||
requestKey: RequestKeys.submitGrade,
|
||||
promise: api.updateGrade(submissionId, gradeData),
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user