feat: add tests and fix bugs

This commit is contained in:
Zainab Amir
2022-12-06 14:26:05 +05:00
committed by Zainab Amir
parent 85fbc54384
commit ed0da96076
12 changed files with 281 additions and 113 deletions

View File

@@ -36,3 +36,4 @@ ZENDESK_KEY=''
ZENDESK_LOGO_URL=''
APP_ID=''
MFE_CONFIG_API_URL=''
SHOW_CONFIGURABLE_EDX_FIELDS='true'

View File

@@ -24,10 +24,9 @@ function RedirectLogistration(props) {
finalRedirectUrl = redirectUrl;
}
// Redirect to Progressive Profiling after successful registration
if (redirectToWelcomePage) {
setCookie('van-504-returning-user', true);
// use this component to redirect WelcomePage after successful registration
// return <Redirect to={WELCOME_PAGE} />;
const registrationResult = { redirectUrl: finalRedirectUrl, success };
return (
<Redirect to={{

View File

@@ -26,7 +26,7 @@ const reducer = (state = defaultState, action) => {
case THIRD_PARTY_AUTH_CONTEXT.SUCCESS:
return {
...state,
extendedProfile: action.payload.fieldDescriptions.extendedProfile,
extendedProfile: action.payload.fieldDescriptions.extended_profile,
fieldDescriptions: action.payload.fieldDescriptions.fields,
optionalFields: action.payload.optionalFields,
thirdPartyAuthContext: action.payload.thirdPartyAuthContext,

View File

@@ -10,6 +10,7 @@ import { MemoryRouter } from 'react-router-dom';
import configureStore from 'redux-mock-store';
import { COMPLETE_STATE, LOGIN_PAGE } from '../../data/constants';
import { backupRegistrationForm } from '../../register/data/actions';
import { RenderInstitutionButton } from '../InstitutionLogistration';
import Logistration from '../Logistration';
@@ -184,4 +185,27 @@ describe('Logistration', () => {
DISABLE_ENTERPRISE_LOGIN: '',
});
});
it('should fire action to backup registration form on tab click', () => {
store = mockStore({
login: {
loginResult: { success: false, redirectUrl: '' },
},
register: {
registrationResult: { success: false, redirectUrl: '' },
registrationError: {},
},
commonComponents: {
thirdPartyAuthContext: {
providers: [],
secondaryProviders: [],
},
},
});
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(backupRegistrationForm());
});
});

View File

@@ -7,7 +7,7 @@ import PropTypes from 'prop-types';
const FormFieldRenderer = (props) => {
let formField = null;
const {
errorMessage, fieldData, onChangeHandler, isRequired, value,
className, errorMessage, fieldData, onChangeHandler, isRequired, value,
} = props;
const handleFocus = (e) => {
@@ -26,6 +26,7 @@ const FormFieldRenderer = (props) => {
formField = (
<Form.Group controlId={fieldData.name} isInvalid={!!(isRequired && errorMessage)}>
<Form.Control
className={className}
as="select"
name={fieldData.name}
value={value}
@@ -54,6 +55,7 @@ const FormFieldRenderer = (props) => {
formField = (
<Form.Group controlId={fieldData.name} isInvalid={!!(isRequired && errorMessage)}>
<Form.Control
className={className}
as="textarea"
name={fieldData.name}
value={value}
@@ -76,6 +78,7 @@ const FormFieldRenderer = (props) => {
formField = (
<Form.Group controlId={fieldData.name} isInvalid={!!(isRequired && errorMessage)}>
<Form.Control
className={className}
name={fieldData.name}
value={value}
aria-invalid={isRequired && Boolean(errorMessage)}
@@ -97,6 +100,7 @@ const FormFieldRenderer = (props) => {
formField = (
<Form.Group isInvalid={!!(isRequired && errorMessage)}>
<Form.Checkbox
className={className}
id={fieldData.name}
checked={!!value}
name={fieldData.name}
@@ -124,6 +128,7 @@ const FormFieldRenderer = (props) => {
return formField;
};
FormFieldRenderer.defaultProps = {
className: '',
value: '',
handleBlur: null,
handleFocus: null,
@@ -132,6 +137,7 @@ FormFieldRenderer.defaultProps = {
};
FormFieldRenderer.propTypes = {
className: PropTypes.string,
fieldData: PropTypes.shape({
type: PropTypes.string,
label: PropTypes.string,
@@ -142,7 +148,10 @@ FormFieldRenderer.propTypes = {
handleFocus: PropTypes.func,
errorMessage: PropTypes.string,
isRequired: PropTypes.bool,
value: PropTypes.string,
value: PropTypes.oneOfType([
PropTypes.string,
PropTypes.bool,
]),
};
export default FormFieldRenderer;

View File

@@ -44,6 +44,7 @@ const ConfigurableRegistrationForm = (props) => {
const flags = {
showConfigurableRegistrationFields: getConfig().ENABLE_DYNAMIC_REGISTRATION_FIELDS,
showConfigurableEdxFields: getConfig().SHOW_CONFIGURABLE_EDX_FIELDS,
showMarketingEmailOptInCheckbox: getConfig().MARKETING_EMAILS_OPT_IN,
};
useEffect(() => {
@@ -160,6 +161,25 @@ const ConfigurableRegistrationForm = (props) => {
);
}
if (flags.showMarketingEmailOptInCheckbox) {
formFieldDescriptions.push(
<span key="marketing_email_opt_in">
<FormFieldRenderer
fieldData={{
type: 'checkbox',
label: intl.formatMessage(messages['registration.opt.in.label'], { siteName: getConfig().SITE_NAME }),
name: 'marketingEmailsOptIn',
}}
value={formFields.marketingEmailsOptIn}
className="opt-checkbox"
onChangeHandler={handleOnChange}
handleBlur={handleOnBlur}
handleFocus={handleOnFocus}
/>
</span>,
);
}
if (flags.showConfigurableEdxFields || showTermsOfServiceAndHonorCode) {
formFieldDescriptions.push(
<span key="honor_code">
@@ -191,6 +211,7 @@ ConfigurableRegistrationForm.propTypes = {
countryCode: PropTypes.string,
}),
honor_code: PropTypes.bool,
marketingEmailsOptIn: PropTypes.bool,
}).isRequired,
intl: intlShape.isRequired,
setFieldErrors: PropTypes.func.isRequired,

View File

@@ -80,6 +80,7 @@ const RegistrationPage = (props) => {
const flags = {
showConfigurableEdxFields: getConfig().SHOW_CONFIGURABLE_EDX_FIELDS,
showConfigurableRegistrationFields: getConfig().ENABLE_DYNAMIC_REGISTRATION_FIELDS,
showMarketingEmailOptInCheckbox: getConfig().MARKETING_EMAILS_OPT_IN,
};
const [formFields, setFormFields] = useState({ ...backedUpFormData.formFields });
@@ -240,7 +241,7 @@ const RegistrationPage = (props) => {
case 'username':
if (!value || value.length <= 1 || value.length > 30) {
fieldError = intl.formatMessage(messages['username.validation.message']);
} else if (!value.match(/^[a-zA-Z\d_-]*$/i)) {
} else if (!value.match(/^[a-zA-Z0-9_-]*$/i)) {
fieldError = intl.formatMessage(messages['username.format.validation.message']);
} else if (shouldValidateFromBackend) {
validateFromBackend(payload);
@@ -402,7 +403,7 @@ const RegistrationPage = (props) => {
payload.social_auth_provider = currentProvider;
}
const { focusedFieldError, countryFieldCode } = focusedField ? (
const { fieldError: focusedFieldError, countryFieldCode } = focusedField ? (
validateInput(
focusedField,
(focusedField in fieldDescriptions || focusedField === 'country') ? (
@@ -419,17 +420,19 @@ const RegistrationPage = (props) => {
return;
}
payload.extendedProfile = [];
Object.keys(configurableFormFields).forEach((fieldName) => {
if (props.extendedProfile.includes(fieldName)) {
payload.extendedProfile.push({ fieldName, fieldValue: configurableFormFields[fieldName] });
} else if (fieldName === 'country') {
if (fieldName === 'country') {
payload[fieldName] = focusedField === 'country' ? countryFieldCode : configurableFormFields[fieldName].countryCode;
} else {
payload[fieldName] = configurableFormFields[fieldName];
}
});
// Don't send the marketing email opt-in value if the flag is turned off
if (!flags.showMarketingEmailOptInCheckbox) {
delete payload.marketingEmailsOptIn;
}
payload = snakeCaseObject(payload);
payload.totalRegistrationTime = totalRegistrationTime;
@@ -521,17 +524,6 @@ const RegistrationPage = (props) => {
floatingLabel={intl.formatMessage(messages['registration.password.label'])}
/>
)}
{getConfig().MARKETING_EMAILS_OPT_IN
&& (
<Form.Checkbox
name="marketingEmailsOptIn"
className="opt-checkbox"
checked={formFields.marketingEmailsOptIn}
onChange={handleOnChange}
>
{intl.formatMessage(messages['registration.opt.in.label'], { siteName: getConfig().SITE_NAME })}
</Form.Checkbox>
)}
<ConfigurableRegistrationForm
countryList={countryList}
email={formFields.email}
@@ -663,9 +655,11 @@ RegistrationPage.propTypes = {
RegistrationPage.defaultProps = {
backedUpFormData: {
configurableFormFields: {},
configurableFormFields: {
marketingEmailsOptIn: true,
},
formFields: {
name: '', email: '', username: '', password: '', marketingEmailsOptIn: true,
name: '', email: '', username: '', password: '',
},
errors: {
name: '', email: '', username: '', password: '',

View File

@@ -15,9 +15,11 @@ export const defaultState = {
registrationError: {},
registrationResult: {},
registrationFormData: {
configurableFormFields: {},
configurableFormFields: {
marketingEmailsOptIn: true,
},
formFields: {
name: '', email: '', username: '', password: '', marketingEmailsOptIn: true,
name: '', email: '', username: '', password: '',
},
emailSuggestion: {
suggestion: '', type: '',

View File

@@ -14,9 +14,11 @@ describe('Registration Reducer Tests', () => {
registrationError: {},
registrationResult: {},
registrationFormData: {
configurableFormFields: {},
configurableFormFields: {
marketingEmailsOptIn: true,
},
formFields: {
name: '', email: '', username: '', password: '', marketingEmailsOptIn: true,
name: '', email: '', username: '', password: '',
},
emailSuggestion: {
suggestion: '', type: '',

View File

@@ -20,7 +20,7 @@ const CountryField = (props) => {
const [displayValue, setDisplayValue] = useState('');
const [trailingIcon, setTrailingIcon] = useState(null);
const onBlurHandler = (event, itemClicked = false) => {
const onBlurHandler = (event, itemClicked = false, countryName = '') => {
const { name } = event.target;
const relatedName = event.relatedTarget ? event.relatedTarget.name : '';
// For a better user experience, do not validate when focus out from 'country' field
@@ -28,7 +28,7 @@ const CountryField = (props) => {
if ((relatedName === 'countryItem' || relatedName === 'countryExpand') && name === 'country') {
return;
}
const countryValue = itemClicked ? event.target.value : displayValue;
const countryValue = itemClicked ? countryName : displayValue;
if (props.onBlurHandler) {
props.onBlurHandler({ target: { name: 'country', value: countryValue } });
}
@@ -53,7 +53,7 @@ const CountryField = (props) => {
className="dropdown-item data-hj-suppress"
value={countryName}
key={country[COUNTRY_CODE_KEY]}
onClick={(event) => onBlurHandler(event, true)}
onClick={(event) => onBlurHandler(event, true, countryName)}
>
{countryName.length > 30 ? countryName.substring(0, 30).concat('...') : countryName}
</button>

View File

@@ -34,7 +34,7 @@ const EmailField = (props) => {
);
}
return (
<span className="small">
<span id="email-warning" className="small">
{intl.formatMessage(messages['did.you.mean.alert.text'])}:{' '}
<Alert.Link
href="#"

View File

@@ -6,15 +6,18 @@ import { getConfig, mergeConfig } from '@edx/frontend-platform';
import * as analytics from '@edx/frontend-platform/analytics';
import { configure, injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
import { mount } from 'enzyme';
import { createMemoryHistory } from 'history';
import { Router } from 'react-router-dom';
import renderer from 'react-test-renderer';
import configureStore from 'redux-mock-store';
import { COMPLETE_STATE, PENDING_STATE } from '../../data/constants';
import { COMPLETE_STATE, PENDING_STATE, WELCOME_PAGE } from '../../data/constants';
import {
backupRegistrationFormBegin,
clearUsernameSuggestions,
fetchRealtimeValidations,
registerNewUser,
setUserPipelineDataLoaded,
} from '../data/actions';
import {
FIELDS, FORBIDDEN_REQUEST, INTERNAL_SERVER_ERROR, TPA_SESSION_EXPIRED,
@@ -30,6 +33,7 @@ analytics.sendPageEvent = jest.fn();
const IntlRegistrationPage = injectIntl(RegistrationPage);
const IntlRegistrationFailure = injectIntl(RegistrationFailureMessage);
const mockStore = configureStore();
const history = createMemoryHistory();
describe('RegistrationPage', () => {
mergeConfig({
@@ -37,15 +41,16 @@ describe('RegistrationPage', () => {
TOS_AND_HONOR_CODE: 'https://tos-and-honot-code.com',
USER_SURVEY_COOKIE_NAME: process.env.USER_SURVEY_COOKIE_NAME,
REGISTER_CONVERSION_COOKIE_NAME: process.env.REGISTER_CONVERSION_COOKIE_NAME,
SHOW_CONFIGURABLE_EDX_FIELDS: true,
});
let props = {};
let store = {};
const registrationFormData = {
configurableFormFields: {},
configurableFormFields: {
marketingEmailsOptIn: true,
},
formFields: {
name: '', email: '', username: '', password: '', marketingEmailsOptIn: true,
name: '', email: '', username: '', password: '',
},
emailSuggestion: {
suggestion: '', type: '',
@@ -74,6 +79,7 @@ describe('RegistrationPage', () => {
register: {
registrationResult: { success: false, redirectUrl: '' },
registrationError: {},
registrationFormData,
},
commonComponents: {
thirdPartyAuthApiStatus: null,
@@ -103,20 +109,24 @@ describe('RegistrationPage', () => {
jest.clearAllMocks();
});
const populateRequiredFields = (registerPage, payload, isThirdPartyAuth = false) => {
registerPage.find('input#name').simulate('change', { target: { value: payload.name, name: 'name' } });
registerPage.find('input#username').simulate('change', { target: { value: payload.username, name: 'username' } });
registerPage.find('input#email').simulate('change', { target: { value: payload.email, name: 'email' } });
const populateRequiredFields = (registrationPage, payload, isThirdPartyAuth = false) => {
registrationPage.find('input#name').simulate('change', { target: { value: payload.name, name: 'name' } });
registrationPage.find('input#username').simulate('change', { target: { value: payload.username, name: 'username' } });
registrationPage.find('input#email').simulate('change', { target: { value: payload.email, name: 'email' } });
registerPage.find('input#country').simulate('change', { target: { value: payload.country, name: 'country' } });
registerPage.find('input#country').simulate('blur', { target: { value: payload.country, name: 'country' } });
registrationPage.find('input#country').simulate('change', { target: { value: payload.country, name: 'country' } });
registrationPage.find('input#country').simulate('blur', { target: { value: payload.country, name: 'country' } });
if (!isThirdPartyAuth) {
registerPage.find('input#password').simulate('change', { target: { value: payload.password, name: 'password' } });
registrationPage.find('input#password').simulate('change', { target: { value: payload.password, name: 'password' } });
}
};
describe('Test Registration Page', () => {
mergeConfig({
SHOW_CONFIGURABLE_EDX_FIELDS: true,
});
const emptyFieldValidation = {
name: 'Enter your full name',
username: 'Username must be between 2 and 30 characters',
@@ -153,15 +163,13 @@ describe('RegistrationPage', () => {
country: 'Pakistan',
honor_code: true,
totalRegistrationTime: 0,
marketing_emails_opt_in: true,
next: '/course/demo-course-url',
extended_profile: [],
};
store.dispatch = jest.fn(store.dispatch);
const registerPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
populateRequiredFields(registerPage, payload);
registerPage.find('button.btn-brand').simulate('click');
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
populateRequiredFields(registrationPage, payload);
registrationPage.find('button.btn-brand').simulate('click');
expect(store.dispatch).toHaveBeenCalledWith(registerNewUser({ ...payload, country: 'PK' }));
});
@@ -176,8 +184,6 @@ describe('RegistrationPage', () => {
honor_code: true,
social_auth_provider: ssoProvider.name,
totalRegistrationTime: 0,
marketing_emails_opt_in: true,
extended_profile: [],
};
store = mockStore({
@@ -191,13 +197,42 @@ describe('RegistrationPage', () => {
},
});
store.dispatch = jest.fn(store.dispatch);
const registerPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
populateRequiredFields(registerPage, formPayload, true);
registerPage.find('button.btn-brand').simulate('click');
populateRequiredFields(registrationPage, formPayload, true);
registrationPage.find('button.btn-brand').simulate('click');
expect(store.dispatch).toHaveBeenCalledWith(registerNewUser({ ...formPayload, country: 'PK' }));
});
it('should submit form with marketing email opt in value', () => {
mergeConfig({
MARKETING_EMAILS_OPT_IN: 'true',
});
jest.spyOn(global.Date, 'now').mockImplementation(() => 0);
const payload = {
name: 'John Doe',
username: 'john_doe',
email: 'john.doe@gmail.com',
password: 'password1',
country: 'Pakistan',
honor_code: true,
totalRegistrationTime: 0,
marketing_emails_opt_in: true,
};
store.dispatch = jest.fn(store.dispatch);
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
populateRequiredFields(registrationPage, payload);
registrationPage.find('button.btn-brand').simulate('click');
expect(store.dispatch).toHaveBeenCalledWith(registerNewUser({ ...payload, country: 'PK' }));
mergeConfig({
MARKETING_EMAILS_OPT_IN: '',
});
});
it('should not dispatch registerNewUser on empty form Submission', () => {
store.dispatch = jest.fn(store.dispatch);
@@ -235,7 +270,15 @@ describe('RegistrationPage', () => {
registrationPage.find('div[feedback-for="password"]').text(),
).toContain('Password criteria has not been met');
registrationPage.find('input#password').simulate('blur', { target: { value: 'invalid-email', name: 'email' } });
registrationPage.find('input#username').simulate('blur', { target: { value: 'u$ername', name: 'username' } });
expect(
registrationPage.find('div[feedback-for="username"]').text(),
).toContain(
'Usernames can only contain letters (A-Z, a-z), numerals (0-9),'
+ ' underscores (_), and hyphens (-). Usernames cannot contain spaces',
);
registrationPage.find('input#email').simulate('blur', { target: { value: 'ab', name: 'email' } });
expect(
registrationPage.find('div[feedback-for="email"]').text(),
).toEqual('Enter a valid email address');
@@ -264,18 +307,49 @@ describe('RegistrationPage', () => {
store.dispatch = jest.fn(store.dispatch);
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
// Enter a valid username so that frontend validations are passed
registrationPage.find('input#username').simulate('change', { target: { value: 'test', name: 'username' } });
registrationPage.find('input#username').simulate('blur');
// Enter a valid name so that frontend validations are passed
registrationPage.find('input#name').simulate('change', { target: { value: 'John Doe', name: 'name' } });
registrationPage.find('input#name').simulate('blur');
expect(store.dispatch).toHaveBeenCalledWith(fetchRealtimeValidations({
form_field_key: 'name', email: '', name: 'John Doe', username: '', password: '',
}));
const formPayload = {
form_field_key: 'username',
email: '',
name: '',
username: 'test',
password: '',
};
expect(store.dispatch).toHaveBeenCalledWith(fetchRealtimeValidations(formPayload));
// Enter a valid username so that frontend validations are passed
registrationPage.find('input#username').simulate('change', { target: { value: 'john', name: 'username' } });
registrationPage.find('input#username').simulate('blur');
expect(store.dispatch).toHaveBeenCalledWith(fetchRealtimeValidations({
form_field_key: 'username', email: '', name: 'John Doe', username: 'john', password: '',
}));
});
it('should run validations for focused field on form submission', () => {
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#country').simulate('focus');
registrationPage.find('button.btn-brand').simulate('click');
expect(registrationPage.find('div[feedback-for="country"]').text()).toEqual(emptyFieldValidation.country);
});
it('should give email suggestions for common service provider domain typos', () => {
store.dispatch = jest.fn(store.dispatch);
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#email').simulate('change', { target: { value: 'john@yopmail.com', name: 'email' } });
registrationPage.find('input#email').simulate('blur');
expect(registrationPage.find('#email-warning').text()).toEqual('Did you mean: john@hotmail.com?');
});
it('should give error for common top level domain mistakes', () => {
store.dispatch = jest.fn(store.dispatch);
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#email').simulate(
'change', { target: { value: 'john@gmail.mistake', name: 'email' } },
);
registrationPage.find('input#email').simulate('blur');
expect(registrationPage.find('.alert-danger').text()).toEqual('Did you mean john@gmail.com?');
});
it('should update props with validations returned by registration api', () => {
@@ -356,8 +430,8 @@ describe('RegistrationPage', () => {
const expectedMessage = `${'You\'ve successfully signed into Apple! We just need a little more information before '
+ 'you start learning with '}${ getConfig().SITE_NAME }.`;
const registerPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registerPage.find('#tpa-alert').find('p').text()).toEqual(expectedMessage);
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registrationPage.find('#tpa-alert').find('p').text()).toEqual(expectedMessage);
});
it('should match internal server error message', () => {
@@ -426,8 +500,8 @@ describe('RegistrationPage', () => {
MARKETING_EMAILS_OPT_IN: 'true',
});
const registerPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registerPage.find('div.opt-checkbox').length).toEqual(1);
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registrationPage.find('div.opt-checkbox').length).toEqual(1);
mergeConfig({
MARKETING_EMAILS_OPT_IN: '',
@@ -524,8 +598,8 @@ describe('RegistrationPage', () => {
},
});
const registerPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registerPage.find('button.username-suggestion').length).toEqual(3);
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registrationPage.find('button.username-suggestion').length).toEqual(3);
});
it('should show username suggestions when full name is populated', () => {
@@ -541,10 +615,10 @@ describe('RegistrationPage', () => {
},
});
const registerPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registerPage.find('input#name').simulate('change', { target: { value: 'test name', name: 'name' } });
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#name').simulate('change', { target: { value: 'test name', name: 'name' } });
expect(registerPage.find('button.username-suggestion').length).toEqual(3);
expect(registrationPage.find('button.username-suggestion').length).toEqual(3);
});
it('should clear username suggestions when close icon is clicked', () => {
@@ -561,9 +635,9 @@ describe('RegistrationPage', () => {
});
store.dispatch = jest.fn(store.dispatch);
const registerPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registerPage.find('input#name').simulate('change', { target: { value: 'test name', name: 'name' } });
registerPage.find('button.suggested-username-close-button').at(0).simulate('click');
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#name').simulate('change', { target: { value: 'test name', name: 'name' } });
registrationPage.find('button.suggested-username-close-button').at(0).simulate('click');
expect(store.dispatch).toHaveBeenCalledWith(clearUsernameSuggestions());
});
@@ -657,6 +731,35 @@ describe('RegistrationPage', () => {
expect(window.location.href).toBe(dashboardUrl);
});
it('should redirect to progressive profiling page if optional fields are configured', () => {
mergeConfig({
ENABLE_PROGRESSIVE_PROFILING: true,
});
store = mockStore({
...initialState,
register: {
...initialState.register,
registrationResult: {
success: true,
},
},
commonComponents: {
optionalFields: {
country: { name: 'country', error_message: false },
},
},
});
const progressiveProfilingPage = mount(reduxWrapper(
<Router history={history}>
<IntlRegistrationPage {...props} />
</Router>,
));
progressiveProfilingPage.update();
expect(history.location.pathname).toEqual(WELCOME_PAGE);
});
// ******** test hinted third party auth ********
it('should render tpa button for tpa_hint id matching one of the primary providers', () => {
@@ -676,9 +779,9 @@ describe('RegistrationPage', () => {
window.location = { href: getConfig().BASE_URL.concat('/login'), search: `?next=/dashboard&tpa_hint=${ssoProvider.id}` };
ssoProvider.iconImage = null;
const registerPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registerPage.find(`button#${ssoProvider.id}`).find('span').text()).toEqual(ssoProvider.name);
expect(registerPage.find(`button#${ssoProvider.id}`).hasClass(`btn-tpa btn-${ssoProvider.id}`)).toEqual(true);
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registrationPage.find(`button#${ssoProvider.id}`).find('span').text()).toEqual(ssoProvider.name);
expect(registrationPage.find(`button#${ssoProvider.id}`).hasClass(`btn-tpa btn-${ssoProvider.id}`)).toEqual(true);
});
it('should render tpa button for tpa_hint id matching one of the secondary providers', () => {
@@ -721,8 +824,8 @@ describe('RegistrationPage', () => {
window.location = { href: getConfig().BASE_URL.concat('/login'), search: '?next=/dashboard&tpa_hint=invalid' };
ssoProvider.iconImage = null;
const registerPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registerPage.find(`button#${ssoProvider.id}`).find('span#provider-name').text()).toEqual(expectedMessage);
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registrationPage.find(`button#${ssoProvider.id}`).find('span#provider-name').text()).toEqual(expectedMessage);
});
// ******** miscellaneous tests ********
@@ -742,8 +845,8 @@ describe('RegistrationPage', () => {
});
it('should render cookie banner', () => {
const registerPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registerPage.find(<CookiePolicyBanner />)).toBeTruthy();
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registrationPage.find(<CookiePolicyBanner />)).toBeTruthy();
});
it('should send page event when register page is rendered', () => {
@@ -769,10 +872,12 @@ describe('RegistrationPage', () => {
},
},
});
store.dispatch = jest.fn(store.dispatch);
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />)).find('RegistrationPage');
expect(registrationPage.find('input#email').props().value).toEqual('test@example.com');
expect(registrationPage.find('input#username').props().value).toEqual('test');
expect(store.dispatch).toHaveBeenCalledWith(setUserPipelineDataLoaded(true));
});
it('should update state from country code present in redux store', () => {
@@ -854,9 +959,9 @@ describe('RegistrationPage', () => {
},
},
});
const registerPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registerPage.find('#profession').exists()).toBeTruthy();
expect(registerPage.find('#tos').exists()).toBeTruthy();
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(registrationPage.find('#profession').exists()).toBeTruthy();
expect(registrationPage.find('#tos').exists()).toBeTruthy();
});
it('should submit form with fields returned by backend in payload', () => {
@@ -879,48 +984,36 @@ describe('RegistrationPage', () => {
password: 'password1',
country: 'Pakistan',
honor_code: true,
profession: 'Engineer',
totalRegistrationTime: 0,
marketing_emails_opt_in: true,
extended_profile: [{ field_name: 'profession', field_value: 'Engineer' }],
};
store.dispatch = jest.fn(store.dispatch);
const registerPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
populateRequiredFields(registerPage, payload);
registerPage.find('input#profession').simulate('change', { target: { value: 'Engineer', name: 'profession' } });
registerPage.find('button.btn-brand').simulate('click');
populateRequiredFields(registrationPage, payload);
registrationPage.find('input#profession').simulate('change', { target: { value: 'Engineer', name: 'profession' } });
registrationPage.find('button.btn-brand').simulate('click');
expect(store.dispatch).toHaveBeenCalledWith(registerNewUser({ ...payload, country: 'PK' }));
});
it('should show error message for fields returned by backend', () => {
it('should show error messages for required fields on empty form submission', () => {
const professionError = 'Enter your profession';
const countryError = 'Select your country or region of residence';
const confirmEmailError = 'Enter your email';
store = mockStore({
...initialState,
commonComponents: {
...initialState.commonComponents,
fieldDescriptions: {
profession: {
name: 'profession', type: 'text', label: 'Profession', error_message: 'Enter profession',
name: 'profession', type: 'text', label: 'Profession', error_message: professionError,
},
},
},
});
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('button.btn-brand').simulate('click');
expect(registrationPage.find('#profession-error').last().text()).toEqual('Enter profession');
});
it('should show error message for confirm email field returned by backend', () => {
store = mockStore({
...initialState,
commonComponents: {
...initialState.commonComponents,
fieldDescriptions: {
confirm_email: {
name: 'confirm_email', type: 'text', label: 'Confirm Email', error_message: 'Enter your confirm email',
name: 'confirm_email', type: 'text', label: 'Confirm Email', error_message: confirmEmailError,
},
country: { name: 'country' },
},
},
});
@@ -928,7 +1021,9 @@ describe('RegistrationPage', () => {
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('button.btn-brand').simulate('click');
expect(registrationPage.find('#confirm_email-error').last().text()).toEqual('Enter your confirm email');
expect(registrationPage.find('#profession-error').last().text()).toEqual(professionError);
expect(registrationPage.find('div[feedback-for="country"]').text()).toEqual(countryError);
expect(registrationPage.find('#confirm_email-error').last().text()).toEqual(confirmEmailError);
});
it('should show error if email and confirm email fields do not match', () => {
@@ -949,5 +1044,26 @@ describe('RegistrationPage', () => {
expect(registrationPage.find('div#confirm_email-error').text()).toEqual('The email addresses do not match.');
});
it('should run validations for configurable focused field on form submission', () => {
const professionError = 'Enter your profession';
store = mockStore({
...initialState,
commonComponents: {
...initialState.commonComponents,
fieldDescriptions: {
profession: {
name: 'profession', type: 'text', label: 'Profession', error_message: professionError,
},
},
},
});
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#profession').simulate('focus', { target: { value: '', name: 'profession' } });
registrationPage.find('button.btn-brand').simulate('click');
expect(registrationPage.find('#profession-error').last().text()).toEqual(professionError);
});
});
});