Merge pull request #22 from edx/aehsan/VAN-94/added_saml_integration_for_logistration
Added saml integration for login and registration
This commit is contained in:
103
src/logistration/InstitutionLogistration.jsx
Normal file
103
src/logistration/InstitutionLogistration.jsx
Normal file
@@ -0,0 +1,103 @@
|
||||
import React from 'react';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button } from '@edx/paragon';
|
||||
import messages from './messages';
|
||||
|
||||
export const RenderInstitutionButton = props => {
|
||||
const { onSubmitHandler, secondaryProviders, buttonTitle } = props;
|
||||
if (secondaryProviders !== undefined && secondaryProviders.length > 0) {
|
||||
return (
|
||||
<Button
|
||||
className="mb-2"
|
||||
block
|
||||
variant="outline-primary"
|
||||
onClick={onSubmitHandler}
|
||||
>
|
||||
{buttonTitle}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
return <></>;
|
||||
};
|
||||
|
||||
|
||||
const InstitutionLogistration = props => {
|
||||
const lmsBaseUrl = getConfig().LMS_BASE_URL;
|
||||
const {
|
||||
intl,
|
||||
onSubmitHandler,
|
||||
secondaryProviders,
|
||||
headingTitle,
|
||||
buttonTitle,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="d-flex justify-content-center institution-login-container">
|
||||
<div className="d-flex flex-column" style={{ width: '450px' }}>
|
||||
<p className="mt-5 ml-3 mb-4" style={{ color: '#23419f', fontSize: '20px' }}>
|
||||
{headingTitle}
|
||||
</p>
|
||||
<div style={{ fontSize: '16px' }}>
|
||||
<p
|
||||
className="mb-2"
|
||||
style={{ fontSize: '16px' }}
|
||||
>
|
||||
{intl.formatMessage(messages['logistration.institution.login.page.sub.heading'])}
|
||||
</p>
|
||||
<div className="mb-2 ml-2">
|
||||
<ul>
|
||||
{secondaryProviders.map(
|
||||
provider => <li key={provider}><a href={lmsBaseUrl + provider.loginUrl}>{provider.name}</a></li>,
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className="section-heading-line mb-4">
|
||||
<h4>or</h4>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline-primary"
|
||||
onClick={onSubmitHandler}
|
||||
>
|
||||
{buttonTitle}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const LogistrationDefaultProps = {
|
||||
secondaryProviders: [],
|
||||
buttonTitle: '',
|
||||
};
|
||||
const LogistrationProps = {
|
||||
onSubmitHandler: PropTypes.func.isRequired,
|
||||
secondaryProviders: PropTypes.arrayOf(PropTypes.shape({
|
||||
name: PropTypes.string.isRequried,
|
||||
loginUrl: PropTypes.string.isRequired,
|
||||
})),
|
||||
buttonTitle: PropTypes.string,
|
||||
};
|
||||
|
||||
RenderInstitutionButton.propTypes = {
|
||||
...LogistrationProps,
|
||||
};
|
||||
RenderInstitutionButton.defaultProps = {
|
||||
...LogistrationDefaultProps,
|
||||
};
|
||||
|
||||
InstitutionLogistration.propTypes = {
|
||||
...LogistrationProps,
|
||||
intl: intlShape.isRequired,
|
||||
headingTitle: PropTypes.string,
|
||||
};
|
||||
InstitutionLogistration.defaultProps = {
|
||||
...LogistrationDefaultProps,
|
||||
headingTitle: '',
|
||||
};
|
||||
|
||||
export default injectIntl(InstitutionLogistration);
|
||||
@@ -5,8 +5,8 @@ import { faCaretDown, faCaretRight } from '@fortawesome/free-solid-svg-icons';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import SwitchContent from './SwitchContent';
|
||||
import messages from './LoginHelpLinks.messages';
|
||||
import { REGISTER_PAGE, RESET_PAGE } from '../data/constants';
|
||||
import messages from './messages';
|
||||
|
||||
const LoginHelpLinks = (props) => {
|
||||
const { intl, page } = props;
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
|
||||
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 my 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',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
@@ -3,6 +3,7 @@ import React from 'react';
|
||||
import { Button, Input, ValidationFormGroup } from '@edx/paragon';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { forgotPasswordResultSelector } from '../forgot-password';
|
||||
import ConfirmationAlert from './ConfirmationAlert';
|
||||
@@ -14,7 +15,8 @@ import LoginFailureMessage from './LoginFailure';
|
||||
import RedirectLogistration from './RedirectLogistration';
|
||||
import SocialAuthProviders from './SocialAuthProviders';
|
||||
import ThirdPartyAuthAlert from './ThirdPartyAuthAlert';
|
||||
|
||||
import InstitutionLogistration, { RenderInstitutionButton } from './InstitutionLogistration';
|
||||
import messages from './messages';
|
||||
|
||||
class LoginPage extends React.Component {
|
||||
constructor(props, context) {
|
||||
@@ -30,6 +32,7 @@ class LoginPage extends React.Component {
|
||||
emailValid: false,
|
||||
passwordValid: false,
|
||||
formValid: false,
|
||||
institutionLogin: false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -41,6 +44,10 @@ class LoginPage extends React.Component {
|
||||
this.props.getThirdPartyAuthContext(payload);
|
||||
}
|
||||
|
||||
handleInstitutionLogin = () => {
|
||||
this.setState(prevState => ({ institutionLogin: !prevState.institutionLogin }));
|
||||
}
|
||||
|
||||
handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
const params = (new URL(document.location)).searchParams;
|
||||
@@ -104,8 +111,18 @@ class LoginPage extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { intl } = this.props;
|
||||
const { currentProvider, finishAuthUrl, providers } = this.props.thirdPartyAuthContext;
|
||||
|
||||
if (this.state.institutionLogin) {
|
||||
return (
|
||||
<InstitutionLogistration
|
||||
onSubmitHandler={this.handleInstitutionLogin}
|
||||
secondaryProviders={this.props.thirdPartyAuthContext.secondaryProviders}
|
||||
headingTitle={intl.formatMessage(messages['logistration.login.institution.login.page.title'])}
|
||||
buttonTitle={intl.formatMessage(messages['logistration.login.institution.login.page.back.button'])}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<RedirectLogistration
|
||||
@@ -129,10 +146,17 @@ class LoginPage extends React.Component {
|
||||
First time here?<a className="ml-1" href={REGISTER_PAGE}>Create an Account.</a>
|
||||
</p>
|
||||
</div>
|
||||
<h3 className="text-left mt-3">{intl.formatMessage(messages['logistration.login.institution.login.sign.in'])}</h3>
|
||||
<RenderInstitutionButton
|
||||
onSubmitHandler={this.handleInstitutionLogin}
|
||||
secondaryProviders={this.props.thirdPartyAuthContext.secondaryProviders}
|
||||
buttonTitle={intl.formatMessage(messages['logistration.login.institution.login.button'])}
|
||||
/>
|
||||
<div className="section-heading-line mb-4">
|
||||
<h4>{intl.formatMessage(messages['logistration.login.institution.login.sign.in.with'])}</h4>
|
||||
</div>
|
||||
<form className="m-0">
|
||||
<div className="form-group">
|
||||
<h3 className="text-center mt-3">Sign In</h3>
|
||||
|
||||
<div className="d-flex flex-column align-items-start">
|
||||
<ValidationFormGroup
|
||||
for="email"
|
||||
@@ -208,6 +232,7 @@ LoginPage.defaultProps = {
|
||||
};
|
||||
|
||||
LoginPage.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
getThirdPartyAuthContext: PropTypes.func.isRequired,
|
||||
loginRequest: PropTypes.func.isRequired,
|
||||
loginResult: PropTypes.shape({
|
||||
@@ -246,4 +271,4 @@ export default connect(
|
||||
getThirdPartyAuthContext,
|
||||
loginRequest,
|
||||
},
|
||||
)(LoginPage);
|
||||
)(injectIntl(LoginPage));
|
||||
|
||||
@@ -7,12 +7,20 @@ import {
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faFacebookF, faGoogle, faMicrosoft } from '@fortawesome/free-brands-svg-icons';
|
||||
import { faGraduationCap } from '@fortawesome/free-solid-svg-icons';
|
||||
import { getLocale, getCountryList } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
getLocale,
|
||||
getCountryList,
|
||||
injectIntl,
|
||||
intlShape,
|
||||
} from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { registerNewUser } from './data/actions';
|
||||
import { registrationRequestSelector } from './data/selectors';
|
||||
import { getThirdPartyAuthContext, registerNewUser } from './data/actions';
|
||||
import { registrationRequestSelector, thirdPartyAuthContextSelector } from './data/selectors';
|
||||
import { DEFAULT_REDIRECT_URL } from '../data/constants';
|
||||
import RedirectLogistration from './RedirectLogistration';
|
||||
import RegistrationFailure from './RegistrationFailure';
|
||||
import InstitutionLogistration, { RenderInstitutionButton } from './InstitutionLogistration';
|
||||
import messages from './messages';
|
||||
|
||||
class RegistrationPage extends React.Component {
|
||||
constructor(props, context) {
|
||||
@@ -37,9 +45,22 @@ class RegistrationPage extends React.Component {
|
||||
passwordValid: false,
|
||||
countryValid: false,
|
||||
formValid: false,
|
||||
institutionLogin: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const params = (new URL(document.location)).searchParams;
|
||||
const payload = {
|
||||
redirect_to: params.get('next') || DEFAULT_REDIRECT_URL,
|
||||
};
|
||||
this.props.getThirdPartyAuthContext(payload);
|
||||
}
|
||||
|
||||
handleInstitutionLogin = () => {
|
||||
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 (
|
||||
<InstitutionLogistration
|
||||
onSubmitHandler={this.handleInstitutionLogin}
|
||||
secondaryProviders={this.props.thirdPartyAuthContext.secondaryProviders}
|
||||
headingTitle={this.props.intl.formatMessage(messages['logistration.register.institution.login.page.title'])}
|
||||
buttonTitle={this.props.intl.formatMessage(messages['logistration.register.institution.login.page.back.button'])}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<RedirectLogistration
|
||||
@@ -158,7 +189,12 @@ class RegistrationPage extends React.Component {
|
||||
<span className="d-block mx-auto mb-4 section-heading-line">Create an account using</span>
|
||||
<button type="button" className="btn-social facebook"><FontAwesomeIcon className="mr-2" icon={faFacebookF} />Facebook</button>
|
||||
<button type="button" className="btn-social google"><FontAwesomeIcon className="mr-2" icon={faGoogle} />Google</button>
|
||||
<button type="button" className="btn-social microsoft"><FontAwesomeIcon className="mr-2" icon={faMicrosoft} />Microsoft</button>
|
||||
<button type="button" className="btn-social microsoft mb-3"><FontAwesomeIcon className="mr-2" icon={faMicrosoft} />Microsoft</button>
|
||||
<RenderInstitutionButton
|
||||
onSubmitHandler={this.handleInstitutionLogin}
|
||||
secondaryProviders={this.props.thirdPartyAuthContext.secondaryProviders}
|
||||
buttonTitle={this.props.intl.formatMessage(messages['logistration.register.institution.login.button'])}
|
||||
/>
|
||||
<span className="d-block mx-auto text-center mt-4 section-heading-line">or create a new one here</span>
|
||||
</div>
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -62,7 +62,6 @@ export async function getThirdPartyAuthContext(urlParams) {
|
||||
.catch((e) => {
|
||||
throw (e);
|
||||
});
|
||||
|
||||
return {
|
||||
thirdPartyAuthContext: camelCaseObject(data),
|
||||
};
|
||||
|
||||
77
src/logistration/messages.jsx
Normal file
77
src/logistration/messages.jsx
Normal file
@@ -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;
|
||||
@@ -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(<IntlLoginPage {...props} />));
|
||||
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(<IntlLoginPage {...props} />));
|
||||
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(<IntlLoginPage {...props} />));
|
||||
expect(root.text().includes('Use my university info')).toBe(true);
|
||||
});
|
||||
|
||||
it('should not display institution login button', () => {
|
||||
const root = mount(reduxWrapper(<IntlLoginPage {...props} />));
|
||||
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(<IntlLoginPage {...props} />));
|
||||
loginPage.find(RenderInstitutionButton).simulate('click', { institutionLogin: true });
|
||||
expect(loginPage.text().includes('Test University')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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 => (
|
||||
<IntlProvider locale="en">
|
||||
<Provider store={store}>{children}</Provider>
|
||||
@@ -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(<IntlRegistrationPage {...props} />));
|
||||
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(<IntlRegistrationPage {...props} />));
|
||||
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(() => ({
|
||||
|
||||
@@ -25,17 +25,24 @@ exports[`LoginPage should match TPA provider snapshot 1`] = `
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<h3
|
||||
className="text-left mt-3"
|
||||
>
|
||||
Sign In
|
||||
</h3>
|
||||
<div
|
||||
className="section-heading-line mb-4"
|
||||
>
|
||||
<h4>
|
||||
or sign in with
|
||||
</h4>
|
||||
</div>
|
||||
<form
|
||||
className="m-0"
|
||||
>
|
||||
<div
|
||||
className="form-group"
|
||||
>
|
||||
<h3
|
||||
className="text-center mt-3"
|
||||
>
|
||||
Sign In
|
||||
</h3>
|
||||
<div
|
||||
className="d-flex flex-column align-items-start"
|
||||
>
|
||||
@@ -223,17 +230,24 @@ exports[`LoginPage should match default section snapshot 1`] = `
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<h3
|
||||
className="text-left mt-3"
|
||||
>
|
||||
Sign In
|
||||
</h3>
|
||||
<div
|
||||
className="section-heading-line mb-4"
|
||||
>
|
||||
<h4>
|
||||
or sign in with
|
||||
</h4>
|
||||
</div>
|
||||
<form
|
||||
className="m-0"
|
||||
>
|
||||
<div
|
||||
className="form-group"
|
||||
>
|
||||
<h3
|
||||
className="text-center mt-3"
|
||||
>
|
||||
Sign In
|
||||
</h3>
|
||||
<div
|
||||
className="d-flex flex-column align-items-start"
|
||||
>
|
||||
@@ -387,17 +401,24 @@ exports[`LoginPage should match forget password alert message snapshot 1`] = `
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<h3
|
||||
className="text-left mt-3"
|
||||
>
|
||||
Sign In
|
||||
</h3>
|
||||
<div
|
||||
className="section-heading-line mb-4"
|
||||
>
|
||||
<h4>
|
||||
or sign in with
|
||||
</h4>
|
||||
</div>
|
||||
<form
|
||||
className="m-0"
|
||||
>
|
||||
<div
|
||||
className="form-group"
|
||||
>
|
||||
<h3
|
||||
className="text-center mt-3"
|
||||
>
|
||||
Sign In
|
||||
</h3>
|
||||
<div
|
||||
className="d-flex flex-column align-items-start"
|
||||
>
|
||||
@@ -574,17 +595,24 @@ exports[`LoginPage should show error message on 400 1`] = `
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<h3
|
||||
className="text-left mt-3"
|
||||
>
|
||||
Sign In
|
||||
</h3>
|
||||
<div
|
||||
className="section-heading-line mb-4"
|
||||
>
|
||||
<h4>
|
||||
or sign in with
|
||||
</h4>
|
||||
</div>
|
||||
<form
|
||||
className="m-0"
|
||||
>
|
||||
<div
|
||||
className="form-group"
|
||||
>
|
||||
<h3
|
||||
className="text-center mt-3"
|
||||
>
|
||||
Sign In
|
||||
</h3>
|
||||
<div
|
||||
className="d-flex flex-column align-items-start"
|
||||
>
|
||||
@@ -769,17 +797,24 @@ exports[`LoginPage should show error message on 400 on receiving link 1`] = `
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<h3
|
||||
className="text-left mt-3"
|
||||
>
|
||||
Sign In
|
||||
</h3>
|
||||
<div
|
||||
className="section-heading-line mb-4"
|
||||
>
|
||||
<h4>
|
||||
or sign in with
|
||||
</h4>
|
||||
</div>
|
||||
<form
|
||||
className="m-0"
|
||||
>
|
||||
<div
|
||||
className="form-group"
|
||||
>
|
||||
<h3
|
||||
className="text-center mt-3"
|
||||
>
|
||||
Sign In
|
||||
</h3>
|
||||
<div
|
||||
className="d-flex flex-column align-items-start"
|
||||
>
|
||||
|
||||
@@ -90,7 +90,7 @@ exports[`./RegistrationPage.js should match default section snapshot 1`] = `
|
||||
Google
|
||||
</button>
|
||||
<button
|
||||
className="btn-social microsoft"
|
||||
className="btn-social microsoft mb-3"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
@@ -1678,7 +1678,7 @@ exports[`./RegistrationPage.js should show error message on 409 1`] = `
|
||||
Google
|
||||
</button>
|
||||
<button
|
||||
className="btn-social microsoft"
|
||||
className="btn-social microsoft mb-3"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
|
||||
Reference in New Issue
Block a user