Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Tests for paging up to find old messages #11633

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
253 changes: 240 additions & 13 deletions cypress/e2e/read-receipts/high-level.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,29 @@ limitations under the License.

/// <reference types="cypress" />

import type { MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
import type { MatrixClient } from "matrix-js-sdk/src/matrix";
import { HomeserverInstance } from "../../plugins/utils/homeserver";
import {
assertMessageLoaded,
assertMessageNotLoaded,
assertRead,
assertReadThread,
assertStillRead,
assertUnread,
assertUnreadGreaterThan,
assertUnreadThread,
closeThreadsPanel,
customEvent,
goTo,
many,
markAsRead,
Message,
MessageContentSpec,
MessageFinder,
openThread,
openThreadList,
pageUp,
saveAndReload,
sendMessageAsClient,
} from "./read-receipts-utils";

Expand All @@ -62,12 +76,19 @@ describe("Read receipts", () => {
let alphaRoomId: string;
let bot: MatrixClient | undefined;

/**
* Map of message content -> event. Allows us to find e.g. edited or
* redacted messages even if their content has changed or disappeared from
* screen.
*/
const messages = new Map<String, MatrixEvent>();
let messageFinder: MessageFinder;

function threadedOff(rootMessage: string, newMessage: string): MessageContentSpec {
return messageFinder.threadedOff(rootMessage, newMessage);
}

function manyThreadedOff(rootMessage: string, newMessages: Array<string>): Array<MessageContentSpec> {
return messageFinder.manyThreadedOff(rootMessage, newMessages);
}

function jumpTo(room: string, message: string, includeThreads = false) {
return messageFinder.jumpTo(room, message, includeThreads);
}

before(() => {
// Note: unusually for the Cypress tests in this repo, we share a single
Expand All @@ -88,7 +109,7 @@ describe("Read receipts", () => {
});

beforeEach(() => {
messages.clear();
messageFinder = new MessageFinder();

// Create 2 rooms: Alpha & Beta. We join the bot to both of them
cy.initTestUser(homeserver, userName)
Expand Down Expand Up @@ -196,11 +217,217 @@ describe("Read receipts", () => {
});

describe("Paging up", () => {
it.skip("Paging up through old messages after a room is read leaves the room read", () => {});
it.skip("Paging up through old messages of an unread room leaves the room unread", () => {});
it.skip("Paging up to find old threads that were previously read leaves the room read", () => {});
it.skip("?? Paging up to find old threads that were never read marks the room unread", () => {});
it.skip("After marking room as read, paging up to find old threads that were never read leaves the room read", () => {});
it("Paging up through old messages after a room is read leaves the room read", () => {
// Given lots of messages are in the room, but we have read them
goTo(room1);
receiveMessages(room2, many("Msg", 110));
assertUnread(room2, 110);
goTo(room2);
assertRead(room2);
goTo(room1);

// When we restart, so only recent messages are loaded
saveAndReload();
goTo(room2);
assertMessageNotLoaded("Msg0010");

// And we page up, loading in old messages
pageUp();
pageUp();
pageUp();
assertMessageLoaded("Msg0010");

// Then the room remains read
assertStillRead(room2);
});
it("Paging up through old messages of an unread room leaves the room unread", () => {
// Given lots of messages are in the room, and they are not read
goTo(room1);
receiveMessages(room2, many("x\ny\nz\nMsg", 40)); // newline to spread out messages
assertUnread(room2, 40);

// When I jump to a message in the middle and page up
jumpTo(room2, "x\ny\nz\nMsg0020");
pageUp();

// Then the room is still unread
assertUnreadGreaterThan(room2, 1);
});
it("Paging up to find old threads that were previously read leaves the room read", () => {
// Given lots of messages in threads are all read
goTo(room1);
receiveMessages(room2, [
"Root1",
"Root2",
"Root3",
...manyThreadedOff("Root1", many("T", 20)),
...manyThreadedOff("Root2", many("T", 20)),
...manyThreadedOff("Root3", many("T", 20)),
]);
goTo(room2);
assertUnread(room2, 60);
openThread("Root1");
assertUnread(room2, 40);
assertReadThread("Root1");
openThread("Root2");
assertUnread(room2, 20);
assertReadThread("Root2");
openThread("Root3");
assertRead(room2);
assertReadThread("Root3");

// When I restart and page up to load old thread roots
goTo(room1);
saveAndReload();
goTo(room2);
pageUp();

// Then the room and threads remain read
assertRead(room2);
assertReadThread("Root1");
assertReadThread("Root2");
assertReadThread("Root3");
});
it("Paging up to find old threads that were never read keeps the room unread", () => {
// Given lots of messages in threads that are unread
goTo(room1);
receiveMessages(room2, [
"Root1",
"Root2",
"Root3",
...manyThreadedOff("Root1", many("T", 2)),
...manyThreadedOff("Root2", many("T", 2)),
...manyThreadedOff("Root3", many("T", 2)),
...many("Msg", 100),
]);
goTo(room2);
assertUnread(room2, 6);
assertUnreadThread("Root1");
assertUnreadThread("Root2");
assertUnreadThread("Root3");

// When I restart
closeThreadsPanel();
goTo(room1);
saveAndReload();

// Then the room remembers it's unread
// TODO: I (andyb) think this will fall in an encrypted room
assertUnread(room2, 6);

// And when I page up to load old thread roots
goTo(room2);
pageUp();

// Then the room remains unread
assertUnread(room2, 6);
assertUnreadThread("Root1");
assertUnreadThread("Root2");
assertUnreadThread("Root3");
});
it("Looking in thread view to find old threads that were never read makes the room unread", () => {
// Given lots of messages in threads that are unread
goTo(room1);
receiveMessages(room2, [
"Root1",
"Root2",
"Root3",
...manyThreadedOff("Root1", many("T", 2)),
...manyThreadedOff("Root2", many("T", 2)),
...manyThreadedOff("Root3", many("T", 2)),
...many("Msg", 100),
]);
goTo(room2);
assertUnread(room2, 6);
assertUnreadThread("Root1");
assertUnreadThread("Root2");
assertUnreadThread("Root3");

// When I restart
closeThreadsPanel();
goTo(room1);
saveAndReload();

// Then the room remembers it's unread
// TODO: I (andyb) think this will fall in an encrypted room
assertUnread(room2, 6);

// And when I open the threads view
goTo(room2);
openThreadList();

// Then the room remains unread
assertUnread(room2, 6);
assertUnreadThread("Root1");
assertUnreadThread("Root2");
assertUnreadThread("Root3");
});
it("After marking room as read, paging up to find old threads that were never read leaves the room read", () => {
// Given lots of messages in threads that are unread but I marked as read on a main timeline message
goTo(room1);
receiveMessages(room2, [
"Root1",
"Root2",
"Root3",
...manyThreadedOff("Root1", many("T", 2)),
...manyThreadedOff("Root2", many("T", 2)),
...manyThreadedOff("Root3", many("T", 2)),
...many("Msg", 100),
]);
markAsRead(room2);
assertRead(room2);

// When I restart
saveAndReload();

// Then the room remembers it's read
assertRead(room2);

// And when I page up to load old thread roots
goTo(room2);
pageUp();
pageUp();
pageUp();

// Then the room remains read
assertStillRead(room2);
assertReadThread("Root1");
assertReadThread("Root2");
assertReadThread("Root3");
});
// XXX: fails because we see a dot instead of an unread number - probably the server and client disagree
it.skip("After marking room as read based on a thread message, opening threads view to find old threads that were never read leaves the room read", () => {
// Given lots of messages in threads that are unread but I marked as read on a thread message
goTo(room1);
receiveMessages(room2, [
"Root1",
"Root2",
"Root3",
...manyThreadedOff("Root1", many("T1-", 2)),
...manyThreadedOff("Root2", many("T2-", 2)),
...manyThreadedOff("Root3", many("T3-", 2)),
...many("Msg", 100),
threadedOff("Msg0099", "Thread off 99"),
]);
markAsRead(room2);
assertRead(room2);

// When I restart
saveAndReload();

// Then the room remembers it's read
assertRead(room2);

// And when I page up to load old thread roots
goTo(room2);
openThreadList();

// Then the room remains read
assertStillRead(room2);
assertReadThread("Root1");
assertReadThread("Root2");
assertReadThread("Root3");
});
});

describe("Room list order", () => {
Expand Down