mirror of
https://github.com/element-hq/element-web
synced 2024-11-27 03:36:07 +03:00
Write tests for message right-click context menu (#8532)
This commit is contained in:
parent
36f2824eb8
commit
5348572439
1 changed files with 190 additions and 12 deletions
|
@ -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>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue