/* Copyright 2019 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 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. */ import React from "react"; import { mount } from "enzyme"; import sdk from "../../../skinned-sdk"; import { mkEvent, mkStubRoom } from "../../../test-utils"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import * as languageHandler from "../../../../src/languageHandler"; import * as TestUtils from "../../../test-utils"; import DMRoomMap from "../../../../src/utils/DMRoomMap"; const _TextualBody = sdk.getComponent("views.messages.TextualBody"); const TextualBody = TestUtils.wrapInMatrixClientContext(_TextualBody); describe("", () => { afterEach(() => { MatrixClientPeg.matrixClient = null; }); it("renders m.emote correctly", () => { MatrixClientPeg.matrixClient = { getRoom: () => mkStubRoom("room_id"), getAccountData: () => undefined, isGuest: () => false, mxcUrlToHttp: (s) => s, }; DMRoomMap.makeShared(); const ev = mkEvent({ type: "m.room.message", room: "room_id", user: "sender", content: { body: "winks", msgtype: "m.emote", }, event: true, }); const wrapper = mount(); expect(wrapper.text()).toBe("* sender winks"); const content = wrapper.find(".mx_EventTile_body"); expect(content.html()).toBe('winks'); }); it("renders m.notice correctly", () => { MatrixClientPeg.matrixClient = { getRoom: () => mkStubRoom("room_id"), getAccountData: () => undefined, isGuest: () => false, mxcUrlToHttp: (s) => s, }; DMRoomMap.makeShared(); const ev = mkEvent({ type: "m.room.message", room: "room_id", user: "bot_sender", content: { body: "this is a notice, probably from a bot", msgtype: "m.notice", }, event: true, }); const wrapper = mount(); expect(wrapper.text()).toBe(ev.getContent().body); const content = wrapper.find(".mx_EventTile_body"); expect(content.html()).toBe(`${ ev.getContent().body }`); }); describe("renders plain-text m.text correctly", () => { beforeEach(() => { MatrixClientPeg.matrixClient = { getRoom: () => mkStubRoom("room_id"), getAccountData: () => undefined, isGuest: () => false, mxcUrlToHttp: (s) => s, }; DMRoomMap.makeShared(); }); it("simple message renders as expected", () => { const ev = mkEvent({ type: "m.room.message", room: "room_id", user: "sender", content: { body: "this is a plaintext message", msgtype: "m.text", }, event: true, }); const wrapper = mount(); expect(wrapper.text()).toBe(ev.getContent().body); const content = wrapper.find(".mx_EventTile_body"); expect(content.html()).toBe(`${ ev.getContent().body }`); }); // If pills were rendered within a Portal/same shadow DOM then it'd be easier to test it("linkification get applied correctly into the DOM", () => { const ev = mkEvent({ type: "m.room.message", room: "room_id", user: "sender", content: { body: "Visit https://matrix.org/", msgtype: "m.text", }, event: true, }); const wrapper = mount(); expect(wrapper.text()).toBe(ev.getContent().body); const content = wrapper.find(".mx_EventTile_body"); expect(content.html()).toBe('' + 'Visit ' + 'https://matrix.org/'); }); }); describe("renders formatted m.text correctly", () => { beforeEach(() => { MatrixClientPeg.matrixClient = { getRoom: () => mkStubRoom("room_id"), getAccountData: () => undefined, getUserId: () => "@me:my_server", getHomeserverUrl: () => "https://my_server/", on: () => undefined, removeListener: () => undefined, isGuest: () => false, mxcUrlToHttp: (s) => s, }; DMRoomMap.makeShared(); }); it("italics, bold, underline and strikethrough render as expected", () => { const ev = mkEvent({ type: "m.room.message", room: "room_id", user: "sender", content: { body: "foo *baz* __bar__ del u", msgtype: "m.text", format: "org.matrix.custom.html", formatted_body: "foo baz bar del u", }, event: true, }); const wrapper = mount(); expect(wrapper.text()).toBe("foo baz bar del u"); const content = wrapper.find(".mx_EventTile_body"); expect(content.html()).toBe('' + ev.getContent().formatted_body + ''); }); it("spoilers get injected properly into the DOM", () => { const ev = mkEvent({ type: "m.room.message", room: "room_id", user: "sender", content: { body: "Hey [Spoiler for movie](mxc://someserver/somefile)", msgtype: "m.text", format: "org.matrix.custom.html", formatted_body: "Hey the movie was awesome", }, event: true, }); const wrapper = mount(); expect(wrapper.text()).toBe("Hey (movie) the movie was awesome"); const content = wrapper.find(".mx_EventTile_body"); expect(content.html()).toBe('' + 'Hey ' + '' + '(movie) ' + 'the movie was awesome' + ''); }); // If pills were rendered within a Portal/same shadow DOM then it'd be easier to test it("pills get injected correctly into the DOM", () => { const ev = mkEvent({ type: "m.room.message", room: "room_id", user: "sender", content: { body: "Hey User", msgtype: "m.text", format: "org.matrix.custom.html", formatted_body: "Hey Member", }, event: true, }); const wrapper = mount(); expect(wrapper.text()).toBe("Hey Member"); const content = wrapper.find(".mx_EventTile_body"); expect(content.html()).toBe('' + 'Hey ' + '' + 'Member' + ''); }); it("pills do not appear in code blocks", () => { const ev = mkEvent({ type: "m.room.message", room: "room_id", user: "sender", content: { body: "`@room`\n```\n@room\n```", msgtype: "m.text", format: "org.matrix.custom.html", formatted_body: "

@room

\n
@room\n
\n", }, event: true, }); const wrapper = mount(); expect(wrapper.text()).toBe("@room\n1@room\n\n"); const content = wrapper.find(".mx_EventTile_body"); expect(content.html()).toMatchSnapshot(); }); it("pills do not appear for event permalinks", () => { const ev = mkEvent({ type: "m.room.message", room: "room_id", user: "sender", content: { body: "An [event link](https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com/" + "$16085560162aNpaH:example.com?via=example.com) with text", msgtype: "m.text", format: "org.matrix.custom.html", formatted_body: "An event link with text", }, event: true, }); const wrapper = mount(); expect(wrapper.text()).toBe("An event link with text"); const content = wrapper.find(".mx_EventTile_body"); expect(content.html()).toBe( '' + 'An event link with text', ); }); it("pills appear for room links with vias", () => { const ev = mkEvent({ type: "m.room.message", room: "room_id", user: "sender", content: { body: "A [room link](https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com" + "?via=example.com&via=bob.com) with vias", msgtype: "m.text", format: "org.matrix.custom.html", formatted_body: "A room link with vias", }, event: true, }); const wrapper = mount(); expect(wrapper.text()).toBe("A !ZxbRYPQXDXKGmDnJNg:example.com with vias"); const content = wrapper.find(".mx_EventTile_body"); expect(content.html()).toBe( '' + 'A ' + '!ZxbRYPQXDXKGmDnJNg:example.com with vias', ); }); it('renders formatted body without html corretly', () => { const ev = mkEvent({ type: "m.room.message", room: "room_id", user: "sender", content: { body: "escaped \\*markdown\\*", msgtype: "m.text", format: "org.matrix.custom.html", formatted_body: "escaped *markdown*", }, event: true, }); const wrapper = mount(); const content = wrapper.find(".mx_EventTile_body"); expect(content.html()).toBe( '' + 'escaped *markdown*' + '', ); }); }); it("renders url previews correctly", () => { languageHandler.setMissingEntryGenerator(key => key.split('|', 2)[1]); MatrixClientPeg.matrixClient = { getRoom: () => mkStubRoom("room_id"), getAccountData: () => undefined, getUrlPreview: (url) => new Promise(() => {}), isGuest: () => false, mxcUrlToHttp: (s) => s, }; DMRoomMap.makeShared(); const ev = mkEvent({ type: "m.room.message", room: "room_id", user: "sender", content: { body: "Visit https://matrix.org/", msgtype: "m.text", }, event: true, }); const wrapper = mount( {}} />); expect(wrapper.text()).toBe(ev.getContent().body); let widgets = wrapper.find("LinkPreviewGroup"); // at this point we should have exactly one link expect(widgets.at(0).prop("links")).toEqual(["https://matrix.org/"]); // simulate an event edit and check the transition from the old URL preview to the new one const ev2 = mkEvent({ type: "m.room.message", room: "room_id", user: "sender", content: { "m.new_content": { body: "Visit https://vector.im/ and https://riot.im/", msgtype: "m.text", }, }, event: true, }); jest.spyOn(ev, 'replacingEventDate').mockReturnValue(new Date(1993, 7, 3)); ev.makeReplaced(ev2); wrapper.setProps({ mxEvent: ev, replacingEventId: ev.getId(), }, () => { expect(wrapper.text()).toBe(ev2.getContent()["m.new_content"].body + "(edited)"); // XXX: this is to give TextualBody enough time for state to settle wrapper.setState({}, () => { widgets = wrapper.find("LinkPreviewGroup"); // at this point we should have exactly two links (not the matrix.org one anymore) expect(widgets.at(0).prop("links")).toEqual(["https://vector.im/", "https://riot.im/"]); }); }); }); });