add tests for feedback form, clean-up form

This commit is contained in:
seotts 2021-01-25 17:52:33 -05:00
parent f2a3dfda1b
commit 9df36b0fcf
4 changed files with 154 additions and 88 deletions

View file

@ -32,18 +32,15 @@ class MuteModal extends React.Component {
'handleNext',
'handlePrevious',
'handleGoToFeedback',
'handleFeedbackInput',
'handleFeedbackSubmit',
'handleSetFeedbackRef',
'handleValidSubmit',
'validateFeedback'
]);
this.numSteps = 2;
if (this.props.showWarning) {
this.numSteps++;
}
this.numSteps = this.props.showWarning ? steps.BAN_WARNING : steps.MUTE_INFO;
this.state = {
step: 0,
feedback: ''
step: 0
};
}
handleNext () {
@ -64,24 +61,18 @@ class MuteModal extends React.Component {
});
}
handleFeedbackSubmit () {
const noError = !this.validateFeedback(this.state.feedback);
// called after feedback validation passes with no errors
handleValidSubmit (formData, formikBag) {
formikBag.setSubmitting(false); // formik makes us do this ourselves
if (noError) {
/* eslint-disable no-console */
console.log(this.state.feedback);
console.log(formData.feedback);
/* eslint-enable no-console */
this.setState({
step: steps.FEEDBACK_SENT
});
}
}
handleFeedbackInput (feedback) {
this.setState({
feedback: feedback
});
}
handleSetFeedbackRef (feedbackInputRef) {
this.feedbackInput = feedbackInputRef;
@ -89,14 +80,24 @@ class MuteModal extends React.Component {
validateFeedback (feedback) {
if (feedback.length === 0) {
return 'Can\'t be empty';
return this.props.intl.formatMessage({id: 'comments.muted.feedbackEmpty'});
}
return null;
}
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 (
<Modal
@ -142,16 +143,7 @@ class MuteModal extends React.Component {
)}}
/>
</p>
<p>
<FormattedMessage
id="comments.muted.mistake"
values={{feedbackLink: (
<a onClick={this.handleGoToFeedback}>
<FormattedMessage id="comments.muted.feedbackLinkText" />
</a>
)}}
/>
</p>
{this.state.step === this.numSteps ? feedbackPrompt : null}
</MuteStep>
<MuteStep
bottomImg="/svgs/commenting/warning.svg"
@ -168,6 +160,7 @@ class MuteModal extends React.Component {
)}}
/>
</p>
{this.state.step === this.numSteps ? feedbackPrompt : null}
</MuteStep>
<MuteStep
header={this.props.intl.formatMessage({id: 'comments.muted.mistakeHeader'})}
@ -182,16 +175,22 @@ class MuteModal extends React.Component {
validate={this.validateFeedback}
validateOnBlur={false}
validateOnChange={false}
onSubmit={this.handleValidSubmit}
>
{props => {
const {
errors,
handleSubmit,
setFieldError,
setFieldTouched,
setFieldValue,
validateField
} = props;
return (
<form
id="feedback-form"
onSubmit={handleSubmit}
>
<FormikInput
autoCapitalize="off"
autoComplete="off"
@ -214,11 +213,11 @@ class MuteModal extends React.Component {
setFieldValue('feedback', e.target.value);
setFieldTouched('feedback');
setFieldError('feedback', null);
this.handleFeedbackInput(e.target.value);
}}
/* eslint-enable react/jsx-no-bind */
onSetRef={this.handleSetFeedbackRef}
/>
</form>
);
}}
</Formik>
@ -242,7 +241,7 @@ class MuteModal extends React.Component {
this.state.step === steps.USER_FEEDBACK ? 'feedback-nav' : 'mute-nav'
)}
>
{this.state.step >= finalStep ? (
{this.state.step >= this.numSteps ? (
<Button
className={classNames('close-button')}
onClick={this.props.onRequestClose}
@ -281,7 +280,8 @@ class MuteModal extends React.Component {
className={classNames(
'send-button',
)}
onClick={this.handleFeedbackSubmit}
form="feedback-form"
type="submit"
>
<div className="action-button-text">
<FormattedMessage id="general.send" />

View file

@ -60,16 +60,9 @@
padding: 24px;
button {
// min-width: 100px;
margin: 0 4px;
}
// .action-button-text {
// span {
// text-align: center;
// }
// }
.close-button {
background-color: $ui-dark-gray;
}
@ -87,16 +80,15 @@
.feedback-text {
text-align: center;
max-width: 360px;
}
textarea, .row-with-tooltip {
#feedback-form, textarea {
height: 180px;
width: 100%;
}
textarea {
padding: 16px;
padding: 1rem;
}
.character-limit {
@ -104,7 +96,7 @@
}
.validation-message {
top: 30%;
margin-left: 4rem;
top: 52px;
left: 36px;
}
}

View file

@ -365,6 +365,7 @@
"comments.muted.thanksFeedback": "Thanks for letting us know!",
"comments.muted.thanksInfo": "Your feedback will help us make Scratch better.",
"comments.muted.characterLimit": "500 characters max",
"comments.muted.feedbackEmpty": "Can't be empty",
"social.embedLabel": "Embed",
"social.copyEmbedLinkText": "Copy embed",

View file

@ -33,19 +33,22 @@ describe('MuteModalTest', () => {
expect(component.find('button.back-button').exists()).toEqual(false);
});
// test('Mute Modal shows extra showWarning step', () => {
// const component = mountWithIntl(
// <MuteModal
// showWarning
// muteModalMessages={defaultMessages}
// />
// );
// component.find('MuteModal').instance()
// .setState({step: 2});
// component.update();
// expect(component.find('MuteStep').prop('bottomImg')).toEqual('/svgs/commenting/warning.svg');
// expect(component.find('MuteStep').prop('totalSteps')).toEqual(3);
// });
test('Mute Modal shows extra showWarning step', () => {
const component = mountWithIntl(
<MuteModal
showWarning
muteModalMessages={defaultMessages}
/>
);
component.find('MuteModal').instance()
.setState({step: 1});
expect(component.find('button.next-button').exists()).toEqual(true);
expect(component.find('button.next-button').getElements()[0].props.onClick)
.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', () => {
const component = mountWithIntl(
@ -113,4 +116,74 @@ describe('MuteModalTest', () => {
component.instance().handlePrevious();
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);
});
});