diff --git a/src/context.jsx b/src/context.jsx
index 3005f5a7..89e3698a 100644
--- a/src/context.jsx
+++ b/src/context.jsx
@@ -1,4 +1,4 @@
-import React from 'react';
-
-const ExamStateContext = React.createContext({});
-export default ExamStateContext;
+// import React from 'react';
+//
+// const ExamStateContext = React.createContext({});
+// export default ExamStateContext;
diff --git a/src/core/ExamStateProvider.jsx b/src/core/ExamStateProvider.jsx
index ced1d07c..17a2e864 100644
--- a/src/core/ExamStateProvider.jsx
+++ b/src/core/ExamStateProvider.jsx
@@ -1,35 +1,35 @@
-import React, { useMemo } from 'react';
-import { withExamStore } from '../hocs';
-import * as dispatchActions from '../data/thunks';
-import ExamStateContext from '../context';
-import { IS_STARTED_STATUS } from '../constants';
-
-/**
- * Make exam state available as a context for all library components.
- * @param children - sequence content
- * @param state - exam state params and actions
- * @returns {JSX.Element}
- */
-
-// eslint-disable-next-line react/prop-types
-const StateProvider = ({ children, ...state }) => {
- const contextValue = useMemo(() => ({
- ...state,
- showTimer: !!(state.activeAttempt && IS_STARTED_STATUS(state.activeAttempt.attempt_status)),
- }), [state]);
- return (
-
- {children}
-
- );
-};
-
-const mapStateToProps = (state) => ({ ...state.examState });
-
-const ExamStateProvider = withExamStore(
- StateProvider,
- mapStateToProps,
- dispatchActions,
-);
-
-export default ExamStateProvider;
+// import React, { useMemo } from 'react';
+// import { withExamStore } from '../hocs';
+// import * as dispatchActions from '../data/thunks';
+// import ExamStateContext from '../context';
+// import { IS_STARTED_STATUS } from '../constants';
+//
+// /**
+// * Make exam state available as a context for all library components.
+// * @param children - sequence content
+// * @param state - exam state params and actions
+// * @returns {JSX.Element}
+// */
+//
+// // eslint-disable-next-line react/prop-types
+// const StateProvider = ({ children, ...state }) => {
+// const contextValue = useMemo(() => ({
+// ...state,
+// showTimer: !!(state.activeAttempt && IS_STARTED_STATUS(state.activeAttempt.attempt_status)),
+// }), [state]);
+// return (
+//
+// {children}
+//
+// );
+// };
+//
+// const mapStateToProps = (state) => ({ ...state.specialExams });
+//
+// const ExamStateProvider = withExamStore(
+// StateProvider,
+// mapStateToProps,
+// dispatchActions,
+// );
+//
+// export default ExamStateProvider;
diff --git a/src/core/OuterExamTimer.jsx b/src/core/OuterExamTimer.jsx
index f5ef7fbf..18886f7e 100644
--- a/src/core/OuterExamTimer.jsx
+++ b/src/core/OuterExamTimer.jsx
@@ -1,23 +1,31 @@
import React, { useEffect, useContext } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import { AppContext } from '@edx/frontend-platform/react';
-import ExamStateContext from '../context';
import { ExamTimerBlock } from '../timer';
import ExamAPIError from '../exam/ExamAPIError';
-import ExamStateProvider from './ExamStateProvider';
+import {
+ getLatestAttemptData,
+ stopExam,
+ submitExam,
+ expireExam,
+ pollAttempt,
+ pingAttempt,
+} from '../data/thunks';
+import { IS_STARTED_STATUS } from '../constants';
const ExamTimer = ({ courseId }) => {
- const state = useContext(ExamStateContext);
const { authenticatedUser } = useContext(AppContext);
+
const {
- activeAttempt, showTimer, stopExam, submitExam,
- expireExam, pollAttempt, apiErrorMsg, pingAttempt,
- getLatestAttemptData,
- } = state;
+ activeAttempt, apiErrorMsg,
+ } = useSelector(state => state.specialExams);
+ const dispatch = useDispatch();
+
+ const showTimer = !!(activeAttempt && IS_STARTED_STATUS(activeAttempt.attempt_status));
useEffect(() => {
- getLatestAttemptData(courseId);
- // eslint-disable-next-line react-hooks/exhaustive-deps
+ dispatch(getLatestAttemptData(courseId));
}, [courseId]);
// if user is not authenticated they cannot have active exam, so no need for timer
@@ -31,11 +39,11 @@ const ExamTimer = ({ courseId }) => {
{showTimer && (
dispatch(stopExam())}
+ submitExam={() => dispatch(submitExam())}
+ expireExamAttempt={() => dispatch(expireExam())}
+ pollExamAttempt={(url) => dispatch(pollAttempt(url))}
+ pingAttempt={(timeout, url) => dispatch(pingAttempt(timeout, url))}
/>
)}
{apiErrorMsg && }
@@ -53,9 +61,7 @@ ExamTimer.propTypes = {
* will be shown.
*/
const OuterExamTimer = ({ courseId }) => (
-
-
-
+
);
OuterExamTimer.propTypes = {
diff --git a/src/core/SequenceExamWrapper.jsx b/src/core/SequenceExamWrapper.jsx
index dea56e2b..4480ac7f 100644
--- a/src/core/SequenceExamWrapper.jsx
+++ b/src/core/SequenceExamWrapper.jsx
@@ -1,6 +1,5 @@
import React from 'react';
import ExamWrapper from '../exam/ExamWrapper';
-import ExamStateProvider from './ExamStateProvider';
/**
* SequenceExamWrapper is the component responsible for handling special exams.
@@ -14,9 +13,7 @@ import ExamStateProvider from './ExamStateProvider';
*
*/
const SequenceExamWrapper = (props) => (
-
-
-
+
);
export default SequenceExamWrapper;
diff --git a/src/data/__factories__/examState.factory.js b/src/data/__factories__/examState.factory.js
index af775148..ccb6e411 100644
--- a/src/data/__factories__/examState.factory.js
+++ b/src/data/__factories__/examState.factory.js
@@ -4,7 +4,7 @@ import './exam.factory';
import './proctoringSettings.factory';
import './examAccessToken.factory';
-Factory.define('examState')
+Factory.define('specialExams')
.attr('proctoringSettings', Factory.build('proctoringSettings'))
.attr('exam', Factory.build('exam'))
.attr('examAccessToken', Factory.build('examAccessToken'))
diff --git a/src/data/store.js b/src/data/store.js
index 916de85c..3ab0617a 100644
--- a/src/data/store.js
+++ b/src/data/store.js
@@ -1,8 +1,8 @@
-import { configureStore } from '@reduxjs/toolkit';
-import examReducer from './slice';
-
-export default configureStore({
- reducer: {
- examState: examReducer,
- },
-});
+// import { configureStore } from '@reduxjs/toolkit';
+// import examReducer from './slice';
+//
+// export default configureStore({
+// reducer: {
+// examState: examReducer,
+// },
+// });
diff --git a/src/data/thunks.js b/src/data/thunks.js
index d1d06cf6..2f68ccbc 100644
--- a/src/data/thunks.js
+++ b/src/data/thunks.js
@@ -473,7 +473,8 @@ export function pingAttempt(timeoutInSeconds, workerUrl) {
// eslint-disable-next-line function-paren-newline
await updateAttemptAfter(
- exam.course_id, exam.content_id, endExamWithFailure(activeAttempt.attempt_id, message))(dispatch);
+ exam.course_id, exam.content_id, endExamWithFailure(activeAttempt.attempt_id, message)
+ )(dispatch);
});
};
}
diff --git a/src/exam/Exam.jsx b/src/exam/Exam.jsx
index 4a2049ad..6ccdb401 100644
--- a/src/exam/Exam.jsx
+++ b/src/exam/Exam.jsx
@@ -1,15 +1,22 @@
-/* eslint-disable react-hooks/exhaustive-deps */
-import React, { useContext, useEffect, useState } from 'react';
+import React, { useEffect, useState } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n';
import { Alert, Spinner } from '@edx/paragon';
import { Info } from '@edx/paragon/icons';
import { ExamTimerBlock } from '../timer';
import Instructions from '../instructions';
-import ExamStateContext from '../context';
import ExamAPIError from './ExamAPIError';
-import { ExamStatus, ExamType } from '../constants';
+import { ExamStatus, ExamType, IS_STARTED_STATUS } from '../constants';
import messages from './messages';
+import {
+ getProctoringSettings,
+ stopExam,
+ submitExam,
+ expireExam,
+ pollAttempt,
+ pingAttempt,
+} from '../data/thunks';
/**
* Exam component is intended to render exam instructions before and after exam.
@@ -23,12 +30,12 @@ import messages from './messages';
const Exam = ({
isGated, isTimeLimited, originalUserIsStaff, canAccessProctoredExams, children, intl,
}) => {
- const state = useContext(ExamStateContext);
const {
- isLoading, activeAttempt, showTimer, stopExam, exam,
- expireExam, pollAttempt, apiErrorMsg, pingAttempt,
- getProctoringSettings, submitExam,
- } = state;
+ isLoading, activeAttempt, exam, apiErrorMsg,
+ } = useSelector(state => state.specialExams);
+ const dispatch = useDispatch();
+
+ const showTimer = !!(activeAttempt && IS_STARTED_STATUS(activeAttempt.attempt_status));
const {
attempt,
@@ -61,7 +68,7 @@ const Exam = ({
if (proctoredExamTypes.includes(examType)) {
// only fetch proctoring settings for a proctored exam
if (examId) {
- getProctoringSettings();
+ dispatch(getProctoringSettings());
}
// Only exclude Timed Exam when restricting access to exams
@@ -106,11 +113,11 @@ const Exam = ({
{showTimer && (
dispatch(stopExam())}
+ submitExam={() => dispatch(submitExam())}
+ expireExamAttempt={() => dispatch(expireExam())}
+ pollExamAttempt={(url) => dispatch(pollAttempt(url))}
+ pingAttempt={(timeout, url) => dispatch(pingAttempt(timeout, url))}
/>
)}
{ // show the error message only if you are in the exam sequence
diff --git a/src/exam/ExamAPIError.jsx b/src/exam/ExamAPIError.jsx
index a6b0e271..157f7e10 100644
--- a/src/exam/ExamAPIError.jsx
+++ b/src/exam/ExamAPIError.jsx
@@ -1,15 +1,14 @@
-import React, { useContext } from 'react';
+import React from 'react';
+import { useSelector } from 'react-redux';
import { getConfig } from '@edx/frontend-platform';
import { Alert, Hyperlink, Icon } from '@edx/paragon';
import { Info } from '@edx/paragon/icons';
import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n';
-import ExamStateContext from '../context';
import messages from './messages';
const ExamAPIError = ({ intl }) => {
- const state = useContext(ExamStateContext);
const { SITE_NAME, SUPPORT_URL } = getConfig();
- const { apiErrorMsg } = state;
+ const { apiErrorMsg } = useSelector(state => state.specialExams);
const shouldShowApiErrorMsg = !!apiErrorMsg && !apiErrorMsg.includes('<');
return (
diff --git a/src/exam/ExamAPIError.test.jsx b/src/exam/ExamAPIError.test.jsx
index b8d276d9..1ae2646b 100644
--- a/src/exam/ExamAPIError.test.jsx
+++ b/src/exam/ExamAPIError.test.jsx
@@ -3,7 +3,6 @@ import React from 'react';
import { getConfig } from '@edx/frontend-platform';
import { store } from '../data';
import { render } from '../setupTest';
-import ExamStateProvider from '../core/ExamStateProvider';
import ExamAPIError from './ExamAPIError';
const originalConfig = jest.requireActual('@edx/frontend-platform').getConfig();
@@ -23,12 +22,10 @@ describe('ExamAPIError', () => {
const defaultMessage = 'A system error has occurred with your exam.';
it('renders with the default information', () => {
- store.getState = () => ({ examState: {} });
+ store.getState = () => ({ specialExams: {} });
const tree = render(
-
-
- ,
+ ,
{ store },
);
@@ -42,12 +39,10 @@ describe('ExamAPIError', () => {
};
getConfig.mockImplementation(() => config);
- store.getState = () => ({ examState: {} });
+ store.getState = () => ({ specialExams: {} });
const { getByTestId } = render(
-
-
- ,
+ ,
{ store },
);
@@ -58,28 +53,24 @@ describe('ExamAPIError', () => {
it('renders error details when provided', () => {
store.getState = () => ({
- examState: { apiErrorMsg: 'Something bad has happened' },
+ specialExams: { apiErrorMsg: 'Something bad has happened' },
});
const { queryByTestId } = render(
-
-
- ,
+ ,
{ store },
);
- expect(queryByTestId('error-details')).toHaveTextContent(store.getState().examState.apiErrorMsg);
+ expect(queryByTestId('error-details')).toHaveTextContent(store.getState().specialExams.apiErrorMsg);
});
it('renders default message when error is HTML', () => {
store.getState = () => ({
- examState: { apiErrorMsg: '' },
+ specialExams: { apiErrorMsg: '' },
});
const { queryByTestId } = render(
-
-
- ,
+ ,
{ store },
);
@@ -88,13 +79,11 @@ describe('ExamAPIError', () => {
it('renders default message when there is no error message', () => {
store.getState = () => ({
- examState: { apiErrorMsg: '' },
+ specialExams: { apiErrorMsg: '' },
});
const { queryByTestId } = render(
-
-
- ,
+ ,
{ store },
);
diff --git a/src/exam/ExamWrapper.jsx b/src/exam/ExamWrapper.jsx
index 68b7eee8..04c26fae 100644
--- a/src/exam/ExamWrapper.jsx
+++ b/src/exam/ExamWrapper.jsx
@@ -1,14 +1,18 @@
+import { useDispatch, useSelector } from 'react-redux';
import React, { useContext, useEffect } from 'react';
import { AppContext } from '@edx/frontend-platform/react';
import PropTypes from 'prop-types';
import Exam from './Exam';
-import ExamStateContext from '../context';
+import {
+ getExamAttemptsData,
+ getAllowProctoringOptOut,
+ checkExamEntry,
+} from '../data/thunks';
/**
* Exam wrapper is responsible for triggering initial exam data fetching and rendering Exam.
*/
const ExamWrapper = ({ children, ...props }) => {
- const state = useContext(ExamStateContext);
const { authenticatedUser } = useContext(AppContext);
const {
sequence,
@@ -17,9 +21,13 @@ const ExamWrapper = ({ children, ...props }) => {
originalUserIsStaff,
canAccessProctoredExams,
} = props;
- const { getExamAttemptsData, getAllowProctoringOptOut, checkExamEntry } = state;
+
+ const { isLoading } = useSelector(state => state.specialExams);
+
+ const dispatch = useDispatch();
+
const loadInitialData = async () => {
- await getExamAttemptsData(courseId, sequence.id);
+ await dispatch(getExamAttemptsData(courseId, sequence.id));
await getAllowProctoringOptOut(sequence.allowProctoringOptOut);
await checkExamEntry();
};
@@ -28,10 +36,9 @@ const ExamWrapper = ({ children, ...props }) => {
useEffect(() => {
// fetch exam data on exam sequences or if no exam data has been fetched yet
- if (sequence.isTimeLimited || state.isLoading) {
+ if (sequence.isTimeLimited || isLoading) {
loadInitialData();
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// if the user is browsing public content (not logged in) they cannot be in an exam
diff --git a/src/exam/ExamWrapper.test.jsx b/src/exam/ExamWrapper.test.jsx
index bee6ed74..ee1d78e5 100644
--- a/src/exam/ExamWrapper.test.jsx
+++ b/src/exam/ExamWrapper.test.jsx
@@ -5,7 +5,6 @@ import SequenceExamWrapper from './ExamWrapper';
import { store, startTimedExam } from '../data';
import { getExamAttemptsData } from '../data/thunks';
import { render, waitFor } from '../setupTest';
-import ExamStateProvider from '../core/ExamStateProvider';
import { ExamStatus, ExamType } from '../constants';
jest.mock('../data', () => ({
@@ -39,18 +38,16 @@ describe('SequenceExamWrapper', () => {
beforeEach(() => {
jest.clearAllMocks();
store.getState = () => ({
- examState: Factory.build('examState'),
+ specialExams: Factory.build('specialExams'),
isLoading: false,
});
});
it('is successfully rendered and shows instructions if the user is not staff', () => {
const { queryByTestId } = render(
-
-
- children
-
- ,
+
+ children
+ ,
{ store },
);
expect(queryByTestId('exam-instructions-title')).toHaveTextContent('Subsection is a Timed Exam (30 minutes)');
@@ -59,18 +56,16 @@ describe('SequenceExamWrapper', () => {
it('is successfully rendered and shows instructions for proctored exam', () => {
store.getState = () => ({
- examState: Factory.build('examState', {
+ specialExams: Factory.build('specialExams', {
exam: Factory.build('exam', {
type: ExamType.PROCTORED,
}),
}),
});
const { queryByTestId } = render(
-
-
- children
-
- ,
+
+ children
+ ,
{ store },
);
expect(queryByTestId('proctored-exam-instructions-title')).toHaveTextContent('This exam is proctored');
@@ -78,16 +73,14 @@ describe('SequenceExamWrapper', () => {
it('shows loader if isLoading true', () => {
store.getState = () => ({
- examState: Factory.build('examState', {
+ specialExams: Factory.build('specialExams', {
isLoading: true,
}),
});
const { queryByTestId } = render(
-
-
- children
-
- ,
+
+ children
+ ,
{ store },
);
expect(queryByTestId('spinner')).toBeInTheDocument();
@@ -95,17 +88,15 @@ describe('SequenceExamWrapper', () => {
it('shows exam api error component together with other content if there is an error', () => {
store.getState = () => ({
- examState: Factory.build('examState', {
+ specialExams: Factory.build('specialExams', {
apiErrorMsg: 'Something bad has happened.',
}),
});
const { queryByTestId } = render(
-
-
- children
-
- ,
+
+ children
+ ,
{ store },
);
expect(queryByTestId('exam-instructions-title')).toHaveTextContent('Subsection is a Timed Exam (30 minutes)');
@@ -114,17 +105,15 @@ describe('SequenceExamWrapper', () => {
it('does not show exam api error component on a non-exam sequence', () => {
store.getState = () => ({
- examState: Factory.build('examState', {
+ specialExams: Factory.build('specialExams', {
apiErrorMsg: 'Something bad has happened.',
}),
});
const { queryByTestId } = render(
-
-
- children
-
- ,
+
+ children
+ ,
{ store },
);
expect(queryByTestId('exam-instructions-title')).not.toBeInTheDocument();
@@ -133,11 +122,9 @@ describe('SequenceExamWrapper', () => {
it('does not fetch exam data if already loaded and the sequence is not an exam', async () => {
render(
-
-
- children
-
- ,
+
+ children
+ ,
{ store },
);
// assert the exam data is not fetched
@@ -147,17 +134,15 @@ describe('SequenceExamWrapper', () => {
it('does fetch exam data for non exam sequences if not already loaded', async () => {
// this would only occur if the user deeplinks directly to a non-exam sequence
store.getState = () => ({
- examState: Factory.build('examState', {
+ specialExams: Factory.build('specialExams', {
isLoading: true,
}),
});
render(
-
-
- children
-
- ,
+
+ children
+ ,
{ store },
);
await waitFor(() => expect(getExamAttemptsData).toHaveBeenCalled());
@@ -165,11 +150,9 @@ describe('SequenceExamWrapper', () => {
it('does not take any actions if sequence item is not exam', () => {
const { getByTestId } = render(
-
-
- children
-
- ,
+
+ children
+ ,
{ store },
);
expect(getByTestId('sequence-content')).toHaveTextContent('children');
@@ -180,11 +163,9 @@ describe('SequenceExamWrapper', () => {
authenticatedUser: null,
};
const { getByTestId } = render(
-
-
- children
-
- ,
+
+ children
+ ,
{ store, appContext },
);
expect(getByTestId('sequence-content')).toHaveTextContent('children');
@@ -192,18 +173,16 @@ describe('SequenceExamWrapper', () => {
it('renders exam content without an active attempt if the user is staff', () => {
store.getState = () => ({
- examState: Factory.build('examState', {
+ specialExams: Factory.build('specialExams', {
exam: Factory.build('exam', {
type: ExamType.PROCTORED,
}),
}),
});
const { queryByTestId } = render(
-
-
- children
-
- ,
+
+ children
+ ,
{ store },
);
expect(queryByTestId('sequence-content')).toHaveTextContent('children');
@@ -211,7 +190,7 @@ describe('SequenceExamWrapper', () => {
it('renders exam content for staff masquerading as a learner', () => {
store.getState = () => ({
- examState: Factory.build('examState', {
+ specialExams: Factory.build('specialExams', {
exam: Factory.build('exam', {
type: ExamType.PROCTORED,
passed_due_date: false,
@@ -220,11 +199,9 @@ describe('SequenceExamWrapper', () => {
}),
});
const { queryByTestId } = render(
-
-
- children
-
- ,
+
+ children
+ ,
{ store },
);
expect(queryByTestId('sequence-content')).toHaveTextContent('children');
@@ -236,18 +213,16 @@ describe('SequenceExamWrapper', () => {
gated: true,
};
store.getState = () => ({
- examState: Factory.build('examState', {
+ specialExams: Factory.build('specialExams', {
exam: Factory.build('exam', {
type: ExamType.PROCTORED,
}),
}),
});
const { queryByTestId } = render(
-
-
- children
-
- ,
+
+ children
+ ,
{ store },
);
expect(queryByTestId('sequence-content')).toHaveTextContent('children');
@@ -255,7 +230,7 @@ describe('SequenceExamWrapper', () => {
it('does not display masquerade alert if specified learner is in the middle of the exam', () => {
store.getState = () => ({
- examState: Factory.build('examState', {
+ specialExams: Factory.build('specialExams', {
exam: Factory.build('exam', {
type: ExamType.PROCTORED,
attempt: {
@@ -267,11 +242,9 @@ describe('SequenceExamWrapper', () => {
}),
});
const { queryByTestId } = render(
-
-
- children
-
- ,
+
+ children
+ ,
{ store },
);
expect(queryByTestId('sequence-content')).toHaveTextContent('children');
@@ -280,7 +253,7 @@ describe('SequenceExamWrapper', () => {
it('does not display masquerade alert if learner can view the exam after the due date', () => {
store.getState = () => ({
- examState: Factory.build('examState', {
+ specialExams: Factory.build('specialExams', {
exam: Factory.build('exam', {
type: ExamType.TIMED,
attempt: {
@@ -292,11 +265,9 @@ describe('SequenceExamWrapper', () => {
}),
});
const { queryByTestId } = render(
-
-
- children
-
- ,
+
+ children
+ ,
{ store },
);
expect(queryByTestId('sequence-content')).toHaveTextContent('children');
@@ -305,11 +276,9 @@ describe('SequenceExamWrapper', () => {
it('does not display masquerade alert if sequence is not time gated', () => {
const { queryByTestId } = render(
-
-
- children
-
- ,
+
+ children
+ ,
{ store },
);
expect(queryByTestId('sequence-content')).toHaveTextContent('children');
@@ -318,7 +287,7 @@ describe('SequenceExamWrapper', () => {
it('shows access denied if learner is not accessible to proctoring exams', () => {
store.getState = () => ({
- examState: Factory.build('examState', {
+ specialExams: Factory.build('specialExams', {
exam: Factory.build('exam', {
type: ExamType.PROCTORED,
attempt: null,
@@ -328,15 +297,13 @@ describe('SequenceExamWrapper', () => {
}),
});
const { queryByTestId } = render(
-
-
- children
-
- ,
+
+ children
+ ,
{ store },
);
expect(queryByTestId('no-access')).toHaveTextContent('You do not have access to proctored exams with your current enrollment.');
@@ -345,7 +312,7 @@ describe('SequenceExamWrapper', () => {
it('learner has access to timed exams', () => {
store.getState = () => ({
- examState: Factory.build('examState', {
+ specialExams: Factory.build('specialExams', {
exam: Factory.build('exam', {
type: ExamType.TIMED,
attempt: null,
@@ -355,15 +322,13 @@ describe('SequenceExamWrapper', () => {
}),
});
const { queryByTestId } = render(
-
-
- children
-
- ,
+
+ children
+ ,
{ store },
);
expect(queryByTestId('no-access')).toBeNull();
@@ -372,7 +337,7 @@ describe('SequenceExamWrapper', () => {
it('learner has access to content that are not exams', () => {
store.getState = () => ({
- examState: Factory.build('examState', {
+ specialExams: Factory.build('specialExams', {
exam: Factory.build('exam', {
type: '',
attempt: null,
@@ -382,15 +347,13 @@ describe('SequenceExamWrapper', () => {
}),
});
const { queryByTestId } = render(
-
-
- children
-
- ,
+
+ children
+ ,
{ store },
);
expect(queryByTestId('no-access')).toBeNull();
diff --git a/src/timer/ExamTimerBlock.jsx b/src/timer/ExamTimerBlock.jsx
index 3744e11a..4310eb2e 100644
--- a/src/timer/ExamTimerBlock.jsx
+++ b/src/timer/ExamTimerBlock.jsx
@@ -54,7 +54,6 @@ const ExamTimerBlock = injectIntl(({
Emitter.off(TIMER_LIMIT_REACHED, expireExamAttempt);
Emitter.off(TIMER_REACHED_NULL, onTimeReachedNull);
};
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (