Write tests for message right-click context menu (#8532)

This commit is contained in:
Šimon Brandner 2022-05-11 18:39:40 +02:00 committed by GitHub
parent 36f2824eb8
commit 5348572439
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -15,31 +15,207 @@ limitations under the License.
*/ */
import React from 'react'; import React from 'react';
import { mount } from 'enzyme'; import { mount, ReactWrapper } from 'enzyme';
import { EventStatus, MatrixEvent } from 'matrix-js-sdk/src/models/event'; import { EventStatus, MatrixEvent } from 'matrix-js-sdk/src/models/event';
import { Room } from 'matrix-js-sdk/src/models/room'; import { Room } from 'matrix-js-sdk/src/models/room';
import { PendingEventOrdering } from 'matrix-js-sdk/src/matrix'; import { PendingEventOrdering } from 'matrix-js-sdk/src/matrix';
import { ExtensibleEvent, MessageEvent, M_POLL_KIND_DISCLOSED, PollStartEvent } from 'matrix-events-sdk'; 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 * as TestUtils from '../../../test-utils';
import MessageContextMenu from '../../../../src/components/views/context_menus/MessageContextMenu';
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
import RoomContext, { TimelineRenderingType } from "../../../../src/contexts/RoomContext";
import { IRoomState } from "../../../../src/components/structures/RoomView";
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', () => {
beforeEach(() => {
jest.resetAllMocks();
});
describe('MessageContextMenu>', () => {
it('allows forwarding a room message', () => { it('allows forwarding a room message', () => {
mocked(canForward).mockReturnValue(true);
mocked(isContentActionable).mockReturnValue(true);
const eventContent = MessageEvent.from("hello"); const eventContent = MessageEvent.from("hello");
const menu = createMessageContextMenu(eventContent); const menu = createMenuWithContent(eventContent);
expect(menu.find('div[aria-label="Forward"]')).toHaveLength(1); expect(menu.find('div[aria-label="Forward"]')).toHaveLength(1);
}); });
it('does not allow forwarding a poll', () => { it('does not allow forwarding a poll', () => {
mocked(canForward).mockReturnValue(false);
const eventContent = PollStartEvent.from("why?", ["42"], M_POLL_KIND_DISCLOSED); 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); 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.props().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);
});
describe("right click", () => {
it('copy button does work as expected', () => {
const text = "hello";
const eventContent = MessageEvent.from(text);
mocked(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);
mocked(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");
mocked(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");
mocked(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,
};
mocked(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,
};
mocked(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,
};
mocked(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);
});
});
}); });
function createMessageContextMenu(eventContent: ExtensibleEvent) { function createRightClickMenuWithContent(
eventContent: ExtensibleEvent,
context?: Partial<IRoomState>,
): ReactWrapper {
return createMenuWithContent(eventContent, { rightClick: true }, context);
}
function createMenuWithContent(
eventContent: ExtensibleEvent,
props?: Partial<React.ComponentProps<typeof MessageContextMenu>>,
context?: Partial<IRoomState>,
): ReactWrapper {
const mxEvent = new MatrixEvent(eventContent.serialize());
return createMenu(mxEvent, props, context);
}
function createMenu(
mxEvent: MatrixEvent,
props?: Partial<React.ComponentProps<typeof MessageContextMenu>>,
context: Partial<IRoomState> = {},
): ReactWrapper {
TestUtils.stubClient(); TestUtils.stubClient();
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.get();
@ -52,17 +228,19 @@ function createMessageContextMenu(eventContent: ExtensibleEvent) {
}, },
); );
const mxEvent = new MatrixEvent(eventContent.serialize());
mxEvent.setStatus(EventStatus.SENT); mxEvent.setStatus(EventStatus.SENT);
client.getUserId = jest.fn().mockReturnValue("@user:example.com"); client.getUserId = jest.fn().mockReturnValue("@user:example.com");
client.getRoom = jest.fn().mockReturnValue(room); client.getRoom = jest.fn().mockReturnValue(room);
return mount( return mount(
<MessageContextMenu <RoomContext.Provider value={context as IRoomState}>
chevronFace={null} <MessageContextMenu
mxEvent={mxEvent} chevronFace={null}
onFinished={jest.fn(() => {})} mxEvent={mxEvent}
/>, onFinished={jest.fn()}
{...props}
/>
</RoomContext.Provider>,
); );
} }