Skip to content

Commit

Permalink
fix: The special exam timer synced with backend to show accurate coun…
Browse files Browse the repository at this point in the history
…t down timer (#45)

This is a revert of a previous revert. This reverts commit e6aa31c. This PR would use the proper sermantic-release commit message.

The special exam timer shown to learners should be updated with the exam attempt remaining time available for each sync interval. This is to ensure our learners don't see a timer which is running slower than the actual time.

Co-authored-by: Simon Chen <[email protected]>
  • Loading branch information
schenedx and Simon Chen authored Sep 23, 2021
1 parent e6aa31c commit a4012e6
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 8 deletions.
63 changes: 63 additions & 0 deletions src/timer/CountDownTimer.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ describe('ExamTimerBlock', () => {
stopExamAttempt={stopExamAttempt}
expireExamAttempt={expireExamAttempt}
pollExamAttempt={pollAttempt}
submitExam={submitAttempt}
/>,
);

Expand Down Expand Up @@ -80,6 +81,7 @@ describe('ExamTimerBlock', () => {
stopExamAttempt={stopExamAttempt}
expireExamAttempt={expireExamAttempt}
pollExamAttempt={pollAttempt}
submitExam={submitAttempt}
/>,
);
expect(container.firstChild).not.toBeInTheDocument();
Expand All @@ -92,6 +94,7 @@ describe('ExamTimerBlock', () => {
stopExamAttempt={stopExamAttempt}
expireExamAttempt={expireExamAttempt}
pollExamAttempt={pollAttempt}
submitExam={submitAttempt}
/>,
);
await waitFor(() => expect(screen.getByText('00:00:09')).toBeInTheDocument());
Expand Down Expand Up @@ -127,6 +130,7 @@ describe('ExamTimerBlock', () => {
stopExamAttempt={stopExamAttempt}
expireExamAttempt={expireExamAttempt}
pollExamAttempt={pollAttempt}
submitExam={submitAttempt}
/>,
);
await waitFor(() => expect(screen.getByText('00:00:04')).toBeInTheDocument());
Expand All @@ -140,6 +144,7 @@ describe('ExamTimerBlock', () => {
stopExamAttempt={stopExamAttempt}
expireExamAttempt={expireExamAttempt}
pollExamAttempt={pollAttempt}
submitExam={submitAttempt}
/>,
);
await waitFor(() => expect(screen.getByText('00:00:09')).toBeInTheDocument());
Expand All @@ -162,6 +167,7 @@ describe('ExamTimerBlock', () => {
stopExamAttempt={stopExamAttempt}
expireExamAttempt={expireExamAttempt}
pollExamAttempt={pollAttempt}
submitExam={submitAttempt}
/>,
);
await waitFor(() => expect(screen.getByText('00:00:09')).toBeInTheDocument());
Expand Down Expand Up @@ -230,4 +236,61 @@ describe('ExamTimerBlock', () => {
fireEvent.click(screen.getByTestId('end-button'));
expect(stopExamAttempt).toHaveBeenCalledTimes(1);
});

it('Update exam timer when attempt time_remaining_seconds is smaller than displayed time', async () => {
const preloadedState = {
examState: {
isLoading: true,
timeIsOver: false,
activeAttempt: {
attempt_status: 'started',
exam_url_path: 'exam_url_path',
exam_display_name: 'exam name',
time_remaining_seconds: 240,
low_threshold_sec: 15,
critically_low_threshold_sec: 5,
exam_started_poll_url: '',
taking_as_proctored: false,
exam_type: 'a timed exam',
},
proctoringSettings: {},
exam: {},
},
};
let testStore = await initializeTestStore(preloadedState);
examStore.getState = store.testStore;
attempt = testStore.getState().examState.activeAttempt;
const { rerender } = render(
<ExamTimerBlock
attempt={attempt}
stopExamAttempt={stopExamAttempt}
expireExamAttempt={expireExamAttempt}
pollExamAttempt={pollAttempt}
submitExam={submitAttempt}
/>,
);
await waitFor(() => expect(screen.getByText('00:03:59')).toBeInTheDocument());

preloadedState.examState.activeAttempt = {
...attempt,
time_remaining_seconds: 20,
};
testStore = await initializeTestStore(preloadedState);
examStore.getState = store.testStore;
const updatedAttempt = testStore.getState().examState.activeAttempt;

expect(updatedAttempt.time_remaining_seconds).toBe(20);

rerender(
<ExamTimerBlock
attempt={updatedAttempt}
stopExamAttempt={stopExamAttempt}
expireExamAttempt={expireExamAttempt}
pollExamAttempt={pollAttempt}
submitExam={submitAttempt}
/>,
);

await waitFor(() => expect(screen.getByText('00:00:19')).toBeInTheDocument());
});
});
19 changes: 11 additions & 8 deletions src/timer/TimerProvider.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ const TimerServiceProvider = ({
critically_low_threshold_sec: criticalLowTime,
low_threshold_sec: lowTime,
} = attempt;
const startValue = Math.floor(timeRemaining);
const LIMIT = GRACE_PERIOD_SECS ? 0 - GRACE_PERIOD_SECS : 0;
let liveInterval = null;

const getTimeString = () => Object.values(timeState).map(
item => {
Expand Down Expand Up @@ -77,26 +77,29 @@ const TimerServiceProvider = ({
};

useEffect(() => {
let secondsLeft = startValue;
let timerTick = 0;
const interval = setInterval(() => {
let secondsLeft = Math.floor(timeRemaining);
liveInterval = setInterval(() => {
secondsLeft -= 1;
timerTick += 1;
setTimeState(getFormattedRemainingTime(secondsLeft));
processTimeLeft(interval, secondsLeft);
processTimeLeft(liveInterval, secondsLeft);
// no polling during grace period
if (timerTick % POLL_INTERVAL === 0 && secondsLeft >= 0) {
pollExam();
}

// if exam is proctored ping provider app also
if (workerUrl && timerTick % pingInterval === pingInterval / 2) {
pingHandler(pingInterval, workerUrl);
}
}, 1000);

return () => { clearInterval(interval); };
}, []);
return () => {
if (liveInterval) {
clearInterval(liveInterval);
liveInterval = null;
}
};
}, [timeRemaining]);

return (
<TimerContext.Provider value={{
Expand Down

0 comments on commit a4012e6

Please sign in to comment.