Merge pull request #31 from edx/adeel/van_19_enable_registration_field_customization

Adds custom fields support to registration form.
This commit is contained in:
adeel khan
2020-12-14 17:55:07 +05:00
committed by GitHub
11 changed files with 719 additions and 5291 deletions

View File

@@ -10,3 +10,18 @@ export const SUPPORTED_ICON_CLASSES = ['apple', 'facebook', 'google', 'microsoft
// Stateful Submit Button States
export const DEFAULT_STATE = 'default';
export const PENDING_STATE = 'pending';
export const REGISTRATION_VALIDITY_MAP = {};
export const REGISTRATION_OPTIONAL_MAP = {};
export const REGISTRATION_EXTRA_FIELDS = [
'confirm_email',
'level_of_education',
'gender',
'year_of_birth',
'mailing_address',
'goals',
'honor_code',
'terms_of_service',
'city',
'country',
];

View File

@@ -36,3 +36,11 @@ export function convertKeyNames(object, nameMap) {
return modifyObjectKeys(object, transformer);
}
export const processLink = (link) => {
let matches;
link.replace(/(.*?)<a href=["']([^"']*).*?>([^<]+)<\/a>(.*)/g, function () { // eslint-disable-line func-names
matches = Array.prototype.slice.call(arguments, 1, 5); // eslint-disable-line prefer-rest-params
});
return matches;
};

View File

@@ -4,31 +4,14 @@ import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/
import { Alert, Hyperlink } from '@edx/paragon';
import PropTypes from 'prop-types';
import { processLink } from '../data/utils/dataUtils';
import { NON_COMPLIANT_PASSWORD_EXCEPTION } from './data/constants';
import messages from './messages';
const processLink = (link) => {
let matches;
link.replace(/(.*)<a href=["']([^"']*).*>([^<]+)<\/a>(.*)/g, function () { // eslint-disable-line func-names
matches = Array.prototype.slice.call(arguments, 1, 5); // eslint-disable-line prefer-rest-params
});
return matches;
};
const LoginFailureMessage = (props) => {
const errorMessage = props.errors;
const { errorCode, intl } = props;
const Link = (args) => (
<>
{args.beforeLink}
<Hyperlink destination={args.link}>
{args.linkText}
</Hyperlink>
{args.afterLink}
</>
);
let errorList;
switch (errorCode) {
@@ -58,12 +41,9 @@ const LoginFailureMessage = (props) => {
const [beforeLink, link, linkText, afterLink] = matches;
return (
<li key={error}>
<Link // eslint-disable-line jsx-a11y/anchor-is-valid
beforeLink={beforeLink}
link={link}
linkText={linkText}
afterLink={afterLink}
/>
{beforeLink}
<Hyperlink destination={link}>{linkText}</Hyperlink>
{afterLink}
</li>
);
}

View File

@@ -1,22 +1,36 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { Input, StatefulButton, ValidationFormGroup } from '@edx/paragon';
import {
getLocale, getCountryList, injectIntl, intlShape,
Input,
StatefulButton,
Hyperlink,
ValidationFormGroup,
} from '@edx/paragon';
import {
injectIntl, intlShape,
} from '@edx/frontend-platform/i18n';
import { getThirdPartyAuthContext, registerNewUser } from './data/actions';
import camelCase from 'lodash.camelcase';
import { getThirdPartyAuthContext, registerNewUser, fetchRegistrationForm } from './data/actions';
import { registrationRequestSelector, thirdPartyAuthContextSelector } from './data/selectors';
import { RedirectLogistration } from '../common-components';
import RegistrationFailure from './RegistrationFailure';
import {
DEFAULT_REDIRECT_URL, DEFAULT_STATE, LOGIN_PAGE, REGISTER_PAGE,
DEFAULT_REDIRECT_URL,
DEFAULT_STATE,
LOGIN_PAGE,
REGISTER_PAGE,
REGISTRATION_VALIDITY_MAP,
REGISTRATION_OPTIONAL_MAP,
REGISTRATION_EXTRA_FIELDS,
} from '../data/constants';
import SocialAuthProviders from './SocialAuthProviders';
import ThirdPartyAuthAlert from './ThirdPartyAuthAlert';
import InstitutionLogistration, { RenderInstitutionButton } from './InstitutionLogistration';
import messages from './messages';
import { processLink } from '../data/utils/dataUtils';
class RegistrationPage extends React.Component {
constructor(props, context) {
@@ -24,22 +38,36 @@ class RegistrationPage extends React.Component {
this.state = {
email: '',
fullname: '',
name: '',
username: '',
password: '',
country: '',
city: '',
gender: '',
yearOfBirth: '',
mailingAddress: '',
goals: '',
honorCode: true,
termsOfService: true,
levelOfEducation: '',
confirmEmail: '',
enableOptionalField: false,
errors: {
email: '',
fullname: '',
name: '',
username: '',
password: '',
country: '',
honorCode: '',
termsOfService: '',
},
emailValid: false,
nameValid: false,
usernameValid: false,
passwordValid: false,
countryValid: false,
honorCodeValid: false,
termsOfServiceValid: false,
formValid: false,
institutionLogin: false,
};
@@ -51,6 +79,7 @@ class RegistrationPage extends React.Component {
redirect_to: params.get('next') || DEFAULT_REDIRECT_URL,
};
this.props.getThirdPartyAuthContext(payload);
this.props.fetchRegistrationForm();
}
handleInstitutionLogin = () => {
@@ -64,10 +93,16 @@ class RegistrationPage extends React.Component {
email: this.state.email,
username: this.state.username,
password: this.state.password,
name: this.state.fullname,
honor_code: true,
country: this.state.country,
name: this.state.name,
};
const fieldMap = { ...REGISTRATION_VALIDITY_MAP, ...REGISTRATION_OPTIONAL_MAP };
Object.keys(fieldMap).forEach((key) => {
const value = fieldMap[key];
if (value) {
payload[key] = this.state[camelCase(key)];
}
});
const next = params.get('next');
const courseId = params.get('course_id');
if (next) {
@@ -78,19 +113,31 @@ class RegistrationPage extends React.Component {
}
if (!this.state.formValid) {
Object.entries(payload).forEach(([key, value]) => {
this.validateInput(key, value);
});
// Special case where honor code and tos is a single field, true by default. We don't need
// to validate this field.
Object.entries(payload).filter(([key]) => (key !== 'honor_code' || !('terms_of_service' in REGISTRATION_EXTRA_FIELDS)))
.forEach(([key, value]) => {
this.validateInput(key, value);
});
return;
}
this.props.registerNewUser(payload);
}
handleOnChange(e) {
const targetValue = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
this.setState({
[e.target.name]: e.target.value,
[camelCase(e.target.name)]: targetValue,
});
this.validateInput(e.target.name, targetValue);
}
handleOnOptional(e) {
const optionalEnable = this.state.enableOptionalField;
const targetValue = e.target.id === 'additionalFields' ? !optionalEnable : e.target.checked;
this.setState({
enableOptionalField: targetValue,
});
this.validateInput(e.target.name, e.target.value);
}
validateInput(inputName, value) {
@@ -101,6 +148,8 @@ class RegistrationPage extends React.Component {
usernameValid,
passwordValid,
countryValid,
honorCodeValid,
termsOfServiceValid,
} = this.state;
switch (inputName) {
@@ -108,22 +157,30 @@ class RegistrationPage extends React.Component {
emailValid = value.match(/^([\w.%+-]+)@([\w-]+\.)+([\w]{2,})$/i);
errors.email = emailValid ? '' : null;
break;
case 'fullname':
case 'name':
nameValid = value.length >= 1;
errors.fullname = nameValid ? '' : null;
errors.name = nameValid ? '' : null;
break;
case 'username':
usernameValid = value.length >= 2 && value.length <= 30;
errors.username = usernameValid ? '' : null;
break;
case 'password':
passwordValid = value.length >= 8 && value.match(/\d+/g);
passwordValid = !!(value.length >= 8 && value.match(/\d+/g));
errors.password = passwordValid ? '' : null;
break;
case 'country':
countryValid = value !== '';
errors.country = countryValid ? '' : null;
break;
case 'honor_code':
honorCodeValid = value !== false;
errors.honorCode = honorCodeValid ? '' : null;
break;
case 'terms_of_service':
termsOfServiceValid = value !== false;
errors.termsOfService = termsOfServiceValid ? '' : null;
break;
default:
break;
}
@@ -135,6 +192,8 @@ class RegistrationPage extends React.Component {
usernameValid,
passwordValid,
countryValid,
honorCodeValid,
termsOfServiceValid,
}, this.validateForm);
}
@@ -144,18 +203,148 @@ class RegistrationPage extends React.Component {
nameValid,
usernameValid,
passwordValid,
countryValid,
} = this.state;
const validityMap = REGISTRATION_VALIDITY_MAP;
const validStates = [];
Object.keys(validityMap).forEach((key) => {
const value = validityMap[key];
if (value) {
const state = camelCase(key);
const stateValid = `${state}Valid`;
validStates.push(stateValid);
}
});
let extraFieldsValid = true;
validStates.forEach((value) => {
extraFieldsValid = extraFieldsValid && this.state[value];
});
this.setState({
formValid: emailValid && nameValid && usernameValid && passwordValid && countryValid,
formValid: emailValid && nameValid && usernameValid && passwordValid && extraFieldsValid,
});
}
renderCountryList() {
const locale = getLocale();
let items = [{ value: '', label: 'Country or Region of Residence (required)' }];
items = items.concat(getCountryList(locale).map(({ code, name }) => ({ value: code, label: name })));
return items;
addExtraRequiredFields() {
const fields = this.props.formData.fields.map((field) => {
let options = null;
if (REGISTRATION_EXTRA_FIELDS.includes(field.name)) {
if (field.required) {
const stateVar = camelCase(field.name);
let beforeLink;
let link;
let linkText;
let afterLink;
const props = {
id: field.name,
name: field.name,
type: field.type,
value: this.state[stateVar],
required: true,
onChange: e => this.handleOnChange(e),
};
REGISTRATION_VALIDITY_MAP[field.name] = true;
if (field.type === 'plaintext' && field.name === 'honor_code') { // special case where honor code and tos are combined
afterLink = field.label;
const nodes = [];
do {
const matches = processLink(afterLink);
[beforeLink, link, linkText, afterLink] = matches;
nodes.push(
<>
{beforeLink}
<Hyperlink destination={link}>{linkText}</Hyperlink>
</>,
);
} while (afterLink.includes('a href'));
nodes.push(<>{afterLink}</>);
return (
<>
<p {...props} />
{ nodes }
</>
);
}
if (field.type === 'checkbox') {
const matches = processLink(field.label);
[beforeLink, link, linkText, afterLink] = matches;
props.checked = this.state[stateVar];
return (
<ValidationFormGroup
for={field.name}
invalid={this.state.errors[stateVar] !== ''}
invalidMessage={field.errorMessages.required}
className="custom-control"
>
<Input {...props} />
{beforeLink}
<Hyperlink destination={link}>{linkText}</Hyperlink>
{afterLink}
</ValidationFormGroup>
);
}
if (field.type === 'select') {
options = field.options.map((item) => ({
value: item.value,
label: item.name,
}));
props.options = options;
}
return (
<ValidationFormGroup
for={field.name}
invalid={this.state.errors[stateVar] !== ''}
invalidMessage={field.errorMessages.required}
>
<label htmlFor={field.name} className="h6 pt-3">{field.label} (required)</label>
<Input {...props} />
</ValidationFormGroup>
);
}
}
return (<></>);
});
return fields;
}
addExtraOptionalFields() {
const fields = this.props.formData.fields.map((field) => {
let options = null;
if (REGISTRATION_EXTRA_FIELDS.includes(field.name)) {
if (!field.required) {
REGISTRATION_OPTIONAL_MAP[field.name] = true;
const props = {
id: field.name,
name: field.name,
type: field.type,
onChange: e => this.handleOnChange(e),
};
if (field.name !== 'honor_code' && field.name !== 'country') {
if (field.type === 'select') {
options = field.options.map((item) => ({
value: item.value,
label: item.name,
}));
props.options = options;
}
return (
<ValidationFormGroup
for={field.name}
>
<label htmlFor={field.name} className="h6 pt-3">{field.label} (optional)</label>
<Input {...props} />
</ValidationFormGroup>
);
}
}
}
return (<></>);
});
return fields;
}
render() {
@@ -164,6 +353,10 @@ class RegistrationPage extends React.Component {
currentProvider, finishAuthUrl, providers, secondaryProviders,
} = this.props.thirdPartyAuthContext;
if (!this.props.formData) {
return <div />;
}
if (this.state.institutionLogin) {
return (
<InstitutionLogistration
@@ -215,17 +408,17 @@ class RegistrationPage extends React.Component {
) : null}
<form className="mb-4 mx-auto form-group">
<ValidationFormGroup
for="fullname"
invalid={this.state.errors.fullname !== ''}
for="name"
invalid={this.state.errors.name !== ''}
invalidMessage="Enter your full name."
>
<label htmlFor="registrationName" className="h6 pt-3">Full Name (required)</label>
<label htmlFor="name" className="h6 pt-3">Full Name (required)</label>
<Input
name="fullname"
id="registrationName"
name="name"
id="name"
type="text"
placeholder="Full Name"
value={this.state.fullname}
placeholder=""
value={this.state.name}
onChange={e => this.handleOnChange(e)}
required
/>
@@ -235,12 +428,12 @@ class RegistrationPage extends React.Component {
invalid={this.state.errors.username !== ''}
invalidMessage="Username must be between 2 and 30 characters long."
>
<label htmlFor="registrationUsername" className="h6 pt-3">Public Username (required)</label>
<label htmlFor="username" className="h6 pt-3">Public Username (required)</label>
<Input
name="username"
id="registrationUsername"
id="username"
type="text"
placeholder="Public Username"
placeholder=""
value={this.state.username}
onChange={e => this.handleOnChange(e)}
required
@@ -251,12 +444,12 @@ class RegistrationPage extends React.Component {
invalid={this.state.errors.email !== ''}
invalidMessage="Enter a valid email address that contains at least 3 characters."
>
<label htmlFor="registrationEmail" className="h6 pt-3">Email (required)</label>
<label htmlFor="email" className="h6 pt-3">Email (required)</label>
<Input
name="email"
id="registrationEmail"
id="email"
type="email"
placeholder="username@domain.com"
placeholder=""
value={this.state.email}
onChange={e => this.handleOnChange(e)}
required
@@ -267,34 +460,34 @@ class RegistrationPage extends React.Component {
invalid={this.state.errors.password !== ''}
invalidMessage="This password is too short. It must contain at least 8 characters. This password must contain at least 1 number."
>
<label htmlFor="registrationPassword" className="h6 pt-3">Password (required)</label>
<label htmlFor="password" className="h6 pt-3">Password (required)</label>
<Input
name="password"
id="registrationPassword"
id="password"
type="password"
placeholder="Password"
placeholder=""
value={this.state.password}
onChange={e => this.handleOnChange(e)}
required
/>
</ValidationFormGroup>
{ this.addExtraRequiredFields() }
<ValidationFormGroup
for="country"
invalid={this.state.errors.country !== ''}
invalidMessage="Select your country or region of residence."
for="optional"
className="custom-control"
>
<label htmlFor="registrationCountry" className="h6 pt-3">Country (required)</label>
<Input
name="country"
type="select"
placeholder="Country or Region of Residence"
value={this.state.country}
options={this.renderCountryList()}
onChange={e => this.handleOnChange(e)}
name="optional"
id="optional"
type="checkbox"
value={this.state.enableOptionalField}
checked={this.state.enableOptionalField}
onChange={e => this.handleOnOptional(e)}
required
/>
<p role="presentation" id="additionalFields" onClick={e => this.handleOnOptional(e)}>Support education research by providing additional information</p>
</ValidationFormGroup>
<span>By creating an account, you agree to the <a href="https://www.edx.org/edx-terms-service">Terms of Service and Honor Code</a> and you acknowledge that edX and each Member process your personal data in accordance with the <a href="https://www.edx.org/edx-privacy-policy">Privacy Policy</a>.</span>
{ this.state.enableOptionalField ? this.addExtraOptionalFields() : null}
<StatefulButton
type="submit"
className="btn-primary submit mt-4"
@@ -322,6 +515,7 @@ RegistrationPage.defaultProps = {
providers: [],
secondaryProviders: [],
},
formData: null,
};
RegistrationPage.propTypes = {
@@ -351,6 +545,11 @@ RegistrationPage.propTypes = {
username: PropTypes.string,
}),
}),
fetchRegistrationForm: PropTypes.func.isRequired,
formData: PropTypes.shape({
fields: PropTypes.array,
}),
};
const mapStateToProps = state => {
@@ -361,6 +560,7 @@ const mapStateToProps = state => {
submitState: state.logistration.submitState,
registrationResult,
thirdPartyAuthContext,
formData: state.logistration.formData,
};
};
@@ -368,6 +568,7 @@ export default connect(
mapStateToProps,
{
getThirdPartyAuthContext,
fetchRegistrationForm,
registerNewUser,
},
)(injectIntl(RegistrationPage));

View File

@@ -3,6 +3,7 @@ import { AsyncActionType } from '../../data/utils';
export const REGISTER_NEW_USER = new AsyncActionType('REGISTRATION', 'REGISTER_NEW_USER');
export const LOGIN_REQUEST = new AsyncActionType('LOGIN', 'REQUEST');
export const THIRD_PARTY_AUTH_CONTEXT = new AsyncActionType('THIRD_PARTY_AUTH', 'GET_THIRD_PARTY_AUTH_CONTEXT');
export const REGISTER_FORM = new AsyncActionType('REGISTRATION', 'GET_FORM_FIELDS');
// Register
@@ -64,3 +65,21 @@ export const getThirdPartyAuthContextSuccess = (thirdPartyAuthContext) => ({
export const getThirdPartyAuthContextFailure = () => ({
type: THIRD_PARTY_AUTH_CONTEXT.FAILURE,
});
// Registration Form Fields
export const fetchRegistrationForm = () => ({
type: REGISTER_FORM.BASE,
});
export const fetchRegistrationFormBegin = () => ({
type: REGISTER_FORM.BEGIN,
});
export const fetchRegistrationFormSuccess = (formData) => ({
type: REGISTER_FORM.SUCCESS,
payload: { formData },
});
export const fetchRegistrationFormFailure = () => ({
type: REGISTER_FORM.FAILURE,
});

View File

@@ -2,6 +2,7 @@ import {
REGISTER_NEW_USER,
LOGIN_REQUEST,
THIRD_PARTY_AUTH_CONTEXT,
REGISTER_FORM,
} from './actions';
import { DEFAULT_STATE, PENDING_STATE } from '../../data/constants';
@@ -11,6 +12,7 @@ export const defaultState = {
loginResult: {},
registrationError: null,
registrationResult: {},
formData: null,
};
const reducer = (state = defaultState, action) => {
@@ -60,6 +62,19 @@ const reducer = (state = defaultState, action) => {
return {
...state,
};
case REGISTER_FORM.BEGIN:
return {
...state,
};
case REGISTER_FORM.SUCCESS:
return {
...state,
formData: action.payload.formData,
};
case REGISTER_FORM.FAILURE:
return {
...state,
};
default:
return state;
}

View File

@@ -16,10 +16,19 @@ import {
getThirdPartyAuthContextBegin,
getThirdPartyAuthContextSuccess,
getThirdPartyAuthContextFailure,
REGISTER_FORM,
fetchRegistrationFormBegin,
fetchRegistrationFormSuccess,
fetchRegistrationFormFailure,
} from './actions';
// Services
import { getThirdPartyAuthContext, postNewUser, login } from './service';
import {
getRegistrationForm,
getThirdPartyAuthContext,
postNewUser,
login,
} from './service';
export function* handleNewUserRegistration(action) {
try {
@@ -71,8 +80,23 @@ export function* fetchThirdPartyAuthContext(action) {
}
}
export function* fetchRegistrationForm() {
try {
yield put(fetchRegistrationFormBegin());
const { registrationForm } = yield call(getRegistrationForm);
yield put(fetchRegistrationFormSuccess(
registrationForm,
));
} catch (e) {
yield put(fetchRegistrationFormFailure());
throw e;
}
}
export default function* saga() {
yield takeEvery(REGISTER_NEW_USER.BASE, handleNewUserRegistration);
yield takeEvery(LOGIN_REQUEST.BASE, handleLoginRequest);
yield takeEvery(THIRD_PARTY_AUTH_CONTEXT.BASE, fetchThirdPartyAuthContext);
yield takeEvery(REGISTER_FORM.BASE, fetchRegistrationForm);
}

View File

@@ -65,3 +65,23 @@ export async function getThirdPartyAuthContext(urlParams) {
thirdPartyAuthContext: camelCaseObject(data),
};
}
export async function getRegistrationForm() {
const requestConfig = {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
isPublic: true,
};
const { data } = await getAuthenticatedHttpClient()
.get(
`${getConfig().LMS_BASE_URL}/user_api/v1/account/registration/`,
requestConfig,
)
.catch((e) => {
throw (e);
});
return {
registrationForm: data,
};
}

View File

@@ -4,8 +4,11 @@ import {
getThirdPartyAuthContextBegin,
getThirdPartyAuthContextSuccess,
getThirdPartyAuthContextFailure,
fetchRegistrationFormBegin,
fetchRegistrationFormSuccess,
fetchRegistrationFormFailure,
} from '../actions';
import { fetchThirdPartyAuthContext } from '../sagas';
import { fetchThirdPartyAuthContext, fetchRegistrationForm } from '../sagas';
import * as api from '../service';
describe('fetchThirdPartyAuthContext', () => {
@@ -53,3 +56,56 @@ describe('fetchThirdPartyAuthContext', () => {
getThirdPartyAuthContext.mockClear();
});
});
describe('fetchRegistrationForm', () => {
const data = {
fields: [{
label: 'City',
name: 'city',
type: 'text',
errorMessages: {
required: 'invalid city',
},
required: true,
},
{
label: 'I agree to the Your Platform Name Here <a href="/honor" rel="noopener" target="_blank">Honor Code</a>',
name: 'honor_code',
type: 'checkbox',
errorMessages: {
required: 'invalid honor code',
},
required: true,
}],
};
it('should call service and dispatch success action', async () => {
const getRegistrationForm = jest.spyOn(api, 'getRegistrationForm')
.mockImplementation(() => Promise.resolve({ registrationForm: data }));
const dispatched = [];
await runSaga(
{ dispatch: (action) => dispatched.push(action) },
fetchRegistrationForm,
);
expect(getRegistrationForm).toHaveBeenCalledTimes(1);
expect(dispatched).toEqual([fetchRegistrationFormBegin(), fetchRegistrationFormSuccess(data)]);
getRegistrationForm.mockClear();
});
it('should call service and dispatch error action', async () => {
const getRegistrationForm = jest.spyOn(api, 'getRegistrationForm')
.mockImplementation(() => Promise.reject());
const dispatched = [];
await runSaga(
{ dispatch: (action) => dispatched.push(action) },
fetchRegistrationForm,
);
expect(getRegistrationForm).toHaveBeenCalledTimes(1);
expect(dispatched).toEqual([fetchRegistrationFormBegin(), fetchRegistrationFormFailure()]);
getRegistrationForm.mockClear();
});
});

View File

@@ -1,14 +1,15 @@
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 configureStore from 'redux-mock-store';
import { getConfig } from '@edx/frontend-platform';
import { IntlProvider, injectIntl, configure } from '@edx/frontend-platform/i18n';
import RegistrationPage from '../RegistrationPage';
import { RenderInstitutionButton } from '../InstitutionLogistration';
import { PENDING_STATE } from '../../data/constants';
import { fetchRegistrationForm } from '../data/actions';
const IntlRegistrationPage = injectIntl(RegistrationPage);
const mockStore = configureStore();
@@ -23,6 +24,17 @@ describe('./RegistrationPage.js', () => {
providers: [],
secondaryProviders: [],
},
registrationError: null,
formData: {
fields: [{
label: 'I agree to the Your Platform Name Here <a href="/honor" rel="noopener" target="_blank">Honor Code</a>',
name: 'honor_code',
type: 'checkbox',
errorMessages: {
required: 'You must agree to the Your Platform Name Here Honor Code',
},
}],
},
},
};
@@ -73,6 +85,170 @@ describe('./RegistrationPage.js', () => {
jest.clearAllMocks();
});
it('should show error message on invalid email', () => {
const validationMessage = 'Enter a valid email address that contains at least 3 characters.';
store = mockStore({
...initialState,
logistration: {
...initialState.logistration,
},
});
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#email').simulate('change', { target: { value: '', name: 'email' } });
registrationPage.update();
expect(registrationPage.find('#email-invalid-feedback').text()).toEqual(validationMessage);
});
it('should show error message on invalid username', () => {
const validationMessage = 'Username must be between 2 and 30 characters long.';
store = mockStore({
...initialState,
logistration: {
...initialState.logistration,
},
});
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#username').simulate('change', { target: { value: '', name: 'username' } });
registrationPage.update();
expect(registrationPage.find('#username-invalid-feedback').text()).toEqual(validationMessage);
});
it('should show error message on invalid name', () => {
const validationMessage = 'Enter your full name.';
store = mockStore({
...initialState,
logistration: {
...initialState.logistration,
},
});
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#name').simulate('change', { target: { value: '', name: 'name' } });
registrationPage.update();
expect(registrationPage.find('#name-invalid-feedback').text()).toEqual(validationMessage);
});
it('should show error message on invalid password', () => {
const validationMessage = 'This password is too short. It must contain at least 8 characters. This password must contain at least 1 number.';
store = mockStore({
...initialState,
logistration: {
...initialState.logistration,
},
});
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#password').simulate('change', { target: { value: '', name: 'password' } });
registrationPage.update();
expect(registrationPage.find('#password-invalid-feedback').text()).toEqual(validationMessage);
});
it('should show error messages on invalid extra fields', () => {
const validationMessage = {
honorCode: 'You must agree to the Your Platform Name Here Honor Code',
country: 'Select your country or region of residence.',
};
store = mockStore({
...initialState,
logistration: {
...initialState.logistration,
formData: {
fields: [
{
label: 'I agree to the Your Platform Name Here <a href="/honor" rel="noopener" target="_blank">Honor Code</a>',
name: 'honor_code',
type: 'checkbox',
errorMessages: {
required: validationMessage.honorCode,
},
required: true,
},
{
label: 'The country or region where you live.',
name: 'country',
type: 'select',
options: [{
value: '', name: '--',
},
{
value: 'AF', name: 'Afghanistan',
}],
errorMessages: {
required: validationMessage.country,
},
required: true,
},
],
},
},
});
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#honor_code').simulate('change', { target: { checked: false, name: 'honor_code', type: 'checkbox' } });
registrationPage.update();
expect(registrationPage.find('#honor_code-invalid-feedback').text()).toEqual(validationMessage.honorCode);
registrationPage.find('select#country').simulate('change', { target: { checked: false, name: 'country', type: 'checkbox' } });
registrationPage.update();
expect(registrationPage.find('#country-invalid-feedback').text()).toEqual(validationMessage.country);
});
it('should toggle optional fields state on checkbox click', () => {
store = mockStore({
...initialState,
logistration: {
...initialState.logistration,
},
});
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#optional').simulate('change', { target: { checked: true } });
registrationPage.update();
expect(registrationPage.find('RegistrationPage').state('enableOptionalField')).toEqual(true);
});
it('should show optional fields section on optional check enabled', () => {
store = mockStore({
...initialState,
logistration: {
...initialState.logistration,
formData: {
fields: [{
label: 'Tell us why you\'re interested in edX',
name: 'goals',
type: 'textarea',
required: false,
},
{
label: 'Highest level of Education completed.',
name: 'level_of_education',
type: 'select',
options: [{
value: '', name: '--',
},
{
value: 'p', name: 'Doctorate',
}],
required: false,
}],
},
},
});
const registrationPage = mount(reduxWrapper(<IntlRegistrationPage {...props} />));
registrationPage.find('input#optional').simulate('change', { target: { checked: true } });
registrationPage.update();
expect(registrationPage.find('textarea#goals').length).toEqual(1);
expect(registrationPage.find('select#level_of_education').length).toEqual(1);
});
it('should dispatch fetchRegistrationForm on ComponentDidMount', () => {
store = mockStore({
...initialState,
});
store.dispatch = jest.fn(store.dispatch);
mount(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(store.dispatch).toHaveBeenCalledWith(fetchRegistrationForm());
});
it('should match default section snapshot', () => {
const tree = renderer.create(reduxWrapper(<IntlRegistrationPage {...props} />));
expect(tree.toJSON()).toMatchSnapshot();
@@ -191,6 +367,16 @@ describe('./RegistrationPage.js', () => {
registerUrl,
}],
},
formData: {
fields: [{
label: 'I agree to the Your Platform Name Here <a href="/honor" rel="noopener" target="_blank">Honor Code</a>',
name: 'honor_code',
type: 'checkbox',
errorMessages: {
required: 'You must agree to the Your Platform Name Here Honor Code',
},
}],
},
},
});
@@ -247,11 +433,11 @@ describe('./RegistrationPage.js', () => {
},
],
},
response_status: 'complete',
},
});
const tree = renderer.create(reduxWrapper(<IntlRegistrationPage {...props} />)).toJSON();
expect(tree).toMatchSnapshot();
windowSpy.mockClear();
});
});

