logistration folder refactored to login and register

This commit is contained in:
adeelehsan
2021-01-21 02:28:53 +05:00
parent 5b58986b71
commit ad2ee9e013
64 changed files with 1025 additions and 1046 deletions

View File

@@ -0,0 +1,49 @@
import React from 'react';
import PropTypes from 'prop-types';
import { getConfig } from '@edx/frontend-platform';
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Alert } from '@edx/paragon';
import messages from './messages';
const ConfirmationAlert = (props) => {
const { email, intl } = props;
return (
<Alert id="confirmation-alert" variant="success">
<Alert.Heading>{intl.formatMessage(messages['forgot.password.confirmation.title'])}</Alert.Heading>
<p>
<FormattedMessage
id="logistration.forgot.password.confirmation.message"
defaultMessage="You entered {strongEmail}. If this email address is associated with your
edX account, we will send a message with password recovery instructions to this email address."
description="Forgot password confirmation message"
values={{ strongEmail: <strong>{email}</strong> }}
/>
</p>
<p>{intl.formatMessage(messages['forgot.password.confirmation.info'])}</p>
<p>
<FormattedMessage
id="forgot.password.technical.support.help.message"
defaultMessage="If you need further assistance, {technicalSupportLink}."
description="Message to help user contact technical support"
values={{
technicalSupportLink: (
<Alert.Link href={getConfig().PASSWORD_RESET_SUPPORT_LINK}>
{intl.formatMessage(messages['forgot.password.confirmation.support.link'])}
</Alert.Link>
),
}}
/>
</p>
</Alert>
);
};
ConfirmationAlert.propTypes = {
email: PropTypes.string.isRequired,
intl: intlShape.isRequired,
};
export default injectIntl(ConfirmationAlert);

View File

@@ -0,0 +1,99 @@
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, Hyperlink } 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="mt-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 m-4">
<div className="flex-column">
<h1 className="mt-5 mb-4 font-weight-normal">
{headingTitle}
</h1>
<p className="mb-2">
{intl.formatMessage(messages['institution.login.page.sub.heading'])}
</p>
<div className="mb-2 ml-2">
<ul>
{secondaryProviders.map(provider => (
<li key={provider}>
<Hyperlink destination={lmsBaseUrl + provider.loginUrl}>{provider.name}</Hyperlink>
</li>
))}
</ul>
</div>
<div className="mb-4">
<h4>or</h4>
</div>
<Button
variant="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);

View File

@@ -0,0 +1,71 @@
import React from 'react';
import PropTypes from 'prop-types';
import { getConfig } from '@edx/frontend-platform';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSignInAlt } from '@fortawesome/free-solid-svg-icons';
import { LOGIN_PAGE, SUPPORTED_ICON_CLASSES } from '../data/constants';
function SocialAuthProviders(props) {
const { referrer, socialAuthProviders } = props;
function handleSubmit(e) {
e.preventDefault();
const url = e.currentTarget.dataset.providerUrl;
window.location.href = getConfig().LMS_BASE_URL + url;
}
const socialAuth = socialAuthProviders.map((provider) => (
<button
id={provider.id}
key={provider.id}
type="button"
className={`btn-social btn-${provider.id}`}
data-provider-url={referrer === LOGIN_PAGE ? provider.loginUrl : provider.registerUrl}
onClick={handleSubmit}
>
{provider.iconImage ? (
<>
<div aria-hidden="true">
<img className="icon-image" src={provider.iconImage} alt={`icon ${provider.name}`} />
</div>
<span className="pl-2" aria-hidden="true">{provider.name}</span>
</>
)
: (
<>
<div className="font-container" aria-hidden="true">
<FontAwesomeIcon
icon={SUPPORTED_ICON_CLASSES.includes(provider.iconClass) ? ['fab', provider.iconClass] : faSignInAlt}
/>
</div>
<span className="pl-2 provider-name" aria-hidden="true">{provider.name}</span>
</>
)}
</button>
));
return <>{socialAuth}</>;
}
SocialAuthProviders.defaultProps = {
referrer: LOGIN_PAGE,
socialAuthProviders: [],
};
SocialAuthProviders.propTypes = {
referrer: PropTypes.string,
socialAuthProviders: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.string,
name: PropTypes.string,
iconClass: PropTypes.string,
iconImage: PropTypes.string,
loginUrl: PropTypes.string,
registerUrl: PropTypes.string,
})),
};
export default SocialAuthProviders;

View File

