2020-01-06 14:52:08 +00:00
/*
2024-09-09 14:57:16 +01:00
Copyright 2024 New Vector Ltd.
Copyright 2019-2022 The Matrix.org Foundation C.I.C.
2020-01-06 14:52:08 +00:00
2025-01-06 11:18:54 +00:00
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
2024-09-09 14:57:16 +01:00
Please see LICENSE files in the repository root for full details.
2020-01-06 14:52:08 +00:00
*/
2020-01-06 13:28:29 +00:00
import React from "react" ;
2023-02-13 11:39:16 +00:00
import { MatrixClient , MatrixEvent } from "matrix-js-sdk/src/matrix" ;
2023-03-22 13:27:24 +01:00
import { mocked , MockedObject } from "jest-mock" ;
2024-10-18 15:57:39 +01:00
import { render , waitFor } from "jest-matrix-react" ;
2020-01-06 13:28:29 +00:00
2024-10-15 14:57:26 +01:00
import { getMockClientWithEventEmitter , mkEvent , mkMessage , mkStubRoom } from "../../../../test-utils" ;
import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg" ;
import * as languageHandler from "../../../../../src/languageHandler" ;
import DMRoomMap from "../../../../../src/utils/DMRoomMap" ;
import TextualBody from "../../../../../src/components/views/messages/TextualBody" ;
import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext" ;
import { RoomPermalinkCreator } from "../../../../../src/utils/permalinks/Permalinks" ;
import { MediaEventHelper } from "../../../../../src/utils/MediaEventHelper" ;
2020-01-06 13:28:29 +00:00
2023-03-22 13:27:24 +01:00
const room1Id = "!room1:example.com" ;
const room2Id = "!room2:example.com" ;
const room2Name = "Room 2" ;
interface MkRoomTextMessageOpts {
roomId? : string ;
}
const mkRoomTextMessage = ( body : string , mkRoomTextMessageOpts? : MkRoomTextMessageOpts ) : MatrixEvent => {
2023-03-02 11:41:17 +01:00
return mkMessage ({
msg : body ,
2023-03-22 13:27:24 +01:00
room : mkRoomTextMessageOpts?.roomId ?? room1Id ,
2023-03-02 11:41:17 +01:00
user : "sender" ,
event : true ,
});
};
2023-03-16 15:01:09 +01:00
const mkFormattedMessage = ( body : string , formattedBody : string ) : MatrixEvent => {
return mkMessage ({
msg : body ,
formattedMsg : formattedBody ,
format : "org.matrix.custom.html" ,
2023-03-22 13:27:24 +01:00
room : room1Id ,
2023-03-16 15:01:09 +01:00
user : "sender" ,
event : true ,
});
};
2020-01-06 13:28:29 +00:00
describe ( "<TextualBody />" , () => {
afterEach (() => {
2022-04-28 11:32:50 +02:00
jest . spyOn ( MatrixClientPeg , "get" ). mockRestore ();
2023-05-05 09:26:11 +01:00
jest . spyOn ( global . Math , "random" ). mockRestore ();
2020-01-06 13:28:29 +00:00
});
2023-03-22 13:27:24 +01:00
const defaultRoom = mkStubRoom ( room1Id , "test room" , undefined );
const otherRoom = mkStubRoom ( room2Id , room2Name , undefined );
2022-04-28 11:32:50 +02:00
let defaultMatrixClient : MockedObject < MatrixClient >;
2023-03-22 13:27:24 +01:00
const defaultEvent = mkEvent ({
type : "m.room.message" ,
room : room1Id ,
user : "sender" ,
content : {
body : "winks" ,
msgtype : "m.emote" ,
},
event : true ,
});
2022-04-28 11:32:50 +02:00
beforeEach (() => {
defaultMatrixClient = getMockClientWithEventEmitter ({
2023-03-22 13:27:24 +01:00
getRoom : ( roomId : string | undefined ) => {
if ( roomId === room1Id ) return defaultRoom ;
if ( roomId === room2Id ) return otherRoom ;
return null ;
},
getRooms : () => [ defaultRoom , otherRoom ],
2023-02-13 11:39:16 +00:00
getAccountData : () : MatrixEvent | undefined => undefined ,
2020-10-29 13:22:09 +00:00
isGuest : () => false ,
2023-02-13 11:39:16 +00:00
mxcUrlToHttp : ( s : string ) => s ,
2023-03-02 11:41:17 +01:00
getUserId : () => "@user:example.com" ,
2023-03-21 10:23:20 +01:00
fetchRoomEvent : () => {
throw new Error ( "MockClient event not found" );
},
2022-04-28 11:32:50 +02:00
});
2023-03-22 13:27:24 +01:00
mocked ( defaultRoom ). findEventById . mockImplementation (( eventId : string ) => {
if ( eventId === defaultEvent . getId ()) return defaultEvent ;
return undefined ;
});
2023-05-05 09:26:11 +01:00
jest . spyOn ( global . Math , "random" ). mockReturnValue ( 0.123456 );
2022-04-28 11:32:50 +02:00
});
const defaultProps = {
mxEvent : defaultEvent ,
2023-02-13 11:39:16 +00:00
highlights : [] as string [],
2022-04-28 11:32:50 +02:00
highlightLink : "" ,
onMessageAllowed : jest.fn (),
onHeightChanged : jest.fn (),
permalinkCreator : new RoomPermalinkCreator ( defaultRoom ),
mediaEventHelper : {} as MediaEventHelper ,
};
2023-03-22 13:27:24 +01:00
2022-12-29 16:21:00 +00:00
const getComponent = ( props = {}, matrixClient : MatrixClient = defaultMatrixClient , renderingFn? : any ) =>
( renderingFn ?? render )(
< MatrixClientContext.Provider value = { matrixClient }>
< TextualBody { ...defaultProps } { ...props } />
</ MatrixClientContext.Provider >,
);
2022-04-28 11:32:50 +02:00
it ( "renders m.emote correctly" , () => {
2023-05-23 16:24:12 +01:00
DMRoomMap . makeShared ( defaultMatrixClient );
2020-01-06 13:28:29 +00:00
const ev = mkEvent ({
type : "m.room.message" ,
2023-03-22 13:27:24 +01:00
room : room1Id ,
2020-01-06 13:28:29 +00:00
user : "sender" ,
content : {
body : "winks" ,
msgtype : "m.emote" ,
},
event : true ,
});
2022-12-29 16:21:00 +00:00
const { container } = getComponent ({ mxEvent : ev });
expect ( container ). toHaveTextContent ( "* sender winks" );
const content = container . querySelector ( ".mx_EventTile_body" );
2024-07-25 18:58:33 +02:00
expect ( content ). toMatchSnapshot ();
2020-01-06 13:28:29 +00:00
});
2020-01-09 17:24:13 -07:00
it ( "renders m.notice correctly" , () => {
2023-05-23 16:24:12 +01:00
DMRoomMap . makeShared ( defaultMatrixClient );
2020-01-06 13:28:29 +00:00
const ev = mkEvent ({
type : "m.room.message" ,
2023-03-22 13:27:24 +01:00
room : room1Id ,
2020-01-06 13:28:29 +00:00
user : "bot_sender" ,
content : {
body : "this is a notice, probably from a bot" ,
msgtype : "m.notice" ,
},
event : true ,
});
2022-12-29 16:21:00 +00:00
const { container } = getComponent ({ mxEvent : ev });
expect ( container ). toHaveTextContent ( ev . getContent (). body );
const content = container . querySelector ( ".mx_EventTile_body" );
2024-07-25 18:58:33 +02:00
expect ( content ). toMatchSnapshot ();
2020-01-06 13:28:29 +00:00
});
describe ( "renders plain-text m.text correctly" , () => {
2020-01-09 17:24:13 -07:00
beforeEach (() => {
2023-05-23 16:24:12 +01:00
DMRoomMap . makeShared ( defaultMatrixClient );
2020-01-09 17:24:13 -07:00
});
2020-01-06 13:28:29 +00:00
2020-01-09 17:24:13 -07:00
it ( "simple message renders as expected" , () => {
2023-03-02 11:41:17 +01:00
const ev = mkRoomTextMessage ( "this is a plaintext message" );
2022-12-29 16:21:00 +00:00
const { container } = getComponent ({ mxEvent : ev });
expect ( container ). toHaveTextContent ( ev . getContent (). body );
const content = container . querySelector ( ".mx_EventTile_body" );
2024-07-25 18:58:33 +02:00
expect ( content ). toMatchSnapshot ();
2020-01-06 13:28:29 +00:00
});
// If pills were rendered within a Portal/same shadow DOM then it'd be easier to test
2020-01-09 17:24:13 -07:00
it ( "linkification get applied correctly into the DOM" , () => {
2023-03-02 11:41:17 +01:00
const ev = mkRoomTextMessage ( "Visit https://matrix.org/" );
2022-12-29 16:21:00 +00:00
const { container } = getComponent ({ mxEvent : ev });
expect ( container ). toHaveTextContent ( ev . getContent (). body );
const content = container . querySelector ( ".mx_EventTile_body" );
2024-07-25 18:58:33 +02:00
expect ( content ). toMatchSnapshot ();
2020-01-06 13:28:29 +00:00
});
2023-03-02 11:41:17 +01:00
2023-03-14 11:56:14 +01:00
it ( "should not pillify MXIDs" , () => {
2023-03-02 11:41:17 +01:00
const ev = mkRoomTextMessage ( "Chat with @user:example.com" );
const { container } = getComponent ({ mxEvent : ev });
const content = container . querySelector ( ".mx_EventTile_body" );
expect ( content . innerHTML ). toMatchInlineSnapshot (
2023-03-14 11:56:14 +01:00
`"Chat with <a href="https://matrix.to/#/@user:example.com" class="linkified" rel="noreferrer noopener">@user:example.com</a>"` ,
2023-03-02 11:41:17 +01:00
);
});
2023-03-16 15:01:09 +01:00
it ( "should pillify an MXID permalink" , () => {
const ev = mkRoomTextMessage ( "Chat with https://matrix.to/#/@user:example.com" );
const { container } = getComponent ({ mxEvent : ev });
const content = container . querySelector ( ".mx_EventTile_body" );
expect ( content . innerHTML ). toMatchInlineSnapshot (
2024-05-15 15:34:27 +02:00
`"Chat with <span><bdi><a class="mx_Pill mx_UserPill mx_UserPill_me" href="https://matrix.to/#/@user:example.com"><span aria-label="Profile picture" aria-hidden="true" data-testid="avatar-img" data-type="round" data-color="2" class="_avatar_mcap2_17 mx_BaseAvatar" style="--cpd-avatar-size: 16px;"><img loading="lazy" alt="" src="mxc://avatar.url/image.png" referrerpolicy="no-referrer" class="_image_mcap2_50" data-type="round" width="16px" height="16px"></span><span class="mx_Pill_text">Member</span></a></bdi></span>"` ,
2023-03-16 15:01:09 +01:00
);
});
2023-03-14 11:56:14 +01:00
it ( "should not pillify room aliases" , () => {
2023-03-02 11:41:17 +01:00
const ev = mkRoomTextMessage ( "Visit #room:example.com" );
const { container } = getComponent ({ mxEvent : ev });
const content = container . querySelector ( ".mx_EventTile_body" );
expect ( content . innerHTML ). toMatchInlineSnapshot (
2023-03-14 11:56:14 +01:00
`"Visit <a href="https://matrix.to/#/#room:example.com" class="linkified" rel="noreferrer noopener">#room:example.com</a>"` ,
2023-03-02 11:41:17 +01:00
);
});
2023-03-16 15:01:09 +01:00
it ( "should pillify a room alias permalink" , () => {
const ev = mkRoomTextMessage ( "Visit https://matrix.to/#/#room:example.com" );
const { container } = getComponent ({ mxEvent : ev });
const content = container . querySelector ( ".mx_EventTile_body" );
expect ( content . innerHTML ). toMatchInlineSnapshot (
2024-10-04 13:42:23 +01:00
`"Visit <span><bdi><a class="mx_Pill mx_RoomPill" href="https://matrix.to/#/#room:example.com"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 24 24" class="mx_Pill_LinkIcon mx_BaseAvatar"><path d="M12 19.071c-.978.978-2.157 1.467-3.536 1.467-1.378 0-2.557-.489-3.535-1.467-.978-.978-1.467-2.157-1.467-3.536 0-1.378.489-2.557 1.467-3.535L7.05 9.879c.2-.2.436-.3.707-.3.271 0 .507.1.707.3.2.2.301.436.301.707 0 .27-.1.506-.3.707l-2.122 2.121a2.893 2.893 0 0 0-.884 2.122c0 .824.295 1.532.884 2.12.59.59 1.296.885 2.121.885s1.533-.295 2.122-.884l2.121-2.121c.2-.2.436-.301.707-.301.271 0 .507.1.707.3.2.2.3.437.3.708 0 .27-.1.506-.3.707L12 19.07Zm-1.414-4.243c-.2.2-.436.3-.707.3a.967.967 0 0 1-.707-.3.969.969 0 0 1-.301-.707c0-.27.1-.507.3-.707l4.243-4.242c.2-.2.436-.301.707-.301.271 0 .507.1.707.3.2.2.3.437.3.708 0 .27-.1.506-.3.707l-4.242 4.242Zm6.364-.707c-.2.2-.436.3-.707.3a.968.968 0 0 1-.707-.3.969.969 0 0 1-.301-.707c0-.27.1-.507.3-.707l2.122-2.121c.59-.59.884-1.297.884-2.122s-.295-1.532-.884-2.12a2.893 2.893 0 0 0-2.121-.885c-.825 0-1.532.295-2.122.884l-2.121 2.121c-.2.2-.436.301-.707.301a.968.968 0 0 1-.707-.3.97.97 0 0 1-.3-.708c0-.27.1-.506.3-.707L12 4.93c.978-.978 2.157-1.467 3.536-1.467 1.378 0 2.557.489 3.535 1.467.978.978 1.467 2.157 1.467 3.535 0 1.38-.489 2.558-1.467 3.536l-2.121 2.121Z"></path></svg><span class="mx_Pill_text">#room:example.com</span></a></bdi></span>"` ,
2023-03-16 15:01:09 +01:00
);
});
2023-03-22 13:27:24 +01:00
it ( "should pillify a permalink to a message in the same room with the label »Message from Member«" , () => {
const ev = mkRoomTextMessage ( `Visit https://matrix.to/#/ ${ room1Id } / ${ defaultEvent . getId () } ` );
const { container } = getComponent ({ mxEvent : ev });
const content = container . querySelector ( ".mx_EventTile_body" );
2024-01-02 18:56:39 +00:00
expect ( content . innerHTML . replace ( defaultEvent . getId (), "%event_id%" )). toMatchSnapshot ();
2023-03-22 13:27:24 +01:00
});
it ( "should pillify a permalink to an unknown message in the same room with the label »Message«" , () => {
const ev = mkRoomTextMessage ( `Visit https://matrix.to/#/ ${ room1Id } /!abc123` );
const { container } = getComponent ({ mxEvent : ev });
const content = container . querySelector ( ".mx_EventTile_body" );
expect ( content ). toMatchSnapshot ();
});
it ( "should pillify a permalink to an event in another room with the label »Message in Room 2«" , () => {
const ev = mkRoomTextMessage ( `Visit https://matrix.to/#/ ${ room2Id } / ${ defaultEvent . getId () } ` );
const { container } = getComponent ({ mxEvent : ev });
const content = container . querySelector ( ".mx_EventTile_body" );
2024-01-02 18:56:39 +00:00
expect ( content . innerHTML . replace ( defaultEvent . getId (), "%event_id%" )). toMatchSnapshot ();
2023-03-22 13:27:24 +01:00
});
2020-01-06 13:28:29 +00:00
});
describe ( "renders formatted m.text correctly" , () => {
2023-02-13 11:39:16 +00:00
let matrixClient : MatrixClient ;
2020-01-09 17:24:13 -07:00
beforeEach (() => {
2022-04-28 11:32:50 +02:00
matrixClient = getMockClientWithEventEmitter ({
2023-03-22 13:27:24 +01:00
getRoom : () => mkStubRoom ( room1Id , "room name" , undefined ),
2023-02-13 11:39:16 +00:00
getAccountData : () : MatrixEvent | undefined => undefined ,
2020-01-09 17:24:13 -07:00
getUserId : () => "@me:my_server" ,
getHomeserverUrl : () => "https://my_server/" ,
2023-02-13 11:39:16 +00:00
on : () : void => undefined ,
removeListener : () : void => undefined ,
2020-10-29 13:22:09 +00:00
isGuest : () => false ,
2023-02-13 11:39:16 +00:00
mxcUrlToHttp : ( s : string ) => s ,
2022-04-28 11:32:50 +02:00
});
2023-05-23 16:24:12 +01:00
DMRoomMap . makeShared ( defaultMatrixClient );
2020-01-09 17:24:13 -07:00
});
2020-01-06 13:28:29 +00:00
2020-01-09 17:24:13 -07:00
it ( "italics, bold, underline and strikethrough render as expected" , () => {
2023-03-16 15:01:09 +01:00
const ev = mkFormattedMessage (
"foo *baz* __bar__ <del>del</del> <u>u</u>" ,
"foo <em>baz</em> <strong>bar</strong> <del>del</del> <u>u</u>" ,
);
2022-12-29 16:21:00 +00:00
const { container } = getComponent ({ mxEvent : ev }, matrixClient );
expect ( container ). toHaveTextContent ( "foo baz bar del u" );
const content = container . querySelector ( ".mx_EventTile_body" );
2024-07-25 18:58:33 +02:00
expect ( content ). toMatchSnapshot ();
2020-01-06 13:28:29 +00:00
});
2020-01-09 17:24:13 -07:00
it ( "spoilers get injected properly into the DOM" , () => {
2023-03-16 15:01:09 +01:00
const ev = mkFormattedMessage (
"Hey [Spoiler for movie](mxc://someserver/somefile)" ,
'Hey <span data-mx-spoiler="movie">the movie was awesome</span>' ,
);
2022-12-29 16:21:00 +00:00
const { container } = getComponent ({ mxEvent : ev }, matrixClient );
expect ( container ). toHaveTextContent ( "Hey (movie) the movie was awesome" );
const content = container . querySelector ( ".mx_EventTile_body" );
2024-07-25 18:58:33 +02:00
expect ( content ). toMatchSnapshot ();
2020-01-06 13:28:29 +00:00
});
2022-05-02 20:26:37 -04:00
it ( "linkification is not applied to code blocks" , () => {
2023-03-16 15:01:09 +01:00
const ev = mkFormattedMessage (
"Visit `https://matrix.org/`\n```\nhttps://matrix.org/\n```" ,
"<p>Visit <code>https://matrix.org/</code></p>\n<pre>https://matrix.org/\n</pre>\n" ,
);
2022-12-29 16:21:00 +00:00
const { container } = getComponent ({ mxEvent : ev }, matrixClient );
expect ( container ). toHaveTextContent ( "Visit https://matrix.org/ 1https://matrix.org/" );
const content = container . querySelector ( ".mx_EventTile_body" );
expect ( content ). toMatchSnapshot ();
2022-05-02 20:26:37 -04:00
});
2024-10-18 15:57:39 +01:00
it ( "should syntax highlight code blocks" , async () => {
const ev = mkFormattedMessage (
"```py\n# Python Program to calculate the square root\n\n# Note: change this value for a different result\nnum = 8 \n\n# To take the input from the user\n#num = float(input('Enter a number: '))\n\nnum_sqrt = num ** 0.5\nprint('The square root of %0.3f is %0.3f'%(num ,num_sqrt))" ,
"<pre><code class=\"language-py\"># Python Program to calculate the square root\n\n# Note: change this value for a different result\nnum = 8 \n\n# To take the input from the user\n#num = float(input('Enter a number: '))\n\nnum_sqrt = num ** 0.5\nprint('The square root of %0.3f is %0.3f'%(num ,num_sqrt))\n</code></pre>\n" ,
);
const { container } = getComponent ({ mxEvent : ev }, matrixClient );
await waitFor (() => expect ( container . querySelector ( ".hljs-built_in" )). toBeInTheDocument ());
const content = container . querySelector ( ".mx_EventTile_body" );
expect ( content ). toMatchSnapshot ();
});
2020-01-06 13:28:29 +00:00
// If pills were rendered within a Portal/same shadow DOM then it'd be easier to test
2020-01-09 17:24:13 -07:00
it ( "pills get injected correctly into the DOM" , () => {
2023-03-16 15:01:09 +01:00
const ev = mkFormattedMessage ( "Hey User" , 'Hey <a href="https://matrix.to/#/@user:server">Member</a>' );
2022-12-29 16:21:00 +00:00
const { container } = getComponent ({ mxEvent : ev }, matrixClient );
expect ( container ). toHaveTextContent ( "Hey Member" );
const content = container . querySelector ( ".mx_EventTile_body" );
expect ( content ). toMatchSnapshot ();
2020-01-06 13:28:29 +00:00
});
2021-01-27 11:46:20 +00:00
2022-02-22 06:46:34 -05:00
it ( "pills do not appear in code blocks" , () => {
2023-03-16 15:01:09 +01:00
const ev = mkFormattedMessage (
"`@room`\n```\n@room\n```" ,
"<p><code>@room</code></p>\n<pre><code>@room\n</code></pre>\n" ,
);
2022-12-29 16:21:00 +00:00
const { container } = getComponent ({ mxEvent : ev });
expect ( container ). toHaveTextContent ( "@room 1@room" );
const content = container . querySelector ( ".mx_EventTile_body" );
expect ( content ). toMatchSnapshot ();
2022-02-22 06:46:34 -05:00
});
2023-03-21 10:23:20 +01:00
it ( "pills do not appear for event permalinks with a custom label" , () => {
2023-03-16 15:01:09 +01:00
const ev = mkFormattedMessage (
"An [event link](https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com/" +
"$16085560162aNpaH:example.com?via=example.com) with text" ,
'An <a href="https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com/' +
'$16085560162aNpaH:example.com?via=example.com">event link</a> with text' ,
);
2023-03-21 10:23:20 +01:00
const { asFragment , container } = getComponent ({ mxEvent : ev }, matrixClient );
2022-12-29 16:21:00 +00:00
expect ( container ). toHaveTextContent ( "An event link with text" );
2023-03-21 10:23:20 +01:00
expect ( asFragment ()). toMatchSnapshot ();
});
it ( "pills appear for event permalinks without a custom label" , () => {
const ev = mkFormattedMessage (
"See this message https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com/$16085560162aNpaH:example.com?via=example.com" ,
'See this message <a href="https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com/$16085560162aNpaH:example.com?via=example.com">' +
"https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com/$16085560162aNpaH:example.com?via=example.com</a>" ,
2021-01-27 11:46:20 +00:00
);
2023-03-21 10:23:20 +01:00
const { asFragment } = getComponent ({ mxEvent : ev }, matrixClient );
expect ( asFragment ()). toMatchSnapshot ();
2021-01-27 11:46:20 +00:00
});
2021-02-03 15:18:19 +00:00
it ( "pills appear for room links with vias" , () => {
2023-03-16 15:01:09 +01:00
const ev = mkFormattedMessage (
"A [room link](https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com" +
"?via=example.com&via=bob.com) with vias" ,
'A <a href="https://matrix.to/#/!ZxbRYPQXDXKGmDnJNg:example.com' +
'?via=example.com&via=bob.com">room link</a> with vias' ,
);
2023-03-21 10:23:20 +01:00
const { asFragment , container } = getComponent ({ mxEvent : ev }, matrixClient );
2022-12-29 16:21:00 +00:00
expect ( container ). toHaveTextContent ( "A room name with vias" );
2023-03-21 10:23:20 +01:00
expect ( asFragment ()). toMatchSnapshot ();
2021-02-03 15:18:19 +00:00
});
2021-12-02 06:25:12 -03:00
2023-03-16 15:01:09 +01:00
it ( "pills appear for an MXID permalink" , () => {
const ev = mkFormattedMessage (
"Chat with [@user:example.com](https://matrix.to/#/@user:example.com)" ,
'Chat with <a href="https://matrix.to/#/@user:example.com">@user:example.com</a>' ,
);
const { container } = getComponent ({ mxEvent : ev }, matrixClient );
const content = container . querySelector ( ".mx_EventTile_body" );
expect ( content ). toMatchSnapshot ();
});
2024-07-25 18:58:33 +02:00
it ( "renders formatted body without html correctly" , () => {
2021-12-02 06:25:12 -03:00
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 ,
});
2022-12-29 16:21:00 +00:00
const { container } = getComponent ({ mxEvent : ev }, matrixClient );
2021-12-02 06:25:12 -03:00
2022-12-29 16:21:00 +00:00
const content = container . querySelector ( ".mx_EventTile_body" );
2024-07-25 18:58:33 +02:00
expect ( content ). toMatchSnapshot ();
2021-12-02 06:25:12 -03:00
});
2020-01-06 13:28:29 +00:00
});
2020-01-06 14:38:21 +00:00
2024-12-18 17:42:37 +01:00
describe ( "url preview" , () => {
let matrixClient : MatrixClient ;
2020-01-06 14:38:21 +00:00
2024-12-18 17:42:37 +01:00
beforeEach (() => {
languageHandler . setMissingEntryGenerator (( key ) => key . split ( "|" , 2 )[ 1 ]);
matrixClient = getMockClientWithEventEmitter ({
getRoom : () => mkStubRoom ( "room_id" , "room name" , undefined ),
getAccountData : () : MatrixClient | undefined => undefined ,
getUrlPreview : ( url : string ) => new Promise (() => {}),
isGuest : () => false ,
mxcUrlToHttp : ( s : string ) => s ,
});
DMRoomMap . makeShared ( defaultMatrixClient );
2022-04-28 11:32:50 +02:00
});
2020-01-06 14:38:21 +00:00
2024-12-18 17:42:37 +01:00
it ( "renders url previews correctly" , () => {
const ev = mkRoomTextMessage ( "Visit https://matrix.org/" );
const { container , rerender } = getComponent (
{ mxEvent : ev , showUrlPreview : true , onHeightChanged : jest.fn () },
matrixClient ,
);
2020-01-06 14:38:21 +00:00
2024-12-18 17:42:37 +01:00
expect ( container ). toHaveTextContent ( ev . getContent (). body );
expect ( container . querySelector ( "a" )). toHaveAttribute ( "href" , "https://matrix.org/" );
2020-01-06 14:38:21 +00:00
2024-12-18 17:42:37 +01:00
// 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" ,
},
2020-01-06 14:38:21 +00:00
},
2024-12-18 17:42:37 +01:00
event : true ,
});
jest . spyOn ( ev , "replacingEventDate" ). mockReturnValue ( new Date ( 1993 , 7 , 3 ));
ev . makeReplaced ( ev2 );
getComponent (
{ mxEvent : ev , showUrlPreview : true , onHeightChanged : jest.fn (), replacingEventId : ev.getId () },
matrixClient ,
rerender ,
);
expect ( container ). toHaveTextContent ( ev2 . getContent ()[ "m.new_content" ]. body + "(edited)" );
const links = [ "https://vector.im/" , "https://riot.im/" ];
const anchorNodes = container . querySelectorAll ( "a" );
Array . from ( anchorNodes ). forEach (( node , index ) => {
expect ( node ). toHaveAttribute ( "href" , links [ index ]);
});
2020-01-06 14:38:21 +00:00
});
2024-12-18 17:42:37 +01:00
it ( "should listen to showUrlPreview change" , () => {
const ev = mkRoomTextMessage ( "Visit https://matrix.org/" );
2022-12-29 16:21:00 +00:00
2024-12-18 17:42:37 +01:00
const { container , rerender } = getComponent (
{ mxEvent : ev , showUrlPreview : false , onHeightChanged : jest.fn () },
matrixClient ,
);
expect ( container . querySelector ( ".mx_LinkPreviewGroup" )). toBeNull ();
2022-12-29 16:21:00 +00:00
2024-12-18 17:42:37 +01:00
getComponent ({ mxEvent : ev , showUrlPreview : true , onHeightChanged : jest.fn () }, matrixClient , rerender );
expect ( container . querySelector ( ".mx_LinkPreviewGroup" )). toBeTruthy ();
2022-12-29 16:21:00 +00:00
});
2020-01-06 14:38:21 +00:00
});
2020-01-06 13:28:29 +00:00
});