-
Sign In
-
{
+ this.setState(prevState => ({ institutionLogin: !prevState.institutionLogin }));
+ }
+
handleSubmit = (e) => {
e.preventDefault();
const params = (new URL(document.location)).searchParams;
@@ -142,6 +163,16 @@ class RegistrationPage extends React.Component {
}
render() {
+ if (this.state.institutionLogin) {
+ return (
+
+ );
+ }
return (
<>
Create an account using
-
+
+
or create a new one here
@@ -267,11 +303,14 @@ RegistrationPage.defaultProps = {
registrationResult: null,
registerNewUser: null,
registrationError: null,
+ thirdPartyAuthContext: {},
};
RegistrationPage.propTypes = {
+ intl: intlShape.isRequired,
registerNewUser: PropTypes.func,
+ getThirdPartyAuthContext: PropTypes.func.isRequired,
registrationResult: PropTypes.shape({
redirectUrl: PropTypes.string,
success: PropTypes.bool,
@@ -280,12 +319,27 @@ RegistrationPage.propTypes = {
email: PropTypes.array,
username: PropTypes.array,
}),
+ thirdPartyAuthContext: PropTypes.shape({
+ currentProvider: PropTypes.string,
+ providers: PropTypes.array,
+ secondaryProviders: PropTypes.array,
+ finishAuthUrl: PropTypes.string,
+ pipelineUserDetails: PropTypes.shape({
+ email: PropTypes.string,
+ fullname: PropTypes.string,
+ firstName: PropTypes.string,
+ lastName: PropTypes.string,
+ username: PropTypes.string,
+ }),
+ }),
};
const mapStateToProps = state => {
const registrationResult = registrationRequestSelector(state);
+ const thirdPartyAuthContext = thirdPartyAuthContextSelector(state);
return {
registrationResult,
+ thirdPartyAuthContext,
registrationError: state.logistration.registrationError,
};
};
@@ -293,6 +347,7 @@ const mapStateToProps = state => {
export default connect(
mapStateToProps,
{
+ getThirdPartyAuthContext,
registerNewUser,
},
-)(RegistrationPage);
+)(injectIntl(RegistrationPage));
diff --git a/src/logistration/data/service.js b/src/logistration/data/service.js
index 715fd740..ec30170e 100644
--- a/src/logistration/data/service.js
+++ b/src/logistration/data/service.js
@@ -62,7 +62,6 @@ export async function getThirdPartyAuthContext(urlParams) {
.catch((e) => {
throw (e);
});
-
return {
thirdPartyAuthContext: camelCaseObject(data),
};
diff --git a/src/logistration/messages.jsx b/src/logistration/messages.jsx
new file mode 100644
index 00000000..7e5905eb
--- /dev/null
+++ b/src/logistration/messages.jsx
@@ -0,0 +1,77 @@
+
+import { defineMessages } from '@edx/frontend-platform/i18n';
+
+const messages = defineMessages({
+ 'logistration.need.help.signing.in.collapsible.menu': {
+ id: 'logistration.need.help.signing.in.collapsible.menu',
+ defaultMessage: 'Need help signing in?',
+ description: 'A button for collapsible need help signing in menu on login page',
+ },
+ 'logistration.need.other.help.signing.in.collapsible.menu': {
+ id: 'logistration.need.other.help.signing.in.collapsible.menu',
+ defaultMessage: 'Need other help signing in?',
+ description: 'A button for collapsible need other help signing in menu on forgot password page',
+ },
+ 'logistration.register.link': {
+ id: 'logistration.register.link',
+ defaultMessage: 'Create an account',
+ description: 'Register page link',
+ },
+ 'logistration.forgot.password.link': {
+ id: 'logistration.forgot.password.link',
+ defaultMessage: 'Forgot password?',
+ description: 'Forgot password link',
+ },
+ 'logistration.other.sign.in.issues': {
+ id: 'logistration.other.sign.in.issues',
+ defaultMessage: 'Other sign-in issues',
+ description: 'A link that redirects to sign-in issues help',
+ },
+ 'logistration.login.institution.login.button': {
+ id: 'logistration.login.institution.login.button',
+ defaultMessage: 'Use my university info',
+ description: 'shows institutions list',
+ },
+ 'logistration.login.institution.login.page.title': {
+ id: 'logistration.login.institution.login.page.title',
+ defaultMessage: 'Sign in with Institution/Campus Credentials',
+ description: 'Heading of institution page',
+ },
+ 'logistration.institution.login.page.sub.heading': {
+ id: 'logistration.institution.login.page.sub.heading',
+ defaultMessage: 'Choose your institution from the list below:',
+ description: 'Heading of the institutions list',
+ },
+ 'logistration.login.institution.login.page.back.button': {
+ id: 'logistration.login.institution.login.page.back.button',
+ defaultMessage: 'Back',
+ description: 'return to login page',
+ },
+ 'logistration.register.institution.login.button': {
+ id: 'logistration.register.institution.login.button',
+ defaultMessage: 'Use my institution/campus credentials',
+ description: 'shows institutions list',
+ },
+ 'logistration.register.institution.login.page.title': {
+ id: 'logistration.register.institution.login.page.title',
+ defaultMessage: 'Register with Institution/Campus Credentials',
+ description: 'Heading of institution page',
+ },
+ 'logistration.register.institution.login.page.back.button': {
+ id: 'logistration.register.institution.login.page.back.button',
+ defaultMessage: 'Create an Account',
+ description: 'return to login page',
+ },
+ 'logistration.login.institution.login.sign.in': {
+ id: 'logistration.login.institution.login.sign.in',
+ defaultMessage: 'Sign In',
+ description: 'Sign In text',
+ },
+ 'logistration.login.institution.login.sign.in.with': {
+ id: 'logistration.login.institution.login.sign.in.with',
+ defaultMessage: 'or sign in with',
+ description: 'gives hint about other sign options ',
+ },
+});
+
+export default messages;
diff --git a/src/logistration/tests/LoginPage.test.jsx b/src/logistration/tests/LoginPage.test.jsx
index bacca972..30b26626 100644
--- a/src/logistration/tests/LoginPage.test.jsx
+++ b/src/logistration/tests/LoginPage.test.jsx
@@ -6,8 +6,8 @@ import configureStore from 'redux-mock-store';
import { getConfig } from '@edx/frontend-platform';
import { IntlProvider, injectIntl } from '@edx/frontend-platform/i18n';
-
import LoginPage from '../LoginPage';
+import { RenderInstitutionButton } from '../InstitutionLogistration';
const IntlLoginPage = injectIntl(LoginPage);
const mockStore = configureStore();
@@ -22,6 +22,7 @@ describe('LoginPage', () => {
currentProvider: null,
finishAuthUrl: null,
providers: [],
+ secondaryProviders: [],
},
},
};
@@ -29,6 +30,13 @@ describe('LoginPage', () => {
let props = {};
let store = {};
+ const secondaryProviders = {
+ id: 'saml-test',
+ name: 'Test University',
+ loginUrl: '/dummy-auth',
+ registerUrl: '/dummy_auth',
+ };
+
const appleProvider = {
id: 'oa2-apple-id',
name: 'Apple',
@@ -169,13 +177,6 @@ describe('LoginPage', () => {
expect(window.location.href).toBe(getConfig().LMS_BASE_URL + authCompleteUrl);
});
- it('should call the componentDidMount lifecycle method', () => {
- const spy = jest.spyOn(LoginPage.WrappedComponent.prototype, 'componentDidMount');
-
- mount(reduxWrapper(
));
- expect(spy).toHaveBeenCalled();
- });
-
it('should redirect to social auth provider url', () => {
const loginUrl = '/auth/login/apple-id/?auth_entry=login&next=/dashboard';
store = mockStore({
@@ -219,4 +220,40 @@ describe('LoginPage', () => {
const loginPage = mount(reduxWrapper(
));
expect(loginPage.find('#tpa-alert').find('span').text()).toEqual(expectedMessage);
});
+
+ it('should display institution login button', () => {
+ store = mockStore({
+ ...initialState,
+ logistration: {
+ ...initialState.logistration,
+ thirdPartyAuthContext: {
+ ...initialState.logistration.thirdPartyAuthContext,
+ secondaryProviders: [secondaryProviders],
+ },
+ },
+ });
+ const root = mount(reduxWrapper(
));
+ expect(root.text().includes('Use my university info')).toBe(true);
+ });
+
+ it('should not display institution login button', () => {
+ const root = mount(reduxWrapper(
));
+ expect(root.text().includes('Use my university info')).toBe(false);
+ });
+
+ it('should display institution login page', () => {
+ store = mockStore({
+ ...initialState,
+ logistration: {
+ ...initialState.logistration,
+ thirdPartyAuthContext: {
+ ...initialState.logistration.thirdPartyAuthContext,
+ secondaryProviders: [secondaryProviders],
+ },
+ },
+ });
+ const loginPage = mount(reduxWrapper(
));
+ loginPage.find(RenderInstitutionButton).simulate('click', { institutionLogin: true });
+ expect(loginPage.text().includes('Test University')).toBe(true);
+ });
});
diff --git a/src/logistration/tests/RegistrationPage.test.jsx b/src/logistration/tests/RegistrationPage.test.jsx
index f7ec2ca3..222dc1ec 100644
--- a/src/logistration/tests/RegistrationPage.test.jsx
+++ b/src/logistration/tests/RegistrationPage.test.jsx
@@ -2,9 +2,11 @@ import React from 'react';
import { Provider } from 'react-redux';
import renderer from 'react-test-renderer';
import configureStore from 'redux-mock-store';
+import { mount } from 'enzyme';
import { IntlProvider, injectIntl, configure } from '@edx/frontend-platform/i18n';
import RegistrationPage from '../RegistrationPage';
+import { RenderInstitutionButton } from '../InstitutionLogistration';
const IntlRegistrationPage = injectIntl(RegistrationPage);
const mockStore = configureStore();
@@ -14,12 +16,20 @@ describe('./RegistrationPage.js', () => {
const initialState = {
logistration: {
registrationResult: { success: false, redirectUrl: '' },
+ thirdPartyAuthContext: { secondaryProviders: [] },
},
};
let props = {};
let store = {};
+ const secondaryProviders = {
+ id: 'saml-test',
+ name: 'Test University',
+ loginUrl: '/dummy-auth',
+ registerUrl: '/dummy_auth',
+ };
+
const reduxWrapper = children => (
{children}
@@ -59,7 +69,7 @@ describe('./RegistrationPage.js', () => {
store = mockStore({
...store,
logistration: {
- ...store.logistration,
+ ...initialState.logistration,
registrationResult: {
success: true,
redirectUrl: dasboardUrl,
@@ -72,6 +82,37 @@ describe('./RegistrationPage.js', () => {
expect(window.location.href).toBe(dasboardUrl);
});
+ it('should display institution register button', () => {
+ store = mockStore({
+ ...initialState,
+ logistration: {
+ ...initialState.logistration,
+ thirdPartyAuthContext: {
+ ...initialState.logistration.thirdPartyAuthContext,
+ secondaryProviders: [secondaryProviders],
+ },
+ },
+ });
+ const root = mount(reduxWrapper());
+ expect(root.text().includes('Use my institution/campus credentials')).toBe(true);
+ });
+
+ it('should not display institution register button', () => {
+ store = mockStore({
+ ...initialState,
+ logistration: {
+ ...initialState.logistration,
+ thirdPartyAuthContext: {
+ ...initialState.logistration.thirdPartyAuthContext,
+ secondaryProviders: [secondaryProviders],
+ },
+ },
+ });
+ const root = mount(reduxWrapper());
+ root.find(RenderInstitutionButton).simulate('click', { institutionLogin: true });
+ expect(root.text().includes('Test University')).toBe(true);
+ });
+
it('should show error message on 409', () => {
const windowSpy = jest.spyOn(global, 'window', 'get');
windowSpy.mockImplementation(() => ({
diff --git a/src/logistration/tests/__snapshots__/LoginPage.test.jsx.snap b/src/logistration/tests/__snapshots__/LoginPage.test.jsx.snap
index 456251ca..e2d70143 100644
--- a/src/logistration/tests/__snapshots__/LoginPage.test.jsx.snap
+++ b/src/logistration/tests/__snapshots__/LoginPage.test.jsx.snap
@@ -25,17 +25,24 @@ exports[`LoginPage should match TPA provider snapshot 1`] = `
+