View File

@@ -64,24 +64,24 @@ exports[`./RegistrationPage.js should match TPA provider snapshot 1`] = `
>
<label
className="h6 pt-3"
htmlFor="registrationName"
htmlFor="name"
>
Full Name (required)
</label>
<input
aria-describedby=""
className="form-control"
id="registrationName"
name="fullname"
id="name"
name="name"
onChange={[Function]}
placeholder="Full Name"
placeholder=""
required={true}
type="text"
value=""
/>
<strong
className="invalid-feedback"
id="fullname-invalid-feedback"
id="name-invalid-feedback"
>
Enter your full name.
</strong>
@@ -91,17 +91,17 @@ exports[`./RegistrationPage.js should match TPA provider snapshot 1`] = `
>
<label
className="h6 pt-3"
htmlFor="registrationUsername"
htmlFor="username"
>
Public Username (required)
</label>
<input
aria-describedby=""
className="form-control"
id="registrationUsername"
id="username"
name="username"
onChange={[Function]}
placeholder="Public Username"
placeholder=""
required={true}
type="text"
value=""
@@ -118,17 +118,17 @@ exports[`./RegistrationPage.js should match TPA provider snapshot 1`] = `
>
<label
className="h6 pt-3"
htmlFor="registrationEmail"
htmlFor="email"
>
Email (required)
</label>
<input
aria-describedby=""
className="form-control"
id="registrationEmail"
id="email"
name="email"
onChange={[Function]}
placeholder="username@domain.com"
placeholder=""
required={true}
type="email"
value=""
@@ -145,17 +145,17 @@ exports[`./RegistrationPage.js should match TPA provider snapshot 1`] = `
>
<label
className="h6 pt-3"
htmlFor="registrationPassword"
htmlFor="password"
>
Password (required)
</label>
<input
aria-describedby=""
className="form-control"
id="registrationPassword"
id="password"
name="password"
onChange={[Function]}
placeholder="Password"
placeholder=""
required={true}
type="password"
value=""
@@ -168,1301 +168,27 @@ exports[`./RegistrationPage.js should match TPA provider snapshot 1`] = `
</strong>
</div>
<div
className="form-group"
className="form-group custom-control"
>
<label
className="h6 pt-3"
htmlFor="registrationCountry"
>
Country (required)
</label>
<select
<input
aria-describedby=""
className="form-control"
name="country"
checked={false}
className="form-check-input"
id="optional"
name="optional"
onChange={[Function]}
placeholder="Country or Region of Residence"
required={true}
value=""
type="checkbox"
value={false}
/>
<p
id="additionalFields"
onClick={[Function]}
role="presentation"
>
<option
value=""
>
Country or Region of Residence (required)
</option>
<option
value="AF"
>
Afghanistan
</option>
<option
value="AL"
>
Albania
</option>
<option
value="DZ"
>
Algeria
</option>
<option
value="AS"
>
American Samoa
</option>
<option
value="AD"
>
Andorra
</option>
<option
value="AO"
>
Angola
</option>
<option
value="AI"
>
Anguilla
</option>
<option
value="AQ"
>
Antarctica
</option>
<option
value="AG"
>
Antigua and Barbuda
</option>
<option
value="AR"
>
Argentina
</option>
<option
value="AM"
>
Armenia
</option>
<option
value="AW"
>
Aruba
</option>
<option
value="AU"
>
Australia
</option>
<option
value="AT"
>
Austria
</option>
<option
value="AZ"
>
Azerbaijan
</option>
<option
value="BS"
>
Bahamas
</option>
<option
value="BH"
>
Bahrain
</option>
<option
value="BD"
>
Bangladesh
</option>
<option
value="BB"
>
Barbados
</option>
<option
value="BY"
>
Belarus
</option>
<option
value="BE"
>
Belgium
</option>
<option
value="BZ"
>
Belize
</option>
<option
value="BJ"
>
Benin
</option>
<option
value="BM"
>
Bermuda
</option>
<option
value="BT"
>
Bhutan
</option>
<option
value="BO"
>
Bolivia
</option>
<option
value="BA"
>
Bosnia and Herzegovina
</option>
<option
value="BW"
>
Botswana
</option>
<option
value="BV"
>
Bouvet Island
</option>
<option
value="BR"
>
Brazil
</option>
<option
value="IO"
>
British Indian Ocean Territory
</option>
<option
value="BN"
>
Brunei Darussalam
</option>
<option
value="BG"
>
Bulgaria
</option>
<option
value="BF"
>
Burkina Faso
</option>
<option
value="BI"
>
Burundi
</option>
<option
value="KH"
>
Cambodia
</option>
<option
value="CM"
>
Cameroon
</option>
<option
value="CA"
>
Canada
</option>
<option
value="CV"
>
Cape Verde
</option>
<option
value="KY"
>
Cayman Islands
</option>
<option
value="CF"
>
Central African Republic
</option>
<option
value="TD"
>
Chad
</option>
<option
value="CL"
>
Chile
</option>
<option
value="CN"
>
China
</option>
<option
value="CX"
>
Christmas Island
</option>
<option
value="CC"
>
Cocos (Keeling) Islands
</option>
<option
value="CO"
>
Colombia
</option>
<option
value="KM"
>
Comoros
</option>
<option
value="CG"
>
Congo
</option>
<option
value="CD"
>
Congo, the Democratic Republic of the
</option>
<option
value="CK"
>
Cook Islands
</option>
<option
value="CR"
>
Costa Rica
</option>
<option
value="CI"
>
Cote D'Ivoire
</option>
<option
value="HR"
>
Croatia
</option>
<option
value="CU"
>
Cuba
</option>
<option
value="CY"
>
Cyprus
</option>
<option
value="CZ"
>
Czech Republic
</option>
<option
value="DK"
>
Denmark
</option>
<option
value="DJ"
>
Djibouti
</option>
<option
value="DM"
>
Dominica
</option>
<option
value="DO"
>
Dominican Republic
</option>
<option
value="EC"
>
Ecuador
</option>
<option
value="EG"
>
Egypt
</option>
<option
value="SV"
>
El Salvador
</option>
<option
value="GQ"
>
Equatorial Guinea
</option>
<option
value="ER"
>
Eritrea
</option>
<option
value="EE"
>
Estonia
</option>
<option
value="ET"
>
Ethiopia
</option>
<option
value="FK"
>
Falkland Islands (Malvinas)
</option>
<option
value="FO"
>
Faroe Islands
</option>
<option
value="FJ"
>
Fiji
</option>
<option
value="FI"
>
Finland
</option>
<option
value="FR"
>
France
</option>
<option
value="GF"
>
French Guiana
</option>
<option
value="PF"
>
French Polynesia
</option>
<option
value="TF"
>
French Southern Territories
</option>
<option
value="GA"
>
Gabon
</option>
<option
value="GM"
>
Gambia
</option>
<option
value="GE"
>
Georgia
</option>
<option
value="DE"
>
Germany
</option>
<option
value="GH"
>
Ghana
</option>
<option
value="GI"
>
Gibraltar
</option>
<option
value="GR"
>
Greece
</option>
<option
value="GL"
>
Greenland
</option>
<option
value="GD"
>
Grenada
</option>
<option
value="GP"
>
Guadeloupe
</option>
<option
value="GU"
>
Guam
</option>
<option
value="GT"
>
Guatemala
</option>
<option
value="GN"
>
Guinea
</option>
<option
value="GW"
>
Guinea-Bissau
</option>
<option
value="GY"
>
Guyana
</option>
<option
value="HT"
>
Haiti
</option>
<option
value="HM"
>
Heard Island and Mcdonald Islands
</option>
<option
value="VA"
>
Holy See (Vatican City State)
</option>
<option
value="HN"
>
Honduras
</option>
<option
value="HK"
>
Hong Kong
</option>
<option
value="HU"
>
Hungary
</option>
<option
value="IS"
>
Iceland
</option>
<option
value="IN"
>
India
</option>
<option
value="ID"
>
Indonesia
</option>
<option
value="IR"
>
Iran, Islamic Republic of
</option>
<option
value="IQ"
>
Iraq
</option>
<option
value="IE"
>
Ireland
</option>
<option
value="IL"
>
Israel
</option>
<option
value="IT"
>
Italy
</option>
<option
value="JM"
>
Jamaica
</option>
<option
value="JP"
>
Japan
</option>
<option
value="JO"
>
Jordan
</option>
<option
value="KZ"
>
Kazakhstan
</option>
<option
value="KE"
>
Kenya
</option>
<option
value="KI"
>
Kiribati
</option>
<option
value="KP"
>
North Korea
</option>
<option
value="KR"
>
South Korea
</option>
<option
value="KW"
>
Kuwait
</option>
<option
value="KG"
>
Kyrgyzstan
</option>
<option
value="LA"
>
Lao People's Democratic Republic
</option>
<option
value="LV"
>
Latvia
</option>
<option
value="LB"
>
Lebanon
</option>
<option
value="LS"
>
Lesotho
</option>
<option
value="LR"
>
Liberia
</option>
<option
value="LY"
>
Libya
</option>
<option
value="LI"
>
Liechtenstein
</option>
<option
value="LT"
>
Lithuania
</option>
<option
value="LU"
>
Luxembourg
</option>
<option
value="MO"
>
Macao
</option>
<option
value="MG"
>
Madagascar
</option>
<option
value="MW"
>
Malawi
</option>
<option
value="MY"
>
Malaysia
</option>
<option
value="MV"
>
Maldives
</option>
<option
value="ML"
>
Mali
</option>
<option
value="MT"
>
Malta
</option>
<option
value="MH"
>
Marshall Islands
</option>
<option
value="MQ"
>
Martinique
</option>
<option
value="MR"
>
Mauritania
</option>
<option
value="MU"
>
Mauritius
</option>
<option
value="YT"
>
Mayotte
</option>
<option
value="MX"
>
Mexico
</option>
<option
value="FM"
>
Micronesia, Federated States of
</option>
<option
value="MD"
>
Moldova, Republic of
</option>
<option
value="MC"
>
Monaco
</option>
<option
value="MN"
>
Mongolia
</option>
<option
value="MS"
>
Montserrat
</option>
<option
value="MA"
>
Morocco
</option>
<option
value="MZ"
>
Mozambique
</option>
<option
value="MM"
>
Myanmar
</option>
<option
value="NA"
>
Namibia
</option>
<option
value="NR"
>
Nauru
</option>
<option
value="NP"
>
Nepal
</option>
<option
value="NL"
>
Netherlands
</option>
<option
value="NC"
>
New Caledonia
</option>
<option
value="NZ"
>
New Zealand
</option>
<option
value="NI"
>
Nicaragua
</option>
<option
value="NE"
>
Niger
</option>
<option
value="NG"
>
Nigeria
</option>
<option
value="NU"
>
Niue
</option>
<option
value="NF"
>
Norfolk Island
</option>
<option
value="MK"
>
North Macedonia, Republic of
</option>
<option
value="MP"
>
Northern Mariana Islands
</option>
<option
value="NO"
>
Norway
</option>
<option
value="OM"
>
Oman
</option>
<option
value="PK"
>
Pakistan
</option>
<option
value="PW"
>
Palau
</option>
<option
value="PS"
>
Palestinian Territory, Occupied
</option>
<option
value="PA"
>
Panama
</option>
<option
value="PG"
>
Papua New Guinea
</option>
<option
value="PY"
>
Paraguay
</option>
<option
value="PE"
>
Peru
</option>
<option
value="PH"
>
Philippines
</option>
<option
value="PN"
>
Pitcairn
</option>
<option
value="PL"
>
Poland
</option>
<option
value="PT"
>
Portugal
</option>
<option
value="PR"
>
Puerto Rico
</option>
<option
value="QA"
>
Qatar
</option>
<option
value="RE"
>
Reunion
</option>
<option
value="RO"
>
Romania
</option>
<option
value="RU"
>
Russian Federation
</option>
<option
value="RW"
>
Rwanda
</option>
<option
value="SH"
>
Saint Helena
</option>
<option
value="KN"
>
Saint Kitts and Nevis
</option>
<option
value="LC"
>
Saint Lucia
</option>
<option
value="PM"
>
Saint Pierre and Miquelon
</option>
<option
value="VC"
>
Saint Vincent and the Grenadines
</option>
<option
value="WS"
>
Samoa
</option>
<option
value="SM"
>
San Marino
</option>
<option
value="ST"
>
Sao Tome and Principe
</option>
<option
value="SA"
>
Saudi Arabia
</option>
<option
value="SN"
>
Senegal
</option>
<option
value="SC"
>
Seychelles
</option>
<option
value="SL"
>
Sierra Leone
</option>
<option
value="SG"
>
Singapore
</option>
<option
value="SK"
>
Slovakia
</option>
<option
value="SI"
>
Slovenia
</option>
<option
value="SB"
>
Solomon Islands
</option>
<option
value="SO"
>
Somalia
</option>
<option
value="ZA"
>
South Africa
</option>
<option
value="GS"
>
South Georgia and the South Sandwich Islands
</option>
<option
value="ES"
>
Spain
</option>
<option
value="LK"
>
Sri Lanka
</option>
<option
value="SD"
>
Sudan
</option>
<option
value="SR"
>
Suriname
</option>
<option
value="SJ"
>
Svalbard and Jan Mayen
</option>
<option
value="SZ"
>
Swaziland
</option>
<option
value="SE"
>
Sweden
</option>
<option
value="CH"
>
Switzerland
</option>
<option
value="SY"
>
Syrian Arab Republic
</option>
<option
value="TW"
>
Taiwan
</option>
<option
value="TJ"
>
Tajikistan
</option>
<option
value="TZ"
>
Tanzania, United Republic of
</option>
<option
value="TH"
>
Thailand
</option>
<option
value="TL"
>
Timor-Leste
</option>
<option
value="TG"
>
Togo
</option>
<option
value="TK"
>
Tokelau
</option>
<option
value="TO"
>
Tonga
</option>
<option
value="TT"
>
Trinidad and Tobago
</option>
<option
value="TN"
>
Tunisia
</option>
<option
value="TR"
>
Turkey
</option>
<option
value="TM"
>
Turkmenistan
</option>
<option
value="TC"
>
Turks and Caicos Islands
</option>
<option
value="TV"
>
Tuvalu
</option>
<option
value="UG"
>
Uganda
</option>
<option
value="UA"
>
Ukraine
</option>
<option
value="AE"
>
United Arab Emirates
</option>
<option
value="GB"
>
United Kingdom
</option>
<option
value="US"
>
United States of America
</option>
<option
value="UM"
>
United States Minor Outlying Islands
</option>
<option
value="UY"
>
Uruguay
</option>
<option
value="UZ"
>
Uzbekistan
</option>
<option
value="VU"
>
Vanuatu
</option>
<option
value="VE"
>
Venezuela
</option>
<option
value="VN"
>
Viet Nam
</option>
<option
value="VG"
>
Virgin Islands, British
</option>
<option
value="VI"
>
Virgin Islands, U.S.
</option>
<option
value="WF"
>
Wallis and Futuna
</option>
<option
value="EH"
>
Western Sahara
</option>
<option
value="YE"
>
Yemen
</option>
<option
value="ZM"
>
Zambia
</option>
<option
value="ZW"
>
Zimbabwe
</option>
<option
value="AX"
>
Åland Islands
</option>
<option
value="BQ"
>
Bonaire, Sint Eustatius and Saba
</option>
<option
value="CW"
>
Curaçao
</option>
<option
value="GG"
>
Guernsey
</option>
<option
value="IM"
>
Isle of Man
</option>
<option
value="JE"
>
Jersey
</option>
<option
value="ME"
>
Montenegro
</option>
<option
value="BL"
>
Saint Barthélemy
</option>
<option
value="MF"
>
Saint Martin (French part)
</option>
<option
value="RS"
>
Serbia
</option>
<option
value="SX"
>
Sint Maarten (Dutch part)
</option>
<option
value="SS"
>
South Sudan
</option>
<option
value="XK"
>
Kosovo
</option>
</select>
<strong
className="invalid-feedback"
id="country-invalid-feedback"
>
Select your country or region of residence.
</strong>
Support education research by providing additional information
</p>
</div>
<span>
By creating an account, you agree to the
<a
href="https://www.edx.org/edx-terms-service"
>
Terms of Service and Honor Code
</a>
and you acknowledge that edX and each Member process your personal data in accordance with the
<a
href="https://www.edx.org/edx-privacy-policy"
>
Privacy Policy
</a>
.
</span>
<button
aria-disabled={false}
aria-live="assertive"
@@ -1505,24 +231,24 @@ exports[`./RegistrationPage.js should match default section snapshot 1`] = `
>
<label
className="h6 pt-3"
htmlFor="registrationName"
htmlFor="name"
>
Full Name (required)
</label>
<input
aria-describedby=""
className="form-control"
id="registrationName"
name="fullname"
id="name"
name="name"
onChange={[Function]}
placeholder="Full Name"
placeholder=""
required={true}
type="text"
value=""
/>
<strong
className="invalid-feedback"
id="fullname-invalid-feedback"
id="name-invalid-feedback"
>
Enter your full name.
</strong>
@@ -1532,17 +258,17 @@ exports[`./RegistrationPage.js should match default section snapshot 1`] = `
>
<label
className="h6 pt-3"
htmlFor="registrationUsername"
htmlFor="username"
>
Public Username (required)
</label>
<input
aria-describedby=""
className="form-control"
id="registrationUsername"
id="username"
name="username"
onChange={[Function]}
placeholder="Public Username"
placeholder=""
required={true}
type="text"
value=""
@@ -1559,17 +285,17 @@ exports[`./RegistrationPage.js should match default section snapshot 1`] = `
>
<label
className="h6 pt-3"
htmlFor="registrationEmail"
htmlFor="email"
>
Email (required)
</label>
<input
aria-describedby=""
className="form-control"
id="registrationEmail"
id="email"
name="email"
onChange={[Function]}
placeholder="username@domain.com"
placeholder=""
required={true}
type="email"
value=""
@@ -1586,17 +312,17 @@ exports[`./RegistrationPage.js should match default section snapshot 1`] = `
>
<label
className="h6 pt-3"
htmlFor="registrationPassword"
htmlFor="password"
>
Password (required)
</label>
<input
aria-describedby=""
className="form-control"
id="registrationPassword"
id="password"
name="password"
onChange={[Function]}
placeholder="Password"
placeholder=""
required={true}
type="password"
value=""
@@ -1609,1301 +335,27 @@ exports[`./RegistrationPage.js should match default section snapshot 1`] = `
</strong>
</div>
<div
className="form-group"
className="form-group custom-control"
>
<label
className="h6 pt-3"
htmlFor="registrationCountry"
>
Country (required)
</label>
<select
<input
aria-describedby=""
className="form-control"
name="country"
checked={false}
className="form-check-input"
id="optional"
name="optional"
onChange={[Function]}
placeholder="Country or Region of Residence"
required={true}
value=""
type="checkbox"
value={false}
/>
<p
id="additionalFields"
onClick={[Function]}
role="presentation"
>
<option
value=""
>
Country or Region of Residence (required)
</option>
<option
value="AF"
>
Afghanistan
</option>
<option
value="AL"
>
Albania
</option>
<option
value="DZ"
>
Algeria
</option>
<option
value="AS"
>
American Samoa
</option>
<option
value="AD"
>
Andorra
</option>
<option
value="AO"
>
Angola
</option>
<option
value="AI"
>
Anguilla
</option>
<option
value="AQ"
>
Antarctica
</option>
<option
value="AG"
>
Antigua and Barbuda
</option>
<option
value="AR"
>
Argentina
</option>
<option
value="AM"
>
Armenia
</option>
<option
value="AW"
>
Aruba
</option>
<option
value="AU"
>
Australia
</option>
<option
value="AT"
>
Austria
</option>
<option
value="AZ"
>
Azerbaijan
</option>
<option
value="BS"
>
Bahamas
</option>
<option
value="BH"
>
Bahrain
</option>
<option
value="BD"
>
Bangladesh
</option>
<option
value="BB"
>
Barbados
</option>
<option
value="BY"
>
Belarus
</option>
<option
value="BE"
>
Belgium
</option>
<option
value="BZ"
>
Belize
</option>
<option
value="BJ"
>
Benin
</option>
<option
value="BM"
>
Bermuda
</option>
<option
value="BT"
>
Bhutan
</option>
<option
value="BO"
>
Bolivia
</option>
<option
value="BA"
>
Bosnia and Herzegovina
</option>
<option
value="BW"
>
Botswana
</option>
<option
value="BV"
>
Bouvet Island
</option>
<option
value="BR"
>
Brazil
</option>
<option
value="IO"
>
British Indian Ocean Territory
</option>
<option
value="BN"
>
Brunei Darussalam
</option>
<option
value="BG"
>
Bulgaria
</option>
<option
value="BF"
>
Burkina Faso
</option>
<option
value="BI"
>
Burundi
</option>
<option
value="KH"
>
Cambodia
</option>
<option
value="CM"
>
Cameroon
</option>
<option
value="CA"
>
Canada
</option>
<option
value="CV"
>
Cape Verde
</option>
<option
value="KY"
>
Cayman Islands
</option>
<option
value="CF"
>
Central African Republic
</option>
<option
value="TD"
>
Chad
</option>
<option
value="CL"
>
Chile
</option>
<option
value="CN"
>
China
</option>
<option
value="CX"
>
Christmas Island
</option>
<option
value="CC"
>
Cocos (Keeling) Islands
</option>
<option
value="CO"
>
Colombia
</option>
<option
value="KM"
>
Comoros
</option>
<option
value="CG"
>
Congo
</option>
<option
value="CD"
>
Congo, the Democratic Republic of the
</option>
<option
value="CK"
>
Cook Islands
</option>
<option
value="CR"
>
Costa Rica
</option>
<option
value="CI"
>
Cote D'Ivoire
</option>
<option
value="HR"
>
Croatia
</option>
<option
value="CU"
>
Cuba
</option>
<option
value="CY"
>
Cyprus
</option>
<option
value="CZ"
>
Czech Republic
</option>
<option
value="DK"
>
Denmark
</option>
<option
value="DJ"
>
Djibouti
</option>
<option
value="DM"
>
Dominica
</option>
<option
value="DO"
>
Dominican Republic
</option>
<option
value="EC"
>
Ecuador
</option>
<option
value="EG"
>
Egypt
</option>
<option
value="SV"
>
El Salvador
</option>
<option
value="GQ"
>
Equatorial Guinea
</option>
<option
value="ER"
>
Eritrea
</option>
<option
value="EE"
>
Estonia
</option>
<option
value="ET"
>
Ethiopia
</option>
<option
value="FK"
>
Falkland Islands (Malvinas)
</option>
<option
value="FO"
>
Faroe Islands
</option>
<option
value="FJ"
>
Fiji
</option>
<option
value="FI"
>
Finland
</option>
<option
value="FR"
>
France
</option>
<option
value="GF"
>
French Guiana
</option>
<option
value="PF"
>
French Polynesia
</option>
<option
value="TF"
>
French Southern Territories
</option>
<option
value="GA"
>
Gabon
</option>
<option
value="GM"
>
Gambia
</option>
<option
value="GE"
>
Georgia
</option>
<option
value="DE"
>
Germany
</option>
<option
value="GH"
>
Ghana
</option>
<option
value="GI"
>
Gibraltar
</option>
<option
value="GR"
>
Greece
</option>
<option
value="GL"
>
Greenland
</option>
<option
value="GD"
>
Grenada
</option>
<option
value="GP"
>
Guadeloupe
</option>
<option
value="GU"
>
Guam
</option>
<option
value="GT"
>
Guatemala
</option>
<option
value="GN"
>
Guinea
</option>
<option
value="GW"
>
Guinea-Bissau
</option>
<option
value="GY"
>
Guyana
</option>
<option
value="HT"
>
Haiti
</option>
<option
value="HM"
>
Heard Island and Mcdonald Islands
</option>
<option
value="VA"
>
Holy See (Vatican City State)
</option>
<option
value="HN"
>
Honduras
</option>
<option
value="HK"
>
Hong Kong
</option>
<option
value="HU"
>
Hungary
</option>
<option
value="IS"
>
Iceland
</option>
<option
value="IN"
>
India
</option>
<option
value="ID"
>
Indonesia
</option>
<option
value="IR"
>
Iran, Islamic Republic of
</option>
<option
value="IQ"
>
Iraq
</option>
<option
value="IE"
>
Ireland
</option>
<option
value="IL"
>
Israel
</option>
<option
value="IT"
>
Italy
</option>
<option
value="JM"
>
Jamaica
</option>
<option
value="JP"
>
Japan
</option>
<option
value="JO"
>
Jordan
</option>
<option
value="KZ"
>
Kazakhstan
</option>
<option
value="KE"
>
Kenya
</option>
<option
value="KI"
>
Kiribati
</option>
<option
value="KP"
>
North Korea
</option>
<option
value="KR"
>
South Korea
</option>
<option
value="KW"
>
Kuwait
</option>
<option
value="KG"
>
Kyrgyzstan
</option>
<option
value="LA"
>
Lao People's Democratic Republic
</option>
<option
value="LV"
>
Latvia
</option>
<option
value="LB"
>
Lebanon
</option>
<option
value="LS"
>
Lesotho
</option>
<option
value="LR"
>
Liberia
</option>
<option
value="LY"
>
Libya
</option>
<option
value="LI"
>
Liechtenstein
</option>
<option
value="LT"
>
Lithuania
</option>
<option
value="LU"
>
Luxembourg
</option>
<option
value="MO"
>
Macao
</option>
<option
value="MG"
>
Madagascar
</option>
<option
value="MW"
>
Malawi
</option>
<option
value="MY"
>
Malaysia
</option>
<option
value="MV"
>
Maldives
</option>
<option
value="ML"
>
Mali
</option>
<option
value="MT"
>
Malta
</option>
<option
value="MH"
>
Marshall Islands
</option>
<option
value="MQ"
>
Martinique
</option>
<option
value="MR"
>
Mauritania
</option>
<option
value="MU"
>
Mauritius
</option>
<option
value="YT"
>
Mayotte
</option>
<option
value="MX"
>
Mexico
</option>
<option
value="FM"
>
Micronesia, Federated States of
</option>
<option
value="MD"
>
Moldova, Republic of
</option>
<option
value="MC"
>
Monaco
</option>
<option
value="MN"
>
Mongolia
</option>
<option
value="MS"
>
Montserrat
</option>
<option
value="MA"
>
Morocco
</option>
<option
value="MZ"
>
Mozambique
</option>
<option
value="MM"
>
Myanmar
</option>
<option
value="NA"
>
Namibia
</option>
<option
value="NR"
>
Nauru
</option>
<option
value="NP"
>
Nepal
</option>
<option
value="NL"
>
Netherlands
</option>
<option
value="NC"
>
New Caledonia
</option>
<option
value="NZ"
>
New Zealand
</option>
<option
value="NI"
>
Nicaragua
</option>
<option
value="NE"
>
Niger
</option>
<option
value="NG"
>
Nigeria
</option>
<option
value="NU"
>
Niue
</option>
<option
value="NF"
>
Norfolk Island
</option>
<option
value="MK"
>
North Macedonia, Republic of
</option>
<option
value="MP"
>
Northern Mariana Islands
</option>
<option
value="NO"
>
Norway
</option>
<option
value="OM"
>
Oman
</option>
<option
value="PK"
>
Pakistan
</option>
<option
value="PW"
>
Palau
</option>
<option
value="PS"
>
Palestinian Territory, Occupied
</option>
<option
value="PA"
>
Panama
</option>
<option
value="PG"
>
Papua New Guinea
</option>
<option
value="PY"
>
Paraguay
</option>
<option
value="PE"
>
Peru
</option>
<option
value="PH"
>
Philippines
</option>
<option
value="PN"
>
Pitcairn
</option>
<option
value="PL"
>
Poland
</option>
<option
value="PT"
>
Portugal
</option>
<option
value="PR"
>
Puerto Rico
</option>
<option
value="QA"
>
Qatar
</option>
<option
value="RE"
>
Reunion
</option>
<option
value="RO"
>
Romania
</option>
<option
value="RU"
>
Russian Federation
</option>
<option
value="RW"
>
Rwanda
</option>
<option
value="SH"
>
Saint Helena
</option>
<option
value="KN"
>
Saint Kitts and Nevis
</option>
<option
value="LC"
>
Saint Lucia
</option>
<option
value="PM"
>
Saint Pierre and Miquelon
</option>
<option
value="VC"
>
Saint Vincent and the Grenadines
</option>
<option
value="WS"
>
Samoa
</option>
<option
value="SM"
>
San Marino
</option>
<option
value="ST"
>
Sao Tome and Principe
</option>
<option
value="SA"
>
Saudi Arabia
</option>
<option
value="SN"
>
Senegal
</option>
<option
value="SC"
>
Seychelles
</option>
<option
value="SL"
>
Sierra Leone
</option>
<option
value="SG"
>
Singapore
</option>
<option
value="SK"
>
Slovakia
</option>
<option
value="SI"
>
Slovenia
</option>
<option
value="SB"
>
Solomon Islands
</option>
<option
value="SO"
>
Somalia
</option>
<option
value="ZA"
>
South Africa
</option>
<option
value="GS"
>
South Georgia and the South Sandwich Islands
</option>
<option
value="ES"
>
Spain
</option>
<option
value="LK"
>
Sri Lanka
</option>
<option
value="SD"
>
Sudan
</option>
<option
value="SR"
>
Suriname
</option>
<option
value="SJ"
>
Svalbard and Jan Mayen
</option>
<option
value="SZ"
>
Swaziland
</option>
<option
value="SE"
>
Sweden
</option>
<option
value="CH"
>
Switzerland
</option>
<option
value="SY"
>
Syrian Arab Republic
</option>
<option
value="TW"
>
Taiwan
</option>
<option
value="TJ"
>
Tajikistan
</option>
<option
value="TZ"
>
Tanzania, United Republic of
</option>
<option
value="TH"
>
Thailand
</option>
<option
value="TL"
>
Timor-Leste
</option>
<option
value="TG"
>
Togo
</option>
<option
value="TK"
>
Tokelau
</option>
<option
value="TO"
>
Tonga
</option>
<option
value="TT"
>
Trinidad and Tobago
</option>
<option
value="TN"
>
Tunisia
</option>
<option
value="TR"
>
Turkey
</option>
<option
value="TM"
>
Turkmenistan
</option>
<option
value="TC"
>
Turks and Caicos Islands
</option>
<option
value="TV"
>
Tuvalu
</option>
<option
value="UG"
>
Uganda
</option>
<option
value="UA"
>
Ukraine
</option>
<option
value="AE"
>
United Arab Emirates
</option>
<option
value="GB"
>
United Kingdom
</option>
<option
value="US"
>
United States of America
</option>
<option
value="UM"
>
United States Minor Outlying Islands
</option>
<option
value="UY"
>
Uruguay
</option>
<option
value="UZ"
>
Uzbekistan
</option>
<option
value="VU"
>
Vanuatu
</option>
<option
value="VE"
>
Venezuela
</option>
<option
value="VN"
>
Viet Nam
</option>
<option
value="VG"
>
Virgin Islands, British
</option>
<option
value="VI"
>
Virgin Islands, U.S.
</option>
<option
value="WF"
>
Wallis and Futuna
</option>
<option
value="EH"
>
Western Sahara
</option>
<option
value="YE"
>
Yemen
</option>
<option
value="ZM"
>
Zambia
</option>
<option
value="ZW"
>
Zimbabwe
</option>
<option
value="AX"
>
Åland Islands
</option>
<option
value="BQ"
>
Bonaire, Sint Eustatius and Saba
</option>
<option
value="CW"
>
Curaçao
</option>
<option
value="GG"
>
Guernsey
</option>
<option
value="IM"
>
Isle of Man
</option>
<option
value="JE"
>
Jersey
</option>
<option
value="ME"
>
Montenegro
</option>
<option
value="BL"
>
Saint Barthélemy
</option>
<option
value="MF"
>
Saint Martin (French part)
</option>
<option
value="RS"
>
Serbia
</option>
<option
value="SX"
>
Sint Maarten (Dutch part)
</option>
<option
value="SS"
>
South Sudan
</option>
<option
value="XK"
>
Kosovo
</option>
</select>
<strong
className="invalid-feedback"
id="country-invalid-feedback"
>
Select your country or region of residence.
</strong>
Support education research by providing additional information
</p>
</div>
<span>
By creating an account, you agree to the
<a
href="https://www.edx.org/edx-terms-service"
>
Terms of Service and Honor Code
</a>
and you acknowledge that edX and each Member process your personal data in accordance with the
<a
href="https://www.edx.org/edx-privacy-policy"
>
Privacy Policy
</a>
.
</span>
<button
aria-disabled={false}
aria-live="assertive"
@@ -2946,24 +398,24 @@ exports[`./RegistrationPage.js should match pending button state snapshot 1`] =
>
<label
className="h6 pt-3"
htmlFor="registrationName"
htmlFor="name"
>
Full Name (required)
</label>
<input
aria-describedby=""
className="form-control"
id="registrationName"
name="fullname"
id="name"
name="name"
onChange={[Function]}
placeholder="Full Name"
placeholder=""
required={true}
type="text"
value=""
/>
<strong
className="invalid-feedback"
id="fullname-invalid-feedback"
id="name-invalid-feedback"
>
Enter your full name.
</strong>
@@ -2973,17 +425,17 @@ exports[`./RegistrationPage.js should match pending button state snapshot 1`] =
>
<label
className="h6 pt-3"
htmlFor="registrationUsername"
htmlFor="username"
>
Public Username (required)
</label>
<input
aria-describedby=""
className="form-control"
id="registrationUsername"
id="username"
name="username"
onChange={[Function]}
placeholder="Public Username"
placeholder=""
required={true}
type="text"
value=""
@@ -3000,17 +452,17 @@ exports[`./RegistrationPage.js should match pending button state snapshot 1`] =
>
<label
className="h6 pt-3"
htmlFor="registrationEmail"
htmlFor="email"
>
Email (required)
</label>
<input
aria-describedby=""
className="form-control"
id="registrationEmail"
id="email"
name="email"
onChange={[Function]}
placeholder="username@domain.com"
placeholder=""
required={true}
type="email"
value=""
@@ -3027,17 +479,17 @@ exports[`./RegistrationPage.js should match pending button state snapshot 1`] =
>
<label
className="h6 pt-3"
htmlFor="registrationPassword"
htmlFor="password"
>
Password (required)
</label>
<input
aria-describedby=""
className="form-control"
id="registrationPassword"
id="password"
name="password"
onChange={[Function]}
placeholder="Password"
placeholder=""
required={true}
type="password"
value=""
@@ -3050,1301 +502,27 @@ exports[`./RegistrationPage.js should match pending button state snapshot 1`] =
</strong>
</div>
<div
className="form-group"
className="form-group custom-control"
>
<label
className="h6 pt-3"
htmlFor="registrationCountry"
>
Country (required)
</label>
<select
<input
aria-describedby=""
className="form-control"
name="country"
checked={false}
className="form-check-input"
id="optional"
name="optional"
onChange={[Function]}
placeholder="Country or Region of Residence"
required={true}
value=""
type="checkbox"
value={false}
/>
<p
id="additionalFields"
onClick={[Function]}
role="presentation"
>
<option
value=""
>
Country or Region of Residence (required)
</option>
<option
value="AF"
>
Afghanistan
</option>
<option
value="AL"
>
Albania
</option>
<option
value="DZ"
>
Algeria
</option>
<option
value="AS"
>
American Samoa
</option>
<option
value="AD"
>
Andorra
</option>
<option
value="AO"
>
Angola
</option>
<option
value="AI"
>
Anguilla
</option>
<option
value="AQ"
>
Antarctica
</option>
<option
value="AG"
>
Antigua and Barbuda
</option>
<option
value="AR"
>
Argentina
</option>
<option
value="AM"
>
Armenia
</option>
<option
value="AW"
>
Aruba
</option>
<option
value="AU"
>
Australia
</option>
<option
value="AT"
>
Austria
</option>
<option
value="AZ"
>
Azerbaijan
</option>
<option
value="BS"
>
Bahamas
</option>
<option
value="BH"
>
Bahrain
</option>
<option
value="BD"
>
Bangladesh
</option>
<option
value="BB"
>
Barbados
</option>
<option
value="BY"
>
Belarus
</option>
<option
value="BE"
>
Belgium
</option>
<option
value="BZ"
>
Belize
</option>
<option
value="BJ"
>
Benin
</option>
<option
value="BM"
>
Bermuda
</option>
<option
value="BT"
>
Bhutan
</option>
<option
value="BO"
>
Bolivia
</option>
<option
value="BA"
>
Bosnia and Herzegovina
</option>
<option
value="BW"
>
Botswana
</option>
<option
value="BV"
>
Bouvet Island
</option>
<option
value="BR"
>
Brazil
</option>
<option
value="IO"
>
British Indian Ocean Territory
</option>
<option
value="BN"
>
Brunei Darussalam
</option>
<option
value="BG"
>
Bulgaria
</option>
<option
value="BF"
>
Burkina Faso
</option>
<option
value="BI"
>
Burundi
</option>
<option
value="KH"
>
Cambodia
</option>
<option
value="CM"
>
Cameroon
</option>
<option
value="CA"
>
Canada
</option>
<option
value="CV"
>
Cape Verde
</option>
<option
value="KY"
>
Cayman Islands
</option>
<option
value="CF"
>
Central African Republic
</option>
<option
value="TD"
>
Chad
</option>
<option
value="CL"
>
Chile
</option>
<option
value="CN"
>
China
</option>
<option
value="CX"
>
Christmas Island
</option>
<option
value="CC"
>
Cocos (Keeling) Islands
</option>
<option
value="CO"
>
Colombia
</option>
<option
value="KM"
>
Comoros
</option>
<option
value="CG"
>
Congo
</option>
<option
value="CD"
>
Congo, the Democratic Republic of the
</option>
<option
value="CK"
>
Cook Islands
</option>
<option
value="CR"
>
Costa Rica
</option>
<option
value="CI"
>
Cote D'Ivoire
</option>
<option
value="HR"
>
Croatia
</option>
<option
value="CU"
>
Cuba
</option>
<option
value="CY"
>
Cyprus
</option>
<option
value="CZ"
>
Czech Republic
</option>
<option
value="DK"
>
Denmark
</option>
<option
value="DJ"
>
Djibouti
</option>
<option
value="DM"
>
Dominica
</option>
<option
value="DO"
>
Dominican Republic
</option>
<option
value="EC"
>
Ecuador
</option>
<option
value="EG"
>
Egypt
</option>
<option
value="SV"
>
El Salvador
</option>
<option
value="GQ"
>
Equatorial Guinea
</option>
<option
value="ER"
>
Eritrea
</option>
<option
value="EE"
>
Estonia
</option>
<option
value="ET"
>
Ethiopia
</option>
<option
value="FK"
>
Falkland Islands (Malvinas)
</option>
<option
value="FO"
>
Faroe Islands
</option>
<option
value="FJ"
>
Fiji
</option>
<option
value="FI"
>
Finland
</option>
<option
value="FR"
>
France
</option>
<option
value="GF"
>
French Guiana
</option>
<option
value="PF"
>
French Polynesia
</option>
<option
value="TF"
>
French Southern Territories
</option>
<option
value="GA"
>
Gabon
</option>
<option
value="GM"
>
Gambia
</option>
<option
value="GE"
>
Georgia
</option>
<option
value="DE"
>
Germany
</option>
<option
value="GH"
>
Ghana
</option>
<option
value="GI"
>
Gibraltar
</option>
<option
value="GR"
>
Greece
</option>
<option
value="GL"
>
Greenland
</option>
<option
value="GD"
>
Grenada
</option>
<option
value="GP"
>
Guadeloupe
</option>
<option
value="GU"
>
Guam
</option>
<option
value="GT"
>
Guatemala
</option>
<option
value="GN"
>
Guinea
</option>
<option
value="GW"
>
Guinea-Bissau
</option>
<option
value="GY"
>
Guyana
</option>
<option
value="HT"
>
Haiti
</option>
<option
value="HM"
>
Heard Island and Mcdonald Islands
</option>
<option
value="VA"
>
Holy See (Vatican City State)
</option>
<option
value="HN"
>
Honduras
</option>
<option
value="HK"
>
Hong Kong
</option>
<option
value="HU"
>
Hungary
</option>
<option
value="IS"
>
Iceland
</option>
<option
value="IN"
>
India
</option>
<option
value="ID"
>
Indonesia
</option>
<option
value="IR"
>
Iran, Islamic Republic of
</option>
<option
value="IQ"
>
Iraq
</option>
<option
value="IE"
>
Ireland
</option>
<option
value="IL"
>
Israel
</option>
<option
value="IT"
>
Italy
</option>
<option
value="JM"
>
Jamaica
</option>
<option
value="JP"
>
Japan
</option>
<option
value="JO"
>
Jordan
</option>
<option
value="KZ"
>
Kazakhstan
</option>
<option
value="KE"
>
Kenya
</option>
<option
value="KI"
>
Kiribati
</option>
<option
value="KP"
>
North Korea
</option>
<option
value="KR"
>
South Korea
</option>
<option
value="KW"
>
Kuwait
</option>
<option
value="KG"
>
Kyrgyzstan
</option>
<option
value="LA"
>
Lao People's Democratic Republic
</option>
<option
value="LV"
>
Latvia
</option>
<option
value="LB"
>
Lebanon
</option>
<option
value="LS"
>
Lesotho
</option>
<option
value="LR"
>
Liberia
</option>
<option
value="LY"
>
Libya
</option>
<option
value="LI"
>
Liechtenstein
</option>
<option
value="LT"
>
Lithuania
</option>
<option
value="LU"
>
Luxembourg
</option>
<option
value="MO"
>
Macao
</option>
<option
value="MG"
>
Madagascar
</option>
<option
value="MW"
>
Malawi
</option>
<option
value="MY"
>
Malaysia
</option>
<option
value="MV"
>
Maldives
</option>
<option
value="ML"
>
Mali
</option>
<option
value="MT"
>
Malta
</option>
<option
value="MH"
>
Marshall Islands
</option>
<option
value="MQ"
>
Martinique
</option>
<option
value="MR"
>
Mauritania
</option>
<option
value="MU"
>
Mauritius
</option>
<option
value="YT"
>
Mayotte
</option>
<option
value="MX"
>
Mexico
</option>
<option
value="FM"
>
Micronesia, Federated States of
</option>
<option
value="MD"
>
Moldova, Republic of
</option>
<option
value="MC"
>
Monaco
</option>
<option
value="MN"
>
Mongolia
</option>
<option
value="MS"
>
Montserrat
</option>
<option
value="MA"
>
Morocco
</option>
<option
value="MZ"
>
Mozambique
</option>
<option
value="MM"
>
Myanmar
</option>
<option
value="NA"
>
Namibia
</option>
<option
value="NR"
>
Nauru
</option>
<option
value="NP"
>
Nepal
</option>
<option
value="NL"
>
Netherlands
</option>
<option
value="NC"
>
New Caledonia
</option>
<option
value="NZ"
>
New Zealand
</option>
<option
value="NI"
>
Nicaragua
</option>
<option
value="NE"
>
Niger
</option>
<option
value="NG"
>
Nigeria
</option>
<option
value="NU"
>
Niue
</option>
<option
value="NF"
>
Norfolk Island
</option>
<option
value="MK"
>
North Macedonia, Republic of
</option>
<option
value="MP"
>
Northern Mariana Islands
</option>
<option
value="NO"
>
Norway
</option>
<option
value="OM"
>
Oman
</option>
<option
value="PK"
>
Pakistan
</option>
<option
value="PW"
>
Palau
</option>
<option
value="PS"
>
Palestinian Territory, Occupied
</option>
<option
value="PA"
>
Panama
</option>
<option
value="PG"
>
Papua New Guinea
</option>
<option
value="PY"
>
Paraguay
</option>
<option
value="PE"
>
Peru
</option>
<option
value="PH"
>
Philippines
</option>
<option
value="PN"
>
Pitcairn
</option>
<option
value="PL"
>
Poland
</option>
<option
value="PT"
>
Portugal
</option>
<option
value="PR"
>
Puerto Rico
</option>
<option
value="QA"
>
Qatar
</option>
<option
value="RE"
>
Reunion
</option>
<option
value="RO"
>
Romania
</option>
<option
value="RU"
>
Russian Federation
</option>
<option
value="RW"
>
Rwanda
</option>
<option
value="SH"
>
Saint Helena
</option>
<option
value="KN"
>
Saint Kitts and Nevis
</option>
<option
value="LC"
>
Saint Lucia
</option>
<option
value="PM"
>
Saint Pierre and Miquelon
</option>
<option
value="VC"
>
Saint Vincent and the Grenadines
</option>
<option
value="WS"
>
Samoa
</option>
<option
value="SM"
>
San Marino
</option>
<option
value="ST"
>
Sao Tome and Principe
</option>
<option
value="SA"
>
Saudi Arabia
</option>
<option
value="SN"
>
Senegal
</option>
<option
value="SC"
>
Seychelles
</option>
<option
value="SL"
>
Sierra Leone
</option>
<option
value="SG"
>
Singapore
</option>
<option
value="SK"
>
Slovakia
</option>
<option
value="SI"
>
Slovenia
</option>
<option
value="SB"
>
Solomon Islands
</option>
<option
value="SO"
>
Somalia
</option>
<option
value="ZA"
>
South Africa
</option>
<option
value="GS"
>
South Georgia and the South Sandwich Islands
</option>
<option
value="ES"
>
Spain
</option>
<option
value="LK"
>
Sri Lanka
</option>
<option
value="SD"
>
Sudan
</option>
<option
value="SR"
>
Suriname
</option>
<option
value="SJ"
>
Svalbard and Jan Mayen
</option>
<option
value="SZ"
>
Swaziland
</option>
<option
value="SE"
>
Sweden
</option>
<option
value="CH"
>
Switzerland
</option>
<option
value="SY"
>
Syrian Arab Republic
</option>
<option
value="TW"
>
Taiwan
</option>
<option
value="TJ"
>
Tajikistan
</option>
<option
value="TZ"
>
Tanzania, United Republic of
</option>
<option
value="TH"
>
Thailand
</option>
<option
value="TL"
>
Timor-Leste
</option>
<option
value="TG"
>
Togo
</option>
<option
value="TK"
>
Tokelau
</option>
<option
value="TO"
>
Tonga
</option>
<option
value="TT"
>
Trinidad and Tobago
</option>
<option
value="TN"
>
Tunisia
</option>
<option
value="TR"
>
Turkey
</option>
<option
value="TM"
>
Turkmenistan
</option>
<option
value="TC"
>
Turks and Caicos Islands
</option>
<option
value="TV"
>
Tuvalu
</option>
<option
value="UG"
>
Uganda
</option>
<option
value="UA"
>
Ukraine
</option>
<option
value="AE"
>
United Arab Emirates
</option>
<option
value="GB"
>
United Kingdom
</option>
<option
value="US"
>
United States of America
</option>
<option
value="UM"
>
United States Minor Outlying Islands
</option>
<option
value="UY"
>
Uruguay
</option>
<option
value="UZ"
>
Uzbekistan
</option>
<option
value="VU"
>
Vanuatu
</option>
<option
value="VE"
>
Venezuela
</option>
<option
value="VN"
>
Viet Nam
</option>
<option
value="VG"
>
Virgin Islands, British
</option>
<option
value="VI"
>
Virgin Islands, U.S.
</option>
<option
value="WF"
>
Wallis and Futuna
</option>
<option
value="EH"
>
Western Sahara
</option>
<option
value="YE"
>
Yemen
</option>
<option
value="ZM"
>
Zambia
</option>
<option
value="ZW"
>
Zimbabwe
</option>
<option
value="AX"
>
Åland Islands
</option>
<option
value="BQ"
>
Bonaire, Sint Eustatius and Saba
</option>
<option
value="CW"
>
Curaçao
</option>
<option
value="GG"
>
Guernsey
</option>
<option
value="IM"
>
Isle of Man
</option>
<option
value="JE"
>
Jersey
</option>
<option
value="ME"
>
Montenegro
</option>
<option
value="BL"
>
Saint Barthélemy
</option>
<option
value="MF"
>
Saint Martin (French part)
</option>
<option
value="RS"
>
Serbia
</option>
<option
value="SX"
>
Sint Maarten (Dutch part)
</option>
<option
value="SS"
>
South Sudan
</option>
<option
value="XK"
>
Kosovo
</option>
</select>
<strong
className="invalid-feedback"
id="country-invalid-feedback"
>
Select your country or region of residence.
</strong>
Support education research by providing additional information
</p>
</div>
<span>
By creating an account, you agree to the
<a
href="https://www.edx.org/edx-terms-service"
>
Terms of Service and Honor Code
</a>
and you acknowledge that edX and each Member process your personal data in accordance with the
<a
href="https://www.edx.org/edx-privacy-policy"
>
Privacy Policy
</a>
.
</span>
<button
aria-disabled={true}
aria-live="assertive"
@@ -4434,24 +612,24 @@ exports[`./RegistrationPage.js should show error message on 409 1`] = `
>
<label
className="h6 pt-3"
htmlFor="registrationName"
htmlFor="name"
>
Full Name (required)
</label>
<input
aria-describedby=""
className="form-control"
id="registrationName"
name="fullname"
id="name"
name="name"
onChange={[Function]}
placeholder="Full Name"
placeholder=""
required={true}
type="text"
value=""
/>
<strong
className="invalid-feedback"
id="fullname-invalid-feedback"
id="name-invalid-feedback"
>
Enter your full name.
</strong>
@@ -4461,17 +639,17 @@ exports[`./RegistrationPage.js should show error message on 409 1`] = `
>
<label
className="h6 pt-3"
htmlFor="registrationUsername"
htmlFor="username"
>
Public Username (required)
</label>
<input
aria-describedby=""
className="form-control"
id="registrationUsername"
id="username"
name="username"
onChange={[Function]}
placeholder="Public Username"
placeholder=""
required={true}
type="text"
value=""
@@ -4488,17 +666,17 @@ exports[`./RegistrationPage.js should show error message on 409 1`] = `
>
<label
className="h6 pt-3"
htmlFor="registrationEmail"
htmlFor="email"
>
Email (required)
</label>
<input
aria-describedby=""
className="form-control"
id="registrationEmail"
id="email"
name="email"
onChange={[Function]}
placeholder="username@domain.com"
placeholder=""
required={true}
type="email"
value=""
@@ -4515,17 +693,17 @@ exports[`./RegistrationPage.js should show error message on 409 1`] = `
>
<label
className="h6 pt-3"
htmlFor="registrationPassword"
htmlFor="password"
>
Password (required)
</label>
<input
aria-describedby=""
className="form-control"
id="registrationPassword"
id="password"
name="password"
onChange={[Function]}
placeholder="Password"
placeholder=""
required={true}
type="password"
value=""
@@ -4538,1301 +716,27 @@ exports[`./RegistrationPage.js should show error message on 409 1`] = `
</strong>
</div>
<div
className="form-group"
className="form-group custom-control"
>
<label
className="h6 pt-3"
htmlFor="registrationCountry"
>
Country (required)
</label>
<select
<input
aria-describedby=""
className="form-control"
name="country"
checked={false}
className="form-check-input"
id="optional"
name="optional"
onChange={[Function]}
placeholder="Country or Region of Residence"
required={true}
value=""
type="checkbox"
value={false}
/>
<p
id="additionalFields"
onClick={[Function]}
role="presentation"
>
<option
value=""
>
Country or Region of Residence (required)
</option>
<option
value="AF"
>
Afghanistan
</option>
<option
value="AL"
>
Albania
</option>
<option
value="DZ"
>
Algeria
</option>
<option
value="AS"
>
American Samoa
</option>
<option
value="AD"
>
Andorra
</option>
<option
value="AO"
>
Angola
</option>
<option
value="AI"
>
Anguilla
</option>
<option
value="AQ"
>
Antarctica
</option>
<option
value="AG"
>
Antigua and Barbuda
</option>
<option
value="AR"
>
Argentina
</option>
<option
value="AM"
>
Armenia
</option>
<option
value="AW"
>
Aruba
</option>
<option
value="AU"
>
Australia
</option>
<option
value="AT"
>
Austria
</option>
<option
value="AZ"
>
Azerbaijan
</option>
<option
value="BS"
>
Bahamas
</option>
<option
value="BH"
>
Bahrain
</option>
<option
value="BD"
>
Bangladesh
</option>
<option
value="BB"
>
Barbados
</option>
<option
value="BY"
>
Belarus
</option>
<option
value="BE"
>
Belgium
</option>
<option
value="BZ"
>
Belize
</option>
<option
value="BJ"
>
Benin
</option>
<option
value="BM"
>
Bermuda
</option>
<option
value="BT"
>
Bhutan
</option>
<option
value="BO"
>
Bolivia
</option>
<option
value="BA"
>
Bosnia and Herzegovina
</option>
<option
value="BW"
>
Botswana
</option>
<option
value="BV"
>
Bouvet Island
</option>
<option
value="BR"
>
Brazil
</option>
<option
value="IO"
>
British Indian Ocean Territory
</option>
<option
value="BN"
>
Brunei Darussalam
</option>
<option
value="BG"
>
Bulgaria
</option>
<option
value="BF"
>
Burkina Faso
</option>
<option
value="BI"
>
Burundi
</option>
<option
value="KH"
>
Cambodia
</option>
<option
value="CM"
>
Cameroon
</option>
<option
value="CA"
>
Canada
</option>
<option
value="CV"
>
Cape Verde
</option>
<option
value="KY"
>
Cayman Islands
</option>
<option
value="CF"
>
Central African Republic
</option>
<option
value="TD"
>
Chad
</option>
<option
value="CL"
>
Chile
</option>
<option
value="CN"
>
China
</option>
<option
value="CX"
>
Christmas Island
</option>
<option
value="CC"
>
Cocos (Keeling) Islands
</option>
<option
value="CO"
>
Colombia
</option>
<option
value="KM"
>
Comoros
</option>
<option
value="CG"
>
Congo
</option>
<option
value="CD"
>
Congo, the Democratic Republic of the
</option>
<option
value="CK"
>
Cook Islands
</option>
<option
value="CR"
>
Costa Rica
</option>
<option
value="CI"
>
Cote D'Ivoire
</option>
<option
value="HR"
>
Croatia
</option>
<option
value="CU"
>
Cuba
</option>
<option
value="CY"
>
Cyprus
</option>
<option
value="CZ"
>
Czech Republic
</option>
<option
value="DK"
>
Denmark
</option>
<option
value="DJ"
>
Djibouti
</option>
<option
value="DM"
>
Dominica
</option>
<option
value="DO"
>
Dominican Republic
</option>
<option
value="EC"
>
Ecuador
</option>
<option
value="EG"
>
Egypt
</option>
<option
value="SV"
>
El Salvador
</option>
<option
value="GQ"
>
Equatorial Guinea
</option>
<option
value="ER"
>
Eritrea
</option>
<option
value="EE"
>
Estonia
</option>
<option
value="ET"
>
Ethiopia
</option>
<option
value="FK"
>
Falkland Islands (Malvinas)
</option>
<option
value="FO"
>
Faroe Islands
</option>
<option
value="FJ"
>
Fiji
</option>
<option
value="FI"
>
Finland
</option>
<option
value="FR"
>
France
</option>
<option
value="GF"
>
French Guiana
</option>
<option
value="PF"
>
French Polynesia
</option>
<option
value="TF"
>
French Southern Territories
</option>
<option
value="GA"
>
Gabon
</option>
<option
value="GM"
>
Gambia
</option>
<option
value="GE"
>
Georgia
</option>
<option
value="DE"
>
Germany
</option>
<option
value="GH"
>
Ghana
</option>
<option
value="GI"
>
Gibraltar
</option>
<option
value="GR"
>
Greece
</option>
<option
value="GL"
>
Greenland
</option>
<option
value="GD"
>
Grenada
</option>
<option
value="GP"
>
Guadeloupe
</option>
<option
value="GU"
>
Guam
</option>
<option
value="GT"
>
Guatemala
</option>
<option
value="GN"
>
Guinea
</option>
<option
value="GW"
>
Guinea-Bissau
</option>
<option
value="GY"
>
Guyana
</option>
<option
value="HT"
>
Haiti
</option>
<option
value="HM"
>
Heard Island and Mcdonald Islands
</option>
<option
value="VA"
>
Holy See (Vatican City State)
</option>
<option
value="HN"
>
Honduras
</option>
<option
value="HK"
>
Hong Kong
</option>
<option
value="HU"
>
Hungary
</option>
<option
value="IS"
>
Iceland
</option>
<option
value="IN"
>
India
</option>
<option
value="ID"
>
Indonesia
</option>
<option
value="IR"
>
Iran, Islamic Republic of
</option>
<option
value="IQ"
>
Iraq
</option>
<option
value="IE"
>
Ireland
</option>
<option
value="IL"
>
Israel
</option>
<option
value="IT"
>
Italy
</option>
<option
value="JM"
>
Jamaica
</option>
<option
value="JP"
>
Japan
</option>
<option
value="JO"
>
Jordan
</option>
<option
value="KZ"
>
Kazakhstan
</option>
<option
value="KE"
>
Kenya
</option>
<option
value="KI"
>
Kiribati
</option>
<option
value="KP"
>
North Korea
</option>
<option
value="KR"
>
South Korea
</option>
<option
value="KW"
>
Kuwait
</option>
<option
value="KG"
>
Kyrgyzstan
</option>
<option
value="LA"
>
Lao People's Democratic Republic
</option>
<option
value="LV"
>
Latvia
</option>
<option
value="LB"
>
Lebanon
</option>
<option
value="LS"
>
Lesotho
</option>
<option
value="LR"
>
Liberia
</option>
<option
value="LY"
>
Libya
</option>
<option
value="LI"
>
Liechtenstein
</option>
<option
value="LT"
>
Lithuania
</option>
<option
value="LU"
>
Luxembourg
</option>
<option
value="MO"
>
Macao
</option>
<option
value="MG"
>
Madagascar
</option>
<option
value="MW"
>
Malawi
</option>
<option
value="MY"
>
Malaysia
</option>
<option
value="MV"
>
Maldives
</option>
<option
value="ML"
>
Mali
</option>
<option
value="MT"
>
Malta
</option>
<option
value="MH"
>
Marshall Islands
</option>
<option
value="MQ"
>
Martinique
</option>
<option
value="MR"
>
Mauritania
</option>
<option
value="MU"
>
Mauritius
</option>
<option
value="YT"
>
Mayotte
</option>
<option
value="MX"
>
Mexico
</option>
<option
value="FM"
>
Micronesia, Federated States of
</option>
<option
value="MD"
>
Moldova, Republic of
</option>
<option
value="MC"
>
Monaco
</option>
<option
value="MN"
>
Mongolia
</option>
<option
value="MS"
>
Montserrat
</option>
<option
value="MA"
>
Morocco
</option>
<option
value="MZ"
>
Mozambique
</option>
<option
value="MM"
>
Myanmar
</option>
<option
value="NA"
>
Namibia
</option>
<option
value="NR"
>
Nauru
</option>
<option
value="NP"
>
Nepal
</option>
<option
value="NL"
>
Netherlands
</option>
<option
value="NC"
>
New Caledonia
</option>
<option
value="NZ"
>
New Zealand
</option>
<option
value="NI"
>
Nicaragua
</option>
<option
value="NE"
>
Niger
</option>
<option
value="NG"
>
Nigeria
</option>
<option
value="NU"
>
Niue
</option>
<option
value="NF"
>
Norfolk Island
</option>
<option
value="MK"
>
North Macedonia, Republic of
</option>
<option
value="MP"
>
Northern Mariana Islands
</option>
<option
value="NO"
>
Norway
</option>
<option
value="OM"
>
Oman
</option>
<option
value="PK"
>
Pakistan
</option>
<option
value="PW"
>
Palau
</option>
<option
value="PS"
>
Palestinian Territory, Occupied
</option>
<option
value="PA"
>
Panama
</option>
<option
value="PG"
>
Papua New Guinea
</option>
<option
value="PY"
>
Paraguay
</option>
<option
value="PE"
>
Peru
</option>
<option
value="PH"
>
Philippines
</option>
<option
value="PN"
>
Pitcairn
</option>
<option
value="PL"
>
Poland
</option>
<option
value="PT"
>
Portugal
</option>
<option
value="PR"
>
Puerto Rico
</option>
<option
value="QA"
>
Qatar
</option>
<option
value="RE"
>
Reunion
</option>
<option
value="RO"
>
Romania
</option>
<option
value="RU"
>
Russian Federation
</option>
<option
value="RW"
>
Rwanda
</option>
<option
value="SH"
>
Saint Helena
</option>
<option
value="KN"
>
Saint Kitts and Nevis
</option>
<option
value="LC"
>
Saint Lucia
</option>
<option
value="PM"
>
Saint Pierre and Miquelon
</option>
<option
value="VC"
>
Saint Vincent and the Grenadines
</option>
<option
value="WS"
>
Samoa
</option>
<option
value="SM"
>
San Marino
</option>
<option
value="ST"
>
Sao Tome and Principe
</option>
<option
value="SA"
>
Saudi Arabia
</option>
<option
value="SN"
>
Senegal
</option>
<option
value="SC"
>
Seychelles
</option>
<option
value="SL"
>
Sierra Leone
</option>
<option
value="SG"
>
Singapore
</option>
<option
value="SK"
>
Slovakia
</option>
<option
value="SI"
>
Slovenia
</option>
<option
value="SB"
>
Solomon Islands
</option>
<option
value="SO"
>
Somalia
</option>
<option
value="ZA"
>
South Africa
</option>
<option
value="GS"
>
South Georgia and the South Sandwich Islands
</option>
<option
value="ES"
>
Spain
</option>
<option
value="LK"
>
Sri Lanka
</option>
<option
value="SD"
>
Sudan
</option>
<option
value="SR"
>
Suriname
</option>
<option
value="SJ"
>
Svalbard and Jan Mayen
</option>
<option
value="SZ"
>
Swaziland
</option>
<option
value="SE"
>
Sweden
</option>
<option
value="CH"
>
Switzerland
</option>
<option
value="SY"
>
Syrian Arab Republic
</option>
<option
value="TW"
>
Taiwan
</option>
<option
value="TJ"
>
Tajikistan
</option>
<option
value="TZ"
>
Tanzania, United Republic of
</option>
<option
value="TH"
>
Thailand
</option>
<option
value="TL"
>
Timor-Leste
</option>
<option
value="TG"
>
Togo
</option>
<option
value="TK"
>
Tokelau
</option>
<option
value="TO"
>
Tonga
</option>
<option
value="TT"
>
Trinidad and Tobago
</option>
<option
value="TN"
>
Tunisia
</option>
<option
value="TR"
>
Turkey
</option>
<option
value="TM"
>
Turkmenistan
</option>
<option
value="TC"
>
Turks and Caicos Islands
</option>
<option
value="TV"
>
Tuvalu
</option>
<option
value="UG"
>
Uganda
</option>
<option
value="UA"
>
Ukraine
</option>
<option
value="AE"
>
United Arab Emirates
</option>
<option
value="GB"
>
United Kingdom
</option>
<option
value="US"
>
United States of America
</option>
<option
value="UM"
>
United States Minor Outlying Islands
</option>
<option
value="UY"
>
Uruguay
</option>
<option
value="UZ"
>
Uzbekistan
</option>
<option
value="VU"
>
Vanuatu
</option>
<option
value="VE"
>
Venezuela
</option>
<option
value="VN"
>
Viet Nam
</option>
<option
value="VG"
>
Virgin Islands, British
</option>
<option
value="VI"
>
Virgin Islands, U.S.
</option>
<option
value="WF"
>
Wallis and Futuna
</option>
<option
value="EH"
>
Western Sahara
</option>
<option
value="YE"
>
Yemen
</option>
<option
value="ZM"
>
Zambia
</option>
<option
value="ZW"
>
Zimbabwe
</option>
<option
value="AX"
>
Åland Islands
</option>
<option
value="BQ"
>
Bonaire, Sint Eustatius and Saba
</option>
<option
value="CW"
>
Curaçao
</option>
<option
value="GG"
>
Guernsey
</option>
<option
value="IM"
>
Isle of Man
</option>
<option
value="JE"
>
Jersey
</option>
<option
value="ME"
>
Montenegro
</option>
<option
value="BL"
>
Saint Barthélemy
</option>
<option
value="MF"
>
Saint Martin (French part)
</option>
<option
value="RS"
>
Serbia
</option>
<option
value="SX"
>
Sint Maarten (Dutch part)
</option>
<option
value="SS"
>
South Sudan
</option>
<option
value="XK"
>
Kosovo
</option>
</select>
<strong
className="invalid-feedback"
id="country-invalid-feedback"
>
Select your country or region of residence.
</strong>
Support education research by providing additional information
</p>
</div>
<span>
By creating an account, you agree to the
<a
href="https://www.edx.org/edx-terms-service"
>
Terms of Service and Honor Code
</a>
and you acknowledge that edX and each Member process your personal data in accordance with the
<a
href="https://www.edx.org/edx-privacy-policy"
>
Privacy Policy
</a>
.
</span>
<button
aria-disabled={false}
aria-live="assertive"