diff --git a/src/tags/helpers/EditTagModal.tsx b/src/tags/helpers/EditTagModal.tsx
index 7cbd5169..e70875f1 100644
--- a/src/tags/helpers/EditTagModal.tsx
+++ b/src/tags/helpers/EditTagModal.tsx
@@ -1,5 +1,5 @@
import { useState } from 'react';
-import { Modal, ModalBody, ModalFooter, ModalHeader, Popover } from 'reactstrap';
+import { Button, Input, Modal, ModalBody, ModalFooter, ModalHeader, Popover } from 'reactstrap';
import { ChromePicker } from 'react-color';
import { faPalette as colorIcon } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
@@ -25,10 +25,12 @@ const EditTagModal = ({ getColorForKey }: ColorGenerator) => (
const [ color, setColor ] = useState(getColorForKey(tag));
const [ showColorPicker, toggleColorPicker, , hideColorPicker ] = useToggle();
const { editing, error, errorData } = tagEdit;
- const saveTag = handleEventPreventingDefault(async () => editTag(tag, newTagName, color)
- .then(() => tagEdited(tag, newTagName, color))
- .then(toggle)
- .catch(() => {}));
+ const saveTag = handleEventPreventingDefault(
+ async () => editTag(tag, newTagName, color)
+ .then(() => tagEdited(tag, newTagName, color))
+ .then(toggle)
+ .catch(() => {}),
+ );
return (
@@ -47,13 +49,11 @@ const EditTagModal = ({ getColorForKey }: ColorGenerator) => (
setColor(hex)} />
- setNewTagName(e.target.value)}
+ onChange={({ target }) => setNewTagName(target.value)}
/>
@@ -64,8 +64,8 @@ const EditTagModal = ({ getColorForKey }: ColorGenerator) => (
)}
-
-
+
+
diff --git a/test/tags/helpers/EditTagModal.test.tsx b/test/tags/helpers/EditTagModal.test.tsx
new file mode 100644
index 00000000..d486fb53
--- /dev/null
+++ b/test/tags/helpers/EditTagModal.test.tsx
@@ -0,0 +1,109 @@
+import { shallow, ShallowWrapper } from 'enzyme';
+import { Mock } from 'ts-mockery';
+import { Button, Input, Modal, ModalHeader, Popover } from 'reactstrap';
+import { TagEdition } from '../../../src/tags/reducers/tagEdit';
+import createEditTagModal from '../../../src/tags/helpers/EditTagModal';
+import ColorGenerator from '../../../src/utils/services/ColorGenerator';
+import { Result } from '../../../src/utils/Result';
+import { ProblemDetailsError } from '../../../src/api/types';
+import { ShlinkApiError } from '../../../src/api/ShlinkApiError';
+import { ChromePicker } from 'react-color';
+
+describe('', () => {
+ const EditTagModal = createEditTagModal(Mock.of({ getColorForKey: jest.fn(() => 'red') }));
+ const editTag = jest.fn().mockReturnValue(Promise.resolve());
+ const tagEdited = jest.fn().mockReturnValue(Promise.resolve());
+ const toggle = jest.fn();
+ let wrapper: ShallowWrapper;
+ const createWrapper = (tagEdit: Partial = {}) => {
+ const edition = Mock.of(tagEdit);
+
+ wrapper = shallow(
+ ,
+ );
+
+ return wrapper;
+ };
+
+ afterEach(jest.clearAllMocks);
+ afterEach(() => wrapper?.unmount());
+
+ test('modal can be toggled with different mechanisms', () => {
+ const wrapper = createWrapper();
+ const modal = wrapper.find(Modal);
+ const modalHeader = wrapper.find(ModalHeader);
+ const cancelBtn = wrapper.find(Button).findWhere((btn) => btn.prop('type') === 'button');
+
+ expect(toggle).not.toHaveBeenCalled();
+
+ (modal.prop('toggle') as Function)();
+ (modalHeader.prop('toggle') as Function)();
+ cancelBtn.simulate('click');
+
+ expect(toggle).toHaveBeenCalledTimes(3);
+ expect(editTag).not.toHaveBeenCalled();
+ expect(tagEdited).not.toHaveBeenCalled();
+ });
+
+ test.each([
+ [ true, 'Saving...' ],
+ [ false, 'Save' ],
+ ])('submit button is rendered in expected state', (editing, expectedText) => {
+ const wrapper = createWrapper({ editing });
+ const submitBtn = wrapper.find(Button).findWhere((btn) => btn.prop('color') === 'primary');
+
+ expect(submitBtn.html()).toContain(expectedText);
+ expect(submitBtn.prop('disabled')).toEqual(editing);
+ });
+
+ test.each([
+ [ true, 1 ],
+ [ false, 0 ],
+ ])('error result is displayed in case of error', (error, expectedResultCount) => {
+ const wrapper = createWrapper({ error, errorData: Mock.all() });
+ const result = wrapper.find(Result);
+ const apiError = wrapper.find(ShlinkApiError);
+
+ expect(result).toHaveLength(expectedResultCount);
+ expect(apiError).toHaveLength(expectedResultCount);
+ });
+
+ test('tag value is updated when text changes', () => {
+ const wrapper = createWrapper();
+
+ expect(wrapper.find(Input).prop('value')).toEqual('foo');
+ wrapper.find(Input).simulate('change', { target: { value: 'bar' } });
+ expect(wrapper.find(Input).prop('value')).toEqual('bar');
+ });
+
+ test('all functions are invoked on form submit', async () => {
+ const wrapper = createWrapper();
+ const form = wrapper.find('form');
+
+ expect(editTag).not.toHaveBeenCalled();
+ expect(tagEdited).not.toHaveBeenCalled();
+
+ await form.simulate('submit', { preventDefault: jest.fn() }); // eslint-disable-line @typescript-eslint/await-thenable
+
+ expect(editTag).toHaveBeenCalled();
+ expect(tagEdited).toHaveBeenCalled();
+ });
+
+ test('color is changed when changing on color picker', () => {
+ const wrapper = createWrapper();
+
+ expect(wrapper.find(ChromePicker).prop('color')).toEqual('red');
+ wrapper.find(ChromePicker).simulate('change', { hex: 'blue' });
+ expect(wrapper.find(ChromePicker).prop('color')).toEqual('blue');
+ });
+
+ test('popover can be toggled with different mechanisms', () => {
+ const wrapper = createWrapper();
+
+ expect(wrapper.find(Popover).prop('isOpen')).toEqual(false);
+ (wrapper.find(Popover).prop('toggle') as Function)();
+ expect(wrapper.find(Popover).prop('isOpen')).toEqual(true);
+ wrapper.find('.input-group-prepend').simulate('click');
+ expect(wrapper.find(Popover).prop('isOpen')).toEqual(false);
+ });
+});