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');