From 63eaba6b0784e40112f95df06784db8b378b18f6 Mon Sep 17 00:00:00 2001 From: Sirius Date: Mon, 20 Jul 2026 10:17:51 +0100 Subject: [PATCH] Include the url preview bundle field in the devtools timeline event editor (#34289) * added urlpreview field in event editor * oxfmt * claude wrote test! * handled reviews * oxlint fix * formatting * removed useless stubclient --- .../views/dialogs/devtools/Event.tsx | 3 + .../views/dialogs/devtools/Event-test.tsx | 97 +++++++++++++------ 2 files changed, 72 insertions(+), 28 deletions(-) diff --git a/apps/web/src/components/views/dialogs/devtools/Event.tsx b/apps/web/src/components/views/dialogs/devtools/Event.tsx index d8aeee932c..c13fe181c6 100644 --- a/apps/web/src/components/views/dialogs/devtools/Event.tsx +++ b/apps/web/src/components/views/dialogs/devtools/Event.tsx @@ -199,6 +199,9 @@ export const TimelineEventEditor: React.FC = ({ mxEvent, onBack }) rel_type: "m.replace", event_id: getBaseEventId(mxEvent), }, + ...("com.beeper.linkpreviews" in originalContent + ? { "com.beeper.linkpreviews": originalContent["com.beeper.linkpreviews"] } + : {}), }; defaultContent = stringify(newContent); diff --git a/apps/web/test/unit-tests/components/views/dialogs/devtools/Event-test.tsx b/apps/web/test/unit-tests/components/views/dialogs/devtools/Event-test.tsx index 330d52b0b1..d8545b30b4 100644 --- a/apps/web/test/unit-tests/components/views/dialogs/devtools/Event-test.tsx +++ b/apps/web/test/unit-tests/components/views/dialogs/devtools/Event-test.tsx @@ -8,54 +8,95 @@ Please see LICENSE files in the repository root for full details. import React from "react"; import { render } from "jest-matrix-react"; -import { Room, PendingEventOrdering } from "matrix-js-sdk/src/matrix"; +import { + Room, + PendingEventOrdering, + EventType, + MsgType, + type MatrixClient, + type MatrixEvent, +} from "matrix-js-sdk/src/matrix"; import MatrixClientContext from "../../../../../../src/contexts/MatrixClientContext"; -import { MatrixClientPeg } from "../../../../../../src/MatrixClientPeg"; -import { stubClient } from "../../../../../test-utils"; +import { createTestClient, mkEvent } from "../../../../../test-utils"; import { DevtoolsContext } from "../../../../../../src/components/views/dialogs/devtools/BaseTool"; import { TimelineEventEditor } from "../../../../../../src/components/views/dialogs/devtools/Event"; -describe("", () => { - beforeEach(() => { - stubClient(); - }); - - it("should render", () => { - const cli = MatrixClientPeg.safeGet(); - const { asFragment } = render( +function renderTimelineEventEditor( + cli: MatrixClient, + { mxEvent, threadRootId }: { mxEvent?: MatrixEvent; threadRootId?: string } = {}, +): ReturnType { + function Wrapper({ children }: { children: React.ReactNode }): React.ReactNode { + return ( - {}} /> + {children} - , + ); + } + + return render( {}} />, { wrapper: Wrapper }); +} + +describe("", () => { + it("should render", () => { + const cli = createTestClient(); + const { asFragment } = renderTimelineEventEditor(cli); expect(asFragment()).toMatchSnapshot(); }); + it("should preserve the com.beeper.linkpreviews field when editing an event", () => { + const cli = createTestClient(); + const linkPreviews = [{ "og:title": "Example", "matrix:image:size": 1234, "og:url": "https://example.com" }]; + const mxEvent = mkEvent({ + event: true, + type: EventType.RoomMessage, + room: "!roomId", + user: "@alice:example.com", + content: { + "body": "https://example.com", + "msgtype": MsgType.Text, + "com.beeper.linkpreviews": linkPreviews, + }, + }); + + const { getByLabelText } = renderTimelineEventEditor(cli, { mxEvent }); + const content = getByLabelText("Event Content") as HTMLTextAreaElement; + expect(JSON.parse(content.value)["com.beeper.linkpreviews"]).toEqual(linkPreviews); + }); + + it("should omit the com.beeper.linkpreviews field when the edited event has none", () => { + const cli = createTestClient(); + const mxEvent = mkEvent({ + event: true, + type: EventType.RoomMessage, + room: "!roomId", + user: "@alice:example.com", + content: { + body: "hello world", + msgtype: MsgType.Text, + }, + }); + + const { getByLabelText } = renderTimelineEventEditor(cli, { mxEvent }); + const content = getByLabelText("Event Content") as HTMLTextAreaElement; + expect(JSON.parse(content.value)).not.toHaveProperty("com.beeper.linkpreviews"); + }); + describe("thread context", () => { it("should pre-populate a thread relationship", () => { - const cli = MatrixClientPeg.safeGet(); - const { asFragment } = render( - - - {}} /> - - , - ); + const cli = createTestClient(); + const { asFragment } = renderTimelineEventEditor(cli, { + threadRootId: "$this_is_a_thread_id", + }); expect(asFragment()).toMatchSnapshot(); }); });