mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2024-11-23 15:47:53 -05:00
add tests for feedback form, clean-up form
This commit is contained in:
parent
f2a3dfda1b
commit
9df36b0fcf
4 changed files with 154 additions and 88 deletions
|
@ -32,18 +32,15 @@ class MuteModal extends React.Component {
|
||||||
'handleNext',
|
'handleNext',
|
||||||
'handlePrevious',
|
'handlePrevious',
|
||||||
'handleGoToFeedback',
|
'handleGoToFeedback',
|
||||||
'handleFeedbackInput',
|
|
||||||
'handleFeedbackSubmit',
|
|
||||||
'handleSetFeedbackRef',
|
'handleSetFeedbackRef',
|
||||||
|
'handleValidSubmit',
|
||||||
'validateFeedback'
|
'validateFeedback'
|
||||||
]);
|
]);
|
||||||
this.numSteps = 2;
|
|
||||||
if (this.props.showWarning) {
|
this.numSteps = this.props.showWarning ? steps.BAN_WARNING : steps.MUTE_INFO;
|
||||||
this.numSteps++;
|
|
||||||
}
|
|
||||||
this.state = {
|
this.state = {
|
||||||
step: 0,
|
step: 0
|
||||||
feedback: ''
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
handleNext () {
|
handleNext () {
|
||||||
|
@ -64,22 +61,16 @@ class MuteModal extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleFeedbackSubmit () {
|
// called after feedback validation passes with no errors
|
||||||
const noError = !this.validateFeedback(this.state.feedback);
|
handleValidSubmit (formData, formikBag) {
|
||||||
|
formikBag.setSubmitting(false); // formik makes us do this ourselves
|
||||||
|
|
||||||
if (noError) {
|
/* eslint-disable no-console */
|
||||||
/* eslint-disable no-console */
|
console.log(formData.feedback);
|
||||||
console.log(this.state.feedback);
|
/* eslint-enable no-console */
|
||||||
/* eslint-enable no-console */
|
|
||||||
this.setState({
|
|
||||||
step: steps.FEEDBACK_SENT
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleFeedbackInput (feedback) {
|
|
||||||
this.setState({
|
this.setState({
|
||||||
feedback: feedback
|
step: steps.FEEDBACK_SENT
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,14 +80,24 @@ class MuteModal extends React.Component {
|
||||||
|
|
||||||
validateFeedback (feedback) {
|
validateFeedback (feedback) {
|
||||||
if (feedback.length === 0) {
|
if (feedback.length === 0) {
|
||||||
return 'Can\'t be empty';
|
return this.props.intl.formatMessage({id: 'comments.muted.feedbackEmpty'});
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const finalStep = this.showWarning ? steps.BAN_WARNING : steps.MUTE_INFO;
|
const feedbackPrompt = (
|
||||||
|
<p className="feedback-prompt">
|
||||||
|
<FormattedMessage
|
||||||
|
id="comments.muted.mistake"
|
||||||
|
values={{feedbackLink: (
|
||||||
|
<a onClick={this.handleGoToFeedback}>
|
||||||
|
<FormattedMessage id="comments.muted.feedbackLinkText" />
|
||||||
|
</a>
|
||||||
|
)}}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -142,16 +143,7 @@ class MuteModal extends React.Component {
|
||||||
)}}
|
)}}
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
{this.state.step === this.numSteps ? feedbackPrompt : null}
|
||||||
<FormattedMessage
|
|
||||||
id="comments.muted.mistake"
|
|
||||||
values={{feedbackLink: (
|
|
||||||
<a onClick={this.handleGoToFeedback}>
|
|
||||||
<FormattedMessage id="comments.muted.feedbackLinkText" />
|
|
||||||
</a>
|
|
||||||
)}}
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
</MuteStep>
|
</MuteStep>
|
||||||
<MuteStep
|
<MuteStep
|
||||||
bottomImg="/svgs/commenting/warning.svg"
|
bottomImg="/svgs/commenting/warning.svg"
|
||||||
|
@ -168,6 +160,7 @@ class MuteModal extends React.Component {
|
||||||
)}}
|
)}}
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
|
{this.state.step === this.numSteps ? feedbackPrompt : null}
|
||||||
</MuteStep>
|
</MuteStep>
|
||||||
<MuteStep
|
<MuteStep
|
||||||
header={this.props.intl.formatMessage({id: 'comments.muted.mistakeHeader'})}
|
header={this.props.intl.formatMessage({id: 'comments.muted.mistakeHeader'})}
|
||||||
|
@ -182,43 +175,49 @@ class MuteModal extends React.Component {
|
||||||
validate={this.validateFeedback}
|
validate={this.validateFeedback}
|
||||||
validateOnBlur={false}
|
validateOnBlur={false}
|
||||||
validateOnChange={false}
|
validateOnChange={false}
|
||||||
|
onSubmit={this.handleValidSubmit}
|
||||||
>
|
>
|
||||||
{props => {
|
{props => {
|
||||||
const {
|
const {
|
||||||
errors,
|
errors,
|
||||||
|
handleSubmit,
|
||||||
setFieldError,
|
setFieldError,
|
||||||
setFieldTouched,
|
setFieldTouched,
|
||||||
setFieldValue,
|
setFieldValue,
|
||||||
validateField
|
validateField
|
||||||
} = props;
|
} = props;
|
||||||
return (
|
return (
|
||||||
<FormikInput
|
<form
|
||||||
autoCapitalize="off"
|
id="feedback-form"
|
||||||
autoComplete="off"
|
onSubmit={handleSubmit}
|
||||||
autoCorrect="off"
|
>
|
||||||
className={classNames(
|
<FormikInput
|
||||||
'compose-feedback',
|
autoCapitalize="off"
|
||||||
)}
|
autoComplete="off"
|
||||||
component="textarea"
|
autoCorrect="off"
|
||||||
error={errors.feedback}
|
className={classNames(
|
||||||
id="feedback"
|
'compose-feedback',
|
||||||
maxLength={MAX_FEEDBACK_LENGTH}
|
)}
|
||||||
name="feedback"
|
component="textarea"
|
||||||
rows={5}
|
error={errors.feedback}
|
||||||
type="text"
|
id="feedback"
|
||||||
validate={this.validateFeedback}
|
maxLength={MAX_FEEDBACK_LENGTH}
|
||||||
validationClassName="validation-full-width-input"
|
name="feedback"
|
||||||
/* eslint-disable react/jsx-no-bind */
|
rows={5}
|
||||||
onBlur={() => validateField('feedback')}
|
type="text"
|
||||||
onChange={e => {
|
validate={this.validateFeedback}
|
||||||
setFieldValue('feedback', e.target.value);
|
validationClassName="validation-full-width-input"
|
||||||
setFieldTouched('feedback');
|
/* eslint-disable react/jsx-no-bind */
|
||||||
setFieldError('feedback', null);
|
onBlur={() => validateField('feedback')}
|
||||||
this.handleFeedbackInput(e.target.value);
|
onChange={e => {
|
||||||
}}
|
setFieldValue('feedback', e.target.value);
|
||||||
/* eslint-enable react/jsx-no-bind */
|
setFieldTouched('feedback');
|
||||||
onSetRef={this.handleSetFeedbackRef}
|
setFieldError('feedback', null);
|
||||||
/>
|
}}
|
||||||
|
/* eslint-enable react/jsx-no-bind */
|
||||||
|
onSetRef={this.handleSetFeedbackRef}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</Formik>
|
</Formik>
|
||||||
|
@ -242,7 +241,7 @@ class MuteModal extends React.Component {
|
||||||
this.state.step === steps.USER_FEEDBACK ? 'feedback-nav' : 'mute-nav'
|
this.state.step === steps.USER_FEEDBACK ? 'feedback-nav' : 'mute-nav'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{this.state.step >= finalStep ? (
|
{this.state.step >= this.numSteps ? (
|
||||||
<Button
|
<Button
|
||||||
className={classNames('close-button')}
|
className={classNames('close-button')}
|
||||||
onClick={this.props.onRequestClose}
|
onClick={this.props.onRequestClose}
|
||||||
|
@ -281,7 +280,8 @@ class MuteModal extends React.Component {
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'send-button',
|
'send-button',
|
||||||
)}
|
)}
|
||||||
onClick={this.handleFeedbackSubmit}
|
form="feedback-form"
|
||||||
|
type="submit"
|
||||||
>
|
>
|
||||||
<div className="action-button-text">
|
<div className="action-button-text">
|
||||||
<FormattedMessage id="general.send" />
|
<FormattedMessage id="general.send" />
|
||||||
|
|
|
@ -60,16 +60,9 @@
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
|
|
||||||
button {
|
button {
|
||||||
// min-width: 100px;
|
|
||||||
margin: 0 4px;
|
margin: 0 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
// .action-button-text {
|
|
||||||
// span {
|
|
||||||
// text-align: center;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
.close-button {
|
.close-button {
|
||||||
background-color: $ui-dark-gray;
|
background-color: $ui-dark-gray;
|
||||||
}
|
}
|
||||||
|
@ -87,16 +80,15 @@
|
||||||
|
|
||||||
.feedback-text {
|
.feedback-text {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
max-width: 360px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea, .row-with-tooltip {
|
#feedback-form, textarea {
|
||||||
height: 180px;
|
height: 180px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
padding: 16px;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.character-limit {
|
.character-limit {
|
||||||
|
@ -104,7 +96,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.validation-message {
|
.validation-message {
|
||||||
top: 30%;
|
top: 52px;
|
||||||
margin-left: 4rem;
|
left: 36px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -365,6 +365,7 @@
|
||||||
"comments.muted.thanksFeedback": "Thanks for letting us know!",
|
"comments.muted.thanksFeedback": "Thanks for letting us know!",
|
||||||
"comments.muted.thanksInfo": "Your feedback will help us make Scratch better.",
|
"comments.muted.thanksInfo": "Your feedback will help us make Scratch better.",
|
||||||
"comments.muted.characterLimit": "500 characters max",
|
"comments.muted.characterLimit": "500 characters max",
|
||||||
|
"comments.muted.feedbackEmpty": "Can't be empty",
|
||||||
|
|
||||||
"social.embedLabel": "Embed",
|
"social.embedLabel": "Embed",
|
||||||
"social.copyEmbedLinkText": "Copy embed",
|
"social.copyEmbedLinkText": "Copy embed",
|
||||||
|
|
|
@ -33,19 +33,22 @@ describe('MuteModalTest', () => {
|
||||||
expect(component.find('button.back-button').exists()).toEqual(false);
|
expect(component.find('button.back-button').exists()).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
// test('Mute Modal shows extra showWarning step', () => {
|
test('Mute Modal shows extra showWarning step', () => {
|
||||||
// const component = mountWithIntl(
|
const component = mountWithIntl(
|
||||||
// <MuteModal
|
<MuteModal
|
||||||
// showWarning
|
showWarning
|
||||||
// muteModalMessages={defaultMessages}
|
muteModalMessages={defaultMessages}
|
||||||
// />
|
/>
|
||||||
// );
|
);
|
||||||
// component.find('MuteModal').instance()
|
component.find('MuteModal').instance()
|
||||||
// .setState({step: 2});
|
.setState({step: 1});
|
||||||
// component.update();
|
expect(component.find('button.next-button').exists()).toEqual(true);
|
||||||
// expect(component.find('MuteStep').prop('bottomImg')).toEqual('/svgs/commenting/warning.svg');
|
expect(component.find('button.next-button').getElements()[0].props.onClick)
|
||||||
// expect(component.find('MuteStep').prop('totalSteps')).toEqual(3);
|
.toEqual(component.find('MuteModal').instance().handleNext);
|
||||||
// });
|
component.find('MuteModal').instance()
|
||||||
|
.handleNext();
|
||||||
|
expect(component.find('MuteModal').instance().state.step).toEqual(2);
|
||||||
|
});
|
||||||
|
|
||||||
test('Mute Modal shows back & close button on last step', () => {
|
test('Mute Modal shows back & close button on last step', () => {
|
||||||
const component = mountWithIntl(
|
const component = mountWithIntl(
|
||||||
|
@ -113,4 +116,74 @@ describe('MuteModalTest', () => {
|
||||||
component.instance().handlePrevious();
|
component.instance().handlePrevious();
|
||||||
expect(component.instance().state.step).toBe(0);
|
expect(component.instance().state.step).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Mute modal asks for feedback', () => {
|
||||||
|
const component = mountWithIntl(
|
||||||
|
<MuteModal muteModalMessages={defaultMessages} />
|
||||||
|
);
|
||||||
|
component.find('MuteModal').instance()
|
||||||
|
.setState({step: 1});
|
||||||
|
component.update();
|
||||||
|
expect(component.find('p.feedback-prompt').exists()).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Mute modal asks for feedback on extra showWarning step', () => {
|
||||||
|
const component = mountWithIntl(
|
||||||
|
<MuteModal
|
||||||
|
showWarning
|
||||||
|
muteModalMessages={defaultMessages}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
component.find('MuteModal').instance()
|
||||||
|
.setState({step: 1});
|
||||||
|
component.update();
|
||||||
|
expect(component.find('p.feedback-prompt').exists()).toEqual(false);
|
||||||
|
component.find('MuteModal').instance()
|
||||||
|
.setState({step: 2});
|
||||||
|
component.update();
|
||||||
|
expect(component.find('p.feedback-prompt').exists()).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Mute modal handle go to feedback', () => {
|
||||||
|
const component = shallowWithIntl(
|
||||||
|
<MuteModal
|
||||||
|
muteModalMessages={defaultMessages}
|
||||||
|
/>
|
||||||
|
).dive();
|
||||||
|
component.instance().handleGoToFeedback();
|
||||||
|
expect(component.instance().state.step).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Mute modal empty feedback invalid', () => {
|
||||||
|
const component = shallowWithIntl(
|
||||||
|
<MuteModal
|
||||||
|
muteModalMessages={defaultMessages}
|
||||||
|
/>
|
||||||
|
).dive();
|
||||||
|
|
||||||
|
const emptyError = 'comments.muted.feedbackEmpty';
|
||||||
|
expect(component.instance().validateFeedback('')).toBe(emptyError);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Mute modal non-empty feedback valid', () => {
|
||||||
|
const component = shallowWithIntl(
|
||||||
|
<MuteModal
|
||||||
|
muteModalMessages={defaultMessages}
|
||||||
|
/>
|
||||||
|
).dive();
|
||||||
|
|
||||||
|
expect(component.instance().validateFeedback('some feedback here')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Mute modal submit feedback gives thank you step', () => {
|
||||||
|
const component = shallowWithIntl(
|
||||||
|
<MuteModal
|
||||||
|
muteModalMessages={defaultMessages}
|
||||||
|
/>
|
||||||
|
).dive();
|
||||||
|
const mockFormikBag = {};
|
||||||
|
mockFormikBag.setSubmitting = jest.fn();
|
||||||
|
component.instance().handleValidSubmit({feedback: 'something'}, mockFormikBag);
|
||||||
|
expect(component.instance().state.step).toBe(4);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue