fix: render tpa pipeline error from django messages on mfe (#829)

VAN-1339

Co-authored-by: Syed Sajjad  Hussain Shah <syed.sajjad@H7FKF7K6XD.local>
This commit is contained in:
Syed Sajjad Hussain Shah
2023-04-10 12:36:40 +05:00
committed by GitHub
parent a2ab6c196a
commit 9d487d7b61
20 changed files with 233 additions and 88 deletions

View File

@@ -20,6 +20,7 @@ import { getTpaHint, getTpaProvider, updatePathWithQueryParams } from '../data/u
import { LoginPage } from '../login';
import { RegistrationPage } from '../register';
import { backupRegistrationForm } from '../register/data/actions';
import { clearThirdPartyAuthContextErrorMessage } from './data/actions';
import {
tpaProvidersSelector,
} from './data/selectors';
@@ -56,6 +57,7 @@ const Logistration = (props) => {
const handleOnSelect = (tabKey) => {
sendTrackEvent(`edx.bi.${tabKey.replace('/', '')}_form.toggled`, { category: 'user-engagement' });
props.clearThirdPartyAuthContextErrorMessage();
if (tabKey === LOGIN_PAGE) {
props.backupRegistrationForm();
}
@@ -135,6 +137,7 @@ const Logistration = (props) => {
Logistration.propTypes = {
selectedPage: PropTypes.string,
backupRegistrationForm: PropTypes.func.isRequired,
clearThirdPartyAuthContextErrorMessage: PropTypes.func.isRequired,
tpaProviders: PropTypes.shape({
providers: PropTypes.arrayOf(PropTypes.shape({})),
secondaryProviders: PropTypes.arrayOf(PropTypes.shape({})),
@@ -160,5 +163,6 @@ export default connect(
mapStateToProps,
{
backupRegistrationForm,
clearThirdPartyAuthContextErrorMessage,
},
)(Logistration);

View File

@@ -21,9 +21,6 @@ const RedirectLogistration = (props) => {
let finalRedirectUrl = '';
if (success) {
// After successful registeration remove the tpaHintedAuthentication flag from local storage if set
localStorage.removeItem('tpaHintedAuthentication');
// If we're in a third party auth pipeline, we must complete the pipeline
// once user has successfully logged in. Otherwise, redirect to the specified redirect url.
// Note: For multiple enterprise use case, we need to make sure that user first visits the

View File

@@ -13,13 +13,9 @@ const SocialAuthProviders = (props) => {
const { formatMessage } = useIntl();
const { referrer, socialAuthProviders } = props;
function handleSubmit(e, skipRegistrationForm) {
function handleSubmit(e) {
e.preventDefault();
if (skipRegistrationForm) {
localStorage.setItem('tpaHintedAuthentication', 'true');
}
const url = e.currentTarget.dataset.providerUrl;
window.location.href = getConfig().LMS_BASE_URL + url;
}
@@ -31,7 +27,7 @@ const SocialAuthProviders = (props) => {
type="button"
className={`btn-social btn-${provider.id} ${index % 2 === 0 ? 'mr-3' : ''}`}
data-provider-url={referrer === LOGIN_PAGE ? provider.loginUrl : provider.registerUrl}
onClick={(e) => handleSubmit(e, provider.skipRegistrationForm)}
onClick={handleSubmit}
>
{provider.iconImage ? (
<div aria-hidden="true">

View File

@@ -1,6 +1,7 @@
import { AsyncActionType } from '../../data/utils';
export const THIRD_PARTY_AUTH_CONTEXT = new AsyncActionType('THIRD_PARTY_AUTH', 'GET_THIRD_PARTY_AUTH_CONTEXT');
export const THIRD_PARTY_AUTH_CONTEXT_CLEAR_ERROR_MSG = 'THIRD_PARTY_AUTH_CONTEXT_CLEAR_ERROR_MSG';
// Third party auth context
export const getThirdPartyAuthContext = (urlParams) => ({
@@ -20,3 +21,7 @@ export const getThirdPartyAuthContextSuccess = (fieldDescriptions, optionalField
export const getThirdPartyAuthContextFailure = () => ({
type: THIRD_PARTY_AUTH_CONTEXT.FAILURE,
});
export const clearThirdPartyAuthContextErrorMessage = () => ({
type: THIRD_PARTY_AUTH_CONTEXT_CLEAR_ERROR_MSG,
});

View File

@@ -1,5 +1,5 @@
import { COMPLETE_STATE, PENDING_STATE } from '../../data/constants';
import { THIRD_PARTY_AUTH_CONTEXT } from './actions';
import { THIRD_PARTY_AUTH_CONTEXT, THIRD_PARTY_AUTH_CONTEXT_CLEAR_ERROR_MSG } from './actions';
export const defaultState = {
fieldDescriptions: {},
@@ -12,6 +12,7 @@ export const defaultState = {
providers: [],
secondaryProviders: [],
pipelineUserDetails: null,
errorMessage: null,
},
};
@@ -36,6 +37,15 @@ const reducer = (state = defaultState, action = {}) => {
...state,
thirdPartyAuthApiStatus: COMPLETE_STATE,
};
case THIRD_PARTY_AUTH_CONTEXT_CLEAR_ERROR_MSG:
return {
...state,
thirdPartyAuthApiStatus: PENDING_STATE,
thirdPartyAuthContext: {
...state.thirdPartyAuthContext,
errorMessage: null,
},
};
default:
return state;
}

View File

@@ -1,4 +1,5 @@
import { THIRD_PARTY_AUTH_CONTEXT } from '../actions';
import { PENDING_STATE } from '../../../data/constants';
import { THIRD_PARTY_AUTH_CONTEXT, THIRD_PARTY_AUTH_CONTEXT_CLEAR_ERROR_MSG } from '../actions';
import reducer from '../reducers';
describe('common components reducer', () => {
@@ -14,6 +15,7 @@ describe('common components reducer', () => {
providers: [],
secondaryProviders: [],
pipelineUserDetails: null,
errorMessage: null,
},
};
const fieldDescriptions = {
@@ -43,4 +45,38 @@ describe('common components reducer', () => {
},
);
});
it('should clear tpa context error message', () => {
const state = {
fieldDescriptions: {},
optionalFields: {},
thirdPartyAuthApiStatus: null,
thirdPartyAuthContext: {
currentProvider: null,
finishAuthUrl: null,
countryCode: null,
providers: [],
secondaryProviders: [],
pipelineUserDetails: null,
errorMessage: 'An error occured',
},
};
const action = {
type: THIRD_PARTY_AUTH_CONTEXT_CLEAR_ERROR_MSG,
};
expect(
reducer(state, action),
).toEqual(
{
...state,
thirdPartyAuthApiStatus: PENDING_STATE,
thirdPartyAuthContext: {
...state.thirdPartyAuthContext,
errorMessage: null,
},
},
);
});
});

View File

@@ -11,6 +11,7 @@ import configureStore from 'redux-mock-store';
import { COMPLETE_STATE, LOGIN_PAGE } from '../../data/constants';
import { backupRegistrationForm } from '../../register/data/actions';
import { clearThirdPartyAuthContextErrorMessage } from '../data/actions';
import { RenderInstitutionButton } from '../InstitutionLogistration';
import Logistration from '../Logistration';
@@ -245,14 +246,13 @@ describe('Logistration', () => {
expect(store.dispatch).toHaveBeenCalledWith(backupRegistrationForm());
});
it('should remove tpaHintedAuthentication from localStorage on registeration success', () => {
localStorage.setItem('tpaHintedAuthentication', 'true');
mergeConfig({
ALLOW_PUBLIC_ACCOUNT_CREATION: true,
});
it('should clear tpa context errorMessage tab click', () => {
store = mockStore({
login: {
loginResult: { success: false, redirectUrl: '' },
},
register: {
registrationResult: { success: true, redirectUrl: '' },
registrationResult: { success: false, redirectUrl: '' },
registrationError: {},
},
commonComponents: {
@@ -262,8 +262,10 @@ describe('Logistration', () => {
},
},
});
mount(reduxWrapper(<IntlLogistration />));
expect(localStorage.getItem('tpaHintedAuthentication')).toEqual(null);
store.dispatch = jest.fn(store.dispatch);
const logistration = mount(reduxWrapper(<IntlLogistration />));
logistration.find('a[data-rb-event-key="/login"]').simulate('click');
expect(store.dispatch).toHaveBeenCalledWith(clearThirdPartyAuthContextErrorMessage());
});
});

View File

@@ -1,7 +1,6 @@
import React from 'react';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { mount } from 'enzyme';
import renderer from 'react-test-renderer';
import registerIcons from '../RegisterFaIcons';
@@ -75,46 +74,4 @@ describe('SocialAuthProviders', () => {
expect(tree).toMatchSnapshot();
});
it('should set tpaHintedAuthentication in localStorage if skipRegistrationForm is true in provider', () => {
localStorage.clear();
props = {
socialAuthProviders: [{
...appleProvider,
iconClass: 'default',
iconImage: null,
skipRegistrationForm: true,
}],
};
const tree = mount(
<IntlProvider locale="en">
<SocialAuthProviders {...props} />
</IntlProvider>,
);
tree.find(`button#${appleProvider.id}`).simulate('click');
expect(localStorage.getItem('tpaHintedAuthentication')).toEqual('true');
});
it('should not set tpaHintedAuthentication in localStorage if skipRegistrationForm is false in provider', () => {
localStorage.clear();
props = {
socialAuthProviders: [{
...appleProvider,
iconClass: 'default',
iconImage: null,
skipRegistrationForm: false,
}],
};
const tree = mount(
<IntlProvider locale="en">
<SocialAuthProviders {...props} />
</IntlProvider>,
);
tree.find(`button#${appleProvider.id}`).simulate('click');
expect(localStorage.getItem('tpaHintedAuthentication')).toEqual(null);
});
});

View File

@@ -20,12 +20,14 @@ import {
NON_COMPLIANT_PASSWORD_EXCEPTION,
NUDGE_PASSWORD_CHANGE,
REQUIRE_PASSWORD_CHANGE,
TPA_AUTHENTICATION_FAILURE,
} from './data/constants';
import messages from './messages';
const LoginFailureMessage = (props) => {
const { formatMessage } = useIntl();
const { context, errorCode } = props.loginError;
const authService = getAuthService();
let errorList;
let resetLink = (
@@ -165,6 +167,16 @@ const LoginFailureMessage = (props) => {
);
case REQUIRE_PASSWORD_CHANGE:
return <ChangePasswordPrompt />;
case TPA_AUTHENTICATION_FAILURE:
errorList = (
<p>{formatMessage(messages['login.tpa.authentication.failure'], {
platform_name: getConfig().SITE_NAME,
lineBreak: <br />,
errorMessage: context.errorMessage,
})}
</p>
);
break;
case INTERNAL_SERVER_ERROR:
default:
errorList = <p>{formatMessage(messages['internal.server.error.message'])}</p>;
@@ -183,6 +195,7 @@ LoginFailureMessage.defaultProps = {
loginError: {
redirectUrl: null,
errorCode: null,
errorMessage: null,
},
};
@@ -196,6 +209,7 @@ LoginFailureMessage.propTypes = {
allowedDomain: PropTypes.string,
remainingAttempts: PropTypes.number,
failureCount: PropTypes.number,
errorMessage: PropTypes.string,
}),
email: PropTypes.string,
errorCode: PropTypes.string,

View File

@@ -37,7 +37,7 @@ import AccountActivationMessage from './AccountActivationMessage';
import {
loginRemovePasswordResetBanner, loginRequest, loginRequestFailure, loginRequestReset, setLoginFormData,
} from './data/actions';
import { INVALID_FORM } from './data/constants';
import { INVALID_FORM, TPA_AUTHENTICATION_FAILURE } from './data/constants';
import { loginErrorSelector, loginFormDataSelector, loginRequestSelector } from './data/selectors';
import LoginFailureMessage from './LoginFailure';
import messages from './messages';
@@ -223,7 +223,13 @@ class LoginPage extends React.Component {
/>
);
}
const tpaAuthenticationError = {};
if (thirdPartyAuthContext.errorMessage) {
tpaAuthenticationError.context = {
errorMessage: thirdPartyAuthContext.errorMessage,
};
tpaAuthenticationError.errorCode = TPA_AUTHENTICATION_FAILURE;
}
if (this.props.loginResult.success) {
setSurveyCookie('login');
@@ -253,6 +259,7 @@ class LoginPage extends React.Component {
platformName={thirdPartyAuthContext.platformName}
/>
{this.props.loginError ? <LoginFailureMessage loginError={this.props.loginError} /> : null}
{thirdPartyAuthContext.errorMessage ? <LoginFailureMessage loginError={tpaAuthenticationError} /> : null}
{submitState === DEFAULT_STATE && this.state.isSubmitted ? windowScrollTo({ left: 0, top: 0, behavior: 'smooth' }) : null}
{activationMsgType && <AccountActivationMessage messageType={activationMsgType} />}
{this.props.resetPassword && !this.props.loginError ? <ResetPasswordSuccess /> : null}
@@ -361,6 +368,7 @@ LoginPage.defaultProps = {
thirdPartyAuthApiStatus: 'pending',
thirdPartyAuthContext: {
currentProvider: null,
errorMessage: null,
finishAuthUrl: null,
providers: [],
secondaryProviders: [],
@@ -395,6 +403,7 @@ LoginPage.propTypes = {
thirdPartyAuthApiStatus: PropTypes.string,
thirdPartyAuthContext: PropTypes.shape({
currentProvider: PropTypes.string,
errorMessage: PropTypes.string,
platformName: PropTypes.string,
providers: PropTypes.arrayOf(PropTypes.shape({})),
secondaryProviders: PropTypes.arrayOf(PropTypes.shape({})),

View File

@@ -10,6 +10,7 @@ export const INCORRECT_EMAIL_PASSWORD = 'incorrect-email-or-password';
export const NUDGE_PASSWORD_CHANGE = 'nudge-password-change';
export const REQUIRE_PASSWORD_CHANGE = 'require-password-change';
export const ALLOWED_DOMAIN_LOGIN_ERROR = 'allowed-domain-login-error';
export const TPA_AUTHENTICATION_FAILURE = 'tpa-authentication-failure';
// Account Activation Message
export const ACCOUNT_ACTIVATION_MESSAGE = {

View File

@@ -209,6 +209,13 @@ const messages = defineMessages({
defaultMessage: 'Reset your password',
description: 'Button to redirect users to Reset Password page',
},
'login.tpa.authentication.failure': {
id: 'login.tpa.authentication.failure',
defaultMessage: 'We are sorry, you are not authorized to access {platform_name} via this channel. '
+ 'Please contact your learning administrator or manager in order to access {platform_name}.'
+ '{lineBreak}{lineBreak}Error Details:{lineBreak}{errorMessage}',
description: 'Error message third party authentication pipeline fails',
},
});
export default messages;

View File

@@ -16,6 +16,7 @@ import {
NON_COMPLIANT_PASSWORD_EXCEPTION,
NUDGE_PASSWORD_CHANGE,
REQUIRE_PASSWORD_CHANGE,
TPA_AUTHENTICATION_FAILURE,
} from '../data/constants';
import LoginFailureMessage from '../LoginFailure';
@@ -219,6 +220,28 @@ describe('LoginFailureMessage', () => {
expect(loginFailureMessage.find('#login-failure-alert').first().text()).toEqual(expectedMessage);
});
it('should match tpa authentication failed error message', () => {
props = {
loginError: {
errorCode: TPA_AUTHENTICATION_FAILURE,
context: {
errorMessage: 'An error occured',
},
},
};
const loginFailureMessage = mount(
<IntlProvider locale="en">
<IntlLoginFailureMessage {...props} />
</IntlProvider>,
);
const expectedMessageSubstring = 'We are sorry, you are not authorized to access';
expect(loginFailureMessage.find('#login-failure-alert').first().text()).toContain(expectedMessageSubstring);
expect(loginFailureMessage.find('#login-failure-alert').first().text()).toContain('An error occured');
});
it('should show modal that nudges users to change password', () => {
props = {
loginError: {

View File

@@ -441,6 +441,23 @@ describe('LoginPage', () => {
expect(loginPage.find('#tpa-alert').find('p').text()).toEqual(expectedMessage);
});
it('should show tpa authentication fails error message', () => {
store = mockStore({
...initialState,
commonComponents: {
...initialState.commonComponents,
thirdPartyAuthContext: {
...initialState.commonComponents.thirdPartyAuthContext,
currentProvider: null,
errorMessage: 'An error occured',
},
},
});
const loginPage = mount(reduxWrapper(<IntlLoginPage {...props} />));
expect(loginPage.find('#login-failure-alert').find('p').text()).toContain('An error occured');
});
it('should match invalid login form error message', () => {
const errorMessage = 'Please fill in the fields below.';
store = mockStore({

View File

@@ -1,12 +1,18 @@
import React, { useEffect } from 'react';
import { getConfig } from '@edx/frontend-platform';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Alert } from '@edx/paragon';
import { Error } from '@edx/paragon/icons';
import PropTypes from 'prop-types';
import { windowScrollTo } from '../data/utils';
import { FORBIDDEN_REQUEST, INTERNAL_SERVER_ERROR, TPA_SESSION_EXPIRED } from './data/constants';
import {
FORBIDDEN_REQUEST,
INTERNAL_SERVER_ERROR,
TPA_AUTHENTICATION_FAILURE,
TPA_SESSION_EXPIRED,
} from './data/constants';
import messages from './messages';
const RegistrationFailureMessage = (props) => {
@@ -31,6 +37,14 @@ const RegistrationFailureMessage = (props) => {
case FORBIDDEN_REQUEST:
errorMessage = formatMessage(messages['registration.rate.limit.error']);
break;
case TPA_AUTHENTICATION_FAILURE:
errorMessage = formatMessage(messages['registration.tpa.authentication.failure'],
{
platform_name: getConfig().SITE_NAME,
lineBreak: <br />,
errorMessage: context.errorMessage,
});
break;
case TPA_SESSION_EXPIRED:
errorMessage = formatMessage(messages['registration.tpa.session.expired'], { provider: context.provider });
break;
@@ -48,12 +62,15 @@ const RegistrationFailureMessage = (props) => {
};
RegistrationFailureMessage.defaultProps = {
context: {},
context: {
errorMessage: null,
},
};
RegistrationFailureMessage.propTypes = {
context: PropTypes.shape({
provider: PropTypes.string,
errorMessage: PropTypes.string,
}),
errorCode: PropTypes.string.isRequired,
failureCount: PropTypes.number.isRequired,

View File

@@ -22,6 +22,7 @@ import {
} from '../common-components/data/selectors';
import EnterpriseSSO from '../common-components/EnterpriseSSO';
import {
COMPLETE_STATE,
DEFAULT_STATE, INVALID_NAME_REGEX, LETTER_REGEX, NUMBER_REGEX, PENDING_STATE, REGISTER_PAGE, VALID_EMAIL_REGEX,
} from '../data/constants';
import {
@@ -41,10 +42,11 @@ import {
COUNTRY_DISPLAY_KEY,
FIELDS,
FORM_SUBMISSION_ERROR,
TPA_AUTHENTICATION_FAILURE,
} from './data/constants';
import { registrationErrorSelector, validationsSelector } from './data/selectors';
import {
getSuggestionForInvalidEmail, isTpaHintedAuthentication, validateCountryField, validateEmailAddress,
getSuggestionForInvalidEmail, validateCountryField, validateEmailAddress,
} from './data/utils';
import messages from './messages';
import RegistrationFailure from './RegistrationFailure';
@@ -95,7 +97,7 @@ const RegistrationPage = (props) => {
const [configurableFormFields, setConfigurableFormFields] = useState({ ...backedUpFormData.configurableFormFields });
const [errors, setErrors] = useState({ ...backedUpFormData.errors });
const [emailSuggestion, setEmailSuggestion] = useState({ ...backedUpFormData.emailSuggestion });
const [autoSubmitRegisterForm, setAutoSubmitRegisterForm] = useState(isTpaHintedAuthentication());
const [autoSubmitRegisterForm, setAutoSubmitRegisterForm] = useState(false);
const [errorCode, setErrorCode] = useState({ type: '', count: 0 });
const [formStartTime, setFormStartTime] = useState(null);
const [focusedField, setFocusedField] = useState(null);
@@ -127,13 +129,13 @@ const RegistrationPage = (props) => {
* Set the userPipelineDetails data in formFields for only first time
*/
useEffect(() => {
if (!userPipelineDataLoaded) {
if (!userPipelineDataLoaded && thirdPartyAuthApiStatus === COMPLETE_STATE) {
const { autoSubmitRegForm, pipelineUserDetails, errorMessage } = thirdPartyAuthContext;
if (errorMessage) {
localStorage.removeItem('tpaHintedAuthentication');
setAutoSubmitRegisterForm(false);
setErrorCode(prevState => ({ type: TPA_AUTHENTICATION_FAILURE, count: prevState.count + 1 }));
} else if (autoSubmitRegForm) {
checkTOSandHonorCodeFields();
setAutoSubmitRegisterForm(true);
}
if (pipelineUserDetails && Object.keys(pipelineUserDetails).length !== 0) {
const { name = '', username = '', email = '' } = pipelineUserDetails;
@@ -538,7 +540,7 @@ const RegistrationPage = (props) => {
<RegistrationFailure
errorCode={errorCode.type}
failureCount={errorCode.count}
context={{ provider: currentProvider }}
context={{ provider: currentProvider, errorMessage: thirdPartyAuthContext.errorMessage }}
/>
<Form id="registration-form" name="registration-form">
<FormGroup

View File

@@ -9,6 +9,7 @@ export const FIELDS = {
export const FORBIDDEN_REQUEST = 'forbidden-request';
export const FORM_SUBMISSION_ERROR = 'form-submission-error';
export const INTERNAL_SERVER_ERROR = 'internal-server-error';
export const TPA_AUTHENTICATION_FAILURE = 'tpa-authentication-failure';
export const TPA_SESSION_EXPIRED = 'tpa-session-expired';
export const YEAR_OF_BIRTH_OPTIONS = (() => {

View File

@@ -111,5 +111,3 @@ export function validateCountryField(value, countryList, errorMessage) {
}
return { error, countryCode, displayValue };
}
export const isTpaHintedAuthentication = () => localStorage.getItem('tpaHintedAuthentication') === 'true';

View File

@@ -162,6 +162,13 @@ const messages = defineMessages({
defaultMessage: 'Registration using {provider} has timed out.',
description: '',
},
'registration.tpa.authentication.failure': {
id: 'registration.tpa.authentication.failure',
defaultMessage: 'We are sorry, you are not authorized to access {platform_name} via this channel. '
+ 'Please contact your learning administrator or manager in order to access {platform_name}.'
+ '{lineBreak}{lineBreak}Error Details:{lineBreak}{errorMessage}',
description: 'Error message third party authentication pipeline fails',
},
// Terms of Service and Honor Code
'terms.of.service.and.honor.code': {
id: 'terms.of.service.and.honor.code',

View File

@@ -22,9 +22,8 @@ import {
setUserPipelineDataLoaded,
} from '../data/actions';
import {
FIELDS, FORBIDDEN_REQUEST, INTERNAL_SERVER_ERROR, TPA_SESSION_EXPIRED,
FIELDS, FORBIDDEN_REQUEST, INTERNAL_SERVER_ERROR, TPA_AUTHENTICATION_FAILURE, TPA_SESSION_EXPIRED,
} from '../data/constants';
import * as utils from '../data/utils';
import RegistrationFailureMessage from '../RegistrationFailure';
import RegistrationPage from '../RegistrationPage';
@@ -482,6 +481,21 @@ describe('RegistrationPage', () => {
expect(registrationPage.find('div.alert').first().text()).toEqual(expectedMessage);
});
it('should match tpa authentication failed error message', () => {
const expectedMessageSubstring = 'We are sorry, you are not authorized to access';
props = {
context: {
provider: 'Google',
},
errorCode: TPA_AUTHENTICATION_FAILURE,
failureCount: 0,
};
const registrationPage = mount(reduxWrapper(<IntlRegistrationFailure {...props} />));
expect(registrationPage.find('div.alert-heading').length).toEqual(1);
expect(registrationPage.find('div.alert').first().text()).toContain(expectedMessageSubstring);
});
// ******** test form buttons and fields ********
it('should match default button state', () => {
@@ -876,6 +890,7 @@ describe('RegistrationPage', () => {
},
commonComponents: {
...initialState.commonComponents,
thirdPartyAuthApiStatus: COMPLETE_STATE,
thirdPartyAuthContext: {
...initialState.commonComponents.thirdPartyAuthContext,
pipelineUserDetails: {
@@ -1134,8 +1149,15 @@ describe('RegistrationPage', () => {
getLocale.mockImplementation(() => ('en-us'));
store = mockStore({
...initialState,
register: { // setting register to display form for testing TOS and honor code value.
...initialState.register,
registrationError: {
errorCode: 'register-error',
},
},
commonComponents: {
...initialState.commonComponents,
thirdPartyAuthApiStatus: COMPLETE_STATE,
thirdPartyAuthContext: {
...initialState.commonComponents.thirdPartyAuthContext,
pipelineUserDetails: {
@@ -1164,17 +1186,6 @@ describe('RegistrationPage', () => {
expect(registrationPage.find('input#honor-code').props().value).toEqual(true);
});
it('should set autoSubmitRegisterForm true if isTpaHintedAuthentication returns true', () => {
jest.spyOn(global.Date, 'now').mockImplementation(() => 0);
getLocale.mockImplementation(() => ('en-us'));
utils.isTpaHintedAuthentication = jest.fn().mockImplementation(() => true);
store.dispatch = jest.fn(store.dispatch);
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registrationPage.find('#tpa-spinner').exists()).toBeTruthy();
});
it('should show spinner instead of form while registering if autoSubmitRegForm is true', () => {
jest.spyOn(global.Date, 'now').mockImplementation(() => 0);
getLocale.mockImplementation(() => ('en-us'));
@@ -1188,6 +1199,7 @@ describe('RegistrationPage', () => {
},
commonComponents: {
...initialState.commonComponents,
thirdPartyAuthApiStatus: COMPLETE_STATE,
thirdPartyAuthContext: {
...initialState.commonComponents.thirdPartyAuthContext,
currentProvider: ssoProvider.name,
@@ -1220,6 +1232,7 @@ describe('RegistrationPage', () => {
},
commonComponents: {
...initialState.commonComponents,
thirdPartyAuthApiStatus: COMPLETE_STATE,
thirdPartyAuthContext: {
...initialState.commonComponents.thirdPartyAuthContext,
currentProvider: ssoProvider.name,
@@ -1234,7 +1247,36 @@ describe('RegistrationPage', () => {
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registrationPage.find('#tpa-spinner').exists()).toBeFalsy();
expect(registrationPage.find('#registration-form').exists()).toBeTruthy();
expect(localStorage.getItem('tpaHintedAuthentication')).toEqual(null);
});
it('should display errorMessage if third party authentication fails', () => {
jest.spyOn(global.Date, 'now').mockImplementation(() => 0);
getLocale.mockImplementation(() => ('en-us'));
store = mockStore({
...initialState,
register: {
...initialState.register,
backendCountryCode: 'PK',
userPipelineDataLoaded: false,
},
commonComponents: {
...initialState.commonComponents,
thirdPartyAuthApiStatus: COMPLETE_STATE,
thirdPartyAuthContext: {
...initialState.commonComponents.thirdPartyAuthContext,
currentProvider: null,
pipelineUserDetails: {},
errorMessage: 'An error occured',
},
},
});
store.dispatch = jest.fn(store.dispatch);
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registrationPage.find('div.alert-heading').length).toEqual(1);
expect(registrationPage.find('div.alert').first().text()).toContain('An error occured');
});
});
});