From b80f66c882e13df82797743d105713dcbd8fe19b Mon Sep 17 00:00:00 2001 From: Edon Zeqiraj Date: Tue, 18 Nov 2025 08:07:02 +0100 Subject: [PATCH] fix: [PROD-12777] prevent adding duplicate tags in TagsEditor component --- src/inputs/TagsEditor/TagsEditor.js | 9 ++++-- src/inputs/TagsEditor/TagsEditor.spec.js | 36 ++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/inputs/TagsEditor/TagsEditor.js b/src/inputs/TagsEditor/TagsEditor.js index 381da10b..5e4eafc4 100644 --- a/src/inputs/TagsEditor/TagsEditor.js +++ b/src/inputs/TagsEditor/TagsEditor.js @@ -44,8 +44,13 @@ export const TagsEditor = (props) => { const addNewTag = useCallback( (newTag) => { setIsEditing(false); - if (newTag.trim().length === 0) return; - onChange([...values, newTag]); + const trimmedTag = newTag.trim(); + if (trimmedTag.length === 0) return; + + const tagAlreadyExists = values.some((existingTag) => existingTag === trimmedTag); + if (tagAlreadyExists) return; + + onChange([...values, trimmedTag]); }, [onChange, values] ); diff --git a/src/inputs/TagsEditor/TagsEditor.spec.js b/src/inputs/TagsEditor/TagsEditor.spec.js index 476e5957..a4c15bd3 100644 --- a/src/inputs/TagsEditor/TagsEditor.spec.js +++ b/src/inputs/TagsEditor/TagsEditor.spec.js @@ -135,5 +135,41 @@ describe('TagsEditor', () => { expect(onChangeMockFunction).not.toHaveBeenCalled(); expect(newTagTextField.TextField).not.toBeInTheDocument(); }); + + test('should not add duplicate tags', async () => { + await tagsEditorContainer.hover(); + expect(queryByTestId(document, 'EditIcon')).toBeVisible(); + + await userEvent.click(queryByTestId(document, 'EditIcon')); + expect(newTagTextField.TextField).toBeVisible(); + + await newTagTextField.type('tag1{enter}'); + expect(onChangeMockFunction).not.toHaveBeenCalled(); + expect(newTagTextField.TextField).not.toBeInTheDocument(); + }); + + test('should not add duplicate tags even with whitespace', async () => { + await tagsEditorContainer.hover(); + expect(queryByTestId(document, 'EditIcon')).toBeVisible(); + + await userEvent.click(queryByTestId(document, 'EditIcon')); + expect(newTagTextField.TextField).toBeVisible(); + + await newTagTextField.type(' tag2 {enter}'); + expect(onChangeMockFunction).not.toHaveBeenCalled(); + expect(newTagTextField.TextField).not.toBeInTheDocument(); + }); + + test('should trim whitespace when adding new tags', async () => { + await tagsEditorContainer.hover(); + expect(queryByTestId(document, 'EditIcon')).toBeVisible(); + + await userEvent.click(queryByTestId(document, 'EditIcon')); + expect(newTagTextField.TextField).toBeVisible(); + + await newTagTextField.type(' newtag {enter}'); + expect(onChangeMockFunction).toHaveBeenCalledWith(['tag1', 'tag2', 'tag3', 'newtag']); + expect(newTagTextField.TextField).not.toBeInTheDocument(); + }); }); });