mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2025-02-17 00:21:20 -05:00
Merge pull request #3291 from benjiwheeler/join-flow-register
join flow register user function, registration error component
This commit is contained in:
commit
290a6ad9ad
11 changed files with 952 additions and 576 deletions
1085
package-lock.json
generated
1085
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -123,6 +123,7 @@
|
|||
"react-string-replace": "0.4.1",
|
||||
"react-telephone-input": "4.3.4",
|
||||
"redux": "3.5.2",
|
||||
"redux-mock-store": "^1.2.3",
|
||||
"redux-thunk": "2.0.1",
|
||||
"sass-loader": "6.0.6",
|
||||
"scratch-gui": "0.1.0-prerelease.20190909235840",
|
||||
|
|
|
@ -12,9 +12,10 @@ const FormikCheckboxSubComponent = ({
|
|||
id,
|
||||
label,
|
||||
labelClassName,
|
||||
outerClassName,
|
||||
...props
|
||||
}) => (
|
||||
<div className="checkbox">
|
||||
<div className={classNames('checkbox', outerClassName)}>
|
||||
<input
|
||||
checked={field.value}
|
||||
className="formik-checkbox"
|
||||
|
@ -50,7 +51,8 @@ FormikCheckboxSubComponent.propTypes = {
|
|||
}),
|
||||
id: PropTypes.string,
|
||||
label: PropTypes.string,
|
||||
labelClassName: PropTypes.string
|
||||
labelClassName: PropTypes.string,
|
||||
outerClassName: PropTypes.string
|
||||
};
|
||||
|
||||
|
||||
|
@ -59,6 +61,7 @@ const FormikCheckbox = ({
|
|||
label,
|
||||
labelClassName,
|
||||
name,
|
||||
outerClassName,
|
||||
...props
|
||||
}) => (
|
||||
<Field
|
||||
|
@ -67,6 +70,7 @@ const FormikCheckbox = ({
|
|||
label={label}
|
||||
labelClassName={labelClassName}
|
||||
name={name}
|
||||
outerClassName={outerClassName}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
@ -75,7 +79,8 @@ FormikCheckbox.propTypes = {
|
|||
id: PropTypes.string,
|
||||
label: PropTypes.string,
|
||||
labelClassName: PropTypes.string,
|
||||
name: PropTypes.string
|
||||
name: PropTypes.string,
|
||||
outerClassName: PropTypes.string
|
||||
};
|
||||
|
||||
module.exports = FormikCheckbox;
|
||||
|
|
|
@ -8,6 +8,7 @@ const {injectIntl, intlShape} = require('react-intl');
|
|||
const countryData = require('../../lib/country-data');
|
||||
const FormikSelect = require('../../components/formik-forms/formik-select.jsx');
|
||||
const JoinFlowStep = require('./join-flow-step.jsx');
|
||||
const FormikCheckbox = require('../../components/formik-forms/formik-checkbox.jsx');
|
||||
|
||||
require('./join-flow-steps.scss');
|
||||
|
||||
|
@ -94,6 +95,13 @@ class CountryStep extends React.Component {
|
|||
validate={this.validateSelect}
|
||||
validationClassName="validation-full-width-input"
|
||||
/>
|
||||
{/* note that this is a hidden checkbox the user will never see */}
|
||||
<FormikCheckbox
|
||||
id="yesno"
|
||||
label={this.props.intl.formatMessage({id: 'registration.receiveEmails'})}
|
||||
name="yesno"
|
||||
outerClassName="yesNoCheckbox"
|
||||
/>
|
||||
</div>
|
||||
</JoinFlowStep>
|
||||
);
|
||||
|
|
|
@ -151,7 +151,7 @@ class EmailStep extends React.Component {
|
|||
innerClassName="join-flow-inner-email-step"
|
||||
nextButton={this.props.intl.formatMessage({id: 'registration.createAccount'})}
|
||||
title={this.props.intl.formatMessage({id: 'registration.emailStepTitle'})}
|
||||
waiting={isSubmitting || this.state.captchaIsLoading}
|
||||
waiting={this.props.waiting || isSubmitting || this.state.captchaIsLoading}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<FormikInput
|
||||
|
@ -200,7 +200,8 @@ class EmailStep extends React.Component {
|
|||
|
||||
EmailStep.propTypes = {
|
||||
intl: intlShape,
|
||||
onNextStep: PropTypes.func
|
||||
onNextStep: PropTypes.func,
|
||||
waiting: PropTypes.bool
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -132,6 +132,10 @@
|
|||
margin-left: -.5rem;
|
||||
}
|
||||
|
||||
.join-flow-registration-error {
|
||||
padding-top: 5.5rem;
|
||||
}
|
||||
|
||||
.join-flow-gender-description {
|
||||
margin-top: .625rem;
|
||||
margin-bottom: 1.25rem;
|
||||
|
@ -180,3 +184,7 @@
|
|||
a.join-flow-link:link, a.join-flow-link:visited, a.join-flow-link:active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.yesNoCheckbox {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
const bindAll = require('lodash.bindall');
|
||||
const connect = require('react-redux').connect;
|
||||
const defaults = require('lodash.defaultsdeep');
|
||||
const PropTypes = require('prop-types');
|
||||
const React = require('react');
|
||||
|
||||
const api = require('../../lib/api');
|
||||
const injectIntl = require('../../lib/intl.jsx').injectIntl;
|
||||
const intlShape = require('../../lib/intl.jsx').intlShape;
|
||||
const sessionActions = require('../../redux/session.js');
|
||||
|
||||
const Progression = require('../progression/progression.jsx');
|
||||
const UsernameStep = require('./username-step.jsx');
|
||||
|
@ -13,44 +16,141 @@ const GenderStep = require('./gender-step.jsx');
|
|||
const CountryStep = require('./country-step.jsx');
|
||||
const EmailStep = require('./email-step.jsx');
|
||||
const WelcomeStep = require('./welcome-step.jsx');
|
||||
const RegistrationErrorStep = require('./registration-error-step.jsx');
|
||||
|
||||
/*
|
||||
eslint-disable react/prefer-stateless-function, react/no-unused-prop-types, no-useless-constructor
|
||||
*/
|
||||
class JoinFlow extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
bindAll(this, [
|
||||
'handleAdvanceStep'
|
||||
'handleAdvanceStep',
|
||||
'handlePrepareToRegister',
|
||||
'handleRegistrationResponse',
|
||||
'handleSubmitRegistration'
|
||||
]);
|
||||
this.state = {
|
||||
formData: {},
|
||||
registrationError: null,
|
||||
step: 0
|
||||
step: 0,
|
||||
waiting: false
|
||||
};
|
||||
}
|
||||
handleAdvanceStep (formData) {
|
||||
formData = formData || {};
|
||||
handlePrepareToRegister (newFormData) {
|
||||
newFormData = newFormData || {};
|
||||
const newState = {
|
||||
formData: defaults({}, newFormData, this.state.formData)
|
||||
};
|
||||
this.setState(newState, () => {
|
||||
this.handleSubmitRegistration(this.state.formData);
|
||||
});
|
||||
}
|
||||
handleRegistrationResponse (err, body, res) {
|
||||
// example of failing response:
|
||||
// [
|
||||
// {
|
||||
// "msg": "This field is required.",
|
||||
// "errors": {
|
||||
// "username": ["This field is required."],
|
||||
// "recaptcha": ["Incorrect, please try again."]
|
||||
// },
|
||||
// "success": false
|
||||
// }
|
||||
// ]
|
||||
this.setState({waiting: false}, () => {
|
||||
let errStr = '';
|
||||
if (!err && res.statusCode === 200) {
|
||||
if (body && body[0]) {
|
||||
if (body[0].success) {
|
||||
this.props.refreshSession();
|
||||
this.setState({
|
||||
step: this.state.step + 1
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (body[0].errors) {
|
||||
// body can include zero or more error objects, each
|
||||
// with its own key and description. Here we assemble
|
||||
// all of them into a single string, errStr.
|
||||
const errorKeys = Object.keys(body[0].errors);
|
||||
errorKeys.forEach(key => {
|
||||
const val = body[0].errors[key];
|
||||
if (val && val[0]) {
|
||||
if (errStr.length) errStr += '; ';
|
||||
errStr += `${key}: ${val[0]}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!errStr.length && body[0].msg) errStr = body[0].msg;
|
||||
}
|
||||
}
|
||||
this.setState({
|
||||
registrationError: errStr ||
|
||||
`${this.props.intl.formatMessage({
|
||||
id: 'registration.generalError'
|
||||
})} (${res.statusCode})`
|
||||
});
|
||||
});
|
||||
}
|
||||
handleSubmitRegistration (formData) {
|
||||
this.setState({waiting: true}, () => {
|
||||
api({
|
||||
host: '',
|
||||
uri: '/accounts/register_new_user/',
|
||||
method: 'post',
|
||||
useCsrf: true,
|
||||
formData: {
|
||||
'username': formData.username,
|
||||
'email': formData.email,
|
||||
'password': formData.password,
|
||||
'birth_month': formData.birth_month,
|
||||
'birth_year': formData.birth_year,
|
||||
'g-recaptcha-response': null,
|
||||
'gender': formData.gender,
|
||||
'country': formData.country,
|
||||
'subscribe': true,
|
||||
'is_robot': formData.yesno
|
||||
// no need to include csrfmiddlewaretoken; will be provided in
|
||||
// X-CSRFToken header, which scratchr2 looks for in
|
||||
// scratchr2/middleware/csrf.py line 237.
|
||||
}
|
||||
}, (err, body, res) => {
|
||||
this.handleRegistrationResponse(err, body, res);
|
||||
});
|
||||
});
|
||||
}
|
||||
handleAdvanceStep (newFormData) {
|
||||
newFormData = newFormData || {};
|
||||
this.setState({
|
||||
step: this.state.step + 1,
|
||||
formData: defaults({}, formData, this.state.formData)
|
||||
formData: defaults({}, newFormData, this.state.formData),
|
||||
step: this.state.step + 1
|
||||
});
|
||||
}
|
||||
render () {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Progression step={this.state.step}>
|
||||
<UsernameStep onNextStep={this.handleAdvanceStep} />
|
||||
<BirthDateStep onNextStep={this.handleAdvanceStep} />
|
||||
<GenderStep onNextStep={this.handleAdvanceStep} />
|
||||
<CountryStep onNextStep={this.handleAdvanceStep} />
|
||||
<EmailStep onNextStep={this.handleAdvanceStep} />
|
||||
<WelcomeStep
|
||||
email={this.state.formData.email}
|
||||
username={this.state.formData.username}
|
||||
onNextStep={this.handleAdvanceStep}
|
||||
{this.state.registrationError ? (
|
||||
<RegistrationErrorStep
|
||||
errorMsg={this.state.registrationError}
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
onTryAgain={() => this.handleSubmitRegistration(this.state.formData)}
|
||||
/* eslint-enable react/jsx-no-bind */
|
||||
/>
|
||||
</Progression>
|
||||
) : (
|
||||
<Progression step={this.state.step}>
|
||||
<UsernameStep onNextStep={this.handleAdvanceStep} />
|
||||
<BirthDateStep onNextStep={this.handleAdvanceStep} />
|
||||
<GenderStep onNextStep={this.handleAdvanceStep} />
|
||||
<CountryStep onNextStep={this.handleAdvanceStep} />
|
||||
<EmailStep
|
||||
waiting={this.state.waiting}
|
||||
onNextStep={this.handlePrepareToRegister}
|
||||
/>
|
||||
<WelcomeStep
|
||||
email={this.state.formData.email}
|
||||
username={this.state.formData.username}
|
||||
onNextStep={this.props.onCompleteRegistration}
|
||||
/>
|
||||
</Progression>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
@ -58,11 +158,27 @@ class JoinFlow extends React.Component {
|
|||
|
||||
JoinFlow.propTypes = {
|
||||
intl: intlShape,
|
||||
onCompleteRegistration: PropTypes.func
|
||||
onCompleteRegistration: PropTypes.func,
|
||||
refreshSession: PropTypes.func
|
||||
};
|
||||
|
||||
module.exports = injectIntl(JoinFlow);
|
||||
const IntlJoinFlow = injectIntl(JoinFlow);
|
||||
|
||||
/*
|
||||
eslint-enable
|
||||
*/
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
refreshSession: () => {
|
||||
dispatch(sessionActions.refreshSession());
|
||||
}
|
||||
});
|
||||
|
||||
// Allow incoming props to override redux-provided props. Used to mock in tests.
|
||||
const mergeProps = (stateProps, dispatchProps, ownProps) => Object.assign(
|
||||
{}, stateProps, dispatchProps, ownProps
|
||||
);
|
||||
|
||||
const ConnectedJoinFlow = connect(
|
||||
() => ({}),
|
||||
mapDispatchToProps,
|
||||
mergeProps
|
||||
)(IntlJoinFlow);
|
||||
|
||||
module.exports = ConnectedJoinFlow;
|
||||
|
|
45
src/components/join-flow/registration-error-step.jsx
Normal file
45
src/components/join-flow/registration-error-step.jsx
Normal file
|
@ -0,0 +1,45 @@
|
|||
const bindAll = require('lodash.bindall');
|
||||
const React = require('react');
|
||||
const PropTypes = require('prop-types');
|
||||
const {injectIntl, intlShape} = require('react-intl');
|
||||
|
||||
const JoinFlowStep = require('./join-flow-step.jsx');
|
||||
|
||||
require('./join-flow-steps.scss');
|
||||
|
||||
class RegistrationErrorStep extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
bindAll(this, [
|
||||
'handleSubmit'
|
||||
]);
|
||||
}
|
||||
handleSubmit (e) {
|
||||
// JoinFlowStep includes a <form> that handles a submit action.
|
||||
// But here, we're not really submitting, so we need to prevent
|
||||
// the form from navigating away from the current page.
|
||||
e.preventDefault();
|
||||
this.props.onTryAgain();
|
||||
}
|
||||
render () {
|
||||
return (
|
||||
<JoinFlowStep
|
||||
description={this.props.errorMsg}
|
||||
innerClassName="join-flow-registration-error"
|
||||
nextButton={this.props.intl.formatMessage({id: 'general.tryAgain'})}
|
||||
title={this.props.intl.formatMessage({id: 'registration.generalError'})}
|
||||
onSubmit={this.handleSubmit}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
RegistrationErrorStep.propTypes = {
|
||||
errorMsg: PropTypes.string,
|
||||
intl: intlShape,
|
||||
onTryAgain: PropTypes.func
|
||||
};
|
||||
|
||||
const IntlRegistrationErrorStep = injectIntl(RegistrationErrorStep);
|
||||
|
||||
module.exports = IntlRegistrationErrorStep;
|
|
@ -89,6 +89,7 @@
|
|||
"general.ideas": "Ideas",
|
||||
"general.tipsWindow": "Tips Window",
|
||||
"general.termsOfUse": "Terms of Use",
|
||||
"general.tryAgain": "Try again",
|
||||
"general.unhandledError": "We are so sorry, but it looks like Scratch has crashed. This bug has been automatically reported to the Scratch Team.",
|
||||
"general.username": "Username",
|
||||
"general.validationEmail": "Please enter a valid email address",
|
||||
|
|
165
test/unit/components/join-flow.test.jsx
Normal file
165
test/unit/components/join-flow.test.jsx
Normal file
|
@ -0,0 +1,165 @@
|
|||
import React from 'react';
|
||||
const {shallowWithIntl} = require('../../helpers/intl-helpers.jsx');
|
||||
import configureStore from 'redux-mock-store';
|
||||
import JoinFlow from '../../../src/components/join-flow/join-flow';
|
||||
import Progression from '../../../src/components/progression/progression.jsx';
|
||||
import RegistrationErrorStep from '../../../src/components/join-flow/registration-error-step';
|
||||
|
||||
describe('JoinFlow', () => {
|
||||
const mockStore = configureStore();
|
||||
let store;
|
||||
|
||||
beforeEach(() => {
|
||||
store = mockStore({sessionActions: {
|
||||
refreshSession: jest.fn()
|
||||
}});
|
||||
});
|
||||
|
||||
const getJoinFlowWrapper = props => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<JoinFlow
|
||||
{...props}
|
||||
/>
|
||||
, {context: {store}}
|
||||
);
|
||||
return wrapper
|
||||
.dive() // unwrap redux connect(injectIntl(JoinFlow))
|
||||
.dive(); // unwrap injectIntl(JoinFlow)
|
||||
};
|
||||
|
||||
test('handleRegistrationResponse with successful response', () => {
|
||||
const props = {
|
||||
refreshSession: jest.fn()
|
||||
};
|
||||
const joinFlowInstance = getJoinFlowWrapper(props).instance();
|
||||
const responseErr = null;
|
||||
const responseBody = [
|
||||
{
|
||||
success: true
|
||||
}
|
||||
];
|
||||
const responseObj = {
|
||||
statusCode: 200
|
||||
};
|
||||
joinFlowInstance.handleRegistrationResponse(responseErr, responseBody, responseObj);
|
||||
expect(joinFlowInstance.props.refreshSession).toHaveBeenCalled();
|
||||
expect(joinFlowInstance.state.registrationError).toBe(null);
|
||||
});
|
||||
|
||||
test('handleRegistrationResponse with healthy response, indicating failure', () => {
|
||||
const props = {
|
||||
refreshSession: jest.fn()
|
||||
};
|
||||
const joinFlowInstance = getJoinFlowWrapper(props).instance();
|
||||
const responseErr = null;
|
||||
const responseBody = [
|
||||
{
|
||||
msg: 'This field is required.',
|
||||
errors: {
|
||||
username: ['This field is required.']
|
||||
},
|
||||
success: false
|
||||
}
|
||||
];
|
||||
const responseObj = {
|
||||
statusCode: 200
|
||||
};
|
||||
joinFlowInstance.handleRegistrationResponse(responseErr, responseBody, responseObj);
|
||||
expect(joinFlowInstance.props.refreshSession).not.toHaveBeenCalled();
|
||||
expect(joinFlowInstance.state.registrationError).toBe('username: This field is required.');
|
||||
});
|
||||
|
||||
test('handleRegistrationResponse with failure response, with error fields missing', () => {
|
||||
const props = {
|
||||
refreshSession: jest.fn()
|
||||
};
|
||||
const joinFlowInstance = getJoinFlowWrapper(props).instance();
|
||||
const responseErr = null;
|
||||
const responseBody = [
|
||||
{
|
||||
msg: 'This field is required.',
|
||||
success: false
|
||||
}
|
||||
];
|
||||
const responseObj = {
|
||||
statusCode: 200
|
||||
};
|
||||
joinFlowInstance.handleRegistrationResponse(responseErr, responseBody, responseObj);
|
||||
expect(joinFlowInstance.props.refreshSession).not.toHaveBeenCalled();
|
||||
expect(joinFlowInstance.state.registrationError).toBe('This field is required.');
|
||||
});
|
||||
|
||||
test('handleRegistrationResponse with failure response, with no text explanation', () => {
|
||||
const props = {
|
||||
refreshSession: jest.fn()
|
||||
};
|
||||
const joinFlowInstance = getJoinFlowWrapper(props).instance();
|
||||
const responseErr = null;
|
||||
const responseBody = [
|
||||
{
|
||||
success: false
|
||||
}
|
||||
];
|
||||
const responseObj = {
|
||||
statusCode: 200
|
||||
};
|
||||
joinFlowInstance.handleRegistrationResponse(responseErr, responseBody, responseObj);
|
||||
expect(joinFlowInstance.props.refreshSession).not.toHaveBeenCalled();
|
||||
expect(joinFlowInstance.state.registrationError).toBe('registration.generalError (200)');
|
||||
});
|
||||
|
||||
test('handleRegistrationResponse with failure status code', () => {
|
||||
const props = {
|
||||
refreshSession: jest.fn()
|
||||
};
|
||||
const joinFlowInstance = getJoinFlowWrapper(props).instance();
|
||||
const responseErr = null;
|
||||
const responseBody = [
|
||||
{
|
||||
success: false
|
||||
}
|
||||
];
|
||||
const responseObj = {
|
||||
statusCode: 400
|
||||
};
|
||||
joinFlowInstance.handleRegistrationResponse(responseErr, responseBody, responseObj);
|
||||
expect(joinFlowInstance.props.refreshSession).not.toHaveBeenCalled();
|
||||
expect(joinFlowInstance.state.registrationError).toBe('registration.generalError (400)');
|
||||
});
|
||||
|
||||
test('handleAdvanceStep', () => {
|
||||
const joinFlowInstance = getJoinFlowWrapper().instance();
|
||||
joinFlowInstance.setState({formData: {username: 'ScratchCat123'}, step: 2});
|
||||
joinFlowInstance.handleAdvanceStep({email: 'scratchcat123@scratch.mit.edu'});
|
||||
expect(joinFlowInstance.state.formData.username).toBe('ScratchCat123');
|
||||
expect(joinFlowInstance.state.formData.email).toBe('scratchcat123@scratch.mit.edu');
|
||||
expect(joinFlowInstance.state.step).toBe(3);
|
||||
});
|
||||
|
||||
test('when state.registrationError has error message, we show RegistrationErrorStep', () => {
|
||||
const joinFlowWrapper = getJoinFlowWrapper();
|
||||
joinFlowWrapper.instance().setState({registrationError: 'halp there is a errors!!'});
|
||||
const registrationErrorWrapper = joinFlowWrapper.find(RegistrationErrorStep);
|
||||
const progressionWrapper = joinFlowWrapper.find(Progression);
|
||||
expect(registrationErrorWrapper).toHaveLength(1);
|
||||
expect(progressionWrapper).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('when state.registrationError has null error message, we show Progression', () => {
|
||||
const joinFlowWrapper = getJoinFlowWrapper();
|
||||
joinFlowWrapper.instance().setState({registrationError: null});
|
||||
const registrationErrorWrapper = joinFlowWrapper.find(RegistrationErrorStep);
|
||||
const progressionWrapper = joinFlowWrapper.find(Progression);
|
||||
expect(registrationErrorWrapper).toHaveLength(0);
|
||||
expect(progressionWrapper).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('when state.registrationError has empty error message, we show Progression', () => {
|
||||
const joinFlowWrapper = getJoinFlowWrapper();
|
||||
joinFlowWrapper.instance().setState({registrationError: ''});
|
||||
const registrationErrorWrapper = joinFlowWrapper.find(RegistrationErrorStep);
|
||||
const progressionWrapper = joinFlowWrapper.find(Progression);
|
||||
expect(registrationErrorWrapper).toHaveLength(0);
|
||||
expect(progressionWrapper).toHaveLength(1);
|
||||
});
|
||||
});
|
33
test/unit/components/registration-error-step.test.jsx
Normal file
33
test/unit/components/registration-error-step.test.jsx
Normal file
|
@ -0,0 +1,33 @@
|
|||
import React from 'react';
|
||||
import {shallowWithIntl} from '../../helpers/intl-helpers.jsx';
|
||||
import JoinFlowStep from '../../../src/components/join-flow/join-flow-step';
|
||||
import RegistrationErrorStep from '../../../src/components/join-flow/registration-error-step';
|
||||
|
||||
describe('RegistrationErrorStep', () => {
|
||||
const onTryAgain = jest.fn();
|
||||
let wrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = shallowWithIntl(
|
||||
<RegistrationErrorStep
|
||||
errorMsg={'error message'}
|
||||
onTryAgain={onTryAgain}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
test('shows JoinFlowStep with props', () => {
|
||||
// Dive to get past the anonymous component.
|
||||
const joinFlowStepWrapper = wrapper.dive().find(JoinFlowStep);
|
||||
expect(joinFlowStepWrapper).toHaveLength(1);
|
||||
expect(joinFlowStepWrapper.props().description).toBe('error message');
|
||||
expect(joinFlowStepWrapper.props().nextButton).toBe('general.tryAgain');
|
||||
});
|
||||
|
||||
test('when submitted, onTryAgain is called', () => {
|
||||
// Dive to get past the anonymous component.
|
||||
const joinFlowStepWrapper = wrapper.dive().find(JoinFlowStep);
|
||||
joinFlowStepWrapper.props().onSubmit(new Event('event')); // eslint-disable-line no-undef
|
||||
expect(onTryAgain).toHaveBeenCalled();
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue