From 0f8dcf1df32a52ffff9e1a168200c28f085bee2f Mon Sep 17 00:00:00 2001 From: diwakarmk7 Date: Mon, 19 May 2025 12:55:13 +0530 Subject: [PATCH 1/6] popup state fix --- src/visualBuilder/eventManager/useCollab.ts | 4 ++++ src/visualBuilder/generators/generateThread.tsx | 1 + 2 files changed, 5 insertions(+) diff --git a/src/visualBuilder/eventManager/useCollab.ts b/src/visualBuilder/eventManager/useCollab.ts index 825ecb69..7f05cc2b 100644 --- a/src/visualBuilder/eventManager/useCollab.ts +++ b/src/visualBuilder/eventManager/useCollab.ts @@ -43,6 +43,10 @@ export const useCollab = () => { "collab.pauseFeedback", data?.data?.collab?.pauseFeedback ); + Config.set( + "collab.isFeedbackMode", + data?.data?.collab?.isFeedbackMode + ); showAllCollabIcons(); return; } diff --git a/src/visualBuilder/generators/generateThread.tsx b/src/visualBuilder/generators/generateThread.tsx index 850cac7e..8f54a506 100644 --- a/src/visualBuilder/generators/generateThread.tsx +++ b/src/visualBuilder/generators/generateThread.tsx @@ -376,6 +376,7 @@ export function hideAllCollabIcons(): void { ".visual-builder__collab-wrapper .collab-thread" ); icons?.forEach((icon) => icon?.classList.add(hiddenClass)); + toggleCollabPopup({ threadUid: "", action: "close" }); } export function showAllCollabIcons(): void { From bfc29e36527e62fa682089769bb3653dbc924dbc Mon Sep 17 00:00:00 2001 From: diwakarmk7 Date: Thu, 22 May 2025 07:18:33 +0530 Subject: [PATCH 2/6] fix(collab): username display difference fix --- .../Collab/ThreadPopup/CommentTextArea.tsx | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/visualBuilder/components/Collab/ThreadPopup/CommentTextArea.tsx b/src/visualBuilder/components/Collab/ThreadPopup/CommentTextArea.tsx index 203842dc..01275762 100644 --- a/src/visualBuilder/components/Collab/ThreadPopup/CommentTextArea.tsx +++ b/src/visualBuilder/components/Collab/ThreadPopup/CommentTextArea.tsx @@ -102,12 +102,22 @@ const MentionSuggestionsList: React.FC<{ tabIndex={-1} aria-selected={index === selectedIndex} > - {(user.display?.length || 0) > 20 ? ( - - {(user.display || "").substring(0, 18) + "..."} - + {user.display == user.email ? ( + user.display.length > 20 ? ( + + {(user.display || "").substring(0, 18) + "..."} + + ) : ( + user.display + ) ) : ( - user.display || "" + + {user.display.length > 20 + ? (user.display || "").substring(0, 18) + "..." + : user.display} + )} ))} From 2ca321b853e524f8d635f6270ca7f26e5bf8807a Mon Sep 17 00:00:00 2001 From: diwakarmk7 Date: Tue, 27 May 2025 19:47:54 +0530 Subject: [PATCH 3/6] added tests for comment text area comp --- .../__test__/CommentTextArea.test.tsx | 367 ++++++++++++++++++ 1 file changed, 367 insertions(+) create mode 100644 src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx diff --git a/src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx b/src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx new file mode 100644 index 00000000..74cead4c --- /dev/null +++ b/src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx @@ -0,0 +1,367 @@ +/** @jsxImportSource preact */ +import { render, screen, fireEvent } from "@testing-library/preact"; +import CommentTextArea from "../CommentTextArea"; +import { useCommentTextArea } from "../../../../hooks/useCommentTextArea"; +import { Mock } from "vitest"; +import React from "preact/compat"; +import classNames from "classnames"; + +// Mock dependencies +vi.mock("../../../../hooks/useCommentTextArea"); +vi.mock("../Tooltip/Tooltip", () => ({ + default: ({ children, content }) => ( +
{children}
+ ), +})); +vi.mock("../../../../collab.style", () => ({ + collabStyles: () => ({ + "collab-thread-input-indicator--error": "mocked-error-class", + "collab-thread-input-indicator--count": "mocked-count-class", + "collab-thread-body--input--wrapper": "mocked-wrapper-class", + "collab-thread-body--input": "mocked-input-class", + "collab-thread-body--input--textarea--wrapper": + "mocked-textarea-wrapper-class", + "collab-thread-body--input--textarea": "mocked-textarea-class", + "collab-thread-body--input--textarea--suggestionsList": + "mocked-suggestions-list-class", + "collab-thread-body--input--textarea--suggestionsList--item": + "mocked-suggestion-item-class", + "collab-thread-body--input--textarea--suggestionsList--item-selected": + "mocked-selected-item-class", + "collab-thread-input-indicator--wrapper": + "mocked-indicator-wrapper-class", + }), + flexAlignCenter: "flex-align-center-class", +})); + +const mockUserState = { + userMap: { + user1: { + uid: "user1", + email: "john.doe@example.com", + }, + }, + currentUser: { + uid: "user1", + email: "john.doe@example.com", + }, + mentionsList: [ + { + uid: "user1", + email: "john.doe@example.com", + display: "John Doe", + }, + { + uid: "user2", + email: "jane.smith@example.com", + display: "Jane Smith", + }, + ], +}; + +const mockComment = { + _id: "comment1", + threadUid: "thread-1", + message: "This is a comment", + author: "john.doe@example.com", + toUsers: [], + images: [], + createdAt: "2022-01-01T12:00:00Z", + createdBy: "user1", +}; + +const mockHandleOnSaveRef = { current: vi.fn() }; +const mockOnClose = vi.fn(); + +// Mock implementation of useCommentTextArea hook +const setupMockHook = (overrides = {}) => { + const defaultMock = { + state: { message: "Test message" }, + error: { message: "" }, + showSuggestions: false, + cursorPosition: { top: 20, showAbove: false }, + selectedIndex: 0, + filteredUsers: [], + inputRef: { current: null }, + listRef: { current: null }, + itemRefs: { current: [] }, + handleInputChange: vi.fn(), + handleKeyDown: vi.fn(), + handleSubmit: vi.fn(), + insertMention: vi.fn(), + maxMessageLength: 1000, + }; + + const mockImplementation = { ...defaultMock, ...overrides }; + (useCommentTextArea as Mock).mockReturnValue(mockImplementation); + return mockImplementation; +}; + +describe("CommentTextArea", () => { + beforeEach(() => { + setupMockHook(); + }); + + afterEach(() => { + vi.clearAllMocks(); + }); + + it("should render the textarea with correct placeholder", () => { + render( + + ); + + // Use a more reliable query that doesn't depend on exact placeholder text + const textarea = screen.getByRole("textbox"); + expect(textarea).toBeInTheDocument(); + + // Check if placeholder contains the expected text without worrying about exact quotes + const placeholder = textarea.getAttribute("placeholder"); + expect(placeholder).toContain("Enter a comment or tag others using"); + expect(placeholder).toContain("@"); + }); + + it("should set handleOnSaveRef.current to handleSubmit from the hook", () => { + const mockHook = setupMockHook(); + render( + + ); + + expect(mockHandleOnSaveRef.current).toBe(mockHook.handleSubmit); + }); + + it("should call handleInputChange when typing in textarea", () => { + const mockHook = setupMockHook(); + render( + + ); + + const textarea = screen.getByRole("textbox"); + fireEvent.change(textarea, { target: { value: "New text" } }); + + expect(mockHook.handleInputChange).toHaveBeenCalled(); + }); + + it("should call handleKeyDown when pressing keys in textarea", () => { + const mockHook = setupMockHook(); + render( + + ); + + const textarea = screen.getByRole("textbox"); + fireEvent.keyDown(textarea, { key: "Enter" }); + + expect(mockHook.handleKeyDown).toHaveBeenCalled(); + }); + + it("should display error message when there is an error", () => { + setupMockHook({ error: { message: "Error message" } }); + render( + + ); + + expect(screen.getByText("Error message")).toBeInTheDocument(); + }); + + it("should display character counter with correct values", () => { + setupMockHook({ state: { message: "Hello" }, maxMessageLength: 100 }); + render( + + ); + + expect(screen.getByText("5/100")).toBeInTheDocument(); + }); + + it("should render MentionSuggestionsList when showSuggestions is true", () => { + setupMockHook({ + showSuggestions: true, + filteredUsers: [ + { + uid: "user1", + email: "john@example.com", + display: "John Doe", + }, + { + uid: "user2", + email: "jane@example.com", + display: "Jane Smith", + }, + ], + selectedIndex: 0, + }); + + render( + + ); + + expect(screen.getByText("John Doe")).toBeInTheDocument(); + expect(screen.getByText("Jane Smith")).toBeInTheDocument(); + }); + + it("should not render MentionSuggestionsList when showSuggestions is false", () => { + setupMockHook({ + showSuggestions: false, + filteredUsers: [ + { + uid: "user1", + email: "john@example.com", + display: "John Doe", + }, + { + uid: "user2", + email: "jane@example.com", + display: "Jane Smith", + }, + ], + }); + + render( + + ); + + expect(screen.queryByText("John Doe")).not.toBeInTheDocument(); + expect(screen.queryByText("Jane Smith")).not.toBeInTheDocument(); + }); +}); + +// Test sub-components individually +describe("ErrorIndicator", () => { + it("should render error message", () => { + // We can access the ErrorIndicator through the CommentTextArea component + setupMockHook({ error: { message: "Test error message" } }); + render( + + ); + + expect(screen.getByText("Test error message")).toBeInTheDocument(); + }); +}); + +describe("CharacterCounter", () => { + it("should display current and max length", () => { + setupMockHook({ state: { message: "Test" }, maxMessageLength: 50 }); + render( + + ); + + expect(screen.getByText("4/50")).toBeInTheDocument(); + }); +}); + +describe("MentionSuggestionsList", () => { + it("should display filtered users and highlight the selected one", () => { + setupMockHook({ + showSuggestions: true, + filteredUsers: [ + { + uid: "user1", + email: "john@example.com", + display: "John Doe", + }, + { + uid: "user2", + email: "jane@example.com", + display: "Jane Smith", + }, + ], + selectedIndex: 1, + }); + + render( + + ); + + const selectedItem = screen.getByText("Jane Smith").closest("li"); + expect(selectedItem).toHaveAttribute("aria-selected", "true"); + }); + + it("should truncate long display names", () => { + setupMockHook({ + showSuggestions: true, + filteredUsers: [ + { + uid: "user3", + email: "very.long.email@example.com", + display: "Very Long Name That Should Be Truncated", + }, + ], + selectedIndex: 0, + }); + + render( + + ); + + // Use a more flexible approach to find truncated text + const truncatedTextElement = screen.getByText((content, element) => { + return ( + content.includes("Very Long Name") && + content.includes("...") && + element.tagName.toLowerCase() !== "html" && + element.tagName.toLowerCase() !== "body" + ); + }); + + expect(truncatedTextElement).toBeInTheDocument(); + }); +}); From 119fc48cedaaa67518096595984d6c4b120edaa0 Mon Sep 17 00:00:00 2001 From: diwakarmk7 Date: Tue, 27 May 2025 19:48:02 +0530 Subject: [PATCH 4/6] added tests for comment text area comp --- .talismanrc | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/.talismanrc b/.talismanrc index 0ca16f73..fd1955f6 100644 --- a/.talismanrc +++ b/.talismanrc @@ -1,11 +1,13 @@ fileignoreconfig: -- filename: .github/workflows/secrets-scan.yml - ignore_detectors: - - filecontent -- filename: README.md - checksum: f9e1aee750713c9c4aea3c1027686a1aefcebd759de0ffd06dbea6fdf9f576e6 -- filename: CHANGELOG.md - checksum: 677807c38f5135fac7ca0377e92953fb09097150ddd3c4f68667fe0368f916ee -- filename: src/visualBuilder/components/__test__/fieldToolbar.test.tsx - checksum: 3badd6a142456b6a361569e6fc546349a38ac6b366bef7fd5255d1e93220444e -version: "1.0" \ No newline at end of file + - filename: .github/workflows/secrets-scan.yml + ignore_detectors: + - filecontent + - filename: README.md + checksum: f9e1aee750713c9c4aea3c1027686a1aefcebd759de0ffd06dbea6fdf9f576e6 + - filename: CHANGELOG.md + checksum: 677807c38f5135fac7ca0377e92953fb09097150ddd3c4f68667fe0368f916ee + - filename: src/visualBuilder/components/__test__/fieldToolbar.test.tsx + checksum: 3badd6a142456b6a361569e6fc546349a38ac6b366bef7fd5255d1e93220444e + - filename: src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx + checksum: d0ef271ee5381d9feab06bda6e7e89bd0a882fee87495627bd811c1f0a5459c7 +version: "1.0" From 5de41afcc84fa760a948168c14636e1a431d2893 Mon Sep 17 00:00:00 2001 From: diwakarmk7 Date: Wed, 28 May 2025 18:37:02 +0530 Subject: [PATCH 5/6] Revert "Collab" --- .talismanrc | 22 +- .../Collab/ThreadPopup/CommentTextArea.tsx | 20 +- .../__test__/CommentTextArea.test.tsx | 367 ------------------ src/visualBuilder/eventManager/useCollab.ts | 4 - .../generators/generateThread.tsx | 1 - 5 files changed, 15 insertions(+), 399 deletions(-) delete mode 100644 src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx diff --git a/.talismanrc b/.talismanrc index 0962f0a9..384bfc36 100644 --- a/.talismanrc +++ b/.talismanrc @@ -1,13 +1,11 @@ fileignoreconfig: - - filename: .github/workflows/secrets-scan.yml - ignore_detectors: - - filecontent - - filename: README.md - checksum: 568289bbe7c088967493db246dbf29e465382648ac574c1b1236be57d5662a38 - - filename: CHANGELOG.md - checksum: 677807c38f5135fac7ca0377e92953fb09097150ddd3c4f68667fe0368f916ee - - filename: src/visualBuilder/components/__test__/fieldToolbar.test.tsx - checksum: 3badd6a142456b6a361569e6fc546349a38ac6b366bef7fd5255d1e93220444e - - filename: src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx - checksum: d0ef271ee5381d9feab06bda6e7e89bd0a882fee87495627bd811c1f0a5459c7 -version: "1.0" +- filename: .github/workflows/secrets-scan.yml + ignore_detectors: + - filecontent +- filename: README.md + checksum: 568289bbe7c088967493db246dbf29e465382648ac574c1b1236be57d5662a38 +- filename: CHANGELOG.md + checksum: 677807c38f5135fac7ca0377e92953fb09097150ddd3c4f68667fe0368f916ee +- filename: src/visualBuilder/components/__test__/fieldToolbar.test.tsx + checksum: 3badd6a142456b6a361569e6fc546349a38ac6b366bef7fd5255d1e93220444e +version: "1.0" \ No newline at end of file diff --git a/src/visualBuilder/components/Collab/ThreadPopup/CommentTextArea.tsx b/src/visualBuilder/components/Collab/ThreadPopup/CommentTextArea.tsx index 01275762..203842dc 100644 --- a/src/visualBuilder/components/Collab/ThreadPopup/CommentTextArea.tsx +++ b/src/visualBuilder/components/Collab/ThreadPopup/CommentTextArea.tsx @@ -102,22 +102,12 @@ const MentionSuggestionsList: React.FC<{ tabIndex={-1} aria-selected={index === selectedIndex} > - {user.display == user.email ? ( - user.display.length > 20 ? ( - - {(user.display || "").substring(0, 18) + "..."} - - ) : ( - user.display - ) - ) : ( - - {user.display.length > 20 - ? (user.display || "").substring(0, 18) + "..." - : user.display} + {(user.display?.length || 0) > 20 ? ( + + {(user.display || "").substring(0, 18) + "..."} + ) : ( + user.display || "" )} ))} diff --git a/src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx b/src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx deleted file mode 100644 index 74cead4c..00000000 --- a/src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx +++ /dev/null @@ -1,367 +0,0 @@ -/** @jsxImportSource preact */ -import { render, screen, fireEvent } from "@testing-library/preact"; -import CommentTextArea from "../CommentTextArea"; -import { useCommentTextArea } from "../../../../hooks/useCommentTextArea"; -import { Mock } from "vitest"; -import React from "preact/compat"; -import classNames from "classnames"; - -// Mock dependencies -vi.mock("../../../../hooks/useCommentTextArea"); -vi.mock("../Tooltip/Tooltip", () => ({ - default: ({ children, content }) => ( -
{children}
- ), -})); -vi.mock("../../../../collab.style", () => ({ - collabStyles: () => ({ - "collab-thread-input-indicator--error": "mocked-error-class", - "collab-thread-input-indicator--count": "mocked-count-class", - "collab-thread-body--input--wrapper": "mocked-wrapper-class", - "collab-thread-body--input": "mocked-input-class", - "collab-thread-body--input--textarea--wrapper": - "mocked-textarea-wrapper-class", - "collab-thread-body--input--textarea": "mocked-textarea-class", - "collab-thread-body--input--textarea--suggestionsList": - "mocked-suggestions-list-class", - "collab-thread-body--input--textarea--suggestionsList--item": - "mocked-suggestion-item-class", - "collab-thread-body--input--textarea--suggestionsList--item-selected": - "mocked-selected-item-class", - "collab-thread-input-indicator--wrapper": - "mocked-indicator-wrapper-class", - }), - flexAlignCenter: "flex-align-center-class", -})); - -const mockUserState = { - userMap: { - user1: { - uid: "user1", - email: "john.doe@example.com", - }, - }, - currentUser: { - uid: "user1", - email: "john.doe@example.com", - }, - mentionsList: [ - { - uid: "user1", - email: "john.doe@example.com", - display: "John Doe", - }, - { - uid: "user2", - email: "jane.smith@example.com", - display: "Jane Smith", - }, - ], -}; - -const mockComment = { - _id: "comment1", - threadUid: "thread-1", - message: "This is a comment", - author: "john.doe@example.com", - toUsers: [], - images: [], - createdAt: "2022-01-01T12:00:00Z", - createdBy: "user1", -}; - -const mockHandleOnSaveRef = { current: vi.fn() }; -const mockOnClose = vi.fn(); - -// Mock implementation of useCommentTextArea hook -const setupMockHook = (overrides = {}) => { - const defaultMock = { - state: { message: "Test message" }, - error: { message: "" }, - showSuggestions: false, - cursorPosition: { top: 20, showAbove: false }, - selectedIndex: 0, - filteredUsers: [], - inputRef: { current: null }, - listRef: { current: null }, - itemRefs: { current: [] }, - handleInputChange: vi.fn(), - handleKeyDown: vi.fn(), - handleSubmit: vi.fn(), - insertMention: vi.fn(), - maxMessageLength: 1000, - }; - - const mockImplementation = { ...defaultMock, ...overrides }; - (useCommentTextArea as Mock).mockReturnValue(mockImplementation); - return mockImplementation; -}; - -describe("CommentTextArea", () => { - beforeEach(() => { - setupMockHook(); - }); - - afterEach(() => { - vi.clearAllMocks(); - }); - - it("should render the textarea with correct placeholder", () => { - render( - - ); - - // Use a more reliable query that doesn't depend on exact placeholder text - const textarea = screen.getByRole("textbox"); - expect(textarea).toBeInTheDocument(); - - // Check if placeholder contains the expected text without worrying about exact quotes - const placeholder = textarea.getAttribute("placeholder"); - expect(placeholder).toContain("Enter a comment or tag others using"); - expect(placeholder).toContain("@"); - }); - - it("should set handleOnSaveRef.current to handleSubmit from the hook", () => { - const mockHook = setupMockHook(); - render( - - ); - - expect(mockHandleOnSaveRef.current).toBe(mockHook.handleSubmit); - }); - - it("should call handleInputChange when typing in textarea", () => { - const mockHook = setupMockHook(); - render( - - ); - - const textarea = screen.getByRole("textbox"); - fireEvent.change(textarea, { target: { value: "New text" } }); - - expect(mockHook.handleInputChange).toHaveBeenCalled(); - }); - - it("should call handleKeyDown when pressing keys in textarea", () => { - const mockHook = setupMockHook(); - render( - - ); - - const textarea = screen.getByRole("textbox"); - fireEvent.keyDown(textarea, { key: "Enter" }); - - expect(mockHook.handleKeyDown).toHaveBeenCalled(); - }); - - it("should display error message when there is an error", () => { - setupMockHook({ error: { message: "Error message" } }); - render( - - ); - - expect(screen.getByText("Error message")).toBeInTheDocument(); - }); - - it("should display character counter with correct values", () => { - setupMockHook({ state: { message: "Hello" }, maxMessageLength: 100 }); - render( - - ); - - expect(screen.getByText("5/100")).toBeInTheDocument(); - }); - - it("should render MentionSuggestionsList when showSuggestions is true", () => { - setupMockHook({ - showSuggestions: true, - filteredUsers: [ - { - uid: "user1", - email: "john@example.com", - display: "John Doe", - }, - { - uid: "user2", - email: "jane@example.com", - display: "Jane Smith", - }, - ], - selectedIndex: 0, - }); - - render( - - ); - - expect(screen.getByText("John Doe")).toBeInTheDocument(); - expect(screen.getByText("Jane Smith")).toBeInTheDocument(); - }); - - it("should not render MentionSuggestionsList when showSuggestions is false", () => { - setupMockHook({ - showSuggestions: false, - filteredUsers: [ - { - uid: "user1", - email: "john@example.com", - display: "John Doe", - }, - { - uid: "user2", - email: "jane@example.com", - display: "Jane Smith", - }, - ], - }); - - render( - - ); - - expect(screen.queryByText("John Doe")).not.toBeInTheDocument(); - expect(screen.queryByText("Jane Smith")).not.toBeInTheDocument(); - }); -}); - -// Test sub-components individually -describe("ErrorIndicator", () => { - it("should render error message", () => { - // We can access the ErrorIndicator through the CommentTextArea component - setupMockHook({ error: { message: "Test error message" } }); - render( - - ); - - expect(screen.getByText("Test error message")).toBeInTheDocument(); - }); -}); - -describe("CharacterCounter", () => { - it("should display current and max length", () => { - setupMockHook({ state: { message: "Test" }, maxMessageLength: 50 }); - render( - - ); - - expect(screen.getByText("4/50")).toBeInTheDocument(); - }); -}); - -describe("MentionSuggestionsList", () => { - it("should display filtered users and highlight the selected one", () => { - setupMockHook({ - showSuggestions: true, - filteredUsers: [ - { - uid: "user1", - email: "john@example.com", - display: "John Doe", - }, - { - uid: "user2", - email: "jane@example.com", - display: "Jane Smith", - }, - ], - selectedIndex: 1, - }); - - render( - - ); - - const selectedItem = screen.getByText("Jane Smith").closest("li"); - expect(selectedItem).toHaveAttribute("aria-selected", "true"); - }); - - it("should truncate long display names", () => { - setupMockHook({ - showSuggestions: true, - filteredUsers: [ - { - uid: "user3", - email: "very.long.email@example.com", - display: "Very Long Name That Should Be Truncated", - }, - ], - selectedIndex: 0, - }); - - render( - - ); - - // Use a more flexible approach to find truncated text - const truncatedTextElement = screen.getByText((content, element) => { - return ( - content.includes("Very Long Name") && - content.includes("...") && - element.tagName.toLowerCase() !== "html" && - element.tagName.toLowerCase() !== "body" - ); - }); - - expect(truncatedTextElement).toBeInTheDocument(); - }); -}); diff --git a/src/visualBuilder/eventManager/useCollab.ts b/src/visualBuilder/eventManager/useCollab.ts index 7f05cc2b..825ecb69 100644 --- a/src/visualBuilder/eventManager/useCollab.ts +++ b/src/visualBuilder/eventManager/useCollab.ts @@ -43,10 +43,6 @@ export const useCollab = () => { "collab.pauseFeedback", data?.data?.collab?.pauseFeedback ); - Config.set( - "collab.isFeedbackMode", - data?.data?.collab?.isFeedbackMode - ); showAllCollabIcons(); return; } diff --git a/src/visualBuilder/generators/generateThread.tsx b/src/visualBuilder/generators/generateThread.tsx index 8f54a506..850cac7e 100644 --- a/src/visualBuilder/generators/generateThread.tsx +++ b/src/visualBuilder/generators/generateThread.tsx @@ -376,7 +376,6 @@ export function hideAllCollabIcons(): void { ".visual-builder__collab-wrapper .collab-thread" ); icons?.forEach((icon) => icon?.classList.add(hiddenClass)); - toggleCollabPopup({ threadUid: "", action: "close" }); } export function showAllCollabIcons(): void { From 087ab2aa818897ce409c61c2472f4b03cbf9762b Mon Sep 17 00:00:00 2001 From: diwakarmk7 Date: Wed, 28 May 2025 18:43:49 +0530 Subject: [PATCH 6/6] Revert "Revert "Collab"" --- .talismanrc | 22 +- .../Collab/ThreadPopup/CommentTextArea.tsx | 20 +- .../__test__/CommentTextArea.test.tsx | 367 ++++++++++++++++++ src/visualBuilder/eventManager/useCollab.ts | 4 + .../generators/generateThread.tsx | 1 + 5 files changed, 399 insertions(+), 15 deletions(-) create mode 100644 src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx diff --git a/.talismanrc b/.talismanrc index 384bfc36..0962f0a9 100644 --- a/.talismanrc +++ b/.talismanrc @@ -1,11 +1,13 @@ fileignoreconfig: -- filename: .github/workflows/secrets-scan.yml - ignore_detectors: - - filecontent -- filename: README.md - checksum: 568289bbe7c088967493db246dbf29e465382648ac574c1b1236be57d5662a38 -- filename: CHANGELOG.md - checksum: 677807c38f5135fac7ca0377e92953fb09097150ddd3c4f68667fe0368f916ee -- filename: src/visualBuilder/components/__test__/fieldToolbar.test.tsx - checksum: 3badd6a142456b6a361569e6fc546349a38ac6b366bef7fd5255d1e93220444e -version: "1.0" \ No newline at end of file + - filename: .github/workflows/secrets-scan.yml + ignore_detectors: + - filecontent + - filename: README.md + checksum: 568289bbe7c088967493db246dbf29e465382648ac574c1b1236be57d5662a38 + - filename: CHANGELOG.md + checksum: 677807c38f5135fac7ca0377e92953fb09097150ddd3c4f68667fe0368f916ee + - filename: src/visualBuilder/components/__test__/fieldToolbar.test.tsx + checksum: 3badd6a142456b6a361569e6fc546349a38ac6b366bef7fd5255d1e93220444e + - filename: src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx + checksum: d0ef271ee5381d9feab06bda6e7e89bd0a882fee87495627bd811c1f0a5459c7 +version: "1.0" diff --git a/src/visualBuilder/components/Collab/ThreadPopup/CommentTextArea.tsx b/src/visualBuilder/components/Collab/ThreadPopup/CommentTextArea.tsx index 203842dc..01275762 100644 --- a/src/visualBuilder/components/Collab/ThreadPopup/CommentTextArea.tsx +++ b/src/visualBuilder/components/Collab/ThreadPopup/CommentTextArea.tsx @@ -102,12 +102,22 @@ const MentionSuggestionsList: React.FC<{ tabIndex={-1} aria-selected={index === selectedIndex} > - {(user.display?.length || 0) > 20 ? ( - - {(user.display || "").substring(0, 18) + "..."} - + {user.display == user.email ? ( + user.display.length > 20 ? ( + + {(user.display || "").substring(0, 18) + "..."} + + ) : ( + user.display + ) ) : ( - user.display || "" + + {user.display.length > 20 + ? (user.display || "").substring(0, 18) + "..." + : user.display} + )} ))} diff --git a/src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx b/src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx new file mode 100644 index 00000000..74cead4c --- /dev/null +++ b/src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx @@ -0,0 +1,367 @@ +/** @jsxImportSource preact */ +import { render, screen, fireEvent } from "@testing-library/preact"; +import CommentTextArea from "../CommentTextArea"; +import { useCommentTextArea } from "../../../../hooks/useCommentTextArea"; +import { Mock } from "vitest"; +import React from "preact/compat"; +import classNames from "classnames"; + +// Mock dependencies +vi.mock("../../../../hooks/useCommentTextArea"); +vi.mock("../Tooltip/Tooltip", () => ({ + default: ({ children, content }) => ( +
{children}
+ ), +})); +vi.mock("../../../../collab.style", () => ({ + collabStyles: () => ({ + "collab-thread-input-indicator--error": "mocked-error-class", + "collab-thread-input-indicator--count": "mocked-count-class", + "collab-thread-body--input--wrapper": "mocked-wrapper-class", + "collab-thread-body--input": "mocked-input-class", + "collab-thread-body--input--textarea--wrapper": + "mocked-textarea-wrapper-class", + "collab-thread-body--input--textarea": "mocked-textarea-class", + "collab-thread-body--input--textarea--suggestionsList": + "mocked-suggestions-list-class", + "collab-thread-body--input--textarea--suggestionsList--item": + "mocked-suggestion-item-class", + "collab-thread-body--input--textarea--suggestionsList--item-selected": + "mocked-selected-item-class", + "collab-thread-input-indicator--wrapper": + "mocked-indicator-wrapper-class", + }), + flexAlignCenter: "flex-align-center-class", +})); + +const mockUserState = { + userMap: { + user1: { + uid: "user1", + email: "john.doe@example.com", + }, + }, + currentUser: { + uid: "user1", + email: "john.doe@example.com", + }, + mentionsList: [ + { + uid: "user1", + email: "john.doe@example.com", + display: "John Doe", + }, + { + uid: "user2", + email: "jane.smith@example.com", + display: "Jane Smith", + }, + ], +}; + +const mockComment = { + _id: "comment1", + threadUid: "thread-1", + message: "This is a comment", + author: "john.doe@example.com", + toUsers: [], + images: [], + createdAt: "2022-01-01T12:00:00Z", + createdBy: "user1", +}; + +const mockHandleOnSaveRef = { current: vi.fn() }; +const mockOnClose = vi.fn(); + +// Mock implementation of useCommentTextArea hook +const setupMockHook = (overrides = {}) => { + const defaultMock = { + state: { message: "Test message" }, + error: { message: "" }, + showSuggestions: false, + cursorPosition: { top: 20, showAbove: false }, + selectedIndex: 0, + filteredUsers: [], + inputRef: { current: null }, + listRef: { current: null }, + itemRefs: { current: [] }, + handleInputChange: vi.fn(), + handleKeyDown: vi.fn(), + handleSubmit: vi.fn(), + insertMention: vi.fn(), + maxMessageLength: 1000, + }; + + const mockImplementation = { ...defaultMock, ...overrides }; + (useCommentTextArea as Mock).mockReturnValue(mockImplementation); + return mockImplementation; +}; + +describe("CommentTextArea", () => { + beforeEach(() => { + setupMockHook(); + }); + + afterEach(() => { + vi.clearAllMocks(); + }); + + it("should render the textarea with correct placeholder", () => { + render( + + ); + + // Use a more reliable query that doesn't depend on exact placeholder text + const textarea = screen.getByRole("textbox"); + expect(textarea).toBeInTheDocument(); + + // Check if placeholder contains the expected text without worrying about exact quotes + const placeholder = textarea.getAttribute("placeholder"); + expect(placeholder).toContain("Enter a comment or tag others using"); + expect(placeholder).toContain("@"); + }); + + it("should set handleOnSaveRef.current to handleSubmit from the hook", () => { + const mockHook = setupMockHook(); + render( + + ); + + expect(mockHandleOnSaveRef.current).toBe(mockHook.handleSubmit); + }); + + it("should call handleInputChange when typing in textarea", () => { + const mockHook = setupMockHook(); + render( + + ); + + const textarea = screen.getByRole("textbox"); + fireEvent.change(textarea, { target: { value: "New text" } }); + + expect(mockHook.handleInputChange).toHaveBeenCalled(); + }); + + it("should call handleKeyDown when pressing keys in textarea", () => { + const mockHook = setupMockHook(); + render( + + ); + + const textarea = screen.getByRole("textbox"); + fireEvent.keyDown(textarea, { key: "Enter" }); + + expect(mockHook.handleKeyDown).toHaveBeenCalled(); + }); + + it("should display error message when there is an error", () => { + setupMockHook({ error: { message: "Error message" } }); + render( + + ); + + expect(screen.getByText("Error message")).toBeInTheDocument(); + }); + + it("should display character counter with correct values", () => { + setupMockHook({ state: { message: "Hello" }, maxMessageLength: 100 }); + render( + + ); + + expect(screen.getByText("5/100")).toBeInTheDocument(); + }); + + it("should render MentionSuggestionsList when showSuggestions is true", () => { + setupMockHook({ + showSuggestions: true, + filteredUsers: [ + { + uid: "user1", + email: "john@example.com", + display: "John Doe", + }, + { + uid: "user2", + email: "jane@example.com", + display: "Jane Smith", + }, + ], + selectedIndex: 0, + }); + + render( + + ); + + expect(screen.getByText("John Doe")).toBeInTheDocument(); + expect(screen.getByText("Jane Smith")).toBeInTheDocument(); + }); + + it("should not render MentionSuggestionsList when showSuggestions is false", () => { + setupMockHook({ + showSuggestions: false, + filteredUsers: [ + { + uid: "user1", + email: "john@example.com", + display: "John Doe", + }, + { + uid: "user2", + email: "jane@example.com", + display: "Jane Smith", + }, + ], + }); + + render( + + ); + + expect(screen.queryByText("John Doe")).not.toBeInTheDocument(); + expect(screen.queryByText("Jane Smith")).not.toBeInTheDocument(); + }); +}); + +// Test sub-components individually +describe("ErrorIndicator", () => { + it("should render error message", () => { + // We can access the ErrorIndicator through the CommentTextArea component + setupMockHook({ error: { message: "Test error message" } }); + render( + + ); + + expect(screen.getByText("Test error message")).toBeInTheDocument(); + }); +}); + +describe("CharacterCounter", () => { + it("should display current and max length", () => { + setupMockHook({ state: { message: "Test" }, maxMessageLength: 50 }); + render( + + ); + + expect(screen.getByText("4/50")).toBeInTheDocument(); + }); +}); + +describe("MentionSuggestionsList", () => { + it("should display filtered users and highlight the selected one", () => { + setupMockHook({ + showSuggestions: true, + filteredUsers: [ + { + uid: "user1", + email: "john@example.com", + display: "John Doe", + }, + { + uid: "user2", + email: "jane@example.com", + display: "Jane Smith", + }, + ], + selectedIndex: 1, + }); + + render( + + ); + + const selectedItem = screen.getByText("Jane Smith").closest("li"); + expect(selectedItem).toHaveAttribute("aria-selected", "true"); + }); + + it("should truncate long display names", () => { + setupMockHook({ + showSuggestions: true, + filteredUsers: [ + { + uid: "user3", + email: "very.long.email@example.com", + display: "Very Long Name That Should Be Truncated", + }, + ], + selectedIndex: 0, + }); + + render( + + ); + + // Use a more flexible approach to find truncated text + const truncatedTextElement = screen.getByText((content, element) => { + return ( + content.includes("Very Long Name") && + content.includes("...") && + element.tagName.toLowerCase() !== "html" && + element.tagName.toLowerCase() !== "body" + ); + }); + + expect(truncatedTextElement).toBeInTheDocument(); + }); +}); diff --git a/src/visualBuilder/eventManager/useCollab.ts b/src/visualBuilder/eventManager/useCollab.ts index 825ecb69..7f05cc2b 100644 --- a/src/visualBuilder/eventManager/useCollab.ts +++ b/src/visualBuilder/eventManager/useCollab.ts @@ -43,6 +43,10 @@ export const useCollab = () => { "collab.pauseFeedback", data?.data?.collab?.pauseFeedback ); + Config.set( + "collab.isFeedbackMode", + data?.data?.collab?.isFeedbackMode + ); showAllCollabIcons(); return; } diff --git a/src/visualBuilder/generators/generateThread.tsx b/src/visualBuilder/generators/generateThread.tsx index 850cac7e..8f54a506 100644 --- a/src/visualBuilder/generators/generateThread.tsx +++ b/src/visualBuilder/generators/generateThread.tsx @@ -376,6 +376,7 @@ export function hideAllCollabIcons(): void { ".visual-builder__collab-wrapper .collab-thread" ); icons?.forEach((icon) => icon?.classList.add(hiddenClass)); + toggleCollabPopup({ threadUid: "", action: "close" }); } export function showAllCollabIcons(): void {