diff --git a/app/client/src/comments/CommentThread/CommentThread.tsx b/app/client/src/comments/CommentThread/CommentThread.tsx index 9071fcb4df..877b98def8 100644 --- a/app/client/src/comments/CommentThread/CommentThread.tsx +++ b/app/client/src/comments/CommentThread/CommentThread.tsx @@ -24,7 +24,9 @@ import { animated } from "react-spring"; import { AppState } from "reducers"; import { useEffect } from "react"; -const ThreadContainer = styled(animated.div)<{ +const ThreadContainer = styled(animated.div).withConfig({ + shouldForwardProp: (prop) => !["visible", "inline"].includes(prop), +})<{ visible?: boolean; inline?: boolean; pinned?: boolean; diff --git a/app/client/src/comments/inlineComments/UnpublishedCommentThread.tsx b/app/client/src/comments/inlineComments/UnpublishedCommentThread.tsx index e22f930043..a1ff4a8bae 100644 --- a/app/client/src/comments/inlineComments/UnpublishedCommentThread.tsx +++ b/app/client/src/comments/inlineComments/UnpublishedCommentThread.tsx @@ -1,5 +1,4 @@ import React from "react"; -import { Position } from "@blueprintjs/core"; import AddCommentInput from "./AddCommentInput"; import { ThreadContainer } from "./StyledComponents"; import { useDispatch } from "react-redux"; @@ -117,7 +116,6 @@ function UnpublishedCommentThread({ placement={"right-start"} popoverClassName="comment-thread" portalClassName="inline-comment-thread" - position={Position.RIGHT_TOP} > diff --git a/app/client/src/comments/tests/Comments.test.tsx b/app/client/src/comments/tests/Comments.test.tsx index 4c55ec0a6d..1fbce10732 100644 --- a/app/client/src/comments/tests/Comments.test.tsx +++ b/app/client/src/comments/tests/Comments.test.tsx @@ -1,149 +1,139 @@ -// import React from "react"; -// import userEvent from "@testing-library/user-event"; -// import { unmountComponentAtNode } from "react-dom"; -// import OverlayCommentsWrapper from "../inlineComments/OverlayCommentsWrapper"; -// import store from "store"; -// import { createEvent, fireEvent, render, waitFor } from "test/testUtils"; -// import { -// fetchApplicationCommentsRequest, -// setAreCommentsEnabled, -// } from "actions/commentActions"; -// import { ReduxActionTypes } from "constants/ReduxActionConstants"; -// import { setCommentMode } from "actions/commentActions"; -// import { resetEditorSuccess } from "actions/initActions"; -// import setMockPages from "./setMockPages"; -// import { -// createNewThreadMockResponse, -// fetchApplicationThreadsMockResponse, -// addCommentToThreadMockResponse, -// } from "mockResponses/CommentApiMockResponse"; -// import { act } from "react-dom/test-utils"; -// import { uniqueId } from "lodash"; -// import { WidgetTypes } from "constants/WidgetConstants"; +import React from "react"; +import userEvent from "@testing-library/user-event"; +import { unmountComponentAtNode } from "react-dom"; +import OverlayCommentsWrapper from "../inlineComments/OverlayCommentsWrapper"; +import store from "store"; +import { createEvent, fireEvent, render, waitFor } from "test/testUtils"; +import { fetchApplicationCommentsRequest } from "actions/commentActions"; +import { ReduxActionTypes } from "constants/ReduxActionConstants"; +import { setCommentMode } from "actions/commentActions"; +import { resetEditorSuccess } from "actions/initActions"; +import setMockPages from "./setMockPages"; +import { + createNewThreadMockResponse, + fetchApplicationThreadsMockResponse, + addCommentToThreadMockResponse, +} from "mockResponses/CommentApiMockResponse"; +import { act } from "react-dom/test-utils"; +import { uniqueId } from "lodash"; +import { WidgetTypes } from "constants/WidgetConstants"; -// let container: any = null; -// describe("Comment threads", () => { -// beforeEach(async () => { -// // setup a DOM element as a render target -// container = document.createElement("div"); -// document.body.appendChild(container); -// // application id is required -// setMockPages(); -// store.dispatch(setAreCommentsEnabled(true)); -// store.dispatch(setCommentMode(true)); -// // dispatch fetch comments and mock the axios req -// store.dispatch(fetchApplicationCommentsRequest()); -// // fetch threads saga waits for init -// store.dispatch({ -// type: ReduxActionTypes.INITIALIZE_EDITOR_SUCCESS, -// }); -// }); -// it("are rendered", async (done) => { -// // find is a combination of get and waitFor -// // follows a approach waiting for the element to appear on screen -// // instead of waiting for the api execution -// const { findAllByDataCy } = render( -// -//
-// , -// container, -// ); -// const commentPins = await findAllByDataCy("inline-comment-pin"); -// expect(commentPins).toHaveLength(8); -// done(); -// }); +let container: any = null; +describe("Comment threads", () => { + beforeEach(async () => { + (window as any).isCommentModeForced = true; + // setup a DOM element as a render target + container = document.createElement("div"); + document.body.appendChild(container); + // application id is required + setMockPages(); + store.dispatch(setCommentMode(true)); + // dispatch fetch comments and mock the axios req + store.dispatch(fetchApplicationCommentsRequest()); + // fetch threads saga waits for init + store.dispatch({ + type: ReduxActionTypes.INITIALIZE_EDITOR_SUCCESS, + }); + }); + it("are rendered", async (done) => { + // find is a combination of get and waitFor + // follows a approach waiting for the element to appear on screen + // instead of waiting for the api execution + const { findAllByDataCy } = render( + +
+ , + container, + ); + const commentPins = await findAllByDataCy("inline-comment-pin"); + expect(commentPins).toHaveLength(8); + done(); + }); -// it("can be created", async (done) => { -// const { findByDataCy, findByText, getAllByDataCy, getByDataCy } = render( -// -//
-// , -// container, -// ); -// // clicking creates a new unpublished comment -// userEvent.click(getByDataCy("overlay-comments-wrapper")); -// const textAreas = await waitFor(() => -// document.querySelectorAll(".public-DraftEditor-content"), -// ); -// const textArea = textAreas[textAreas.length - 1]; -// expect(textArea).toBeTruthy(); + it("can be created", async (done) => { + const { findByDataCy, findByText, getAllByDataCy, getByDataCy } = render( + +
+ , + container, + ); + // clicking creates a new unpublished comment + userEvent.click(getByDataCy("overlay-comments-wrapper")); + const textAreas = await waitFor(() => + document.querySelectorAll(".public-DraftEditor-content"), + ); + const textArea = textAreas[textAreas.length - 1]; + expect(textArea).toBeTruthy(); -// if (textArea) { -// const newComment = uniqueId(); -// const event = createEvent.paste(textArea, { -// clipboardData: { -// types: ["text/plain"], -// getData: () => newComment, -// }, -// }); -// act(() => { -// fireEvent(textArea, event); -// }); -// // wait for text change to be propogated -// await findByText(newComment); -// userEvent.click(getByDataCy("add-comment-submit")); -// const createdThreadId = createNewThreadMockResponse.data.id; -// // wait for the new thread to be rendered -// await findByDataCy(`t--inline-comment-pin-trigger-${createdThreadId}`); -// const commentPins = getAllByDataCy("inline-comment-pin"); -// // now we should have 9 threads rendered -// expect(commentPins).toHaveLength(9); -// } -// done(); -// }); -// it("accept replies", async (done) => { -// const { findByDataCy, findByText, getByDataCy } = render( -// -//
-// , -// container, -// ); -// const existingThreadId = fetchApplicationThreadsMockResponse.data[0].id; -// const pin = await findByDataCy( -// `t--inline-comment-pin-trigger-${existingThreadId}`, -// ); -// // show comment thread popover -// userEvent.click(pin); + if (textArea) { + const newComment = uniqueId(); + const event = createEvent.paste(textArea, { + clipboardData: { + types: ["text/plain"], + getData: () => newComment, + }, + }); + act(() => { + fireEvent(textArea, event); + }); + // wait for text change to be propogated + await findByText(newComment); + userEvent.click(getByDataCy("add-comment-submit")); + const createdThreadId = createNewThreadMockResponse.data.id; + // wait for the new thread to be rendered + await findByDataCy(`t--inline-comment-pin-trigger-${createdThreadId}`); + const commentPins = getAllByDataCy("inline-comment-pin"); + // now we should have 9 threads rendered + expect(commentPins).toHaveLength(9); + } + done(); + }); + it("accept replies", async (done) => { + const { findByDataCy, findByText, getByDataCy } = render( + +
+ , + container, + ); + const existingThreadId = fetchApplicationThreadsMockResponse.data[0].id; + const pin = await findByDataCy( + `t--inline-comment-pin-trigger-${existingThreadId}`, + ); + // show comment thread popover + userEvent.click(pin); -// const textAreas = await waitFor(() => -// document.querySelectorAll(".public-DraftEditor-content"), -// ); -// const textArea = textAreas[textAreas.length - 1]; -// expect(textArea).toBeTruthy(); + const textAreas = await waitFor(() => + document.querySelectorAll(".public-DraftEditor-content"), + ); + const textArea = textAreas[textAreas.length - 1]; + expect(textArea).toBeTruthy(); -// if (textArea) { -// const event = createEvent.paste(textArea, { -// clipboardData: { -// types: ["text/plain"], -// getData: () => "new", -// }, -// }); -// fireEvent(textArea, event); -// // wait for text change to be propogated -// await findByText("new"); -// userEvent.click(getByDataCy("add-comment-submit")); -// // newly created comment should be visible -// const createdCommentId = addCommentToThreadMockResponse.data.id; -// await findByDataCy(`t--comment-card-${createdCommentId}`); -// } -// done(); -// }); + if (textArea) { + const event = createEvent.paste(textArea, { + clipboardData: { + types: ["text/plain"], + getData: () => "new", + }, + }); + fireEvent(textArea, event); + // wait for text change to be propogated + await findByText("new"); + userEvent.click(getByDataCy("add-comment-submit")); + // newly created comment should be visible + const createdCommentId = addCommentToThreadMockResponse.data.id; + await findByDataCy(`t--comment-card-${createdCommentId}`); + } + done(); + }); -// afterEach(() => { -// // cleanup on exiting -// unmountComponentAtNode(container); -// container.remove(); -// container = null; -// store.dispatch(resetEditorSuccess()); -// // close any open comment thread popovers -// userEvent.keyboard("{esc}"); -// }); -// }); - -describe("test", () => { - it("test", () => { - expect("test").toBe("test"); + afterEach(() => { + // cleanup on exiting + unmountComponentAtNode(container); + container.remove(); + container = null; + store.dispatch(resetEditorSuccess()); + // close any open comment thread popovers + userEvent.keyboard("{esc}"); + (window as any).isCommentModeForced = false; }); }); - -export {}; diff --git a/app/client/src/selectors/commentsSelectors.ts b/app/client/src/selectors/commentsSelectors.ts index daac5c679a..3bc5bf7e62 100644 --- a/app/client/src/selectors/commentsSelectors.ts +++ b/app/client/src/selectors/commentsSelectors.ts @@ -27,6 +27,9 @@ export const commentModeSelector = (state: AppState) => { const pathName = window.location.pathname; const onEditorOrViewerPage = matchBuilderPath(pathName) || matchViewerPath(pathName); + + if ((window as any).isCommentModeForced) return true; + return ( state.ui.comments?.isCommentMode && !!onEditorOrViewerPage && diff --git a/app/client/test/__mocks__/apiHandlers.ts b/app/client/test/__mocks__/apiHandlers.ts index 3467a53343..b58e7ff091 100644 --- a/app/client/test/__mocks__/apiHandlers.ts +++ b/app/client/test/__mocks__/apiHandlers.ts @@ -7,6 +7,11 @@ import { import CreateOrganisationMockResponse from "mockResponses/CreateOrganisationMockResponse.json"; import ApplicationsNewMockResponse from "mockResponses/ApplicationsNewMockResponse.json"; +const mockSuccessRes = { + responseMeta: { status: 200, success: true }, + data: {}, +}; + export const handlers = [ // mock apis here rest.post("/api/v1/organizations", (req, res, ctx) => { @@ -28,4 +33,19 @@ export const handlers = [ rest.post("/api/v1/comments", (req, res, ctx) => { return res(ctx.status(200), ctx.json(addCommentToThreadMockResponse)); }), + rest.put(/.*/, (req, res, ctx) => { + return res(ctx.status(200), ctx.json(mockSuccessRes)); + }), + rest.post(/.*/, (req, res, ctx) => { + return res(ctx.status(200), ctx.json(mockSuccessRes)); + }), + rest.get(/.*/, (req, res, ctx) => { + return res(ctx.status(200), ctx.json(mockSuccessRes)); + }), + rest.patch(/.*/, (req, res, ctx) => { + return res(ctx.status(200), ctx.json(mockSuccessRes)); + }), + rest.delete(/.*/, (req, res, ctx) => { + return res(ctx.status(200), ctx.json(mockSuccessRes)); + }), ];