@@ -0,0 +1,61 @@
import React from 'react';
import PropTypes from 'prop-types';
import { TransitionReplace } from '@edx/paragon';
const onChildExit = (htmlNode) => {
// If the leaving child has focus, take control and redirect it
if (htmlNode.contains(document.activeElement)) {
// Get the newly entering sibling.
// It's the previousSibling, but not for any explicit reason. So checking for both.
const enteringChild = htmlNode.previousSibling || htmlNode.nextSibling;
// There's no replacement, do nothing.
if (!enteringChild) return; // eslint-disable-line curly
// Get all the focusable elements in the entering child and focus the first one
const focusableElements = enteringChild.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
if (focusableElements.length) {
focusableElements[0].focus();
}
}
};
function SwitchContent({ expression, cases, className }) {
const getContent = (caseKey) => {
if (cases[caseKey]) {
if (typeof cases[caseKey] === 'string') {
return getContent(cases[caseKey]);
}
return React.cloneElement(cases[caseKey], { key: caseKey });
} else if (cases.default) { // eslint-disable-line no-else-return
if (typeof cases.default === 'string') {
return getContent(cases.default);
}
React.cloneElement(cases.default, { key: 'default' });
}
return null;
};
return (
<TransitionReplace
className={className}
onChildExit={onChildExit}
>
{getContent(expression)}
</TransitionReplace>
);
}
SwitchContent.propTypes = {
expression: PropTypes.string,
cases: PropTypes.objectOf(PropTypes.node).isRequired,
className: PropTypes.string,
};
SwitchContent.defaultProps = {
expression: null,
className: null,
};
export default SwitchContent;

View File

@@ -0,0 +1,45 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { Alert } from '@edx/paragon';
import { LOGIN_PAGE } from '../data/constants';
const ThirdPartyAuthAlert = (props) => {
const { currentProvider, referrer, platformName } = props;
let message;
if (referrer === LOGIN_PAGE) {
message = (
<FormattedMessage
id="login.third.party.auth.account.not.linked.message"
defaultMessage="You have successfully signed into {currentProvider}, but your {currentProvider} account does not have a linked {platformName} account. To link your accounts, sign in now using your {platformName} password."
description="Message that appears on login page if user has successfully authenticated with TPA but no associated platform account exists"
values={{ currentProvider, platformName }}
/>
);
} else {
message = (
<FormattedMessage
id="register.third.party.auth.account.not.linked.message"
defaultMessage="You've successfully signed into {currentProvider}. We just need a little more information before you start learning with {platformName}."
description="Message that appears on register page if user has successfully authenticated with TPA but no associated platform account exists"
values={{ currentProvider, platformName }}
/>
);
}
return <Alert id="tpa-alert" className="alert-warning mt-n2">{ message }</Alert>;
};
ThirdPartyAuthAlert.defaultProps = {
referrer: LOGIN_PAGE,
};
ThirdPartyAuthAlert.propTypes = {
currentProvider: PropTypes.string.isRequired,
platformName: PropTypes.string.isRequired,
referrer: PropTypes.string,
};
export default ThirdPartyAuthAlert;

View File

@@ -0,0 +1,22 @@
import { AsyncActionType } from '../../data/utils';
export const THIRD_PARTY_AUTH_CONTEXT = new AsyncActionType('THIRD_PARTY_AUTH', 'GET_THIRD_PARTY_AUTH_CONTEXT');
// Third party auth context
export const getThirdPartyAuthContext = (urlParams) => ({
type: THIRD_PARTY_AUTH_CONTEXT.BASE,
payload: { urlParams },
});
export const getThirdPartyAuthContextBegin = () => ({
type: THIRD_PARTY_AUTH_CONTEXT.BEGIN,
});
export const getThirdPartyAuthContextSuccess = (thirdPartyAuthContext) => ({
type: THIRD_PARTY_AUTH_CONTEXT.SUCCESS,
payload: { thirdPartyAuthContext },
});
export const getThirdPartyAuthContextFailure = () => ({
type: THIRD_PARTY_AUTH_CONTEXT.FAILURE,
});

View File

@@ -0,0 +1,32 @@
import { THIRD_PARTY_AUTH_CONTEXT } from './actions';
import { PENDING_STATE, COMPLETE_STATE } from '../../data/constants';
export const defaultState = {
thirdPartyAuthApiStatus: null,
};
const reducer = (state = defaultState, action) => {
switch (action.type) {
case THIRD_PARTY_AUTH_CONTEXT.BEGIN:
return {
...state,
thirdPartyAuthApiStatus: PENDING_STATE,
};
case THIRD_PARTY_AUTH_CONTEXT.SUCCESS:
return {
...state,
thirdPartyAuthContext: action.payload.thirdPartyAuthContext,
thirdPartyAuthApiStatus: COMPLETE_STATE,
};
case THIRD_PARTY_AUTH_CONTEXT.FAILURE:
return {
...state,
thirdPartyAuthApiStatus: COMPLETE_STATE,
};
default:
return state;
}
};
export default reducer;

