Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: export special exams store #130

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/core/ExamStateProvider.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ import { IS_STARTED_STATUS } from '../constants';

// eslint-disable-next-line react/prop-types
const StateProvider = ({ children, ...state }) => {
// This is bizzare and unecessary maybe, or maybe it wasn't documented as to why
// They took stuff out of redux and put it in a context, but they could have just used the redux store???
// This was meant to only make "showTimer" change when the state would change.
// useMemo is used when computations are expensive
// But this isn't so why use it here?
// Idk why this is optimal
const contextValue = useMemo(() => ({
...state,
showTimer: !!(state.activeAttempt && IS_STARTED_STATUS(state.activeAttempt.attempt_status)),
Expand Down
35 changes: 24 additions & 11 deletions src/core/OuterExamTimer.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
import React, { useEffect, useContext } from 'react';
import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import { AppContext } from '@edx/frontend-platform/react';
import ExamStateContext from '../context';

// new imports
// import ExamStateContext from '../context';
import { IS_STARTED_STATUS } from '../constants';
import { stopExam, submitExam, expireExam, pollAttempt, pingAttempt, getLatestAttemptData } from '../data/thunks';

Check failure on line 9 in src/core/OuterExamTimer.jsx

View workflow job for this annotation

GitHub Actions / tests

Expected a line break after this opening brace

Check failure on line 9 in src/core/OuterExamTimer.jsx

View workflow job for this annotation

GitHub Actions / tests

Expected a line break before this closing brace

Check failure on line 9 in src/core/OuterExamTimer.jsx

View workflow job for this annotation

GitHub Actions / tests

Expected a line break after this opening brace

Check failure on line 9 in src/core/OuterExamTimer.jsx

View workflow job for this annotation

GitHub Actions / tests

Expected a line break before this closing brace
import * as selectors from '../data/selectors';

import { ExamTimerBlock } from '../timer';
import ExamAPIError from '../exam/ExamAPIError';
import ExamStateProvider from './ExamStateProvider';
// import ExamStateProvider from './ExamStateProvider';

const ExamTimer = ({ courseId }) => {
const state = useContext(ExamStateContext);
// const state = useContext(ExamStateContext);
const { authenticatedUser } = useContext(AppContext);
const {
activeAttempt, showTimer, stopExam, submitExam,
expireExam, pollAttempt, apiErrorMsg, pingAttempt,
getLatestAttemptData,
} = state;

// const {
// activeAttempt, showTimer, apiErrorMsg,
// } = state;
const activeAttempt = useSelector(selectors.activeAttempt);
// TODO: The logic surrounding this showTimer var is WEIRD.
//TODO:Move this boolean to some file to encapsulate. Probably best in constants also there's no hooks file.

Check failure on line 25 in src/core/OuterExamTimer.jsx

View workflow job for this annotation

GitHub Actions / tests

Expected exception block, space or tab after '//' in comment

Check failure on line 25 in src/core/OuterExamTimer.jsx

View workflow job for this annotation

GitHub Actions / tests

Expected exception block, space or tab after '//' in comment
const showTimer = !!(activeAttempt && IS_STARTED_STATUS(activeAttempt.attempt_status));
// console.log(showTimer);
console.log(activeAttempt);

Check warning on line 28 in src/core/OuterExamTimer.jsx

View workflow job for this annotation

GitHub Actions / tests

Unexpected console statement

Check warning on line 28 in src/core/OuterExamTimer.jsx

View workflow job for this annotation

GitHub Actions / tests

Unexpected console statement
const apiErrorMsg = useSelector(selectors.apiErrorMsg);

useEffect(() => {
getLatestAttemptData(courseId);
Expand Down Expand Up @@ -53,9 +66,9 @@
* will be shown.
*/
const OuterExamTimer = ({ courseId }) => (
<ExamStateProvider>
<ExamTimer courseId={courseId} />
</ExamStateProvider>
// <ExamStateProvider>
<ExamTimer courseId={courseId} />
// </ExamStateProvider>
);

OuterExamTimer.propTypes = {
Expand Down
29 changes: 29 additions & 0 deletions src/data/selectors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
Slice: activeAttempt, apiErrorMsg
In ExamStateProviders, needs to be moved to slice: showTimer,
Thunks, which need to be imported instead: stopExam, submitExam, expireExam, pollAttempt, pingAttempt, getLatestAttemptData,

Check failure on line 4 in src/data/selectors.js

View workflow job for this annotation

GitHub Actions / tests

This line has a length of 124. Maximum allowed is 120

Check failure on line 4 in src/data/selectors.js

View workflow job for this annotation

GitHub Actions / tests

This line has a length of 124. Maximum allowed is 120
*/

// TODO: Perhaps name the slice 'name:' var to 'currentExam',
// or change the one in frontend-app-exams-dashboard to 'examsList' or something.

/*
I got this error:

OuterExamTimer › is successfully rendered and shows timer if there is an exam in progress

TypeError: Cannot read properties of undefined (reading 'activeAttempt')

7 | // TODO: Perhaps name the slice 'name:' var to 'currentExam',
8 | // or change the one in frontend-app-exams-dashboard to 'examsList' or something.
> 9 | export const activeAttempt = state => state.exam.activeAttempt;
| ^
10 | export const apiErrorMsg = state => state.exam.apiErrorMsg;
11 | export const showTimer = state => state.exam.showTimer;

Why isn't the selector working?
*/
export const activeAttempt = state => state.examState.activeAttempt;
export const apiErrorMsg = state => state.examState.apiErrorMsg;
export const showTimer = state => state.examState.showTimer;

Check failure on line 29 in src/data/selectors.js

View workflow job for this annotation

GitHub Actions / tests

Too many blank lines at the end of file. Max of 0 allowed

Check failure on line 29 in src/data/selectors.js

View workflow job for this annotation

GitHub Actions / tests

Too many blank lines at the end of file. Max of 0 allowed
5 changes: 5 additions & 0 deletions src/data/slice.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export const examSlice = createSlice({
exam_access_token: '',
exam_access_token_expiration: '',
},
// showTimer: !!(state.activeAttempt && IS_STARTED_STATUS(state.activeAttempt.attempt_status)),
},
reducers: {
setAllowProctoringOptOut: (state, { payload }) => {
Expand Down Expand Up @@ -106,4 +107,8 @@ export const {
setReviewPolicy, setApiError, setAllowProctoringOptOut,
} = examSlice.actions;

export const {
reducer,
} = examSlice;

export default examSlice.reducer;
10 changes: 10 additions & 0 deletions src/exam/ExamWrapper.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,19 @@ jest.mock('../data/thunks', () => {
};
});

// TODO: Make changes to what's mocked. should only be API functions and react/redux initialState stuff.

// When we mock out the thunks below, we stamp out a lot of the non-async stuff
// Like loading states and other redux goodness. We can't ever change the loading state if
// The function it's in has been mocked away.
// The ONLY thing we should need to mock out in this app are API REST calls.
getExamAttemptsData.mockReturnValue(jest.fn());
startTimedExam.mockReturnValue(jest.fn());
// No idea what "subscribe" does but it probably shouldn't be mocked
store.subscribe = jest.fn();
// We should not mock this. This makes the dispatch function useless. It just needs the right setup to work.
// Things were mocked, then broke, then they mocked other things that didn't need to be mocked.
// This all can work out of the box with the right set up
store.dispatch = jest.fn();

describe('SequenceExamWrapper', () => {
Expand Down
Loading