2020-01-06 22:52:08 +08:00
/ *
2024-09-09 21:57:16 +08:00
Copyright 2024 New Vector Ltd .
Copyright 2019 - 2022 The Matrix . org Foundation C . I . C .
2020-01-06 22:52:08 +08:00
2024-09-09 21:57:16 +08:00
SPDX - License - Identifier : AGPL - 3.0 - only OR GPL - 3.0 - only
Please see LICENSE files in the repository root for full details .
2020-01-06 22:52:08 +08:00
* /
2020-01-06 21:28:29 +08:00
import React from "react" ;
2023-02-13 19:39:16 +08:00
import { MatrixClient , MatrixEvent } from "matrix-js-sdk/src/matrix" ;
2023-03-22 20:27:24 +08:00
import { mocked , MockedObject } from "jest-mock" ;
2024-10-18 22:57:39 +08:00
import { render , waitFor } from "jest-matrix-react" ;
2020-01-06 21:28:29 +08:00
2024-10-15 21:57:26 +08: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 21:28:29 +08:00
2023-03-22 20:27:24 +08: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 18:41:17 +08:00
return mkMessage ( {
msg : body ,
2023-03-22 20:27:24 +08:00
room : mkRoomTextMessageOpts?.roomId ? ? room1Id ,
2023-03-02 18:41:17 +08:00
user : "sender" ,
event : true ,
} ) ;
} ;
2023-03-16 22:01:09 +08:00
const mkFormattedMessage = ( body : string , formattedBody : string ) : MatrixEvent = > {
return mkMessage ( {
msg : body ,
formattedMsg : formattedBody ,
format : "org.matrix.custom.html" ,
2023-03-22 20:27:24 +08:00
room : room1Id ,
2023-03-16 22:01:09 +08:00
user : "sender" ,
event : true ,
} ) ;
} ;
2020-01-06 21:28:29 +08:00
describe ( "<TextualBody />" , ( ) = > {
afterEach ( ( ) = > {
2022-12-12 19:24:14 +08:00
jest . spyOn ( MatrixClientPeg , "get" ) . mockRestore ( ) ;
2023-05-05 16:26:11 +08:00
jest . spyOn ( global . Math , "random" ) . mockRestore ( ) ;
2020-01-06 21:28:29 +08:00
} ) ;
2023-03-22 20:27:24 +08:00
const defaultRoom = mkStubRoom ( room1Id , "test room" , undefined ) ;
const otherRoom = mkStubRoom ( room2Id , room2Name , undefined ) ;
2022-04-28 17:32:50 +08:00
let defaultMatrixClient : MockedObject < MatrixClient > ;
2023-03-22 20:27:24 +08:00
const defaultEvent = mkEvent ( {
type : "m.room.message" ,
room : room1Id ,
user : "sender" ,
content : {
body : "winks" ,
msgtype : "m.emote" ,
} ,
event : true ,
} ) ;
2022-04-28 17:32:50 +08:00
beforeEach ( ( ) = > {
defaultMatrixClient = getMockClientWithEventEmitter ( {
2023-03-22 20:27:24 +08:00
getRoom : ( roomId : string | undefined ) = > {
if ( roomId === room1Id ) return defaultRoom ;
if ( roomId === room2Id ) return otherRoom ;
return null ;
} ,
getRooms : ( ) = > [ defaultRoom , otherRoom ] ,
2023-02-13 19:39:16 +08:00
getAccountData : ( ) : MatrixEvent | undefined = > undefined ,
2020-10-29 21:22:09 +08:00
isGuest : ( ) = > false ,
2023-02-13 19:39:16 +08:00
mxcUrlToHttp : ( s : string ) = > s ,
2023-03-02 18:41:17 +08:00
getUserId : ( ) = > "@user:example.com" ,
2023-03-21 17:23:20 +08:00
fetchRoomEvent : ( ) = > {
throw new Error ( "MockClient event not found" ) ;
} ,
2022-04-28 17:32:50 +08:00
} ) ;
2023-03-22 20:27:24 +08:00
mocked ( defaultRoom ) . findEventById . mockImplementation ( ( eventId : string ) = > {
if ( eventId === defaultEvent . getId ( ) ) return defaultEvent ;
return undefined ;
} ) ;
2023-05-05 16:26:11 +08:00
jest . spyOn ( global . Math , "random" ) . mockReturnValue ( 0.123456 ) ;
2022-04-28 17:32:50 +08:00
} ) ;
2023-03-22 20:27:24 +08:00
2022-04-28 17:32:50 +08:00
const defaultProps = {
mxEvent : defaultEvent ,
2023-02-13 19:39:16 +08:00
highlights : [ ] as string [ ] ,
2022-12-12 19:24:14 +08:00
highlightLink : "" ,
2022-04-28 17:32:50 +08:00
onMessageAllowed : jest.fn ( ) ,
onHeightChanged : jest.fn ( ) ,
permalinkCreator : new RoomPermalinkCreator ( defaultRoom ) ,
mediaEventHelper : { } as MediaEventHelper ,
} ;
2023-03-22 20:27:24 +08:00
2022-12-30 00:21:00 +08:00
const getComponent = ( props = { } , matrixClient : MatrixClient = defaultMatrixClient , renderingFn? : any ) = >
( renderingFn ? ? render ) (
< MatrixClientContext.Provider value = { matrixClient } >
< TextualBody { ...defaultProps } { ...props } / >
< / MatrixClientContext.Provider > ,
) ;
2022-04-28 17:32:50 +08:00
it ( "renders m.emote correctly" , ( ) = > {
2023-05-23 23:24:12 +08:00
DMRoomMap . makeShared ( defaultMatrixClient ) ;
2020-01-06 21:28:29 +08:00
const ev = mkEvent ( {
type : "m.room.message" ,
2023-03-22 20:27:24 +08:00
room : room1Id ,
2020-01-06 21:28:29 +08:00
user : "sender" ,
content : {
body : "winks" ,
msgtype : "m.emote" ,
} ,
event : true ,
} ) ;
2022-12-30 00:21:00 +08:00
const { container } = getComponent ( { mxEvent : ev } ) ;
expect ( container ) . toHaveTextContent ( "* sender winks" ) ;
const content = container . querySelector ( ".mx_EventTile_body" ) ;
2024-07-26 00:58:33 +08:00
expect ( content ) . toMatchSnapshot ( ) ;
2020-01-06 21:28:29 +08:00
} ) ;
2020-01-10 08:24:13 +08:00
it ( "renders m.notice correctly" , ( ) = > {
2023-05-23 23:24:12 +08:00
DMRoomMap . makeShared ( defaultMatrixClient ) ;
2020-01-06 21:28:29 +08:00
const ev = mkEvent ( {
type : "m.room.message" ,
2023-03-22 20:27:24 +08:00
room : room1Id ,
2020-01-06 21:28:29 +08:00
user : "bot_sender" ,
content : {
body : "this is a notice, probably from a bot" ,
msgtype : "m.notice" ,
} ,
event : true ,
} ) ;
2022-12-30 00:21:00 +08:00
const { container } = getComponent ( { mxEvent : ev } ) ;
expect ( container ) . toHaveTextContent ( ev . getContent ( ) . body ) ;
const content = container . querySelector ( ".mx_EventTile_body" ) ;
2024-07-26 00:58:33 +08:00
expect ( content ) . toMatchSnapshot ( ) ;
2020-01-06 21:28:29 +08:00
} ) ;
describe ( "renders plain-text m.text correctly" , ( ) = > {
2020-01-10 08:24:13 +08:00
beforeEach ( ( ) = > {
2023-05-23 23:24:12 +08:00
DMRoomMap . makeShared ( defaultMatrixClient ) ;
2020-01-10 08:24:13 +08:00
} ) ;
2020-01-06 21:28:29 +08:00
2020-01-10 08:24:13 +08:00
it ( "simple message renders as expected" , ( ) = > {
2023-03-02 18:41:17 +08:00
const ev = mkRoomTextMessage ( "this is a plaintext message" ) ;
2022-12-30 00:21:00 +08:00
const { container } = getComponent ( { mxEvent : ev } ) ;
expect ( container ) . toHaveTextContent ( ev . getContent ( ) . body ) ;
const content = container . querySelector ( ".mx_EventTile_body" ) ;
2024-07-26 00:58:33 +08:00
expect ( content ) . toMatchSnapshot ( ) ;
2020-01-06 21:28:29 +08:00
} ) ;
// If pills were rendered within a Portal/same shadow DOM then it'd be easier to test
2020-01-10 08:24:13 +08:00
it ( "linkification get applied correctly into the DOM" , ( ) = > {
2023-03-02 18:41:17 +08:00
const ev = mkRoomTextMessage ( "Visit https://matrix.org/" ) ;
2022-12-30 00:21:00 +08:00
const { container } = getComponent ( { mxEvent : ev } ) ;
expect ( container ) . toHaveTextContent ( ev . getContent ( ) . body ) ;
const content = container . querySelector ( ".mx_EventTile_body" ) ;
2024-07-26 00:58:33 +08:00
expect ( content ) . toMatchSnapshot ( ) ;
2020-01-06 21:28:29 +08:00
} ) ;
2023-03-02 18:41:17 +08:00
2023-03-14 18:56:14 +08:00
it ( "should not pillify MXIDs" , ( ) = > {
2023-03-02 18:41:17 +08: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 18:56:14 +08:00
` "Chat with <a href="https://matrix.to/#/@user:example.com" class="linkified" rel="noreferrer noopener">@user:example.com</a>" ` ,
2023-03-02 18:41:17 +08:00
) ;
} ) ;
2023-03-16 22:01:09 +08: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 21:34:27 +08: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 22:01:09 +08:00
) ;
} ) ;
2023-03-14 18:56:14 +08:00
it ( "should not pillify room aliases" , ( ) = > {
2023-03-02 18:41:17 +08: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 18:56:14 +08:00
` "Visit <a href="https://matrix.to/#/#room:example.com" class="linkified" rel="noreferrer noopener">#room:example.com</a>" ` ,
2023-03-02 18:41:17 +08:00
) ;
} ) ;
2023-03-16 22:01:09 +08: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 20:42:23 +08: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 22:01:09 +08:00
) ;
} ) ;
2023-03-22 20:27:24 +08: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-03 02:56:39 +08:00
expect ( content . innerHTML . replace ( defaultEvent . getId ( ) , "%event_id%" ) ) . toMatchSnapshot ( ) ;
2023-03-22 20:27:24 +08: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-03 02:56:39 +08:00
expect ( content . innerHTML . replace ( defaultEvent . getId ( ) , "%event_id%" ) ) . toMatchSnapshot ( ) ;
2023-03-22 20:27:24 +08:00
} ) ;
2020-01-06 21:28:29 +08:00
} ) ;
describe ( "renders formatted m.text correctly" , ( ) = > {
2023-02-13 19:39:16 +08:00
let matrixClient : MatrixClient ;
2020-01-10 08:24:13 +08:00
beforeEach ( ( ) = > {
2022-04-28 17:32:50 +08:00
matrixClient = getMockClientWithEventEmitter ( {
2023-03-22 20:27:24 +08:00
getRoom : ( ) = > mkStubRoom ( room1Id , "room name" , undefined ) ,
2023-02-13 19:39:16 +08:00
getAccountData : ( ) : MatrixEvent | undefined = > undefined ,
2020-01-10 08:24:13 +08:00
getUserId : ( ) = > "@me:my_server" ,
getHomeserverUrl : ( ) = > "https://my_server/" ,
2023-02-13 19:39:16 +08:00
on : ( ) : void = > undefined ,
removeListener : ( ) : void = > undefined ,
2020-10-29 21:22:09 +08:00
isGuest : ( ) = > false ,
2023-02-13 19:39:16 +08:00
mxcUrlToHttp : ( s : string ) = > s ,
2022-04-28 17:32:50 +08:00
} ) ;
2023-05-23 23:24:12 +08:00
DMRoomMap . makeShared ( defaultMatrixClient ) ;
2020-01-10 08:24:13 +08:00
} ) ;
2020-01-06 21:28:29 +08:00
2020-01-10 08:24:13 +08:00
it ( "italics, bold, underline and strikethrough render as expected" , ( ) = > {
2023-03-16 22:01:09 +08: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-30 00:21:00 +08:00
const { container } = getComponent ( { mxEvent : ev } , matrixClient ) ;
expect ( container ) . toHaveTextContent ( "foo baz bar del u" ) ;
const content = container . querySelector ( ".mx_EventTile_body" ) ;
2024-07-26 00:58:33 +08:00
expect ( content ) . toMatchSnapshot ( ) ;
2020-01-06 21:28:29 +08:00
} ) ;
2020-01-10 08:24:13 +08:00
it ( "spoilers get injected properly into the DOM" , ( ) = > {
2023-03-16 22:01:09 +08:00
const ev = mkFormattedMessage (
"Hey [Spoiler for movie](mxc://someserver/somefile)" ,
'Hey <span data-mx-spoiler="movie">the movie was awesome</span>' ,
) ;
2022-12-30 00:21:00 +08: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-26 00:58:33 +08:00
expect ( content ) . toMatchSnapshot ( ) ;
2020-01-06 21:28:29 +08:00
} ) ;
2022-05-03 08:26:37 +08:00
it ( "linkification is not applied to code blocks" , ( ) = > {
2023-03-16 22:01:09 +08: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-30 00:21:00 +08: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-03 08:26:37 +08:00
} ) ;
2024-10-18 22:57:39 +08: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 21:28:29 +08:00
// If pills were rendered within a Portal/same shadow DOM then it'd be easier to test
2020-01-10 08:24:13 +08:00
it ( "pills get injected correctly into the DOM" , ( ) = > {
2023-03-16 22:01:09 +08:00
const ev = mkFormattedMessage ( "Hey User" , 'Hey <a href="https://matrix.to/#/@user:server">Member</a>' ) ;
2022-12-30 00:21:00 +08: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 21:28:29 +08:00
} ) ;
2021-01-27 19:46:20 +08:00
2022-02-22 19:46:34 +08:00
it ( "pills do not appear in code blocks" , ( ) = > {
2023-03-16 22:01:09 +08:00
const ev = mkFormattedMessage (
"`@room`\n```\n@room\n```" ,
"<p><code>@room</code></p>\n<pre><code>@room\n</code></pre>\n" ,
) ;
2022-12-30 00:21:00 +08: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 19:46:34 +08:00
} ) ;
2023-03-21 17:23:20 +08:00
it ( "pills do not appear for event permalinks with a custom label" , ( ) = > {
2023-03-16 22:01:09 +08: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 17:23:20 +08:00
const { asFragment , container } = getComponent ( { mxEvent : ev } , matrixClient ) ;
2022-12-30 00:21:00 +08:00
expect ( container ) . toHaveTextContent ( "An event link with text" ) ;
2023-03-21 17:23:20 +08: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 19:46:20 +08:00
) ;
2023-03-21 17:23:20 +08:00
const { asFragment } = getComponent ( { mxEvent : ev } , matrixClient ) ;
expect ( asFragment ( ) ) . toMatchSnapshot ( ) ;
2021-01-27 19:46:20 +08:00
} ) ;
2021-02-03 23:18:19 +08:00
it ( "pills appear for room links with vias" , ( ) = > {
2023-03-16 22:01:09 +08: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 17:23:20 +08:00
const { asFragment , container } = getComponent ( { mxEvent : ev } , matrixClient ) ;
2022-12-30 00:21:00 +08:00
expect ( container ) . toHaveTextContent ( "A room name with vias" ) ;
2023-03-21 17:23:20 +08:00
expect ( asFragment ( ) ) . toMatchSnapshot ( ) ;
2021-02-03 23:18:19 +08:00
} ) ;
2021-12-02 17:25:12 +08:00
2023-03-16 22:01:09 +08: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-26 00:58:33 +08:00
it ( "renders formatted body without html correctly" , ( ) = > {
2021-12-02 17:25:12 +08: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-30 00:21:00 +08:00
const { container } = getComponent ( { mxEvent : ev } , matrixClient ) ;
2021-12-02 17:25:12 +08:00
2022-12-30 00:21:00 +08:00
const content = container . querySelector ( ".mx_EventTile_body" ) ;
2024-07-26 00:58:33 +08:00
expect ( content ) . toMatchSnapshot ( ) ;
2021-12-02 17:25:12 +08:00
} ) ;
2020-01-06 21:28:29 +08:00
} ) ;
2020-01-06 22:38:21 +08:00
2020-01-10 08:24:13 +08:00
it ( "renders url previews correctly" , ( ) = > {
2022-12-12 19:24:14 +08:00
languageHandler . setMissingEntryGenerator ( ( key ) = > key . split ( "|" , 2 ) [ 1 ] ) ;
2020-01-06 22:38:21 +08:00
2022-04-28 17:32:50 +08:00
const matrixClient = getMockClientWithEventEmitter ( {
getRoom : ( ) = > mkStubRoom ( "room_id" , "room name" , undefined ) ,
2023-02-13 19:39:16 +08:00
getAccountData : ( ) : MatrixClient | undefined = > undefined ,
getUrlPreview : ( url : string ) = > new Promise ( ( ) = > { } ) ,
2021-01-15 01:39:58 +08:00
isGuest : ( ) = > false ,
2023-02-13 19:39:16 +08:00
mxcUrlToHttp : ( s : string ) = > s ,
2022-04-28 17:32:50 +08:00
} ) ;
2023-05-23 23:24:12 +08:00
DMRoomMap . makeShared ( defaultMatrixClient ) ;
2020-01-06 22:38:21 +08:00
2023-03-02 18:41:17 +08:00
const ev = mkRoomTextMessage ( "Visit https://matrix.org/" ) ;
2022-12-30 00:21:00 +08:00
const { container , rerender } = getComponent (
{ mxEvent : ev , showUrlPreview : true , onHeightChanged : jest.fn ( ) } ,
matrixClient ,
) ;
2020-01-06 22:38:21 +08:00
2022-12-30 00:21:00 +08:00
expect ( container ) . toHaveTextContent ( ev . getContent ( ) . body ) ;
expect ( container . querySelector ( "a" ) ) . toHaveAttribute ( "href" , "https://matrix.org/" ) ;
2020-01-06 22:38:21 +08: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" ,
} ,
} ,
event : true ,
} ) ;
2022-12-12 19:24:14 +08:00
jest . spyOn ( ev , "replacingEventDate" ) . mockReturnValue ( new Date ( 1993 , 7 , 3 ) ) ;
2020-01-06 22:38:21 +08:00
ev . makeReplaced ( ev2 ) ;
2022-12-30 00:21:00 +08:00
getComponent (
{ mxEvent : ev , showUrlPreview : true , onHeightChanged : jest.fn ( ) , replacingEventId : ev.getId ( ) } ,
matrixClient ,
rerender ,
2022-12-12 19:24:14 +08:00
) ;
2022-12-30 00:21:00 +08:00
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 22:38:21 +08:00
} ) ;
2020-01-06 21:28:29 +08:00
} ) ;