View File

@@ -0,0 +1,34 @@
import { call, put, takeEvery } from 'redux-saga/effects';
import { logError } from '@edx/frontend-platform/logging';
// Actions
import {
THIRD_PARTY_AUTH_CONTEXT,
getThirdPartyAuthContextBegin,
getThirdPartyAuthContextSuccess,
getThirdPartyAuthContextFailure,
} from './actions';
// Services
import {
getThirdPartyAuthContext,
} from './service';
export function* fetchThirdPartyAuthContext(action) {
try {
yield put(getThirdPartyAuthContextBegin());
const { thirdPartyAuthContext } = yield call(getThirdPartyAuthContext, action.payload.urlParams);
yield put(getThirdPartyAuthContextSuccess(
thirdPartyAuthContext,
));
} catch (e) {
yield put(getThirdPartyAuthContextFailure());
logError(e);
}
}
export default function* saga() {
yield takeEvery(THIRD_PARTY_AUTH_CONTEXT.BASE, fetchThirdPartyAuthContext);
}

View File

@@ -0,0 +1,10 @@
import { createSelector } from 'reselect';
export const storeName = 'commonComponents';
export const commonComponentsSelector = state => ({ ...state[storeName] });
export const thirdPartyAuthContextSelector = createSelector(
commonComponentsSelector,
commonComponents => commonComponents.thirdPartyAuthContext,
);

View File

@@ -0,0 +1,23 @@
import { camelCaseObject, convertKeyNames, getConfig } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
// eslint-disable-next-line import/prefer-default-export
export async function getThirdPartyAuthContext(urlParams) {
const requestConfig = {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
params: urlParams,
isPublic: true,
};
const { data } = await getAuthenticatedHttpClient()
.get(
`${getConfig().LMS_BASE_URL}/api/third_party_auth_context`,
requestConfig,
)
.catch((e) => {
throw (e);
});
return {
thirdPartyAuthContext: camelCaseObject(convertKeyNames(data, { fullname: 'name' })),
};
}

View File

@@ -0,0 +1,65 @@
import { runSaga } from 'redux-saga';
import * as actions from '../actions';
import { fetchThirdPartyAuthContext } from '../sagas';
import * as api from '../service';
import initializeMockLogging from '../../../setupTest';
const { loggingService } = initializeMockLogging();
describe('fetchThirdPartyAuthContext', () => {
const params = {
payload: { urlParams: {} },
};
const data = {
currentProvider: null,
providers: [],
secondaryProviders: [],
finishAuthUrl: null,
pipelineUserDetails: {},
};
beforeEach(() => {
loggingService.logError.mockReset();
});
it('should call service and dispatch success action', async () => {
const getThirdPartyAuthContext = jest.spyOn(api, 'getThirdPartyAuthContext')
.mockImplementation(() => Promise.resolve({ thirdPartyAuthContext: data }));
const dispatched = [];
await runSaga(
{ dispatch: (action) => dispatched.push(action) },
fetchThirdPartyAuthContext,
params,
);
expect(getThirdPartyAuthContext).toHaveBeenCalledTimes(1);
expect(dispatched).toEqual([
actions.getThirdPartyAuthContextBegin(),
actions.getThirdPartyAuthContextSuccess(data),
]);
getThirdPartyAuthContext.mockClear();
});
it('should call service and dispatch error action', async () => {
const getThirdPartyAuthContext = jest.spyOn(api, 'getThirdPartyAuthContext')
.mockImplementation(() => Promise.reject(new Error('something went wrong')));
const dispatched = [];
await runSaga(
{ dispatch: (action) => dispatched.push(action) },
fetchThirdPartyAuthContext,
params,
);
expect(getThirdPartyAuthContext).toHaveBeenCalledTimes(1);
expect(loggingService.logError).toHaveBeenCalled();
expect(dispatched).toEqual([
actions.getThirdPartyAuthContextBegin(),
actions.getThirdPartyAuthContextFailure(),
]);
getThirdPartyAuthContext.mockClear();
});
});

View File

