diff --git a/src/courseware/course/Course.test.jsx b/src/courseware/course/Course.test.jsx
index 62d3084cf6..d2c60d8fbe 100644
--- a/src/courseware/course/Course.test.jsx
+++ b/src/courseware/course/Course.test.jsx
@@ -15,6 +15,10 @@ import { executeThunk } from '../../utils';
import * as thunks from '../data/thunks';
jest.mock('@edx/frontend-platform/analytics');
+jest.mock('@edx/frontend-lib-special-exams/dist/data/thunks.js', () => ({
+ ...jest.requireActual('@edx/frontend-lib-special-exams/dist/data/thunks.js'),
+ checkExamEntry: () => jest.fn(),
+}));
const recordFirstSectionCelebration = jest.fn();
// eslint-disable-next-line no-import-assign
diff --git a/src/courseware/course/CourseBreadcrumbs.test.jsx b/src/courseware/course/CourseBreadcrumbs.test.jsx
index 614538df1e..f51ead34c3 100644
--- a/src/courseware/course/CourseBreadcrumbs.test.jsx
+++ b/src/courseware/course/CourseBreadcrumbs.test.jsx
@@ -121,7 +121,7 @@ describe('CourseBreadcrumbs', () => {
sequenceId="block-v1:edX+DemoX+Demo_Course+type@sequential+block@basic_questions"
isStaff
/>
-
+ ,
,
);
it('renders course breadcrumbs as expected', async () => {
diff --git a/src/courseware/course/course-exit/CourseExit.jsx b/src/courseware/course/course-exit/CourseExit.jsx
index a54cec45e3..7f74204776 100644
--- a/src/courseware/course/course-exit/CourseExit.jsx
+++ b/src/courseware/course/course-exit/CourseExit.jsx
@@ -4,7 +4,7 @@ import { getConfig } from '@edx/frontend-platform';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Button } from '@edx/paragon';
import { useSelector } from 'react-redux';
-import { useNavigate } from 'react-router-dom';
+import { Navigate } from 'react-router-dom';
import CourseCelebration from './CourseCelebration';
import CourseInProgress from './CourseInProgress';
@@ -16,7 +16,6 @@ import { unsubscribeFromGoalReminders } from './data/thunks';
import { useModel } from '../../../generic/model-store';
const CourseExit = ({ intl }) => {
- const navigate = useNavigate();
const { courseId } = useSelector(state => state.courseware);
const {
certificateData,
@@ -58,14 +57,10 @@ const CourseExit = ({ intl }) => {
body = ();
} else if (mode === COURSE_EXIT_MODES.celebration) {
body = ();
+ } else {
+ return ();
}
- useEffect(() => {
- if ((mode === COURSE_EXIT_MODES.disabled) || (!(mode in COURSE_EXIT_MODES))) {
- navigate(`/course/${courseId}`);
- }
- }, []);
-
return (
<>
diff --git a/src/courseware/course/sequence/Sequence.test.jsx b/src/courseware/course/sequence/Sequence.test.jsx
index 4dc0291aad..dea0649d83 100644
--- a/src/courseware/course/sequence/Sequence.test.jsx
+++ b/src/courseware/course/sequence/Sequence.test.jsx
@@ -11,6 +11,10 @@ import Sequence from './Sequence';
import { fetchSequenceFailure } from '../../data/slice';
jest.mock('@edx/frontend-platform/analytics');
+jest.mock('@edx/frontend-lib-special-exams/dist/data/thunks.js', () => ({
+ ...jest.requireActual('@edx/frontend-lib-special-exams/dist/data/thunks.js'),
+ checkExamEntry: () => jest.fn(),
+}));
describe('Sequence', () => {
let mockData;
diff --git a/src/courseware/course/sequence/content-lock/ContentLock.jsx b/src/courseware/course/sequence/content-lock/ContentLock.jsx
index dec64e7878..319dcdb70a 100644
--- a/src/courseware/course/sequence/content-lock/ContentLock.jsx
+++ b/src/courseware/course/sequence/content-lock/ContentLock.jsx
@@ -1,11 +1,11 @@
import React, { useCallback } from 'react';
import PropTypes from 'prop-types';
+import { useNavigate } from 'react-router-dom';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faLock } from '@fortawesome/free-solid-svg-icons';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Button } from '@edx/paragon';
-import { useNavigate } from 'react-router-dom';
import messages from './messages';
const ContentLock = ({
diff --git a/src/courseware/course/sequence/content-lock/ContentLock.test.jsx b/src/courseware/course/sequence/content-lock/ContentLock.test.jsx
index c53523c4c3..c2ab9d3dac 100644
--- a/src/courseware/course/sequence/content-lock/ContentLock.test.jsx
+++ b/src/courseware/course/sequence/content-lock/ContentLock.test.jsx
@@ -4,11 +4,11 @@ import {
} from '../../../../setupTest';
import ContentLock from './ContentLock';
-const mockedNavigator = jest.fn();
+const mockNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
- useNavigate: () => mockedNavigator,
+ useNavigate: () => mockNavigate,
}));
describe('Content Lock', () => {
@@ -43,6 +43,6 @@ describe('Content Lock', () => {
render(, { wrapWithRouter: true });
fireEvent.click(screen.getByRole('button'));
- expect(mockedNavigator).toHaveBeenCalledWith(`/course/${mockData.courseId}/${mockData.prereqId}`);
+ expect(mockNavigate).toHaveBeenCalledWith(`/course/${mockData.courseId}/${mockData.prereqId}`);
});
});
diff --git a/src/courseware/course/sequence/honor-code/HonorCode.test.jsx b/src/courseware/course/sequence/honor-code/HonorCode.test.jsx
index 1ce7ec54a3..d0c38bde4d 100644
--- a/src/courseware/course/sequence/honor-code/HonorCode.test.jsx
+++ b/src/courseware/course/sequence/honor-code/HonorCode.test.jsx
@@ -9,12 +9,12 @@ import {
} from '../../../../setupTest';
import HonorCode from './HonorCode';
-const mockedNavigator = jest.fn();
+const mockNavigate = jest.fn();
initializeMockApp();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
- useNavigate: () => mockedNavigator,
+ useNavigate: () => mockNavigate,
}));
describe('Honor Code', () => {
@@ -41,7 +41,7 @@ describe('Honor Code', () => {
render(, { wrapWithRouter: true });
const cancelButton = screen.getByText('Cancel');
fireEvent.click(cancelButton);
- expect(mockedNavigator).toHaveBeenCalledWith(`/course/${mockData.courseId}/home`);
+ expect(mockNavigate).toHaveBeenCalledWith(`/course/${mockData.courseId}/home`);
});
it('calls to save integrity_signature when agreeing', async () => {
diff --git a/src/decode-page-route/index.jsx b/src/decode-page-route/index.jsx
index be588b23c8..eff47fa3fd 100644
--- a/src/decode-page-route/index.jsx
+++ b/src/decode-page-route/index.jsx
@@ -4,6 +4,7 @@ import React from 'react';
import {
generatePath, useMatch, Navigate,
} from 'react-router-dom';
+
import { DECODE_ROUTES } from '../constants';
const ROUTES = [].concat(
diff --git a/src/generic/CourseAccessErrorPage.jsx b/src/generic/CourseAccessErrorPage.jsx
index 210d2b3a48..8eff1f7aec 100644
--- a/src/generic/CourseAccessErrorPage.jsx
+++ b/src/generic/CourseAccessErrorPage.jsx
@@ -1,7 +1,7 @@
import React, { useEffect } from 'react';
import { LearningHeader as Header } from '@edx/frontend-component-header';
import Footer from '@edx/frontend-component-footer';
-import { useParams, useNavigate } from 'react-router-dom';
+import { useParams, Navigate } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import useActiveEnterpriseAlert from '../alerts/active-enteprise-alert';
@@ -13,7 +13,6 @@ import messages from '../tab-page/messages';
const CourseAccessErrorPage = ({ intl }) => {
const { courseId } = useParams();
- const navigate = useNavigate();
const dispatch = useDispatch();
const activeEnterpriseAlert = useActiveEnterpriseAlert(courseId);
@@ -38,7 +37,7 @@ const CourseAccessErrorPage = ({ intl }) => {
);
}
if (courseStatus === LOADED) {
- navigate(`/redirect/home/${courseId}`, { replace: true });
+ return ;
}
return (
<>
diff --git a/src/generic/CourseAccessErrorPage.test.jsx b/src/generic/CourseAccessErrorPage.test.jsx
index 7812246cef..340e5d07b9 100644
--- a/src/generic/CourseAccessErrorPage.test.jsx
+++ b/src/generic/CourseAccessErrorPage.test.jsx
@@ -5,7 +5,7 @@ import { initializeTestStore, render, screen } from '../setupTest';
import CourseAccessErrorPage from './CourseAccessErrorPage';
const mockDispatch = jest.fn();
-const mockedNavigator = jest.fn();
+const mockNavigate = jest.fn();
let mockCourseStatus;
jest.mock('react-redux', () => ({
@@ -18,7 +18,7 @@ jest.mock('./PageLoading', () => function () {
});
jest.mock('react-router-dom', () => ({
...(jest.requireActual('react-router-dom')),
- useNavigate: () => mockedNavigator,
+ useNavigate: () => mockNavigate,
}));
describe('CourseAccessErrorPage', () => {
@@ -40,7 +40,7 @@ describe('CourseAccessErrorPage', () => {
{ wrapWithRouter: true },
);
expect(screen.getByTestId('page-loading')).toBeInTheDocument();
- expect(history.location.pathname).toBe(accessDeniedUrl);
+ expect(window.location.pathname).toBe(accessDeniedUrl);
});
it('Redirect user to homepage if user has access', () => {
@@ -51,7 +51,7 @@ describe('CourseAccessErrorPage', () => {
,
{ wrapWithRouter: true },
);
- expect(mockedNavigator).toHaveBeenCalledWith('/redirect/home/course-v1:edX+DemoX+Demo_Course', { replace: true });
+ expect(window.location.pathname).toBe('/redirect/home/course-v1:edX+DemoX+Demo_Course');
});
it('For access denied it should render access denied page', () => {
@@ -64,6 +64,6 @@ describe('CourseAccessErrorPage', () => {
{ wrapWithRouter: true },
);
expect(screen.getByTestId('access-denied-main')).toBeInTheDocument();
- expect(history.location.pathname).toBe(accessDeniedUrl);
+ expect(window.location.pathname).toBe(accessDeniedUrl);
});
});
diff --git a/src/generic/path-fixes/PathFixesProvider.jsx b/src/generic/path-fixes/PathFixesProvider.jsx
index 021ed15c08..83e9552c99 100644
--- a/src/generic/path-fixes/PathFixesProvider.jsx
+++ b/src/generic/path-fixes/PathFixesProvider.jsx
@@ -1,8 +1,7 @@
-import { useLocation, useNavigate } from 'react-router-dom';
+import { Navigate, useLocation } from 'react-router-dom';
import PropTypes from 'prop-types';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
-import { useEffect } from 'react';
/**
* We have seen evidence of learners hitting MFE pages with spaces instead of plus signs (which are used commonly
@@ -14,27 +13,24 @@ import { useEffect } from 'react';
*/
const PathFixesProvider = ({ children }) => {
const location = useLocation();
- const navigate = useNavigate();
-
- useEffect(() => {
- // We only check for spaces. That's not the only kind of character that is escaped in URLs, but it would always be
- // present for our cases, and I believe it's the only one we use normally.
- if (location.pathname.includes(' ') || location.pathname.includes('%20')) {
- const newLocation = {
- ...location,
- pathname: (location.pathname.replaceAll(' ', '+')).replaceAll('%20', '+'),
- };
-
- sendTrackEvent('edx.ui.lms.path_fixed', {
- new_path: newLocation.pathname,
- old_path: location.pathname,
- referrer: document.referrer,
- search: location.search,
- });
-
- navigate(newLocation);
- }
- }, [location.pathname]);
+
+ // We only check for spaces. That's not the only kind of character that is escaped in URLs, but it would always be
+ // present for our cases, and I believe it's the only one we use normally.
+ if (location.pathname.includes(' ') || location.pathname.includes('%20')) {
+ const newLocation = {
+ ...location,
+ pathname: (location.pathname.replaceAll(' ', '+')).replaceAll('%20', '+'),
+ };
+
+ sendTrackEvent('edx.ui.lms.path_fixed', {
+ new_path: newLocation.pathname,
+ old_path: location.pathname,
+ referrer: document.referrer,
+ search: location.search,
+ });
+
+ return ();
+ }
return children; // pass through
};