[MM-54842] Convert LocalizedInput of 'abstract_command.tsx' to regular input component (#24886)

This commit is contained in:
Rafael Kristoforus Yanto 2023-10-17 20:50:01 +08:00 committed by GitHub
parent f86ec9da18
commit 09adf9ae91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 100 additions and 166 deletions

View File

@ -106,17 +106,12 @@ exports[`components/integrations/AbstractCommand should match snapshot 1`] = `
<div
className="col-md-5 col-sm-8"
>
<LocalizedInput
<input
className="form-control"
id="trigger"
maxLength={128}
onChange={[Function]}
placeholder={
Object {
"defaultMessage": "Command trigger e.g. \\"hello\\" not including the slash",
"id": "add_command.trigger.placeholder",
}
}
placeholder="Command trigger e.g. \\"hello\\" not including the slash"
type="text"
value="trigger"
/>
@ -174,17 +169,12 @@ exports[`components/integrations/AbstractCommand should match snapshot 1`] = `
<div
className="col-md-5 col-sm-8"
>
<LocalizedInput
<input
className="form-control"
id="url"
maxLength={1024}
onChange={[Function]}
placeholder={
Object {
"defaultMessage": "Must start with http:// or https://",
"id": "add_command.url.placeholder",
}
}
placeholder="Must start with http:// or https://"
type="text"
value="https://google.com/command"
/>
@ -255,17 +245,12 @@ exports[`components/integrations/AbstractCommand should match snapshot 1`] = `
<div
className="col-md-5 col-sm-8"
>
<LocalizedInput
<input
className="form-control"
id="username"
maxLength={64}
onChange={[Function]}
placeholder={
Object {
"defaultMessage": "Username",
"id": "add_command.username.placeholder",
}
}
placeholder="Username"
type="text"
value="username"
/>
@ -294,17 +279,12 @@ exports[`components/integrations/AbstractCommand should match snapshot 1`] = `
<div
className="col-md-5 col-sm-8"
>
<LocalizedInput
<input
className="form-control"
id="iconUrl"
maxLength={1024}
onChange={[Function]}
placeholder={
Object {
"defaultMessage": "https://www.example.com/myicon.png",
"id": "add_command.iconUrl.placeholder",
}
}
placeholder="https://www.example.com/myicon.png"
type="text"
value="https://google.com/icon"
/>
@ -364,17 +344,12 @@ exports[`components/integrations/AbstractCommand should match snapshot 1`] = `
<div
className="col-md-5 col-sm-8"
>
<LocalizedInput
<input
className="form-control"
id="autocompleteHint"
maxLength={1024}
onChange={[Function]}
placeholder={
Object {
"defaultMessage": "Example: [Patient Name]",
"id": "add_command.autocompleteHint.placeholder",
}
}
placeholder="Example: [Patient Name]"
type="text"
value="auto_complete_hint"
/>
@ -403,17 +378,12 @@ exports[`components/integrations/AbstractCommand should match snapshot 1`] = `
<div
className="col-md-5 col-sm-8"
>
<LocalizedInput
<input
className="form-control"
id="description"
maxLength={128}
onChange={[Function]}
placeholder={
Object {
"defaultMessage": "Example: \\"Returns search results for patient records\\"",
"id": "add_command.autocompleteDescription.placeholder",
}
}
placeholder="Example: \\"Returns search results for patient records\\""
type="text"
value="auto_complete_desc"
/>
@ -576,17 +546,12 @@ exports[`components/integrations/AbstractCommand should match snapshot when head
<div
className="col-md-5 col-sm-8"
>
<LocalizedInput
<input
className="form-control"
id="trigger"
maxLength={128}
onChange={[Function]}
placeholder={
Object {
"defaultMessage": "Command trigger e.g. \\"hello\\" not including the slash",
"id": "add_command.trigger.placeholder",
}
}
placeholder="Command trigger e.g. \\"hello\\" not including the slash"
type="text"
value="trigger"
/>
@ -644,17 +609,12 @@ exports[`components/integrations/AbstractCommand should match snapshot when head
<div
className="col-md-5 col-sm-8"
>
<LocalizedInput
<input
className="form-control"
id="url"
maxLength={1024}
onChange={[Function]}
placeholder={
Object {
"defaultMessage": "Must start with http:// or https://",
"id": "add_command.url.placeholder",
}
}
placeholder="Must start with http:// or https://"
type="text"
value="https://google.com/command"
/>
@ -725,17 +685,12 @@ exports[`components/integrations/AbstractCommand should match snapshot when head
<div
className="col-md-5 col-sm-8"
>
<LocalizedInput
<input
className="form-control"
id="username"
maxLength={64}
onChange={[Function]}
placeholder={
Object {
"defaultMessage": "Username",
"id": "add_command.username.placeholder",
}
}
placeholder="Username"
type="text"
value="username"
/>
@ -764,17 +719,12 @@ exports[`components/integrations/AbstractCommand should match snapshot when head
<div
className="col-md-5 col-sm-8"
>
<LocalizedInput
<input
className="form-control"
id="iconUrl"
maxLength={1024}
onChange={[Function]}
placeholder={
Object {
"defaultMessage": "https://www.example.com/myicon.png",
"id": "add_command.iconUrl.placeholder",
}
}
placeholder="https://www.example.com/myicon.png"
type="text"
value="https://google.com/icon"
/>
@ -834,17 +784,12 @@ exports[`components/integrations/AbstractCommand should match snapshot when head
<div
className="col-md-5 col-sm-8"
>
<LocalizedInput
<input
className="form-control"
id="autocompleteHint"
maxLength={1024}
onChange={[Function]}
placeholder={
Object {
"defaultMessage": "Example: [Patient Name]",
"id": "add_command.autocompleteHint.placeholder",
}
}
placeholder="Example: [Patient Name]"
type="text"
value="auto_complete_hint"
/>
@ -873,17 +818,12 @@ exports[`components/integrations/AbstractCommand should match snapshot when head
<div
className="col-md-5 col-sm-8"
>
<LocalizedInput
<input
className="form-control"
id="description"
maxLength={128}
onChange={[Function]}
placeholder={
Object {
"defaultMessage": "Example: \\"Returns search results for patient records\\"",
"id": "add_command.autocompleteDescription.placeholder",
}
}
placeholder="Example: \\"Returns search results for patient records\\""
type="text"
value="auto_complete_desc"
/>
@ -1046,17 +986,12 @@ exports[`components/integrations/AbstractCommand should match snapshot, displays
<div
className="col-md-5 col-sm-8"
>
<LocalizedInput
<input
className="form-control"
id="trigger"
maxLength={128}
onChange={[Function]}
placeholder={
Object {
"defaultMessage": "Command trigger e.g. \\"hello\\" not including the slash",
"id": "add_command.trigger.placeholder",
}
}
placeholder="Command trigger e.g. \\"hello\\" not including the slash"
type="text"
value=""
/>
@ -1114,17 +1049,12 @@ exports[`components/integrations/AbstractCommand should match snapshot, displays
<div
className="col-md-5 col-sm-8"
>
<LocalizedInput
<input
className="form-control"
id="url"
maxLength={1024}
onChange={[Function]}
placeholder={
Object {
"defaultMessage": "Must start with http:// or https://",
"id": "add_command.url.placeholder",
}
}
placeholder="Must start with http:// or https://"
type="text"
value="https://google.com/command"
/>
@ -1195,17 +1125,12 @@ exports[`components/integrations/AbstractCommand should match snapshot, displays
<div
className="col-md-5 col-sm-8"
>
<LocalizedInput
<input
className="form-control"
id="username"
maxLength={64}
onChange={[Function]}
placeholder={
Object {
"defaultMessage": "Username",
"id": "add_command.username.placeholder",
}
}
placeholder="Username"
type="text"
value="username"
/>
@ -1234,17 +1159,12 @@ exports[`components/integrations/AbstractCommand should match snapshot, displays
<div
className="col-md-5 col-sm-8"
>
<LocalizedInput
<input
className="form-control"
id="iconUrl"
maxLength={1024}
onChange={[Function]}
placeholder={
Object {
"defaultMessage": "https://www.example.com/myicon.png",
"id": "add_command.iconUrl.placeholder",
}
}
placeholder="https://www.example.com/myicon.png"
type="text"
value="https://google.com/icon"
/>
@ -1304,17 +1224,12 @@ exports[`components/integrations/AbstractCommand should match snapshot, displays
<div
className="col-md-5 col-sm-8"
>
<LocalizedInput
<input
className="form-control"
id="autocompleteHint"
maxLength={1024}
onChange={[Function]}
placeholder={
Object {
"defaultMessage": "Example: [Patient Name]",
"id": "add_command.autocompleteHint.placeholder",
}
}
placeholder="Example: [Patient Name]"
type="text"
value="auto_complete_hint"
/>
@ -1343,17 +1258,12 @@ exports[`components/integrations/AbstractCommand should match snapshot, displays
<div
className="col-md-5 col-sm-8"
>
<LocalizedInput
<input
className="form-control"
id="description"
maxLength={128}
onChange={[Function]}
placeholder={
Object {
"defaultMessage": "Example: \\"Returns search results for patient records\\"",
"id": "add_command.autocompleteDescription.placeholder",
}
}
placeholder="Example: \\"Returns search results for patient records\\""
type="text"
value="auto_complete_desc"
/>

View File

@ -1,13 +1,14 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import type {FormEvent} from 'react';
import {FormattedMessage} from 'react-intl';
import AbstractCommand from 'components/integrations/abstract_command';
import type {AbstractCommand as AbstractCommandClass} from 'components/integrations/abstract_command';
import {shallowWithIntl} from 'tests/helpers/intl-test-helper';
import {TestHelper} from 'utils/test_helper';
describe('components/integrations/AbstractCommand', () => {
@ -56,14 +57,14 @@ describe('components/integrations/AbstractCommand', () => {
};
test('should match snapshot', () => {
const wrapper = shallow<AbstractCommand>(
const wrapper = shallowWithIntl(
<AbstractCommand {...baseProps}/>,
);
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot when header/footer/loading is a string', () => {
const wrapper = shallow<AbstractCommand>(
const wrapper = shallowWithIntl(
<AbstractCommand
{...baseProps}
header='Header as string'
@ -77,7 +78,7 @@ describe('components/integrations/AbstractCommand', () => {
test('should match snapshot, displays client error', () => {
const newSeverError = 'server error';
const props = {...baseProps, serverError: newSeverError};
const wrapper = shallow<AbstractCommand>(
const wrapper = shallowWithIntl(
<AbstractCommand {...props}/>,
);
@ -89,7 +90,7 @@ describe('components/integrations/AbstractCommand', () => {
});
test('should call action function', () => {
const wrapper = shallow<AbstractCommand>(
const wrapper = shallowWithIntl(
<AbstractCommand {...baseProps}/>,
);
@ -100,9 +101,10 @@ describe('components/integrations/AbstractCommand', () => {
});
test('should match object returned by getStateFromCommand', () => {
const wrapper = shallow<AbstractCommand>(
const wrapper = shallowWithIntl(
<AbstractCommand {...baseProps}/>,
);
const instance = wrapper.instance() as AbstractCommandClass;
const expectedOutput = {
autocomplete: true,
@ -119,63 +121,65 @@ describe('components/integrations/AbstractCommand', () => {
username: 'username',
};
expect(wrapper.instance().getStateFromCommand(command)).toEqual(expectedOutput);
expect(instance.getStateFromCommand(command)).toEqual(expectedOutput);
});
test('should match state when method is called', () => {
const wrapper = shallow<AbstractCommand>(
const wrapper = shallowWithIntl(
<AbstractCommand {...baseProps}/>,
);
const instance = wrapper.instance() as AbstractCommandClass;
const displayName = 'new display_name';
const displayNameEvent = {preventDefault: jest.fn(), target: {value: displayName}} as any;
wrapper.instance().updateDisplayName(displayNameEvent);
instance.updateDisplayName(displayNameEvent);
expect(wrapper.state('displayName')).toEqual(displayName);
const description = 'new description';
const descriptionEvent = {preventDefault: jest.fn(), target: {value: description}} as any;
wrapper.instance().updateDescription(descriptionEvent);
instance.updateDescription(descriptionEvent);
expect(wrapper.state('description')).toEqual(description);
const trigger = 'new trigger';
const triggerEvent = {preventDefault: jest.fn(), target: {value: trigger}} as any;
wrapper.instance().updateTrigger(triggerEvent);
instance.updateTrigger(triggerEvent);
expect(wrapper.state('trigger')).toEqual(trigger);
const url = 'new url';
const urlEvent = {preventDefault: jest.fn(), target: {value: url}} as any;
wrapper.instance().updateUrl(urlEvent);
instance.updateUrl(urlEvent);
expect(wrapper.state('url')).toEqual(url);
const method = 'P';
const methodEvent = {preventDefault: jest.fn(), target: {value: method}} as any;
wrapper.instance().updateMethod(methodEvent);
instance.updateMethod(methodEvent);
expect(wrapper.state('method')).toEqual(method);
const username = 'new username';
const usernameEvent = {preventDefault: jest.fn(), target: {value: username}} as any;
wrapper.instance().updateUsername(usernameEvent);
instance.updateUsername(usernameEvent);
expect(wrapper.state('username')).toEqual(username);
const iconUrl = 'new iconUrl';
const iconUrlEvent = {preventDefault: jest.fn(), target: {value: iconUrl}} as any;
wrapper.instance().updateIconUrl(iconUrlEvent);
instance.updateIconUrl(iconUrlEvent);
expect(wrapper.state('iconUrl')).toEqual(iconUrl);
const trueUpdateAutocompleteEvent = {target: {checked: true}} as any;
const falseeUpdateAutocompleteEvent = {target: {checked: false}} as any;
wrapper.instance().updateAutocomplete(trueUpdateAutocompleteEvent);
instance.updateAutocomplete(trueUpdateAutocompleteEvent);
expect(wrapper.state('autocomplete')).toEqual(true);
wrapper.instance().updateAutocomplete(falseeUpdateAutocompleteEvent);
instance.updateAutocomplete(falseeUpdateAutocompleteEvent);
expect(wrapper.state('autocomplete')).toEqual(false);
const autocompleteHint = 'new autocompleteHint';
const autocompleteHintEvent = {preventDefault: jest.fn(), target: {value: autocompleteHint}} as any;
wrapper.instance().updateAutocompleteHint(autocompleteHintEvent);
instance.updateAutocompleteHint(autocompleteHintEvent);
expect(wrapper.state('autocompleteHint')).toEqual(autocompleteHint);
const autocompleteDescription = 'new autocompleteDescription';
const autocompleteDescriptionEvent = {preventDefault: jest.fn(), target: {value: autocompleteDescription}} as any;
wrapper.instance().updateAutocompleteDescription(autocompleteDescriptionEvent);
instance.updateAutocompleteDescription(autocompleteDescriptionEvent);
expect(wrapper.state('autocompleteDescription')).toEqual(autocompleteDescription);
});
@ -188,13 +192,14 @@ describe('components/integrations/AbstractCommand', () => {
},
);
const props = {...baseProps, action: newAction};
const wrapper = shallow<AbstractCommand>(
const wrapper = shallowWithIntl(
<AbstractCommand {...props}/>,
);
const instance = wrapper.instance() as AbstractCommandClass;
expect(newAction).toHaveBeenCalledTimes(0);
const evt = {preventDefault: jest.fn()} as unknown as FormEvent<Element>;
const handleSubmit = wrapper.instance().handleSubmit;
const handleSubmit = instance.handleSubmit;
handleSubmit(evt);
expect(wrapper.state('saving')).toEqual(true);
expect(wrapper.state('clientError')).toEqual('');

View File

@ -3,8 +3,7 @@
import React from 'react';
import type {ChangeEvent} from 'react';
import {FormattedMessage} from 'react-intl';
import type {MessageDescriptor} from 'react-intl';
import {FormattedMessage, type MessageDescriptor, injectIntl, type IntlShape} from 'react-intl';
import {Link} from 'react-router-dom';
import type {Command} from '@mattermost/types/integrations';
@ -13,11 +12,9 @@ import type {Team} from '@mattermost/types/teams';
import BackstageHeader from 'components/backstage/components/backstage_header';
import ExternalLink from 'components/external_link';
import FormError from 'components/form_error';
import LocalizedInput from 'components/localized_input/localized_input';
import SpinnerButton from 'components/spinner_button';
import {Constants, DeveloperLinks} from 'utils/constants';
import {t} from 'utils/i18n';
import * as Utils from 'utils/utils';
const REQUEST_POST = 'P';
@ -64,6 +61,8 @@ type Props = {
* The async function to run when the action button is pressed
*/
action: (command: Command) => Promise<void>;
intl: IntlShape;
}
type State= {
@ -81,7 +80,7 @@ type State= {
autocompleteDescription: string;
}
export default class AbstractCommand extends React.PureComponent<Props, State> {
export class AbstractCommand extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
@ -330,14 +329,17 @@ export default class AbstractCommand extends React.PureComponent<Props, State> {
/>
</label>
<div className='col-md-5 col-sm-8'>
<LocalizedInput
<input
id='autocompleteHint'
type='text'
maxLength={1024}
className='form-control'
value={this.state.autocompleteHint}
onChange={this.updateAutocompleteHint}
placeholder={{id: t('add_command.autocompleteHint.placeholder'), defaultMessage: 'Example: [Patient Name]'}}
placeholder={this.props.intl.formatMessage({
id: 'add_command.autocompleteHint.placeholder',
defaultMessage: 'Example: [Patient Name]',
})}
/>
<div className='form__help'>
<FormattedMessage
@ -361,14 +363,17 @@ export default class AbstractCommand extends React.PureComponent<Props, State> {
/>
</label>
<div className='col-md-5 col-sm-8'>
<LocalizedInput
<input
id='description'
type='text'
maxLength={128}
className='form-control'
value={this.state.autocompleteDescription}
onChange={this.updateAutocompleteDescription}
placeholder={{id: t('add_command.autocompleteDescription.placeholder'), defaultMessage: 'Example: "Returns search results for patient records"'}}
placeholder={this.props.intl.formatMessage({
id: 'add_command.autocompleteDescription.placeholder',
defaultMessage: 'Example: "Returns search results for patient records"',
})}
/>
<div className='form__help'>
<FormattedMessage
@ -462,14 +467,17 @@ export default class AbstractCommand extends React.PureComponent<Props, State> {
/>
</label>
<div className='col-md-5 col-sm-8'>
<LocalizedInput
<input
id='trigger'
type='text'
maxLength={Constants.MAX_TRIGGER_LENGTH}
className='form-control'
value={this.state.trigger}
onChange={this.updateTrigger}
placeholder={{id: t('add_command.trigger.placeholder'), defaultMessage: 'Command trigger e.g. "hello" not including the slash'}}
placeholder={this.props.intl.formatMessage({
id: 'add_command.trigger.placeholder',
defaultMessage: 'Command trigger e.g. "hello" not including the slash',
})}
/>
<div className='form__help'>
<FormattedMessage
@ -515,14 +523,17 @@ export default class AbstractCommand extends React.PureComponent<Props, State> {
/>
</label>
<div className='col-md-5 col-sm-8'>
<LocalizedInput
<input
id='url'
type='text'
maxLength={1024}
className='form-control'
value={this.state.url}
onChange={this.updateUrl}
placeholder={{id: t('add_command.url.placeholder'), defaultMessage: 'Must start with http:// or https://'}}
placeholder={this.props.intl.formatMessage({
id: 'add_command.url.placeholder',
defaultMessage: 'Must start with http:// or https://',
})}
/>
<div className='form__help'>
<FormattedMessage
@ -575,14 +586,17 @@ export default class AbstractCommand extends React.PureComponent<Props, State> {
/>
</label>
<div className='col-md-5 col-sm-8'>
<LocalizedInput
<input
id='username'
type='text'
maxLength={64}
className='form-control'
value={this.state.username}
onChange={this.updateUsername}
placeholder={{id: t('add_command.username.placeholder'), defaultMessage: 'Username'}}
placeholder={this.props.intl.formatMessage({
id: 'add_command.username.placeholder',
defaultMessage: 'Username',
})}
/>
<div className='form__help'>
<FormattedMessage
@ -603,14 +617,17 @@ export default class AbstractCommand extends React.PureComponent<Props, State> {
/>
</label>
<div className='col-md-5 col-sm-8'>
<LocalizedInput
<input
id='iconUrl'
type='text'
maxLength={1024}
className='form-control'
value={this.state.iconUrl}
onChange={this.updateIconUrl}
placeholder={{id: t('add_command.iconUrl.placeholder'), defaultMessage: 'https://www.example.com/myicon.png'}}
placeholder={this.props.intl.formatMessage({
id: 'add_command.iconUrl.placeholder',
defaultMessage: 'https://www.example.com/myicon.png',
})}
/>
<div className='form__help'>
<FormattedMessage
@ -679,3 +696,5 @@ export default class AbstractCommand extends React.PureComponent<Props, State> {
);
}
}
export default injectIntl(AbstractCommand);

View File

@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`components/integrations/AddCommand should match snapshot 1`] = `
<AbstractCommand
<injectIntl(AbstractCommand)
action={[Function]}
footer="Save"
header="Add"

View File

@ -29,7 +29,7 @@ exports[`components/integrations/EditCommand should have match renderExtra 1`] =
`;
exports[`components/integrations/EditCommand should match snapshot 1`] = `
<AbstractCommand
<injectIntl(AbstractCommand)
action={[Function]}
footer={
Object {