@@ -3,3 +3,10 @@ export { default as RedirectLogistration } from './RedirectLogistration';
export { default as registerIcons } from './RegisterFaIcons';
export { default as UnAuthOnlyRoute } from './UnAuthOnlyRoute';
export { default as NotFoundPage } from './NotFoundPage';
export { default as SocialAuthProviders } from './SocialAuthProviders';
export { default as ThirdPartyAuthAlert } from './ThirdPartyAuthAlert';
export { default as InstitutionLogistration } from './InstitutionLogistration';
export { RenderInstitutionButton } from './InstitutionLogistration';
export { default as reducer } from './data/reducers';
export { default as saga } from './data/sagas';
export { storeName } from './data/selectors';

View File

@@ -0,0 +1,28 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
'institution.login.page.sub.heading': {
id: 'institution.login.page.sub.heading',
defaultMessage: 'Choose your institution from the list below:',
description: 'Heading of the institutions list',
},
// Confirmation Alert Message
'forgot.password.confirmation.title': {
id: 'forgot.password.confirmation.title',
defaultMessage: 'Check Your Email',
description: 'Forgot password confirmation message title',
},
'forgot.password.confirmation.support.link': {
id: 'forgot.password.confirmation.support.link',
defaultMessage: 'contact technical support',
description: 'Technical support link text',
},
'forgot.password.confirmation.info': {
id: 'forgot.password.confirmation.info',
defaultMessage: 'If you do not receive a password reset message after 1 minute, verify that you entered the correct '
+ 'email address, or check your spam folder.',
description: 'Part of message that appears after user requests password change',
},
});
export default messages;

View File

@@ -0,0 +1,34 @@
import React from 'react';
import { mount } from 'enzyme';
import { mergeConfig } from '@edx/frontend-platform';
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import ConfirmationAlert from '../ConfirmationAlert';
const IntlConfirmationAlertMessage = injectIntl(ConfirmationAlert);
describe('ConfirmationAlert', () => {
const supportLink = 'https://support.test.com/What-if-I-did-not-receive-a-password-reset-message';
mergeConfig({
PASSWORD_RESET_SUPPORT_LINK: supportLink,
});
it('should match default confirmation message', () => {
const confirmationAlertMessage = mount(
<IntlProvider locale="en">
<IntlConfirmationAlertMessage email="test@example.com" />
</IntlProvider>,
);
const expectedMessage = 'Check Your Email'
+ 'You entered test@example.com. If this email address is associated with your edX account, '
+ 'we will send a message with password recovery instructions to this email address.'
+ 'If you do not receive a password reset message after 1 minute, verify that you entered '
+ 'the correct email address, or check your spam folder.'
+ 'If you need further assistance, contact technical support.';
expect(confirmationAlertMessage.find('#confirmation-alert').first().text()).toEqual(expectedMessage);
expect(confirmationAlertMessage.find('#confirmation-alert').find('a').props().href).toEqual(supportLink);
});
});

View File

@@ -0,0 +1,68 @@
import React from 'react';
import renderer from 'react-test-renderer';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import SocialAuthProviders from '../SocialAuthProviders';
import registerIcons from '../RegisterFaIcons';
registerIcons();
describe('SocialAuthProviders', () => {
let props = {};
const appleProvider = {
id: 'oa2-apple-id',
name: 'Apple',
iconClass: null,
iconImage: 'https://edx.devstack.lms/logo.png',
loginUrl: '/auth/login/apple-id/?auth_entry=login&next=/dashboard',
};
it('should match social auth provider with iconImage snapshot', () => {
props = { socialAuthProviders: [appleProvider] };
const tree = renderer.create(
<IntlProvider locale="en">
<SocialAuthProviders {...props} />
</IntlProvider>,
).toJSON();
expect(tree).toMatchSnapshot();
});
it('should match social auth provider with iconClass snapshot', () => {
props = {
socialAuthProviders: [{
...appleProvider,
iconClass: 'google',
iconImage: null,
}],
};
const tree = renderer.create(
<IntlProvider locale="en">
<SocialAuthProviders {...props} />
</IntlProvider>,
).toJSON();
expect(tree).toMatchSnapshot();
});
it('should match social auth provider with default icon snapshot', () => {
props = {
socialAuthProviders: [{
...appleProvider,
iconClass: 'default',
iconImage: null,
}],
};
const tree = renderer.create(
<IntlProvider locale="en">
<SocialAuthProviders {...props} />
</IntlProvider>,
).toJSON();
expect(tree).toMatchSnapshot();
});
});

View File

