diff --git a/src/common-components/HeaderLayout.jsx b/src/common-components/HeaderLayout.jsx
new file mode 100644
index 00000000..d328401b
--- /dev/null
+++ b/src/common-components/HeaderLayout.jsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import Header from '@edx/frontend-component-header';
+
+const HeaderLayout = ({ children }) => (
+
+
+
+ {children}
+
+
+);
+
+HeaderLayout.propTypes = {
+ children: PropTypes.node.isRequired,
+};
+
+export default HeaderLayout;
diff --git a/src/common-components/LoggedInRedirect.jsx b/src/common-components/LoggedInRedirect.jsx
new file mode 100644
index 00000000..f3f66f94
--- /dev/null
+++ b/src/common-components/LoggedInRedirect.jsx
@@ -0,0 +1,26 @@
+import { useContext } from 'react';
+import PropTypes from 'prop-types';
+import { AppContext } from '@edx/frontend-platform/react';
+
+import { DEFAULT_REDIRECT_URL } from '../data/constants';
+
+/**
+ * This wrapper component redirects the requester to our default redirect url if they are
+ * already authenticated.
+ *
+ * @param {node} children The child nodes to render if there is an unauthenticated user.
+ */
+export default function LoggedInRedirect({ children }) {
+ const { authenticatedUser, config } = useContext(AppContext);
+
+ if (authenticatedUser) {
+ global.location.href = config.LMS_BASE_URL.concat(DEFAULT_REDIRECT_URL);
+ return null;
+ }
+
+ return children;
+}
+
+LoggedInRedirect.propTypes = {
+ children: PropTypes.node.isRequired,
+};
diff --git a/src/logistration/RedirectLogistration.jsx b/src/common-components/RedirectLogistration.jsx
similarity index 100%
rename from src/logistration/RedirectLogistration.jsx
rename to src/common-components/RedirectLogistration.jsx
diff --git a/src/RegisterFaIcons.jsx b/src/common-components/RegisterFaIcons.jsx
similarity index 100%
rename from src/RegisterFaIcons.jsx
rename to src/common-components/RegisterFaIcons.jsx
diff --git a/src/common-components/index.jsx b/src/common-components/index.jsx
new file mode 100644
index 00000000..bb310481
--- /dev/null
+++ b/src/common-components/index.jsx
@@ -0,0 +1,4 @@
+export { default as HeaderLayout } from './HeaderLayout';
+export { default as LoggedInRedirect } from './LoggedInRedirect';
+export { default as RedirectLogistration } from './RedirectLogistration';
+export { default as registerIcons } from './RegisterFaIcons';
diff --git a/src/common-components/tests/LoggedInRedirect.test.jsx b/src/common-components/tests/LoggedInRedirect.test.jsx
new file mode 100644
index 00000000..9e0f4542
--- /dev/null
+++ b/src/common-components/tests/LoggedInRedirect.test.jsx
@@ -0,0 +1,46 @@
+import React from 'react';
+import { mount } from 'enzyme';
+
+import { getConfig } from '@edx/frontend-platform';
+
+import LoggedInRedirect from '../LoggedInRedirect';
+import { DEFAULT_REDIRECT_URL } from '../../data/constants';
+
+describe('LoggedInRedirect', () => {
+ const loggedInRedirect = (
+
+ test
+
+ );
+ const dashboardURL = getConfig().LMS_BASE_URL.concat(DEFAULT_REDIRECT_URL);
+
+ it('should redirect to dashboard if already logged in', () => {
+ delete window.location;
+ window.location = { href: '' };
+ const user = {
+ username: 'gonzo',
+ other: 'data',
+ };
+ const mockUseContext = jest.fn().mockImplementation(() => ({
+ authenticatedUser: user,
+ config: getConfig(),
+ }));
+
+ React.useContext = mockUseContext;
+ mount(loggedInRedirect);
+
+ expect(window.location.href).toBe(dashboardURL);
+ });
+
+ it('should render child components', () => {
+ const mockUseContext = jest.fn().mockImplementation(() => ({
+ authenticatedUser: null,
+ config: null,
+ }));
+
+ React.useContext = mockUseContext;
+ const wrapper = mount(loggedInRedirect);
+
+ expect(wrapper.find('div').length).toBe(1);
+ });
+});
diff --git a/src/index.jsx b/src/index.jsx
index e473446b..2ce2d8b5 100755
--- a/src/index.jsx
+++ b/src/index.jsx
@@ -6,15 +6,15 @@ import {
import { AppProvider, ErrorPage } from '@edx/frontend-platform/react';
import React from 'react';
import ReactDOM from 'react-dom';
-import { Route, Switch } from 'react-router-dom';
+import { Redirect, Route, Switch } from 'react-router-dom';
-import Header, { messages as headerMessages } from '@edx/frontend-component-header';
+import { messages as headerMessages } from '@edx/frontend-component-header';
import configureStore from './data/configureStore';
import { LoginPage, RegistrationPage, NotFoundPage } from './logistration';
import { LOGIN_PAGE, REGISTER_PAGE, RESET_PAGE } from './data/constants';
import ForgotPasswordPage from './forgot-password';
-import registerIcons from './RegisterFaIcons';
+import { HeaderLayout, LoggedInRedirect, registerIcons } from './common-components';
import ResetPasswordPage from './reset-password';
import appMessages from './i18n';
@@ -23,28 +23,24 @@ import './assets/favicon.ico';
registerIcons();
-const HeaderLayout = ({ children }) => ( // eslint-disable-line react/prop-types
-
-
-
- {children}
-
-
-);
-
subscribe(APP_READY, () => {
ReactDOM.render(
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
,
document.getElementById('root'),
);
diff --git a/src/logistration/LoginPage.jsx b/src/logistration/LoginPage.jsx
index e187abe2..234dd93a 100644
--- a/src/logistration/LoginPage.jsx
+++ b/src/logistration/LoginPage.jsx
@@ -12,7 +12,7 @@ import InstitutionLogistration, { RenderInstitutionButton } from './InstitutionL
import LoginHelpLinks from './LoginHelpLinks';
import LoginFailureMessage from './LoginFailure';
import messages from './messages';
-import RedirectLogistration from './RedirectLogistration';
+import { RedirectLogistration } from '../common-components';
import SocialAuthProviders from './SocialAuthProviders';
import ThirdPartyAuthAlert from './ThirdPartyAuthAlert';
diff --git a/src/logistration/RegistrationPage.jsx b/src/logistration/RegistrationPage.jsx
index f8a351c1..b59e3170 100644
--- a/src/logistration/RegistrationPage.jsx
+++ b/src/logistration/RegistrationPage.jsx
@@ -8,7 +8,7 @@ import {
import { getThirdPartyAuthContext, registerNewUser } from './data/actions';
import { registrationRequestSelector, thirdPartyAuthContextSelector } from './data/selectors';
-import RedirectLogistration from './RedirectLogistration';
+import { RedirectLogistration } from '../common-components';
import RegistrationFailure from './RegistrationFailure';
import {
DEFAULT_REDIRECT_URL, DEFAULT_STATE, LOGIN_PAGE, REGISTER_PAGE,
diff --git a/src/logistration/tests/SocialAuthProviders.test.jsx b/src/logistration/tests/SocialAuthProviders.test.jsx
index cc9c833e..b8b8b8bd 100644
--- a/src/logistration/tests/SocialAuthProviders.test.jsx
+++ b/src/logistration/tests/SocialAuthProviders.test.jsx
@@ -3,7 +3,7 @@ import renderer from 'react-test-renderer';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import SocialAuthProviders from '../SocialAuthProviders';
-import registerIcons from '../../RegisterFaIcons';
+import { registerIcons } from '../../common-components';
registerIcons();
diff --git a/src/reset-password/tests/ResetPasswordPage.test.jsx b/src/reset-password/tests/ResetPasswordPage.test.jsx
index e761f0fd..38c62648 100644
--- a/src/reset-password/tests/ResetPasswordPage.test.jsx
+++ b/src/reset-password/tests/ResetPasswordPage.test.jsx
@@ -139,7 +139,7 @@ describe('ResetPasswordPage', () => {
expect(resetPasswordPage.find('#reset-password-input-invalid-feedback').text()).toEqual(validationMessage);
});
- it('with valid inputs resetPassword action is dispatch', () => {
+ it('with valid inputs resetPassword action is dispatch', async () => {
const newPassword = 'test-password1';
store = mockStore({
...store,
@@ -151,6 +151,13 @@ describe('ResetPasswordPage', () => {
token: 'token',
};
+ auth.getHttpClient = jest.fn(() => ({
+ post: async () => ({
+ data: {},
+ catch: () => {},
+ }),
+ }));
+
const formPayload = {
new_password1: newPassword,
new_password2: newPassword,
@@ -158,7 +165,9 @@ describe('ResetPasswordPage', () => {
store.dispatch = jest.fn(store.dispatch);
const resetPage = mount(reduxWrapper());
- resetPage.find('input#reset-password-input').simulate('blur', { target: { value: newPassword } });
+ await act(async () => {
+ resetPage.find('input#reset-password-input').simulate('blur', { target: { value: newPassword } });
+ });
resetPage.find('input#confirm-password-input').simulate('change', { target: { value: newPassword } });
resetPage.find('button.submit').simulate('click');