diff --git a/.env.test b/.env.test
index 6f8232c..0b6574a 100644
--- a/.env.test
+++ b/.env.test
@@ -18,6 +18,7 @@ LOGO_TRADEMARK_URL=https://edx-cdn.org/v3/default/logo-trademark.svg
LOGO_WHITE_URL=https://edx-cdn.org/v3/default/logo-white.svg
FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico
ENABLE_LEARNER_RECORD_MFE=''
+ENABLE_SKILLS_BUILDER='true'
ENABLE_SKILLS_BUILDER_PROFILE=''
LEARNER_RECORD_MFE_BASE_URL='http://localhost:1990'
COLLECT_YEAR_OF_BIRTH=true
diff --git a/package-lock.json b/package-lock.json
index 4d92555..bfb96cf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,6 +22,7 @@
"algoliasearch": "4.6.0",
"classnames": "2.3.2",
"core-js": "3.27.2",
+ "history": "4.10.1",
"lodash.camelcase": "4.3.0",
"lodash.get": "4.4.2",
"lodash.pick": "4.4.0",
@@ -10495,7 +10496,8 @@
},
"node_modules/history": {
"version": "4.10.1",
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
+ "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
"dependencies": {
"@babel/runtime": "^7.1.2",
"loose-envify": "^1.2.0",
@@ -28272,6 +28274,8 @@
},
"history": {
"version": "4.10.1",
+ "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
+ "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
"requires": {
"@babel/runtime": "^7.1.2",
"loose-envify": "^1.2.0",
diff --git a/package.json b/package.json
index 79a4e1b..4ab3e2c 100644
--- a/package.json
+++ b/package.json
@@ -40,6 +40,7 @@
"algoliasearch": "4.6.0",
"classnames": "2.3.2",
"core-js": "3.27.2",
+ "history": "4.10.1",
"lodash.camelcase": "4.3.0",
"lodash.get": "4.4.2",
"lodash.pick": "4.4.0",
diff --git a/src/index.jsx b/src/index.jsx
index 7705089..680c0a0 100755
--- a/src/index.jsx
+++ b/src/index.jsx
@@ -4,7 +4,6 @@ import 'regenerator-runtime/runtime';
import {
APP_INIT_ERROR,
APP_READY,
- getConfig,
initialize,
mergeConfig,
subscribe,
@@ -16,33 +15,25 @@ import {
import React from 'react';
import ReactDOM from 'react-dom';
-import { Route, Switch } from 'react-router-dom';
import Header, { messages as headerMessages } from '@edx/frontend-component-header';
import Footer, { messages as footerMessages } from '@edx/frontend-component-footer';
import appMessages from './i18n';
-import { ProfilePage, NotFoundPage } from './profile';
-import { SkillsBuilder } from './skills-builder';
import configureStore from './data/configureStore';
import './index.scss';
import Head from './head/Head';
+import AppRoutes from './routes/AppRoutes';
+
subscribe(APP_READY, () => {
ReactDOM.render(
-
- {getConfig().ENABLE_SKILLS_BUILDER && (
-
- )}
-
-
-
-
+
,
@@ -60,7 +51,6 @@ initialize({
headerMessages,
footerMessages,
],
- requireAuthenticatedUser: true,
hydrateAuthenticatedUser: true,
handlers: {
config: () => {
diff --git a/src/routes/AppRoutes.jsx b/src/routes/AppRoutes.jsx
new file mode 100644
index 0000000..8d202ef
--- /dev/null
+++ b/src/routes/AppRoutes.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import { getConfig } from '@edx/frontend-platform';
+import {
+ AuthenticatedPageRoute,
+ PageRoute,
+} from '@edx/frontend-platform/react';
+import { Switch } from 'react-router-dom';
+import { ProfilePage, NotFoundPage } from '../profile';
+import { SkillsBuilder } from '../skills-builder';
+
+const AppRoutes = () => (
+
+ {getConfig().ENABLE_SKILLS_BUILDER && (
+
+ )}
+
+
+
+
+);
+
+export default AppRoutes;
diff --git a/src/routes/routes.test.jsx b/src/routes/routes.test.jsx
new file mode 100644
index 0000000..c344814
--- /dev/null
+++ b/src/routes/routes.test.jsx
@@ -0,0 +1,91 @@
+import React from 'react';
+import { AppContext } from '@edx/frontend-platform/react';
+import { getConfig } from '@edx/frontend-platform';
+import { Router } from 'react-router';
+import { render, screen } from '@testing-library/react';
+import { createMemoryHistory } from 'history';
+import { getLoginRedirectUrl } from '@edx/frontend-platform/auth';
+import AppRoutes from './AppRoutes';
+
+jest.mock('@edx/frontend-platform/analytics');
+
+jest.mock('@edx/frontend-platform/auth', () => ({
+ getLoginRedirectUrl: jest.fn(),
+}));
+
+jest.mock('@edx/frontend-platform', () => ({
+ getConfig: jest.fn(() => ({
+ ENABLE_SKILLS_BUILDER: true,
+ })),
+}));
+
+jest.mock('../profile', () => ({
+ ProfilePage: () => (
Profile page
),
+ NotFoundPage: () => (Not found page
),
+}));
+
+jest.mock('../skills-builder', () => ({
+ SkillsBuilder: () => (Skills Builder
),
+}));
+
+const RoutesWithProvider = (context, history) => (
+
+
+
+
+
+);
+
+const unauthenticatedUser = {
+ authenticatedUser: null,
+ config: getConfig(),
+};
+
+describe('routes', () => {
+ let history;
+
+ beforeEach(() => {
+ history = createMemoryHistory();
+ });
+
+ test('Profile page should redirect for unauthenticated users', () => {
+ history.push('/u/edx');
+ render(
+ RoutesWithProvider(unauthenticatedUser, history),
+ );
+ expect(getLoginRedirectUrl).toHaveBeenCalled();
+ });
+
+ test('Profile page should be accessible for authenticated users', () => {
+ history.push('/u/edx');
+ render(
+ RoutesWithProvider(
+ {
+ authenticatedUser: {
+ username: 'edx',
+ email: 'edx@example.com',
+ },
+ config: getConfig(),
+ },
+ history,
+ ),
+ );
+ expect(screen.getByText('Profile page')).toBeTruthy();
+ });
+
+ test('Skills Builder page should be accessible to unauthenticated users', () => {
+ history.push('/skills');
+ render(
+ RoutesWithProvider(unauthenticatedUser, history),
+ );
+ expect(screen.getByText('Skills Builder')).toBeTruthy();
+ });
+
+ test('should show NotFound page for a bad route', () => {
+ history.push('/nonMatchingRoute');
+ render(
+ RoutesWithProvider(unauthenticatedUser, history),
+ );
+ expect(screen.getByText('Not found page')).toBeTruthy();
+ });
+});