@@ -0,0 +1,39 @@
import React from 'react';
import renderer from 'react-test-renderer';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import ThirdPartyAuthAlert from '../ThirdPartyAuthAlert';
describe('ThirdPartyAuthAlert', () => {
let props = {};
beforeEach(() => {
props = {
currentProvider: 'Google',
platformName: 'edX',
};
});
it('should match login page third party auth alert message snapshot', () => {
const tree = renderer.create(
<IntlProvider locale="en">
<ThirdPartyAuthAlert {...props} />
</IntlProvider>,
).toJSON();
expect(tree).toMatchSnapshot();
});
it('should match register page third party auth alert message snapshot', () => {
props = {
...props,
referrer: 'register',
};
const tree = renderer.create(
<IntlProvider locale="en">
<ThirdPartyAuthAlert {...props} />
</IntlProvider>,
).toJSON();
expect(tree).toMatchSnapshot();
});
});

View File

@@ -0,0 +1,105 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`SocialAuthProviders should match social auth provider with default icon snapshot 1`] = `
<button
className="btn-social btn-oa2-apple-id"
data-provider-url="/auth/login/apple-id/?auth_entry=login&next=/dashboard"
id="oa2-apple-id"
onClick={[Function]}
type="button"
>
<div
aria-hidden="true"
className="font-container"
>
<svg
aria-hidden="true"
className="svg-inline--fa fa-sign-in-alt fa-w-16 "
data-icon="sign-in-alt"
data-prefix="fas"
focusable="false"
role="img"
style={Object {}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M416 448h-84c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h84c17.7 0 32-14.3 32-32V160c0-17.7-14.3-32-32-32h-84c-6.6 0-12-5.4-12-12V76c0-6.6 5.4-12 12-12h84c53 0 96 43 96 96v192c0 53-43 96-96 96zm-47-201L201 79c-15-15-41-4.5-41 17v96H24c-13.3 0-24 10.7-24 24v96c0 13.3 10.7 24 24 24h136v96c0 21.5 26 32 41 17l168-168c9.3-9.4 9.3-24.6 0-34z"
fill="currentColor"
style={Object {}}
/>
</svg>
</div>
<span
aria-hidden="true"
className="pl-2 provider-name"
>
Apple
</span>
</button>
`;
exports[`SocialAuthProviders should match social auth provider with iconClass snapshot 1`] = `
<button
className="btn-social btn-oa2-apple-id"
data-provider-url="/auth/login/apple-id/?auth_entry=login&next=/dashboard"
id="oa2-apple-id"
onClick={[Function]}
type="button"
>
<div
aria-hidden="true"
className="font-container"
>
<svg
aria-hidden="true"
className="svg-inline--fa fa-google fa-w-16 "
data-icon="google"
data-prefix="fab"
focusable="false"
role="img"
style={Object {}}
viewBox="0 0 488 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M488 261.8C488 403.3 391.1 504 248 504 110.8 504 0 393.2 0 256S110.8 8 248 8c66.8 0 123 24.5 166.3 64.9l-67.5 64.9C258.5 52.6 94.3 116.6 94.3 256c0 86.5 69.1 156.6 153.7 156.6 98.2 0 135-70.4 140.8-106.9H248v-85.3h236.1c2.3 12.7 3.9 24.9 3.9 41.4z"
fill="currentColor"
style={Object {}}
/>
</svg>
</div>
<span
aria-hidden="true"
className="pl-2 provider-name"
>
Apple
</span>
</button>
`;
exports[`SocialAuthProviders should match social auth provider with iconImage snapshot 1`] = `
<button
className="btn-social btn-oa2-apple-id"
data-provider-url="/auth/login/apple-id/?auth_entry=login&next=/dashboard"
id="oa2-apple-id"
onClick={[Function]}
type="button"
>
<div
aria-hidden="true"
>
<img
alt="icon Apple"
className="icon-image"
src="https://edx.devstack.lms/logo.png"
/>
</div>
<span
aria-hidden="true"
className="pl-2"
>
Apple
</span>
</button>
`;

View File

@@ -0,0 +1,25 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ThirdPartyAuthAlert should match login page third party auth alert message snapshot 1`] = `
<div
className="fade alert-warning mt-n2 alert show"
id="tpa-alert"
role="alert"
>
<span>
You have successfully signed into Google, but your Google account does not have a linked edX account. To link your accounts, sign in now using your edX password.
</span>
</div>
`;
exports[`ThirdPartyAuthAlert should match register page third party auth alert message snapshot 1`] = `
<div
className="fade alert-warning mt-n2 alert show"
id="tpa-alert"
role="alert"
>
<span>
You've successfully signed into Google. We just need a little more information before you start learning with edX.
</span>
</div>
`;