fix: fix broken/copy-pasta tests
This commit is contained in:
102
src/App.test.jsx
102
src/App.test.jsx
@@ -1,75 +1,41 @@
|
||||
// import React from 'react';
|
||||
// import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
// import Footer from '@edx/frontend-component-footer';
|
||||
// import { LearningHeader as Header } from '@edx/frontend-component-header';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
|
||||
// import ListView from 'containers/ListView';
|
||||
import Footer from '@edx/frontend-component-footer';
|
||||
|
||||
// import { App } from './App';
|
||||
import Dashboard from 'containers/Dashboard';
|
||||
import { App } from './App';
|
||||
|
||||
// jest.mock('data/redux', () => ({
|
||||
// app: {
|
||||
// selectors: {
|
||||
// courseMetadata: (state) => ({ courseMetadata: state }),
|
||||
// isEnabled: (state) => ({ isEnabled: state }),
|
||||
// },
|
||||
// },
|
||||
// }));
|
||||
jest.mock('@edx/frontend-component-footer', () => 'Footer');
|
||||
|
||||
// jest.mock('@edx/frontend-component-header', () => ({
|
||||
// LearningHeader: 'Header',
|
||||
// }));
|
||||
// jest.mock('@edx/frontend-component-footer', () => 'Footer');
|
||||
jest.mock('containers/Dashboard', () => 'Dashboard');
|
||||
jest.mock('containers/LearnerDashboardHeader', () => 'LearnerDashboardHeader');
|
||||
|
||||
// jest.mock('containers/DemoWarning', () => 'DemoWarning');
|
||||
// jest.mock('containers/ListView', () => 'ListView');
|
||||
const logo = 'fakeLogo.png';
|
||||
let el;
|
||||
let router;
|
||||
|
||||
// const logo = 'fakeLogo.png';
|
||||
// let el;
|
||||
// let router;
|
||||
|
||||
// describe('App router component', () => {
|
||||
// const props = {
|
||||
// courseMetadata: {
|
||||
// org: 'course-org',
|
||||
// number: 'course-number',
|
||||
// title: 'course-title',
|
||||
// },
|
||||
// isEnabled: true,
|
||||
// };
|
||||
// test('snapshot: enabled', () => {
|
||||
// expect(shallow(<App {...props} />)).toMatchSnapshot();
|
||||
// });
|
||||
// test('snapshot: disabled (show demo warning)', () => {
|
||||
// expect(shallow(<App {...props} isEnabled={false} />)).toMatchSnapshot();
|
||||
// });
|
||||
// describe('component', () => {
|
||||
// beforeEach(() => {
|
||||
// process.env.LOGO_POWERED_BY_OPEN_EDX_URL_SVG = logo;
|
||||
// el = shallow(<App {...props} />);
|
||||
// router = el.childAt(0);
|
||||
// });
|
||||
// describe('Router', () => {
|
||||
// test('Routing - ListView is only route', () => {
|
||||
// expect(router.find('main')).toEqual(shallow(
|
||||
// <main><ListView /></main>,
|
||||
// ));
|
||||
// });
|
||||
// });
|
||||
// test('Footer logo drawn from env variable', () => {
|
||||
// expect(router.find(Footer).props().logo).toEqual(logo);
|
||||
// });
|
||||
|
||||
// test('Header to use courseMetadata props', () => {
|
||||
// const {
|
||||
// courseTitle,
|
||||
// courseNumber,
|
||||
// courseOrg,
|
||||
// } = router.find(Header).props();
|
||||
// expect(courseTitle).toEqual(props.courseMetadata.title);
|
||||
// expect(courseNumber).toEqual(props.courseMetadata.number);
|
||||
// expect(courseOrg).toEqual(props.courseMetadata.org);
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
describe('App router component', () => {
|
||||
test('snapshot: enabled', () => {
|
||||
expect(shallow(<App />)).toMatchSnapshot();
|
||||
});
|
||||
describe('component', () => {
|
||||
beforeEach(() => {
|
||||
process.env.LOGO_POWERED_BY_OPEN_EDX_URL_SVG = logo;
|
||||
el = shallow(<App />);
|
||||
router = el.find(BrowserRouter);
|
||||
});
|
||||
describe('Router', () => {
|
||||
test('Routing - ListView is only route', () => {
|
||||
expect(router.find('main')).toEqual(shallow(
|
||||
<main><Dashboard /></main>,
|
||||
));
|
||||
});
|
||||
});
|
||||
test('Footer logo drawn from env variable', () => {
|
||||
expect(router.find(Footer).props().logo).toEqual(logo);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
15
src/__snapshots__/App.test.jsx.snap
Normal file
15
src/__snapshots__/App.test.jsx.snap
Normal file
@@ -0,0 +1,15 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`App router component snapshot: enabled 1`] = `
|
||||
<BrowserRouter>
|
||||
<div>
|
||||
<LearnerDashboardHeader />
|
||||
<main>
|
||||
<Dashboard />
|
||||
</main>
|
||||
<Footer
|
||||
logo="https://edx-cdn.org/v3/stage/open-edx-tag.svg"
|
||||
/>
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
`;
|
||||
@@ -13,11 +13,7 @@ exports[`app registry subscribe: APP_READY. links App to root element 1`] = `
|
||||
<AppProvider
|
||||
store={
|
||||
Object {
|
||||
"dispatch": [Function],
|
||||
"getState": [Function],
|
||||
"replaceReducer": [Function],
|
||||
"subscribe": [Function],
|
||||
Symbol(Symbol.observable): [Function],
|
||||
"redux": "store",
|
||||
}
|
||||
}
|
||||
>
|
||||
|
||||
@@ -58,7 +58,6 @@ ReasonPane.propTypes = {
|
||||
}),
|
||||
selected: PropTypes.string,
|
||||
submit: PropTypes.func,
|
||||
isSubmited: PropTypes.bool,
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
import { MockUseState, testCardValues } from 'testUtils';
|
||||
import * as hooks from './hooks';
|
||||
import { MockUseState } from 'testUtils';
|
||||
import { thunkActions } from 'data/redux';
|
||||
import * as hooks from './hooks';
|
||||
|
||||
jest.mock('data/redux/thunkActions/app', () => ({
|
||||
refreshList: jest.fn((args) => ({ refreshList: args })),
|
||||
|
||||
@@ -1,43 +1,16 @@
|
||||
import { initialState, reducer, actions } from './reducer';
|
||||
|
||||
describe('app reducer', () => {
|
||||
describe('initialState', () => {
|
||||
test('populated, but empty course metadata', () => {
|
||||
const data = initialState.courseMetadata;
|
||||
expect(data.name).toEqual('');
|
||||
expect(data.number).toEqual('');
|
||||
expect(data.org).toEqual('');
|
||||
expect(data.courseId).toEqual('');
|
||||
});
|
||||
test('disabled (waffle flag)', () => {
|
||||
expect(initialState.isEnabled).toEqual(false);
|
||||
});
|
||||
test('not grading', () => {
|
||||
expect(initialState.isGrading).toEqual(false);
|
||||
});
|
||||
test('populated, but empty ora metadata', () => {
|
||||
const data = initialState.oraMetadata;
|
||||
expect(data.prompt).toEqual('');
|
||||
expect(data.name).toEqual('');
|
||||
expect(data.type).toEqual('');
|
||||
expect(data.rubricConfig).toEqual(null);
|
||||
});
|
||||
test('not showing review', () => {
|
||||
expect(initialState.showReview).toEqual(false);
|
||||
});
|
||||
test('not showing rubric', () => {
|
||||
expect(initialState.showRubric).toEqual(false);
|
||||
});
|
||||
});
|
||||
describe('reducers', () => {
|
||||
it('returns initial state', () => {
|
||||
expect(reducer(undefined, {})).toEqual(initialState);
|
||||
});
|
||||
const testState = {
|
||||
...initialState,
|
||||
showRubric: true,
|
||||
showReview: true,
|
||||
arbitrary: 'state',
|
||||
enrollments: [],
|
||||
courseData: {
|
||||
},
|
||||
entitlements: [],
|
||||
};
|
||||
const testValue = 'my-test-value';
|
||||
const testAction = (action, expected) => {
|
||||
@@ -47,26 +20,46 @@ describe('app reducer', () => {
|
||||
});
|
||||
};
|
||||
describe('action handlers', () => {
|
||||
test('loadIsEnabled loads isEnabled from payload', () => {
|
||||
testAction(actions.loadIsEnabled(testValue), { isEnabled: testValue });
|
||||
test('loadEntitlements loads entitlements from payload', () => {
|
||||
testAction(
|
||||
actions.loadEntitlements(testValue),
|
||||
{ entitlements: testValue },
|
||||
);
|
||||
});
|
||||
test('loadCourseMetadata loads courseMetadata from payload', () => {
|
||||
testAction(actions.loadCourseMetadata(testValue), { courseMetadata: testValue });
|
||||
});
|
||||
test('loadOraMetadata loads oraMetadata from payload', () => {
|
||||
testAction(actions.loadOraMetadata(testValue), { oraMetadata: testValue });
|
||||
});
|
||||
describe('setShowReview', () => {
|
||||
it('loads showReview, sets showRubric to false if set to false', () => {
|
||||
testAction(actions.setShowReview(true), { showReview: true });
|
||||
testAction(actions.setShowReview(false), { showReview: false, showRubric: false });
|
||||
describe('loadEnrollments', () => {
|
||||
const enrollments = [
|
||||
'course-1',
|
||||
'course-2',
|
||||
'course-3',
|
||||
];
|
||||
const courseData = {
|
||||
[enrollments[0]]: {
|
||||
courseRun: { courseNumber: enrollments[0] },
|
||||
course: 1,
|
||||
some: 'data',
|
||||
},
|
||||
[enrollments[1]]: {
|
||||
courseRun: { courseNumber: enrollments[1] },
|
||||
course: 2,
|
||||
some: 'other data',
|
||||
},
|
||||
[enrollments[2]]: {
|
||||
courseRun: { courseNumber: enrollments[2] },
|
||||
course: 3,
|
||||
some: 'still different data',
|
||||
},
|
||||
};
|
||||
const enrollmentData = enrollments.map(v => courseData[v]);
|
||||
let out;
|
||||
beforeEach(() => {
|
||||
out = reducer(testState, actions.loadEnrollments(enrollmentData));
|
||||
});
|
||||
it('loads list of courseRun ids into enrollments field', () => {
|
||||
expect(out.enrollments).toEqual(enrollments);
|
||||
});
|
||||
it('loads object keyed by courseRun ids into courseData field', () => {
|
||||
expect(out.courseData).toEqual(courseData);
|
||||
});
|
||||
});
|
||||
test('setShowRubric loads showRubric from payload', () => {
|
||||
testAction(actions.setShowRubric(testValue), { showRubric: testValue });
|
||||
});
|
||||
test('toggleShowRubric toggles showRubric value', () => {
|
||||
testAction(actions.toggleShowRubric(), { showRubric: !testState.showRubric });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -30,12 +30,6 @@ describe('requests selectors unit tests', () => {
|
||||
test('requestStatus returns data associated with given key', () => {
|
||||
expect(selectors.requestStatus(testState, { requestKey })).toEqual(requestData);
|
||||
});
|
||||
describe('allowNavigation', () => {
|
||||
it('returns false if any requests are pending', () => {
|
||||
expect(selectors.allowNavigation(testState)).toEqual(true);
|
||||
expect(selectors.allowNavigation({ requests: { key1: pendingRequest } })).toEqual(false);
|
||||
});
|
||||
});
|
||||
const testStatusSelector = (selector, matchingRequest) => {
|
||||
expect(selector(testState, { requestKey })).toEqual(false);
|
||||
expect(selector(
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
import { locationId } from 'data/constants/app';
|
||||
|
||||
import { selectors, actions } from 'data/redux';
|
||||
import { keyStore } from 'utils';
|
||||
import * as thunkActions from './app';
|
||||
|
||||
jest.mock('./requests', () => ({
|
||||
initializeApp: (args) => ({ initializeApp: args }),
|
||||
batchUnlock: (args) => ({ batchUnlock: args }),
|
||||
}));
|
||||
|
||||
const dispatch = jest.fn((action) => ({ dispatch: action }));
|
||||
const testState = { my: 'test state' };
|
||||
const getState = () => testState;
|
||||
const moduleKeys = keyStore(thunkActions);
|
||||
|
||||
describe('app thunkActions', () => {
|
||||
let dispatchedAction;
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
describe('initialize', () => {
|
||||
beforeEach(() => {
|
||||
thunkActions.initialize()(dispatch);
|
||||
[[dispatchedAction]] = dispatch.mock.calls;
|
||||
});
|
||||
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 isEnabled, oraMetadata, courseMetadata and list data', () => {
|
||||
const response = {
|
||||
courseMetadata: { some: 'course-metadata' },
|
||||
isEnabled: { is: 'enabled?' },
|
||||
oraMetadata: { some: 'ora-metadata' },
|
||||
submissions: { some: 'submissions' },
|
||||
};
|
||||
dispatch.mockClear();
|
||||
dispatchedAction.initializeApp.onSuccess(response);
|
||||
expect(dispatch.mock.calls).toEqual([
|
||||
[actions.app.loadIsEnabled(response.isEnabled)],
|
||||
[actions.app.loadOraMetadata(response.oraMetadata)],
|
||||
[actions.app.loadCourseMetadata(response.courseMetadata)],
|
||||
[actions.submissions.loadList(response.submissions)],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('cancelReview', () => {
|
||||
const gradingSelection = (args) => ({ gradingSelection: args });
|
||||
const mockInitialize = (args) => ({ initialize: args });
|
||||
const gradingKeys = keyStore(selectors.grading);
|
||||
beforeEach(() => {
|
||||
jest.spyOn(thunkActions, moduleKeys.initialize)
|
||||
.mockImplementationOnce(mockInitialize);
|
||||
jest.spyOn(selectors.grading, gradingKeys.selection)
|
||||
.mockImplementationOnce(gradingSelection);
|
||||
thunkActions.cancelReview()(dispatch, getState);
|
||||
[[dispatchedAction]] = dispatch.mock.calls;
|
||||
});
|
||||
it('dispatches batchUnlock with submissionUUIDs and onSuccess', () => {
|
||||
expect(dispatchedAction.batchUnlock.submissionUUIDs)
|
||||
.toEqual(gradingSelection(testState));
|
||||
expect(typeof dispatchedAction.batchUnlock.onSuccess).toEqual('function');
|
||||
});
|
||||
it('clears show review state and calls dispatches initialize thunkAction on success', () => {
|
||||
dispatch.mockClear();
|
||||
dispatchedAction.batchUnlock.onSuccess();
|
||||
expect(dispatch.mock.calls).toEqual([
|
||||
[actions.app.setShowReview(false)],
|
||||
[mockInitialize()],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,16 +1,9 @@
|
||||
import { actions } from 'data/redux';
|
||||
import { RequestKeys } from 'data/constants/requests';
|
||||
import api from 'data/services/lms/api';
|
||||
// import api from 'data/services/lms/api';
|
||||
import * as requests from './requests';
|
||||
|
||||
jest.mock('data/services/lms/api', () => ({
|
||||
batchUnlockSubmissions: (submissionUUIDs) => ({ batchUnlockSubmissions: submissionUUIDs }),
|
||||
initializeApp: (locationId) => ({ initializeApp: locationId }),
|
||||
fetchSubmissionStatus: (submissionUUID) => ({ fetchSubmissionStatus: submissionUUID }),
|
||||
fetchSubmission: (submissionUUID) => ({ fetchSubmission: submissionUUID }),
|
||||
lockSubmission: ({ submissionUUID }) => ({ lockSubmission: { submissionUUID } }),
|
||||
unlockSubmission: ({ submissionUUID }) => ({ unlockSubmission: { submissionUUID } }),
|
||||
updateGrade: (submissionUUID, gradeData) => ({ updateGrade: { submissionUUID, gradeData } }),
|
||||
// initializeList: (locationId) => ({ initializeList: locationId }),
|
||||
}));
|
||||
|
||||
const dispatch = jest.fn();
|
||||
@@ -91,6 +84,7 @@ describe('requests thunkActions module', () => {
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
const testNetworkRequestAction = ({
|
||||
action,
|
||||
args,
|
||||
@@ -117,92 +111,13 @@ describe('requests thunkActions module', () => {
|
||||
});
|
||||
});
|
||||
};
|
||||
*/
|
||||
|
||||
describe('network request actions', () => {
|
||||
const submissionUUID = '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('fetchSubmissionStatus', () => {
|
||||
testNetworkRequestAction({
|
||||
action: requests.fetchSubmissionStatus,
|
||||
args: { submissionUUID },
|
||||
expectedString: 'with fetchSubmissionStatus promise',
|
||||
expectedData: {
|
||||
requestKey: RequestKeys.fetchSubmissionStatus,
|
||||
promise: api.fetchSubmissionStatus(submissionUUID),
|
||||
},
|
||||
});
|
||||
});
|
||||
describe('fetchSubmission', () => {
|
||||
testNetworkRequestAction({
|
||||
action: requests.fetchSubmission,
|
||||
args: { submissionUUID },
|
||||
expectedString: 'with fetchSubmission promise',
|
||||
expectedData: {
|
||||
requestKey: RequestKeys.fetchSubmission,
|
||||
promise: api.fetchSubmission(submissionUUID),
|
||||
},
|
||||
});
|
||||
});
|
||||
describe('setLock: true', () => {
|
||||
testNetworkRequestAction({
|
||||
action: requests.setLock,
|
||||
args: { submissionUUID, value: true },
|
||||
expectedString: 'with setLock promise',
|
||||
expectedData: {
|
||||
requestKey: RequestKeys.setLock,
|
||||
promise: api.lockSubmission(submissionUUID),
|
||||
},
|
||||
});
|
||||
});
|
||||
describe('setLock: false', () => {
|
||||
testNetworkRequestAction({
|
||||
action: requests.setLock,
|
||||
args: { submissionUUID, value: false },
|
||||
expectedString: 'with setLock promise',
|
||||
expectedData: {
|
||||
requestKey: RequestKeys.setLock,
|
||||
promise: api.unlockSubmission(submissionUUID),
|
||||
},
|
||||
});
|
||||
});
|
||||
describe('batchUnlock', () => {
|
||||
const submissionUUIDs = [1, 2, 3, 4, 5];
|
||||
testNetworkRequestAction({
|
||||
action: requests.batchUnlock,
|
||||
args: { submissionUUIDs, value: false },
|
||||
expectedString: 'with batchUnlock promise',
|
||||
expectedData: {
|
||||
requestKey: RequestKeys.batchUnlock,
|
||||
promise: api.batchUnlockSubmissions(submissionUUIDs),
|
||||
value: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
describe('submitGrade', () => {
|
||||
const gradeData = 'test-grade-data';
|
||||
testNetworkRequestAction({
|
||||
action: requests.submitGrade,
|
||||
args: { submissionUUID, gradeData },
|
||||
expectedString: 'with submitGrade promise',
|
||||
expectedData: {
|
||||
requestKey: RequestKeys.submitGrade,
|
||||
promise: api.updateGrade(submissionUUID, gradeData),
|
||||
},
|
||||
});
|
||||
describe('initializeList', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -35,6 +35,7 @@ jest.mock('@edx/frontend-platform', () => ({
|
||||
jest.mock('@edx/frontend-component-footer', () => ({
|
||||
messages: ['some', 'messages'],
|
||||
}));
|
||||
jest.mock('data/store', () => ({ redux: 'store' }));
|
||||
jest.mock('./App', () => 'App');
|
||||
|
||||
const testValue = 'my-test-value';
|
||||
|
||||
@@ -32,6 +32,7 @@ jest.mock('@edx/frontend-platform/i18n', () => {
|
||||
),
|
||||
formatDate: jest.fn().mockName('useIntl.formatDate'),
|
||||
}),
|
||||
IntlProvider: () => 'IntlProvider',
|
||||
defineMessages: m => m,
|
||||
FormattedMessage: () => 'FormattedMessage',
|
||||
};
|
||||
|
||||
@@ -15,9 +15,7 @@ import thunk from 'redux-thunk';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import urls from 'data/services/lms/urls';
|
||||
import { ErrorStatuses, RequestKeys, RequestStates } from 'data/constants/requests';
|
||||
import { gradeStatuses, lockStatuses } from 'data/services/lms/constants';
|
||||
import fakeData from 'data/services/lms/fakeData';
|
||||
// import fakeData from 'data/services/lms/fakeData/courses';
|
||||
import api from 'data/services/lms/api';
|
||||
import reducers from 'data/redux';
|
||||
import messages from 'i18n';
|
||||
@@ -40,21 +38,6 @@ jest.mock('@edx/frontend-platform/auth', () => ({
|
||||
getLoginRedirectUrl: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('react-pdf', () => ({
|
||||
Document: () => <div>Document</div>,
|
||||
Image: () => <div>Image</div>,
|
||||
Page: () => <div>Page</div>,
|
||||
PDFViewer: jest.fn(() => null),
|
||||
StyleSheet: { create: () => {} },
|
||||
Text: () => <div>Text</div>,
|
||||
View: () => <div>View</div>,
|
||||
pdfjs: { GlobalWorkerOptions: {} },
|
||||
}));
|
||||
/*
|
||||
jest.mock('react-pdf/node_modules/pdfjs-dist/build/pdf.worker.entry', () => (
|
||||
jest.requireActual('react-pdf/dist/umd/entry.jest')
|
||||
));
|
||||
*/
|
||||
const configureStore = () => redux.createStore(
|
||||
reducers,
|
||||
redux.compose(redux.applyMiddleware(thunk)),
|
||||
@@ -66,8 +49,6 @@ let state;
|
||||
let retryLink;
|
||||
let inspector;
|
||||
|
||||
const { rubricConfig } = fakeData.oraMetadata;
|
||||
|
||||
/**
|
||||
* Simple wrapper for updating the top-level state variable, that also returns the new value
|
||||
* @return {obj} - current redux store state
|
||||
@@ -77,16 +58,6 @@ const getState = () => {
|
||||
return state;
|
||||
};
|
||||
|
||||
/** Fake Data for quick access */
|
||||
const submissionUUIDs = [
|
||||
fakeData.ids.submissionUUID(0),
|
||||
fakeData.ids.submissionUUID(1),
|
||||
fakeData.ids.submissionUUID(2),
|
||||
fakeData.ids.submissionUUID(3),
|
||||
fakeData.ids.submissionUUID(4),
|
||||
];
|
||||
const submissions = submissionUUIDs.map(id => fakeData.mockSubmission(id));
|
||||
|
||||
/**
|
||||
* Object to be filled with resolve/reject functions for all controlled network comm channels
|
||||
*/
|
||||
@@ -103,58 +74,7 @@ const mockForbiddenError = (reject) => () => reject(new Error({
|
||||
}));
|
||||
|
||||
const mockApi = () => {
|
||||
api.initializeApp = jest.fn(() => new Promise(
|
||||
(resolve, reject) => {
|
||||
resolveFns.init = {
|
||||
success: () => resolve({
|
||||
isEnabled: true,
|
||||
oraMetadata: fakeData.oraMetadata,
|
||||
courseMetadata: fakeData.courseMetadata,
|
||||
submissions: fakeData.submissions,
|
||||
}),
|
||||
networkError: mockNetworkError(reject),
|
||||
};
|
||||
},
|
||||
));
|
||||
api.fetchSubmission = jest.fn((submissionUUID) => new Promise(
|
||||
(resolve, reject) => {
|
||||
resolveFns.fetch = {
|
||||
success: () => resolve(fakeData.mockSubmission(submissionUUID)),
|
||||
networkError: mockNetworkError(reject),
|
||||
};
|
||||
},
|
||||
));
|
||||
api.fetchSubmissionStatus = jest.fn((submissionUUID) => Promise.resolve(
|
||||
fakeData.mockSubmissionStatus(submissionUUID)
|
||||
));
|
||||
api.lockSubmission = jest.fn(() => new Promise(
|
||||
(resolve, reject) => {
|
||||
resolveFns.lock = {
|
||||
success: () => resolve({ lockStatus: lockStatuses.inProgress }),
|
||||
networkError: mockForbiddenError(reject),
|
||||
};
|
||||
},
|
||||
));
|
||||
api.unlockSubmission = jest.fn(() => new Promise(
|
||||
(resolve, reject) => {
|
||||
resolveFns.unlock = {
|
||||
success: () => resolve({ lockStatus: lockStatuses.unlocked }),
|
||||
networkError: mockNetworkError(reject),
|
||||
};
|
||||
},
|
||||
));
|
||||
api.updateGrade = jest.fn((uuid, gradeData) => new Promise(
|
||||
(resolve, reject) => {
|
||||
resolveFns.updateGrade = {
|
||||
success: () => resolve({
|
||||
gradeData,
|
||||
gradeStatus: gradeStatuses.graded,
|
||||
lockStatus: lockStatuses.unlocked,
|
||||
}),
|
||||
networkError: mockNetworkError(reject),
|
||||
};
|
||||
},
|
||||
));
|
||||
api.initializeList = jest.fn(() => new Promise());
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -172,344 +92,17 @@ const renderEl = async () => {
|
||||
getState();
|
||||
};
|
||||
|
||||
/**
|
||||
* resolve the initalization promise, and update state object
|
||||
*/
|
||||
const initialize = async () => {
|
||||
resolveFns.init.success();
|
||||
await inspector.find.listView.viewAllResponsesBtn();
|
||||
getState();
|
||||
};
|
||||
|
||||
/**
|
||||
* Select the first 5 entries in the table and click the 'View Selected Responses' button
|
||||
* Wait for the review page to show and update the top-level state object.
|
||||
*/
|
||||
const makeTableSelections = async () => {
|
||||
[0, 1, 2, 3, 4].forEach(index => userEvent.click(inspector.listView.listCheckbox(index)));
|
||||
userEvent.click(inspector.listView.selectedBtn(5));
|
||||
// wait for navigation, which will show while request is pending
|
||||
try {
|
||||
await inspector.find.review.prevNav();
|
||||
} catch (e) {
|
||||
throw(e);
|
||||
}
|
||||
getState();
|
||||
};
|
||||
|
||||
const waitForEqual = async (valFn, expected, key) => waitFor(() => {
|
||||
expect(valFn(), `${key} is expected to equal ${expected}`).toEqual(expected);
|
||||
});
|
||||
const waitForRequestStatus = (key, status) => waitForEqual(
|
||||
() => getState().requests[key].status,
|
||||
status,
|
||||
key,
|
||||
);
|
||||
|
||||
describe('ESG app integration tests', () => {
|
||||
describe('Learner Dashbpard app integration tests', () => {
|
||||
beforeEach(async () => {
|
||||
mockApi();
|
||||
await renderEl();
|
||||
inspector = new Inspector(el);
|
||||
// inspector = new Inspector(el);
|
||||
});
|
||||
|
||||
test('initialization', async (done) => {
|
||||
const verifyInitialState = async () => {
|
||||
await waitForRequestStatus(RequestKeys.initialize, RequestStates.pending);
|
||||
const testInitialState = (key) => expect(
|
||||
state[key],
|
||||
`${key} store should have its configured initial state`,
|
||||
).toEqual(
|
||||
jest.requireActual(`data/redux/${key}/reducer`).initialState,
|
||||
);
|
||||
testInitialState('app');
|
||||
testInitialState('submissions');
|
||||
testInitialState('grading');
|
||||
expect(
|
||||
inspector.listView.loadingResponses(),
|
||||
'Loading Responses pending state text should be displayed in the ListView',
|
||||
).toBeVisible();
|
||||
}
|
||||
await verifyInitialState();
|
||||
|
||||
// initialization network error
|
||||
const forceAndVerifyInitNetworkError = async () => {
|
||||
resolveFns.init.networkError();
|
||||
await waitForRequestStatus(RequestKeys.initialize, RequestStates.failed);
|
||||
expect(
|
||||
await inspector.find.listView.loadErrorHeading(),
|
||||
'List Error should be available (by heading component)',
|
||||
).toBeVisible();
|
||||
const backLink = inspector.listView.backLink();
|
||||
expect(
|
||||
backLink.href,
|
||||
'Back to responses button href should link to urls.openResponse(courseId)',
|
||||
).toEqual(urls.openResponse(getState().app.courseMetadata.courseId));
|
||||
};
|
||||
await forceAndVerifyInitNetworkError();
|
||||
|
||||
// initialization retry/pending
|
||||
retryLink = inspector.listView.reloadBtn();
|
||||
await userEvent.click(retryLink);
|
||||
await waitForRequestStatus(RequestKeys.initialize, RequestStates.pending);
|
||||
|
||||
// initialization success
|
||||
const forceAndVerifyInitSuccess = async () => {
|
||||
await initialize();
|
||||
await waitForRequestStatus(RequestKeys.initialize, RequestStates.completed);
|
||||
expect(
|
||||
state.app.courseMetadata,
|
||||
'Course metadata in redux should be populated with fake data',
|
||||
).toEqual(fakeData.courseMetadata);
|
||||
expect(
|
||||
state.app.oraMetadata,
|
||||
'ORA metadata in redux should be populated with fake data',
|
||||
).toEqual(fakeData.oraMetadata);
|
||||
expect(
|
||||
state.submissions.allSubmissions,
|
||||
'submissions data in redux should be populated with fake data',
|
||||
).toEqual(fakeData.submissions);
|
||||
};
|
||||
await forceAndVerifyInitSuccess();
|
||||
|
||||
await makeTableSelections();
|
||||
await waitForRequestStatus(RequestKeys.fetchSubmission, RequestStates.pending);
|
||||
done();
|
||||
});
|
||||
|
||||
describe('initialized', () => {
|
||||
beforeEach(async () => {
|
||||
await initialize();
|
||||
await waitForRequestStatus(RequestKeys.initialize, RequestStates.completed);
|
||||
await makeTableSelections();
|
||||
await waitForRequestStatus(RequestKeys.fetchSubmission, RequestStates.pending);
|
||||
});
|
||||
|
||||
test('initial review state', async (done) => {
|
||||
// Make table selection and load Review pane
|
||||
expect(
|
||||
state.grading.selection,
|
||||
'submission IDs should be loaded',
|
||||
).toEqual(submissionUUIDs);
|
||||
expect(state.app.showReview, 'app store should have showReview: true').toEqual(true);
|
||||
expect(inspector.review.username(0), 'username should be visible').toBeVisible();
|
||||
const nextNav = inspector.review.nextNav();
|
||||
const prevNav = inspector.review.prevNav();
|
||||
expect(nextNav, 'next nav should be displayed').toBeVisible();
|
||||
expect(nextNav, 'next nav should be disabled').toHaveAttribute('disabled');
|
||||
expect(prevNav, 'prev nav should be displayed').toBeVisible();
|
||||
expect(prevNav, 'prev nav should be disabled').toHaveAttribute('disabled');
|
||||
expect(
|
||||
inspector.review.loadingResponse(),
|
||||
'Loading Responses pending state text should be displayed in the ReviewModal',
|
||||
).toBeVisible();
|
||||
done();
|
||||
});
|
||||
|
||||
test('fetch network error and retry', async (done) => {
|
||||
await resolveFns.fetch.networkError();
|
||||
await waitForRequestStatus(RequestKeys.fetchSubmission, RequestStates.failed);
|
||||
expect(
|
||||
await inspector.find.review.loadErrorHeading(),
|
||||
'Load Submission error should be displayed in ReviewModal',
|
||||
).toBeVisible();
|
||||
// fetch: retry and succeed
|
||||
await userEvent.click(inspector.review.retryFetchLink());
|
||||
await waitForRequestStatus(RequestKeys.fetchSubmission, RequestStates.pending);
|
||||
done()
|
||||
});
|
||||
|
||||
test('fetch success and nav chain', async (done) => {
|
||||
let showRubric = false;
|
||||
// fetch: success with chained navigation
|
||||
const verifyFetchSuccess = async (submissionIndex) => {
|
||||
const submissionString = `for submission ${submissionIndex}`;
|
||||
const submission = submissions[submissionIndex];
|
||||
const forceAndVerifyFetchSuccess = async () => {
|
||||
await resolveFns.fetch.success();
|
||||
await waitForRequestStatus(RequestKeys.fetchSubmission, RequestStates.completed);
|
||||
expect(
|
||||
inspector.review.gradingStatus(submission),
|
||||
`Should display current submission grading status ${submissionString}`,
|
||||
).toBeVisible();
|
||||
};
|
||||
await forceAndVerifyFetchSuccess();
|
||||
|
||||
showRubric = showRubric || selectors.grading.selected.isGrading(getState());
|
||||
|
||||
const verifyRubricVisibility = async () => {
|
||||
getState();
|
||||
expect(
|
||||
state.app.showRubric,
|
||||
`${showRubric ? 'Should' : 'Should not'} show rubric ${submissionString}`,
|
||||
).toEqual(showRubric);
|
||||
if (showRubric) {
|
||||
expect(
|
||||
inspector.review.hideRubricBtn(),
|
||||
`Hide Rubric button should be visible when rubric is shown ${submissionString}`,
|
||||
).toBeVisible();
|
||||
|
||||
} else {
|
||||
expect(
|
||||
inspector.review.showRubricBtn(),
|
||||
`Show Rubric button should be visible when rubric is hidden ${submissionString}`,
|
||||
).toBeVisible();
|
||||
}
|
||||
}
|
||||
await verifyRubricVisibility();
|
||||
|
||||
// loads current submission
|
||||
const testSubmissionGradingState = () => {
|
||||
expect(
|
||||
state.grading.current,
|
||||
`Redux current grading state should load the current submission ${submissionString}`,
|
||||
).toEqual({
|
||||
submissionUUID: submissionUUIDs[submissionIndex],
|
||||
...submissions[submissionIndex],
|
||||
});
|
||||
};
|
||||
testSubmissionGradingState();
|
||||
|
||||
const testNavState = () => {
|
||||
const expectDisabled = (getNav, name) => (
|
||||
expect(getNav(), `${name} should be disabled`).toHaveAttribute('disabled')
|
||||
);
|
||||
const expectEnabled = (getNav, name) => (
|
||||
expect(getNav(), `${name} should be enabled`).not.toHaveAttribute('disabled')
|
||||
);
|
||||
(submissionIndex > 0 ? expectEnabled : expectDisabled)(
|
||||
inspector.review.prevNav,
|
||||
'Prev nav',
|
||||
);
|
||||
const hasNext = submissionIndex < submissions.length - 1;
|
||||
(hasNext ? expectEnabled : expectDisabled)(inspector.review.nextNav, 'Next nav');
|
||||
};
|
||||
testNavState();
|
||||
};
|
||||
await verifyFetchSuccess(0);
|
||||
for (let i = 1; i < 5; i++) {
|
||||
await userEvent.click(inspector.review.nextNav());
|
||||
await verifyFetchSuccess(i);
|
||||
}
|
||||
for (let i = 3; i >= 0; i--) {
|
||||
await userEvent.click(inspector.review.prevNav());
|
||||
await verifyFetchSuccess(i);
|
||||
}
|
||||
done();
|
||||
});
|
||||
|
||||
describe('grading (basic)', () => {
|
||||
beforeEach(async () => {
|
||||
await resolveFns.fetch.success();
|
||||
await waitForRequestStatus(RequestKeys.fetchSubmission, RequestStates.completed);
|
||||
await userEvent.click(await inspector.find.review.startGradingBtn());
|
||||
});
|
||||
|
||||
describe('active grading', () => {
|
||||
beforeEach(async () => {
|
||||
await resolveFns.lock.success();
|
||||
});
|
||||
|
||||
const selectedOptions = [1, 2];
|
||||
const feedback = ['feedback 0', 'feedback 1'];
|
||||
const overallFeedback = 'some overall feedback';
|
||||
|
||||
// Set basic grade and feedback
|
||||
const setGrade = async (done) => {
|
||||
const {
|
||||
criterionOption,
|
||||
criterionFeedback,
|
||||
feedbackInput,
|
||||
} = inspector.review.rubric;
|
||||
const options = [
|
||||
criterionOption(0, selectedOptions[0]),
|
||||
criterionOption(1, selectedOptions[1]),
|
||||
];
|
||||
await userEvent.click(options[0]);
|
||||
await userEvent.type(criterionFeedback(0), feedback[0]);
|
||||
await userEvent.click(options[1]);
|
||||
await userEvent.type(criterionFeedback(1), feedback[1]);
|
||||
await userEvent.type(inspector.review.rubric.feedbackInput(), overallFeedback);
|
||||
return;
|
||||
};
|
||||
|
||||
// Verify active-grading state
|
||||
const checkGradingState = (submissionUUID=submissionUUIDs[0]) => {
|
||||
const entry = getState().grading.gradingData[submissionUUID];
|
||||
const checkCriteria = (index) => {
|
||||
const criterion = entry.criteria[index];
|
||||
const selected = rubricConfig.criteria[index].options[selectedOptions[index]].name;
|
||||
expect(criterion.selectedOption).toEqual(selected);
|
||||
expect(criterion.feedback).toEqual(feedback[index]);
|
||||
}
|
||||
[0, 1].forEach(checkCriteria);
|
||||
expect(entry.overallFeedback).toEqual(overallFeedback);
|
||||
}
|
||||
|
||||
// Verify after-submission-success grade state
|
||||
const checkGradeSuccess = () => {
|
||||
const { gradeData, current } = getState().grading;
|
||||
const entry = gradeData[submissionUUIDs[0]];
|
||||
const checkCriteria = (index) => {
|
||||
const criterion = entry.criteria[index];
|
||||
const rubricOptions = rubricConfig.criteria[index].options;
|
||||
expect(criterion.selectedOption).toEqual(rubricOptions[selectedOptions[index]].name);
|
||||
expect(criterion.feedback).toEqual(feedback[index]);
|
||||
}
|
||||
[0, 1].forEach(checkCriteria);
|
||||
expect(entry.overallFeedback).toEqual(overallFeedback);
|
||||
expect(current.gradeStatus).toEqual(gradeStatuses.graded);
|
||||
expect(current.lockStatus).toEqual(lockStatuses.unlocked);
|
||||
}
|
||||
|
||||
const loadNext = async () => {
|
||||
await userEvent.click(inspector.review.nextNav());
|
||||
await resolveFns.fetch.success();
|
||||
};
|
||||
|
||||
const loadPrev = async () => {
|
||||
await userEvent.click(inspector.review.prevNav());
|
||||
await resolveFns.fetch.success();
|
||||
}
|
||||
|
||||
const startGrading = async () => {
|
||||
await waitForRequestStatus(RequestKeys.fetchSubmission, RequestStates.completed);
|
||||
await userEvent.click(await inspector.find.review.startGradingBtn());
|
||||
await resolveFns.lock.success();
|
||||
}
|
||||
/*
|
||||
test('submit pending', async (done) => {
|
||||
done();
|
||||
});
|
||||
test('submit failed', async (done) => {
|
||||
done();
|
||||
});
|
||||
*/
|
||||
test('grade and submit',
|
||||
async (done) => {
|
||||
expect(await inspector.find.review.submitGradeBtn()).toBeVisible();
|
||||
await setGrade();
|
||||
checkGradingState();
|
||||
await userEvent.click(inspector.review.rubric.submitGradeBtn());
|
||||
await resolveFns.updateGrade.success();
|
||||
checkGradeSuccess();
|
||||
done();
|
||||
},
|
||||
);
|
||||
test('grade, navigate, and return, maintaining gradingState',
|
||||
async (done) => {
|
||||
expect(await inspector.find.review.submitGradeBtn()).toBeVisible();
|
||||
await setGrade();
|
||||
checkGradingState();
|
||||
await loadNext();
|
||||
await waitForEqual(() => getState().grading.activeIndex, 1, 'activeIndex');
|
||||
await loadPrev();
|
||||
await waitForEqual(() => getState().grading.activeIndex, 0, 'activeIndex');
|
||||
checkGradingState();
|
||||
done();
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user