From 38d9dbc6bf0c57995fbab054c4c899a401fc119a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 10 May 2022 18:25:36 +0200 Subject: [PATCH 01/10] Prepare for new tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- .../context_menus/MessageContextMenu-test.tsx | 57 +++++++++++++++---- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/test/components/views/context_menus/MessageContextMenu-test.tsx b/test/components/views/context_menus/MessageContextMenu-test.tsx index 567e54b4189..ca8779a6b6e 100644 --- a/test/components/views/context_menus/MessageContextMenu-test.tsx +++ b/test/components/views/context_menus/MessageContextMenu-test.tsx @@ -13,35 +13,66 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ +/* eslint-disable @typescript-eslint/no-var-requires */ import React from 'react'; -import { mount } from 'enzyme'; +import { mount, ReactWrapper } from 'enzyme'; import { EventStatus, MatrixEvent } from 'matrix-js-sdk/src/models/event'; import { Room } from 'matrix-js-sdk/src/models/room'; import { PendingEventOrdering } from 'matrix-js-sdk/src/matrix'; import { ExtensibleEvent, MessageEvent, M_POLL_KIND_DISCLOSED, PollStartEvent } from 'matrix-events-sdk'; +import { Thread } from "matrix-js-sdk/src/models/thread"; import * as TestUtils from '../../../test-utils'; -import MessageContextMenu from '../../../../src/components/views/context_menus/MessageContextMenu'; import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; +import RoomContext, { TimelineRenderingType } from "../../../../src/contexts/RoomContext"; + +const PATH_TO_STRING_UTILS = "../../../../src/utils/strings"; +const PATH_TO_EVENT_UTILS = "../../../../src/utils/EventUtils"; + +jest.mock(PATH_TO_STRING_UTILS); +jest.mock(PATH_TO_EVENT_UTILS); + +const { copyPlaintext, getSelectedText } = require(PATH_TO_STRING_UTILS); +const { canEditContent, canForward, isContentActionable } = require(PATH_TO_EVENT_UTILS); + +describe('MessageContextMenu', () => { + beforeAll(() => { + jest.resetAllMocks(); + }); -describe('MessageContextMenu>', () => { it('allows forwarding a room message', () => { + canForward.mockReturnValue(true); + isContentActionable.mockReturnValue(true); + const eventContent = MessageEvent.from("hello"); - const menu = createMessageContextMenu(eventContent); + const menu = createMenuWithContent(eventContent); expect(menu.find('div[aria-label="Forward"]')).toHaveLength(1); }); it('does not allow forwarding a poll', () => { + canForward.mockReturnValue(false); + const eventContent = PollStartEvent.from("why?", ["42"], M_POLL_KIND_DISCLOSED); - const menu = createMessageContextMenu(eventContent); + const menu = createMenuWithContent(eventContent); expect(menu.find('div[aria-label="Forward"]')).toHaveLength(0); }); }); -function createMessageContextMenu(eventContent: ExtensibleEvent) { + +function createMenuWithContent( + eventContent: ExtensibleEvent, + props?, + context?, +): ReactWrapper { + const mxEvent = new MatrixEvent(eventContent.serialize()); + return createMenu(mxEvent, props, context); +} + +function createMenu(mxEvent: MatrixEvent, props?, context = {}): ReactWrapper { TestUtils.stubClient(); const client = MatrixClientPeg.get(); + const MessageContextMenu = require("../../../../src/components/views/context_menus/MessageContextMenu")["default"]; const room = new Room( "roomid", @@ -52,17 +83,19 @@ function createMessageContextMenu(eventContent: ExtensibleEvent) { }, ); - const mxEvent = new MatrixEvent(eventContent.serialize()); mxEvent.setStatus(EventStatus.SENT); client.getUserId = jest.fn().mockReturnValue("@user:example.com"); client.getRoom = jest.fn().mockReturnValue(room); return mount( - {})} - />, + + {})} + {...props} + /> + , ); } From b73dd49f0409f93690e9ca4f91a8df9a625b89ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 10 May 2022 18:27:18 +0200 Subject: [PATCH 02/10] Add new button visibility tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- .../context_menus/MessageContextMenu-test.tsx | 156 +++++++++++++++++- 1 file changed, 155 insertions(+), 1 deletion(-) diff --git a/test/components/views/context_menus/MessageContextMenu-test.tsx b/test/components/views/context_menus/MessageContextMenu-test.tsx index ca8779a6b6e..59184f8620c 100644 --- a/test/components/views/context_menus/MessageContextMenu-test.tsx +++ b/test/components/views/context_menus/MessageContextMenu-test.tsx @@ -57,8 +57,162 @@ describe('MessageContextMenu', () => { const menu = createMenuWithContent(eventContent); expect(menu.find('div[aria-label="Forward"]')).toHaveLength(0); }); -}); + it('does show copy link button when supplied a link', () => { + const eventContent = MessageEvent.from("hello"); + const props = { + link: "https://google.com/", + }; + const menu = createMenuWithContent(eventContent, props); + const copyLinkButton = menu.find('a[aria-label="Copy link"]'); + expect(copyLinkButton).toHaveLength(1); + expect((copyLinkButton.getDOMNode() as HTMLAnchorElement)?.href).toBe(props.link); + }); + + it('does not show copy link button when not supplied a link', () => { + const eventContent = MessageEvent.from("hello"); + const menu = createMenuWithContent(eventContent); + const copyLinkButton = menu.find('a[aria-label="Copy link"]'); + expect(copyLinkButton).toHaveLength(0); + }); + + it('(right click) copy button does work as expected', () => { + const text = "hello"; + const eventContent = MessageEvent.from(text); + const props = { + rightClick: true, + }; + getSelectedText.mockReturnValue(text); + + const menu = createMenuWithContent(eventContent, props); + const copyButton = menu.find('div[aria-label="Copy"]'); + copyButton.simulate("mousedown"); + expect(copyPlaintext).toHaveBeenCalledWith(text); + }); + + it('(right click) copy button is not shown when there is nothing to copy', () => { + const text = "hello"; + const eventContent = MessageEvent.from(text); + const props = { + rightClick: true, + }; + getSelectedText.mockReturnValue(""); + + const menu = createMenuWithContent(eventContent, props); + const copyButton = menu.find('div[aria-label="Copy"]'); + expect(copyButton).toHaveLength(0); + }); + + it('(right click) shows edit button when we can edit', () => { + const eventContent = MessageEvent.from("hello"); + const props = { + rightClick: true, + }; + canEditContent.mockReturnValue(true); + + const menu = createMenuWithContent(eventContent, props); + const editButton = menu.find('div[aria-label="Edit"]'); + expect(editButton).toHaveLength(1); + }); + + it('(right click) does not show edit button when we cannot edit', () => { + const eventContent = MessageEvent.from("hello"); + const props = { + rightClick: true, + }; + canEditContent.mockReturnValue(false); + + const menu = createMenuWithContent(eventContent, props); + const editButton = menu.find('div[aria-label="Edit"]'); + expect(editButton).toHaveLength(0); + }); + + it('(right click) shows reply button when we can reply', () => { + const eventContent = MessageEvent.from("hello"); + const props = { + rightClick: true, + }; + const context = { + canSendMessages: true, + }; + isContentActionable.mockReturnValue(true); + + const menu = createMenuWithContent(eventContent, props, context); + const replyButton = menu.find('div[aria-label="Reply"]'); + expect(replyButton).toHaveLength(1); + }); + + it('(right click) does not show reply button when we cannot reply', () => { + const eventContent = MessageEvent.from("hello"); + const props = { + rightClick: true, + }; + const context = { + canSendMessages: true, + }; + isContentActionable.mockReturnValue(false); + + const menu = createMenuWithContent(eventContent, props, context); + const replyButton = menu.find('div[aria-label="Reply"]'); + expect(replyButton).toHaveLength(0); + }); + + it('(right click) shows react button when we can react', () => { + const eventContent = MessageEvent.from("hello"); + const props = { + rightClick: true, + }; + const context = { + canReact: true, + }; + isContentActionable.mockReturnValue(true); + + const menu = createMenuWithContent(eventContent, props, context); + const reactButton = menu.find('div[aria-label="React"]'); + expect(reactButton).toHaveLength(1); + }); + + it('(right click) does not show react button when we cannot react', () => { + const eventContent = MessageEvent.from("hello"); + const props = { + rightClick: true, + }; + const context = { + canReact: false, + }; + + const menu = createMenuWithContent(eventContent, props, context); + const reactButton = menu.find('div[aria-label="React"]'); + expect(reactButton).toHaveLength(0); + }); + + it('(right click) shows view in room button when the event is a thread root', () => { + const eventContent = MessageEvent.from("hello"); + const mxEvent = new MatrixEvent(eventContent.serialize()); + mxEvent.getThread = () => ({ rootEvent: mxEvent }) as Thread; + const props = { + rightClick: true, + }; + const context = { + timelineRenderingType: TimelineRenderingType.Thread, + }; + + const menu = createMenu(mxEvent, props, context); + const reactButton = menu.find('div[aria-label="View in room"]'); + expect(reactButton).toHaveLength(1); + }); + + it('(right click) does not show view in room button when the event is not a thread root', () => { + const eventContent = MessageEvent.from("hello"); + const props = { + rightClick: true, + }; + + const menu = createMenuWithContent(eventContent, props); + const reactButton = menu.find('div[aria-label="View in room"]'); + expect(reactButton).toHaveLength(0); + }); +}); function createMenuWithContent( eventContent: ExtensibleEvent, From 662466bfa0098248dd7a5c2c9038ef1f024ee126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 10 May 2022 19:23:01 +0200 Subject: [PATCH 03/10] Use `props()` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- test/components/views/context_menus/MessageContextMenu-test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/components/views/context_menus/MessageContextMenu-test.tsx b/test/components/views/context_menus/MessageContextMenu-test.tsx index 59184f8620c..1f49d9564b9 100644 --- a/test/components/views/context_menus/MessageContextMenu-test.tsx +++ b/test/components/views/context_menus/MessageContextMenu-test.tsx @@ -66,7 +66,7 @@ describe('MessageContextMenu', () => { const menu = createMenuWithContent(eventContent, props); const copyLinkButton = menu.find('a[aria-label="Copy link"]'); expect(copyLinkButton).toHaveLength(1); - expect((copyLinkButton.getDOMNode() as HTMLAnchorElement)?.href).toBe(props.link); + expect(copyLinkButton.props().href).toBe(props.link); }); it('does not show copy link button when not supplied a link', () => { From b83dcb6af1ea10836d5a6fd3ae1530fb45c59acf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 10 May 2022 19:24:04 +0200 Subject: [PATCH 04/10] Cast to `IRoomState` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- .../components/views/context_menus/MessageContextMenu-test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/components/views/context_menus/MessageContextMenu-test.tsx b/test/components/views/context_menus/MessageContextMenu-test.tsx index 1f49d9564b9..12998a5f34b 100644 --- a/test/components/views/context_menus/MessageContextMenu-test.tsx +++ b/test/components/views/context_menus/MessageContextMenu-test.tsx @@ -26,6 +26,7 @@ import { Thread } from "matrix-js-sdk/src/models/thread"; import * as TestUtils from '../../../test-utils'; import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; import RoomContext, { TimelineRenderingType } from "../../../../src/contexts/RoomContext"; +import { IRoomState } from "../../../../src/components/structures/RoomView"; const PATH_TO_STRING_UTILS = "../../../../src/utils/strings"; const PATH_TO_EVENT_UTILS = "../../../../src/utils/EventUtils"; @@ -243,7 +244,7 @@ function createMenu(mxEvent: MatrixEvent, props?, context = {}): ReactWrapper { client.getRoom = jest.fn().mockReturnValue(room); return mount( - + Date: Tue, 10 May 2022 19:32:35 +0200 Subject: [PATCH 05/10] Add `createRightClickMenuWithContent` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- .../context_menus/MessageContextMenu-test.tsx | 52 ++++++------------- 1 file changed, 16 insertions(+), 36 deletions(-) diff --git a/test/components/views/context_menus/MessageContextMenu-test.tsx b/test/components/views/context_menus/MessageContextMenu-test.tsx index 12998a5f34b..63f06133d03 100644 --- a/test/components/views/context_menus/MessageContextMenu-test.tsx +++ b/test/components/views/context_menus/MessageContextMenu-test.tsx @@ -80,12 +80,9 @@ describe('MessageContextMenu', () => { it('(right click) copy button does work as expected', () => { const text = "hello"; const eventContent = MessageEvent.from(text); - const props = { - rightClick: true, - }; getSelectedText.mockReturnValue(text); - const menu = createMenuWithContent(eventContent, props); + const menu = createRightClickMenuWithContent(eventContent); const copyButton = menu.find('div[aria-label="Copy"]'); copyButton.simulate("mousedown"); expect(copyPlaintext).toHaveBeenCalledWith(text); @@ -94,95 +91,74 @@ describe('MessageContextMenu', () => { it('(right click) copy button is not shown when there is nothing to copy', () => { const text = "hello"; const eventContent = MessageEvent.from(text); - const props = { - rightClick: true, - }; getSelectedText.mockReturnValue(""); - const menu = createMenuWithContent(eventContent, props); + const menu = createRightClickMenuWithContent(eventContent); const copyButton = menu.find('div[aria-label="Copy"]'); expect(copyButton).toHaveLength(0); }); it('(right click) shows edit button when we can edit', () => { const eventContent = MessageEvent.from("hello"); - const props = { - rightClick: true, - }; canEditContent.mockReturnValue(true); - const menu = createMenuWithContent(eventContent, props); + const menu = createRightClickMenuWithContent(eventContent); const editButton = menu.find('div[aria-label="Edit"]'); expect(editButton).toHaveLength(1); }); it('(right click) does not show edit button when we cannot edit', () => { const eventContent = MessageEvent.from("hello"); - const props = { - rightClick: true, - }; canEditContent.mockReturnValue(false); - const menu = createMenuWithContent(eventContent, props); + const menu = createRightClickMenuWithContent(eventContent); const editButton = menu.find('div[aria-label="Edit"]'); expect(editButton).toHaveLength(0); }); it('(right click) shows reply button when we can reply', () => { const eventContent = MessageEvent.from("hello"); - const props = { - rightClick: true, - }; const context = { canSendMessages: true, }; isContentActionable.mockReturnValue(true); - const menu = createMenuWithContent(eventContent, props, context); + const menu = createRightClickMenuWithContent(eventContent, context); const replyButton = menu.find('div[aria-label="Reply"]'); expect(replyButton).toHaveLength(1); }); it('(right click) does not show reply button when we cannot reply', () => { const eventContent = MessageEvent.from("hello"); - const props = { - rightClick: true, - }; const context = { canSendMessages: true, }; isContentActionable.mockReturnValue(false); - const menu = createMenuWithContent(eventContent, props, context); + const menu = createRightClickMenuWithContent(eventContent, context); const replyButton = menu.find('div[aria-label="Reply"]'); expect(replyButton).toHaveLength(0); }); it('(right click) shows react button when we can react', () => { const eventContent = MessageEvent.from("hello"); - const props = { - rightClick: true, - }; const context = { canReact: true, }; isContentActionable.mockReturnValue(true); - const menu = createMenuWithContent(eventContent, props, context); + const menu = createRightClickMenuWithContent(eventContent, context); const reactButton = menu.find('div[aria-label="React"]'); expect(reactButton).toHaveLength(1); }); it('(right click) does not show react button when we cannot react', () => { const eventContent = MessageEvent.from("hello"); - const props = { - rightClick: true, - }; const context = { canReact: false, }; - const menu = createMenuWithContent(eventContent, props, context); + const menu = createRightClickMenuWithContent(eventContent, context); const reactButton = menu.find('div[aria-label="React"]'); expect(reactButton).toHaveLength(0); }); @@ -205,16 +181,20 @@ describe('MessageContextMenu', () => { it('(right click) does not show view in room button when the event is not a thread root', () => { const eventContent = MessageEvent.from("hello"); - const props = { - rightClick: true, - }; - const menu = createMenuWithContent(eventContent, props); + const menu = createRightClickMenuWithContent(eventContent); const reactButton = menu.find('div[aria-label="View in room"]'); expect(reactButton).toHaveLength(0); }); }); +function createRightClickMenuWithContent( + eventContent: ExtensibleEvent, + context?, +): ReactWrapper { + return createMenuWithContent(eventContent, { rightClick: true }, context); +} + function createMenuWithContent( eventContent: ExtensibleEvent, props?, From 2eb3405049f9407733165af5a294f15de0b30341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 10 May 2022 19:34:03 +0200 Subject: [PATCH 06/10] Wrap in describe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- .../context_menus/MessageContextMenu-test.tsx | 218 +++++++++--------- 1 file changed, 110 insertions(+), 108 deletions(-) diff --git a/test/components/views/context_menus/MessageContextMenu-test.tsx b/test/components/views/context_menus/MessageContextMenu-test.tsx index 63f06133d03..71a8f678a48 100644 --- a/test/components/views/context_menus/MessageContextMenu-test.tsx +++ b/test/components/views/context_menus/MessageContextMenu-test.tsx @@ -77,114 +77,116 @@ describe('MessageContextMenu', () => { expect(copyLinkButton).toHaveLength(0); }); - it('(right click) copy button does work as expected', () => { - const text = "hello"; - const eventContent = MessageEvent.from(text); - getSelectedText.mockReturnValue(text); - - const menu = createRightClickMenuWithContent(eventContent); - const copyButton = menu.find('div[aria-label="Copy"]'); - copyButton.simulate("mousedown"); - expect(copyPlaintext).toHaveBeenCalledWith(text); - }); - - it('(right click) copy button is not shown when there is nothing to copy', () => { - const text = "hello"; - const eventContent = MessageEvent.from(text); - getSelectedText.mockReturnValue(""); - - const menu = createRightClickMenuWithContent(eventContent); - const copyButton = menu.find('div[aria-label="Copy"]'); - expect(copyButton).toHaveLength(0); - }); - - it('(right click) shows edit button when we can edit', () => { - const eventContent = MessageEvent.from("hello"); - canEditContent.mockReturnValue(true); - - const menu = createRightClickMenuWithContent(eventContent); - const editButton = menu.find('div[aria-label="Edit"]'); - expect(editButton).toHaveLength(1); - }); - - it('(right click) does not show edit button when we cannot edit', () => { - const eventContent = MessageEvent.from("hello"); - canEditContent.mockReturnValue(false); - - const menu = createRightClickMenuWithContent(eventContent); - const editButton = menu.find('div[aria-label="Edit"]'); - expect(editButton).toHaveLength(0); - }); - - it('(right click) shows reply button when we can reply', () => { - const eventContent = MessageEvent.from("hello"); - const context = { - canSendMessages: true, - }; - isContentActionable.mockReturnValue(true); - - const menu = createRightClickMenuWithContent(eventContent, context); - const replyButton = menu.find('div[aria-label="Reply"]'); - expect(replyButton).toHaveLength(1); - }); - - it('(right click) does not show reply button when we cannot reply', () => { - const eventContent = MessageEvent.from("hello"); - const context = { - canSendMessages: true, - }; - isContentActionable.mockReturnValue(false); - - const menu = createRightClickMenuWithContent(eventContent, context); - const replyButton = menu.find('div[aria-label="Reply"]'); - expect(replyButton).toHaveLength(0); - }); - - it('(right click) shows react button when we can react', () => { - const eventContent = MessageEvent.from("hello"); - const context = { - canReact: true, - }; - isContentActionable.mockReturnValue(true); - - const menu = createRightClickMenuWithContent(eventContent, context); - const reactButton = menu.find('div[aria-label="React"]'); - expect(reactButton).toHaveLength(1); - }); - - it('(right click) does not show react button when we cannot react', () => { - const eventContent = MessageEvent.from("hello"); - const context = { - canReact: false, - }; - - const menu = createRightClickMenuWithContent(eventContent, context); - const reactButton = menu.find('div[aria-label="React"]'); - expect(reactButton).toHaveLength(0); - }); - - it('(right click) shows view in room button when the event is a thread root', () => { - const eventContent = MessageEvent.from("hello"); - const mxEvent = new MatrixEvent(eventContent.serialize()); - mxEvent.getThread = () => ({ rootEvent: mxEvent }) as Thread; - const props = { - rightClick: true, - }; - const context = { - timelineRenderingType: TimelineRenderingType.Thread, - }; - - const menu = createMenu(mxEvent, props, context); - const reactButton = menu.find('div[aria-label="View in room"]'); - expect(reactButton).toHaveLength(1); - }); - - it('(right click) does not show view in room button when the event is not a thread root', () => { - const eventContent = MessageEvent.from("hello"); - - const menu = createRightClickMenuWithContent(eventContent); - const reactButton = menu.find('div[aria-label="View in room"]'); - expect(reactButton).toHaveLength(0); + describe("right click", () => { + it('copy button does work as expected', () => { + const text = "hello"; + const eventContent = MessageEvent.from(text); + getSelectedText.mockReturnValue(text); + + const menu = createRightClickMenuWithContent(eventContent); + const copyButton = menu.find('div[aria-label="Copy"]'); + copyButton.simulate("mousedown"); + expect(copyPlaintext).toHaveBeenCalledWith(text); + }); + + it('copy button is not shown when there is nothing to copy', () => { + const text = "hello"; + const eventContent = MessageEvent.from(text); + getSelectedText.mockReturnValue(""); + + const menu = createRightClickMenuWithContent(eventContent); + const copyButton = menu.find('div[aria-label="Copy"]'); + expect(copyButton).toHaveLength(0); + }); + + it('shows edit button when we can edit', () => { + const eventContent = MessageEvent.from("hello"); + canEditContent.mockReturnValue(true); + + const menu = createRightClickMenuWithContent(eventContent); + const editButton = menu.find('div[aria-label="Edit"]'); + expect(editButton).toHaveLength(1); + }); + + it('does not show edit button when we cannot edit', () => { + const eventContent = MessageEvent.from("hello"); + canEditContent.mockReturnValue(false); + + const menu = createRightClickMenuWithContent(eventContent); + const editButton = menu.find('div[aria-label="Edit"]'); + expect(editButton).toHaveLength(0); + }); + + it('shows reply button when we can reply', () => { + const eventContent = MessageEvent.from("hello"); + const context = { + canSendMessages: true, + }; + isContentActionable.mockReturnValue(true); + + const menu = createRightClickMenuWithContent(eventContent, context); + const replyButton = menu.find('div[aria-label="Reply"]'); + expect(replyButton).toHaveLength(1); + }); + + it('does not show reply button when we cannot reply', () => { + const eventContent = MessageEvent.from("hello"); + const context = { + canSendMessages: true, + }; + isContentActionable.mockReturnValue(false); + + const menu = createRightClickMenuWithContent(eventContent, context); + const replyButton = menu.find('div[aria-label="Reply"]'); + expect(replyButton).toHaveLength(0); + }); + + it('shows react button when we can react', () => { + const eventContent = MessageEvent.from("hello"); + const context = { + canReact: true, + }; + isContentActionable.mockReturnValue(true); + + const menu = createRightClickMenuWithContent(eventContent, context); + const reactButton = menu.find('div[aria-label="React"]'); + expect(reactButton).toHaveLength(1); + }); + + it('does not show react button when we cannot react', () => { + const eventContent = MessageEvent.from("hello"); + const context = { + canReact: false, + }; + + const menu = createRightClickMenuWithContent(eventContent, context); + const reactButton = menu.find('div[aria-label="React"]'); + expect(reactButton).toHaveLength(0); + }); + + it('shows view in room button when the event is a thread root', () => { + const eventContent = MessageEvent.from("hello"); + const mxEvent = new MatrixEvent(eventContent.serialize()); + mxEvent.getThread = () => ({ rootEvent: mxEvent }) as Thread; + const props = { + rightClick: true, + }; + const context = { + timelineRenderingType: TimelineRenderingType.Thread, + }; + + const menu = createMenu(mxEvent, props, context); + const reactButton = menu.find('div[aria-label="View in room"]'); + expect(reactButton).toHaveLength(1); + }); + + it('does not show view in room button when the event is not a thread root', () => { + const eventContent = MessageEvent.from("hello"); + + const menu = createRightClickMenuWithContent(eventContent); + const reactButton = menu.find('div[aria-label="View in room"]'); + expect(reactButton).toHaveLength(0); + }); }); }); From 916d731d0bb39d38376216691b77e0024dfac8b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 10 May 2022 19:34:49 +0200 Subject: [PATCH 07/10] Just use `jest.fn()` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- test/components/views/context_menus/MessageContextMenu-test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/components/views/context_menus/MessageContextMenu-test.tsx b/test/components/views/context_menus/MessageContextMenu-test.tsx index 71a8f678a48..c124d50a726 100644 --- a/test/components/views/context_menus/MessageContextMenu-test.tsx +++ b/test/components/views/context_menus/MessageContextMenu-test.tsx @@ -230,7 +230,7 @@ function createMenu(mxEvent: MatrixEvent, props?, context = {}): ReactWrapper { {})} + onFinished={jest.fn()} {...props} /> , From 75638ec8f940746718fb3145ef583d0b1a3f2e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 11 May 2022 06:28:27 +0200 Subject: [PATCH 08/10] `require` `MessageContextMenu` at the top MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- .../context_menus/MessageContextMenu-test.tsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/test/components/views/context_menus/MessageContextMenu-test.tsx b/test/components/views/context_menus/MessageContextMenu-test.tsx index c124d50a726..aaf57087a18 100644 --- a/test/components/views/context_menus/MessageContextMenu-test.tsx +++ b/test/components/views/context_menus/MessageContextMenu-test.tsx @@ -36,6 +36,7 @@ jest.mock(PATH_TO_EVENT_UTILS); const { copyPlaintext, getSelectedText } = require(PATH_TO_STRING_UTILS); const { canEditContent, canForward, isContentActionable } = require(PATH_TO_EVENT_UTILS); +const MessageContextMenu = require("../../../../src/components/views/context_menus/MessageContextMenu")["default"]; describe('MessageContextMenu', () => { beforeAll(() => { @@ -192,24 +193,27 @@ describe('MessageContextMenu', () => { function createRightClickMenuWithContent( eventContent: ExtensibleEvent, - context?, + context?: Partial, ): ReactWrapper { return createMenuWithContent(eventContent, { rightClick: true }, context); } function createMenuWithContent( eventContent: ExtensibleEvent, - props?, - context?, + props?: React.ComponentProps, + context?: Partial, ): ReactWrapper { const mxEvent = new MatrixEvent(eventContent.serialize()); return createMenu(mxEvent, props, context); } -function createMenu(mxEvent: MatrixEvent, props?, context = {}): ReactWrapper { +function createMenu( + mxEvent: MatrixEvent, + props?: React.ComponentProps, + context: Partial = {}, +): ReactWrapper { TestUtils.stubClient(); const client = MatrixClientPeg.get(); - const MessageContextMenu = require("../../../../src/components/views/context_menus/MessageContextMenu")["default"]; const room = new Room( "roomid", From c5ddf19323e8c2d6930d92adcba02ff972750eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 11 May 2022 15:22:11 +0200 Subject: [PATCH 09/10] Set default mocks and avoid `require` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- .../context_menus/MessageContextMenu-test.tsx | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/test/components/views/context_menus/MessageContextMenu-test.tsx b/test/components/views/context_menus/MessageContextMenu-test.tsx index aaf57087a18..32beacfa0ba 100644 --- a/test/components/views/context_menus/MessageContextMenu-test.tsx +++ b/test/components/views/context_menus/MessageContextMenu-test.tsx @@ -22,30 +22,35 @@ import { Room } from 'matrix-js-sdk/src/models/room'; import { PendingEventOrdering } from 'matrix-js-sdk/src/matrix'; import { ExtensibleEvent, MessageEvent, M_POLL_KIND_DISCLOSED, PollStartEvent } from 'matrix-events-sdk'; import { Thread } from "matrix-js-sdk/src/models/thread"; +import { mocked } from "jest-mock"; import * as TestUtils from '../../../test-utils'; import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; import RoomContext, { TimelineRenderingType } from "../../../../src/contexts/RoomContext"; import { IRoomState } from "../../../../src/components/structures/RoomView"; - -const PATH_TO_STRING_UTILS = "../../../../src/utils/strings"; -const PATH_TO_EVENT_UTILS = "../../../../src/utils/EventUtils"; - -jest.mock(PATH_TO_STRING_UTILS); -jest.mock(PATH_TO_EVENT_UTILS); - -const { copyPlaintext, getSelectedText } = require(PATH_TO_STRING_UTILS); -const { canEditContent, canForward, isContentActionable } = require(PATH_TO_EVENT_UTILS); -const MessageContextMenu = require("../../../../src/components/views/context_menus/MessageContextMenu")["default"]; +import { canEditContent, canForward, isContentActionable } from "../../../../src/utils/EventUtils"; +import { copyPlaintext, getSelectedText } from "../../../../src/utils/strings"; +import MessageContextMenu from "../../../../src/components/views/context_menus/MessageContextMenu"; + +jest.mock("../../../../src/utils/strings", () => ({ + copyPlaintext: jest.fn(), + getSelectedText: jest.fn(), +})); +jest.mock("../../../../src/utils/EventUtils", () => ({ + canEditContent: jest.fn(), + canForward: jest.fn(), + isContentActionable: jest.fn(), + isLocationEvent: jest.fn(), +})); describe('MessageContextMenu', () => { - beforeAll(() => { + beforeEach(() => { jest.resetAllMocks(); }); it('allows forwarding a room message', () => { - canForward.mockReturnValue(true); - isContentActionable.mockReturnValue(true); + mocked(canForward).mockReturnValue(true); + mocked(isContentActionable).mockReturnValue(true); const eventContent = MessageEvent.from("hello"); const menu = createMenuWithContent(eventContent); @@ -53,7 +58,7 @@ describe('MessageContextMenu', () => { }); it('does not allow forwarding a poll', () => { - canForward.mockReturnValue(false); + mocked(canForward).mockReturnValue(false); const eventContent = PollStartEvent.from("why?", ["42"], M_POLL_KIND_DISCLOSED); const menu = createMenuWithContent(eventContent); @@ -82,7 +87,7 @@ describe('MessageContextMenu', () => { it('copy button does work as expected', () => { const text = "hello"; const eventContent = MessageEvent.from(text); - getSelectedText.mockReturnValue(text); + mocked(getSelectedText).mockReturnValue(text); const menu = createRightClickMenuWithContent(eventContent); const copyButton = menu.find('div[aria-label="Copy"]'); @@ -93,7 +98,7 @@ describe('MessageContextMenu', () => { it('copy button is not shown when there is nothing to copy', () => { const text = "hello"; const eventContent = MessageEvent.from(text); - getSelectedText.mockReturnValue(""); + mocked(getSelectedText).mockReturnValue(""); const menu = createRightClickMenuWithContent(eventContent); const copyButton = menu.find('div[aria-label="Copy"]'); @@ -102,7 +107,7 @@ describe('MessageContextMenu', () => { it('shows edit button when we can edit', () => { const eventContent = MessageEvent.from("hello"); - canEditContent.mockReturnValue(true); + mocked(canEditContent).mockReturnValue(true); const menu = createRightClickMenuWithContent(eventContent); const editButton = menu.find('div[aria-label="Edit"]'); @@ -111,7 +116,7 @@ describe('MessageContextMenu', () => { it('does not show edit button when we cannot edit', () => { const eventContent = MessageEvent.from("hello"); - canEditContent.mockReturnValue(false); + mocked(canEditContent).mockReturnValue(false); const menu = createRightClickMenuWithContent(eventContent); const editButton = menu.find('div[aria-label="Edit"]'); @@ -123,7 +128,7 @@ describe('MessageContextMenu', () => { const context = { canSendMessages: true, }; - isContentActionable.mockReturnValue(true); + mocked(isContentActionable).mockReturnValue(true); const menu = createRightClickMenuWithContent(eventContent, context); const replyButton = menu.find('div[aria-label="Reply"]'); @@ -135,7 +140,7 @@ describe('MessageContextMenu', () => { const context = { canSendMessages: true, }; - isContentActionable.mockReturnValue(false); + mocked(isContentActionable).mockReturnValue(false); const menu = createRightClickMenuWithContent(eventContent, context); const replyButton = menu.find('div[aria-label="Reply"]'); @@ -147,7 +152,7 @@ describe('MessageContextMenu', () => { const context = { canReact: true, }; - isContentActionable.mockReturnValue(true); + mocked(isContentActionable).mockReturnValue(true); const menu = createRightClickMenuWithContent(eventContent, context); const reactButton = menu.find('div[aria-label="React"]'); @@ -200,7 +205,7 @@ function createRightClickMenuWithContent( function createMenuWithContent( eventContent: ExtensibleEvent, - props?: React.ComponentProps, + props?: Partial>, context?: Partial, ): ReactWrapper { const mxEvent = new MatrixEvent(eventContent.serialize()); @@ -209,7 +214,7 @@ function createMenuWithContent( function createMenu( mxEvent: MatrixEvent, - props?: React.ComponentProps, + props?: Partial>, context: Partial = {}, ): ReactWrapper { TestUtils.stubClient(); From 4a764a6912adc1dd547d4ecbde72eb85feb5a250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 11 May 2022 15:22:43 +0200 Subject: [PATCH 10/10] Remove typescript rule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- test/components/views/context_menus/MessageContextMenu-test.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/test/components/views/context_menus/MessageContextMenu-test.tsx b/test/components/views/context_menus/MessageContextMenu-test.tsx index 32beacfa0ba..e449fad52a4 100644 --- a/test/components/views/context_menus/MessageContextMenu-test.tsx +++ b/test/components/views/context_menus/MessageContextMenu-test.tsx @@ -13,7 +13,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -/* eslint-disable @typescript-eslint/no-var-requires */ import React from 'react'; import { mount, ReactWrapper } from 'enzyme';