diff options
author | Wouter Admiraal <wouter.admiraal@sonarsource.com> | 2020-11-30 15:02:02 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2020-12-03 20:06:38 +0000 |
commit | 112871533342442cbdd5bf18028ef924dfc52c6f (patch) | |
tree | 8b77606a7c99576f26071b52ba7a53c81ca0ba27 /server | |
parent | 07cd210069bba37cc26a7bbadfcc7e99bd6bbe98 (diff) | |
download | sonarqube-112871533342442cbdd5bf18028ef924dfc52c6f.tar.gz sonarqube-112871533342442cbdd5bf18028ef924dfc52c6f.zip |
SONAR-13984 Do not use email address from controlled input
Diffstat (limited to 'server')
3 files changed, 372 insertions, 23 deletions
diff --git a/server/sonar-web/src/main/js/apps/settings/components/EmailForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/EmailForm.tsx index ad34b04c5b2..90fe52ce511 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/EmailForm.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/EmailForm.tsx @@ -35,7 +35,7 @@ interface State { subject: string; message: string; loading: boolean; - success: boolean; + success?: string; error?: string; } @@ -48,8 +48,7 @@ export class EmailForm extends React.PureComponent<Props, State> { recipient: this.props.currentUser.email || '', subject: translate('email_configuration.test.subject'), message: translate('email_configuration.test.message_text'), - loading: false, - success: false + loading: false }; } @@ -71,11 +70,11 @@ export class EmailForm extends React.PureComponent<Props, State> { handleFormSubmit = (event: React.FormEvent) => { event.preventDefault(); - this.setState({ success: false, error: undefined, loading: true }); + this.setState({ success: undefined, error: undefined, loading: true }); const { recipient, subject, message } = this.state; sendTestEmail(recipient, subject, message).then(() => { if (this.mounted) { - this.setState({ success: true, loading: false }); + this.setState({ success: recipient, loading: false }); } }, this.handleError); }; @@ -93,6 +92,7 @@ export class EmailForm extends React.PureComponent<Props, State> { }; render() { + const { error, loading, message, recipient, subject, success } = this.state; return ( <div className="settings-definition"> <div className="settings-definition-left"> @@ -102,20 +102,17 @@ export class EmailForm extends React.PureComponent<Props, State> { </div> <form className="settings-definition-right" onSubmit={this.handleFormSubmit}> - {this.state.success && ( + {success && ( <div className="form-field"> <Alert variant="success"> - {translateWithParameters( - 'email_configuration.test.email_was_sent_to_x', - this.state.recipient - )} + {translateWithParameters('email_configuration.test.email_was_sent_to_x', success)} </Alert> </div> )} - {this.state.error != null && ( + {error !== undefined && ( <div className="form-field"> - <Alert variant="error">{this.state.error}</Alert> + <Alert variant="error">{error}</Alert> </div> )} @@ -126,12 +123,12 @@ export class EmailForm extends React.PureComponent<Props, State> { </label> <input className="settings-large-input" - disabled={this.state.loading} + disabled={loading} id="test-email-to" onChange={this.onRecipientChange} required={true} type="email" - value={this.state.recipient} + value={recipient} /> </div> <div className="form-field"> @@ -140,11 +137,11 @@ export class EmailForm extends React.PureComponent<Props, State> { </label> <input className="settings-large-input" - disabled={this.state.loading} + disabled={loading} id="test-email-subject" onChange={this.onSubjectChange} type="text" - value={this.state.subject} + value={subject} /> </div> <div className="form-field"> @@ -154,19 +151,19 @@ export class EmailForm extends React.PureComponent<Props, State> { </label> <textarea className="settings-large-input" - disabled={this.state.loading} + disabled={loading} id="test-email-message" onChange={this.onMessageChange} required={true} rows={5} - value={this.state.message} + value={message} /> </div> - <SubmitButton disabled={this.state.loading}> + <SubmitButton disabled={loading}> {translate('email_configuration.test.send')} </SubmitButton> - {this.state.loading && <DeferredSpinner className="spacer-left" />} + {loading && <DeferredSpinner className="spacer-left" />} </form> </div> ); diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/EmailForm-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/EmailForm-test.tsx index e98ad8f8707..b5e7b2e10f6 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/EmailForm-test.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/EmailForm-test.tsx @@ -17,11 +17,75 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/* eslint-disable sonarjs/no-duplicate-string */ import { shallow } from 'enzyme'; import * as React from 'react'; +import { change, submit, waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; +import { sendTestEmail } from '../../../../api/settings'; import { mockLoggedInUser } from '../../../../helpers/testMocks'; import { EmailForm } from '../EmailForm'; +jest.mock('sonar-ui-common/helpers/request', () => ({ + parseError: jest.fn().mockResolvedValue('Error message') +})); + +jest.mock('../../../../api/settings', () => ({ + sendTestEmail: jest.fn().mockResolvedValue(null) +})); + it('should render correctly', () => { - expect(shallow(<EmailForm currentUser={mockLoggedInUser()} />)).toMatchSnapshot(); + const wrapper = shallowRender(); + expect(wrapper).toMatchSnapshot('default'); + wrapper.setState({ loading: true }); + expect(wrapper).toMatchSnapshot('sending'); + wrapper.setState({ loading: false, success: 'email@example.com' }); + expect(wrapper).toMatchSnapshot('success'); + wrapper.setState({ success: undefined, error: 'Some error message' }); + expect(wrapper).toMatchSnapshot('error'); }); + +it('should correctly control the inputs', () => { + const wrapper = shallowRender(); + + change(wrapper.find('#test-email-to'), 'new@recipient.com'); + expect(wrapper.state().recipient).toBe('new@recipient.com'); + + change(wrapper.find('#test-email-subject'), 'New subject'); + expect(wrapper.state().subject).toBe('New subject'); + + change(wrapper.find('#test-email-message'), 'New message'); + expect(wrapper.state().message).toBe('New message'); +}); + +it('should correctly test the email sending', async () => { + const wrapper = shallowRender(); + + submit(wrapper.find('form')); + expect(sendTestEmail).toHaveBeenCalledWith( + 'luke@skywalker.biz', + 'email_configuration.test.subject', + 'email_configuration.test.message_text' + ); + expect(wrapper.state().loading).toBe(true); + + await waitAndUpdate(wrapper); + + expect(wrapper.state().loading).toBe(false); + expect(wrapper.state().error).toBeUndefined(); + expect(wrapper.state().success).toBe('luke@skywalker.biz'); + + (sendTestEmail as jest.Mock).mockRejectedValueOnce(null); + + submit(wrapper.find('form')); + + await waitAndUpdate(wrapper); + + expect(wrapper.state().success).toBeUndefined(); + expect(wrapper.state().error).toBe('Error message'); +}); + +function shallowRender(props: Partial<EmailForm['props']> = {}) { + return shallow<EmailForm>( + <EmailForm currentUser={mockLoggedInUser({ email: 'luke@skywalker.biz' })} {...props} /> + ); +} diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/EmailForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/EmailForm-test.tsx.snap index cc15cb3104d..96b6595eb05 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/EmailForm-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/EmailForm-test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`should render correctly 1`] = ` +exports[`should render correctly: default 1`] = ` <div className="settings-definition" > @@ -37,7 +37,295 @@ exports[`should render correctly 1`] = ` onChange={[Function]} required={true} type="email" - value="" + value="luke@skywalker.biz" + /> + </div> + <div + className="form-field" + > + <label + htmlFor="test-email-subject" + > + email_configuration.test.subject + </label> + <input + className="settings-large-input" + disabled={false} + id="test-email-subject" + onChange={[Function]} + type="text" + value="email_configuration.test.subject" + /> + </div> + <div + className="form-field" + > + <label + htmlFor="test-email-message" + > + email_configuration.test.message + <em + className="mandatory" + > + * + </em> + </label> + <textarea + className="settings-large-input" + disabled={false} + id="test-email-message" + onChange={[Function]} + required={true} + rows={5} + value="email_configuration.test.message_text" + /> + </div> + <SubmitButton + disabled={false} + > + email_configuration.test.send + </SubmitButton> + </form> +</div> +`; + +exports[`should render correctly: error 1`] = ` +<div + className="settings-definition" +> + <div + className="settings-definition-left" + > + <h3 + className="settings-definition-name" + > + email_configuration.test.title + </h3> + </div> + <form + className="settings-definition-right" + onSubmit={[Function]} + > + <div + className="form-field" + > + <Alert + variant="error" + > + Some error message + </Alert> + </div> + <div + className="form-field" + > + <label + htmlFor="test-email-to" + > + email_configuration.test.to_address + <em + className="mandatory" + > + * + </em> + </label> + <input + className="settings-large-input" + disabled={false} + id="test-email-to" + onChange={[Function]} + required={true} + type="email" + value="luke@skywalker.biz" + /> + </div> + <div + className="form-field" + > + <label + htmlFor="test-email-subject" + > + email_configuration.test.subject + </label> + <input + className="settings-large-input" + disabled={false} + id="test-email-subject" + onChange={[Function]} + type="text" + value="email_configuration.test.subject" + /> + </div> + <div + className="form-field" + > + <label + htmlFor="test-email-message" + > + email_configuration.test.message + <em + className="mandatory" + > + * + </em> + </label> + <textarea + className="settings-large-input" + disabled={false} + id="test-email-message" + onChange={[Function]} + required={true} + rows={5} + value="email_configuration.test.message_text" + /> + </div> + <SubmitButton + disabled={false} + > + email_configuration.test.send + </SubmitButton> + </form> +</div> +`; + +exports[`should render correctly: sending 1`] = ` +<div + className="settings-definition" +> + <div + className="settings-definition-left" + > + <h3 + className="settings-definition-name" + > + email_configuration.test.title + </h3> + </div> + <form + className="settings-definition-right" + onSubmit={[Function]} + > + <div + className="form-field" + > + <label + htmlFor="test-email-to" + > + email_configuration.test.to_address + <em + className="mandatory" + > + * + </em> + </label> + <input + className="settings-large-input" + disabled={true} + id="test-email-to" + onChange={[Function]} + required={true} + type="email" + value="luke@skywalker.biz" + /> + </div> + <div + className="form-field" + > + <label + htmlFor="test-email-subject" + > + email_configuration.test.subject + </label> + <input + className="settings-large-input" + disabled={true} + id="test-email-subject" + onChange={[Function]} + type="text" + value="email_configuration.test.subject" + /> + </div> + <div + className="form-field" + > + <label + htmlFor="test-email-message" + > + email_configuration.test.message + <em + className="mandatory" + > + * + </em> + </label> + <textarea + className="settings-large-input" + disabled={true} + id="test-email-message" + onChange={[Function]} + required={true} + rows={5} + value="email_configuration.test.message_text" + /> + </div> + <SubmitButton + disabled={true} + > + email_configuration.test.send + </SubmitButton> + <DeferredSpinner + className="spacer-left" + /> + </form> +</div> +`; + +exports[`should render correctly: success 1`] = ` +<div + className="settings-definition" +> + <div + className="settings-definition-left" + > + <h3 + className="settings-definition-name" + > + email_configuration.test.title + </h3> + </div> + <form + className="settings-definition-right" + onSubmit={[Function]} + > + <div + className="form-field" + > + <Alert + variant="success" + > + email_configuration.test.email_was_sent_to_x.email@example.com + </Alert> + </div> + <div + className="form-field" + > + <label + htmlFor="test-email-to" + > + email_configuration.test.to_address + <em + className="mandatory" + > + * + </em> + </label> + <input + className="settings-large-input" + disabled={false} + id="test-email-to" + onChange={[Function]} + required={true} + type="email" + value="luke@skywalker.biz" /> </div> <div |