Skip to content

Commit 711bf47

Browse files
authored
Test inserting edit events into the thread timeline "on demand" (#3410)
* Fix an existing test for editing messages in threads While attempting to test a new change, I discovered that the test "should allow edits to be added to thread timeline" did not actually fail if its assertions failed. Further, those assertions were incorrect. So this change fixes the test to create the thread, wait for it to be initialised, and then add events to it. This simplifies the flow and ensures the test fails if something unexpected happens. * Move editing test into thread.spec.ts * Isolate Thread global modification in beforeAll() * Delete unneeded setUnsigned call * Use standard message-creation methods * Rename event variables * Rename sender->user * Remove unneeded variables * Extract distractions into functions * Fetch edits for thread messages Modifies fetchEditsWhereNeeded to allow edits of threaded messages. The code before prevented any relations from fetching edits, but of course events in threads are relations. We definitely want thread messages to get their edits fetched, and I assume this is working in the real code, probably because the event being looked at is some kind of eventmapped thing that doesn't have proper relations visible on it. In tests, if we don't make this change, we can't see edits getting fetched. * Add a test for fetching edits on demand in a thread This test demonstrates the current behaviour, which contains a bug - we don't actually add the right event to the timeline.
1 parent 48b60bb commit 711bf47

File tree

2 files changed

+48
-6
lines changed

2 files changed

+48
-6
lines changed

spec/unit/models/thread.spec.ts

+46-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { Thread, THREAD_RELATION_TYPE, ThreadEvent, FeatureSupport } from "../..
2222
import { makeThreadEvent, mkThread } from "../../test-utils/thread";
2323
import { TestClient } from "../../TestClient";
2424
import { emitPromise, mkEdit, mkMessage, mkReaction, mock } from "../../test-utils/test-utils";
25-
import { Direction, EventStatus, MatrixEvent } from "../../../src";
25+
import { Direction, EventStatus, EventType, MatrixEvent } from "../../../src";
2626
import { ReceiptType } from "../../../src/@types/read_receipts";
2727
import { getMockClientWithEventEmitter, mockClientMethodsUser } from "../../test-utils/client";
2828
import { ReEmitter } from "../../../src/ReEmitter";
@@ -615,7 +615,7 @@ describe("Thread", () => {
615615
Thread.hasServerSideSupport = previousThreadHasServerSideSupport;
616616
});
617617

618-
it("should allow edits to be added to thread timeline", async () => {
618+
it("Adds edits from sync to the thread timeline and applies them", async () => {
619619
// Given a thread
620620
const client = createClient();
621621
const user = "@alice:matrix.org";
@@ -637,6 +637,45 @@ describe("Thread", () => {
637637
// And the first message has been edited
638638
expect(secondLastEvent.getContent().body).toEqual("edit");
639639
});
640+
641+
it("Adds edits fetched on demand to the thread timeline and applies them", async () => {
642+
// Given we don't support recursive relations
643+
const client = createClient(new Map([[Feature.RelationsRecursion, ServerSupport.Unsupported]]));
644+
// And we have a thread
645+
const user = "@alice:matrix.org";
646+
const room = "!room:z";
647+
const thread = await createThread(client, user, room);
648+
649+
// When a message is added to the thread, and an edit to it is provided on demand
650+
const messageToEdit = createThreadMessage(thread.id, user, room, "Thread reply");
651+
// (fetchEditsWhereNeeded only applies to encrypted messages for some reason)
652+
messageToEdit.event.type = EventType.RoomMessageEncrypted;
653+
const editEvent = mkEdit(messageToEdit, client, user, room, "edit");
654+
mocked(client.relations).mockImplementation(async (_roomId, eventId) => {
655+
if (eventId === messageToEdit.getId()) {
656+
return { events: [editEvent] };
657+
} else {
658+
return { events: [] };
659+
}
660+
});
661+
await thread.addEvent(messageToEdit, false);
662+
663+
// THIS IS THE CORRECT BEHAVIOUR
664+
// Then both events end up in the timeline
665+
//const lastEvent = thread.timeline.at(-1)!;
666+
//const secondLastEvent = thread.timeline.at(-2)!;
667+
//expect(lastEvent).toBe(editEvent);
668+
//expect(secondLastEvent).toBe(messageToEdit);
669+
670+
//// And the first message has been edited
671+
//expect(secondLastEvent.getContent().body).toEqual("edit");
672+
673+
// TODO: For now, we incorrecly DON'T add the event to the timeline
674+
const lastEvent = thread.timeline.at(-1)!;
675+
expect(lastEvent).toBe(messageToEdit);
676+
// But the original is edited, as expected
677+
expect(lastEvent.getContent().body).toEqual("edit");
678+
});
640679
});
641680
});
642681
});
@@ -661,8 +700,10 @@ function createThreadMessage(threadId: string, user: string, room: string, msg:
661700
*/
662701
async function createThread(client: MatrixClient, user: string, roomId: string): Promise<Thread> {
663702
const root = mkMessage({ event: true, user, room: roomId, msg: "Thread root" });
664-
665703
const room = new Room(roomId, client, "@roomcreator:x");
704+
705+
// Ensure the root is in the room timeline
706+
root.setThreadId(root.getId());
666707
room.addLiveEvents([root]);
667708

668709
// Create the thread and wait for it to be initialised
@@ -676,10 +717,10 @@ async function createThread(client: MatrixClient, user: string, roomId: string):
676717
* Create a MatrixClient that supports threads and has all the methods used when
677718
* creating a thread that call out to HTTP endpoints mocked out.
678719
*/
679-
function createClient(): MatrixClient {
720+
function createClient(canSupport = new Map()): MatrixClient {
680721
const client = mock(MatrixClient, "MatrixClient");
681722
client.reEmitter = mock(ReEmitter, "ReEmitter");
682-
client.canSupport = new Map();
723+
client.canSupport = canSupport;
683724

684725
jest.spyOn(client, "supportsThreads").mockReturnValue(true);
685726
jest.spyOn(client, "getEventMapper").mockReturnValue(eventMapperFor(client, {}));

src/models/thread.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,8 @@ export class Thread extends ReadReceipt<EmittedEvents, EventHandlerMap> {
522522
events
523523
.filter((e) => e.isEncrypted())
524524
.map((event: MatrixEvent) => {
525-
if (event.isRelation()) return; // skip - relations don't get edits
525+
// The only type of relation that gets edits is a thread message.
526+
if (event.getThread() === undefined && event.isRelation()) return;
526527
return this.client
527528
.relations(this.roomId, event.getId()!, RelationType.Replace, event.getType(), {
528529
limit: 1,

0 commit comments

Comments
 (0)