Cypress tests for redactions in threads (#11594)
* Tests for redacting messages not increasing unreads * Comment explaining tips for writing high level rr tests * Test for restarting with a receipt pointing at a redacted thread root * Two failing tests for counting correctly when a thread message was redacted * Test for reading a thread containing an earlier redaction * Failing tests for redacted messages in threads
This commit is contained in:
parent
5a3c32e26c
commit
e887c6d71f
1 changed files with 262 additions and 11 deletions
|
@ -14,6 +14,29 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* # High Level Read Receipt Tests
|
||||||
|
*
|
||||||
|
* Tips for writing these tests:
|
||||||
|
*
|
||||||
|
* * Break up your tests into the smallest test case possible. The purpose of
|
||||||
|
* these tests is to understand hard-to-find bugs, so small tests are necessary.
|
||||||
|
* We know that Cypress recommends combining tests together for performance, but
|
||||||
|
* that will frustrate our goals here. (We will need to find a different way to
|
||||||
|
* reduce CI time.)
|
||||||
|
*
|
||||||
|
* * Try to assert something after every action, to make sure it has completed.
|
||||||
|
* E.g.:
|
||||||
|
* markAsRead(room2);
|
||||||
|
* assertRead(room2);
|
||||||
|
* You should especially follow this rule if you are jumping to a different
|
||||||
|
* room or similar straight afterwards.
|
||||||
|
*
|
||||||
|
* * Use assertStillRead() if you are asserting something is read when it was
|
||||||
|
* also read before. This waits a little while to make sure you're not getting a
|
||||||
|
* false positive.
|
||||||
|
*/
|
||||||
|
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import type { MatrixClient, MatrixEvent, Room, IndexedDBStore } from "matrix-js-sdk/src/matrix";
|
import type { MatrixClient, MatrixEvent, Room, IndexedDBStore } from "matrix-js-sdk/src/matrix";
|
||||||
|
@ -137,6 +160,16 @@ describe("Read receipts", () => {
|
||||||
cy.get(".mx_ThreadView_timelinePanelWrapper", { log: false }).should("have.length", 1);
|
cy.get(".mx_ThreadView_timelinePanelWrapper", { log: false }).should("have.length", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the threads panel. (Actually, close any right panel, but for these
|
||||||
|
* tests we only open the threads panel.)
|
||||||
|
*/
|
||||||
|
function closeThreadsPanel() {
|
||||||
|
cy.log("Close threads panel");
|
||||||
|
cy.get(".mx_RightPanel").findByTitle("Close").click();
|
||||||
|
cy.get(".mx_RightPanel").should("not.exist");
|
||||||
|
}
|
||||||
|
|
||||||
function sendMessageAsClient(cli: MatrixClient, room: string, messages: Message[]) {
|
function sendMessageAsClient(cli: MatrixClient, room: string, messages: Message[]) {
|
||||||
findRoomByName(room).then(async ({ roomId }) => {
|
findRoomByName(room).then(async ({ roomId }) => {
|
||||||
const room = cli.getRoom(roomId);
|
const room = cli.getRoom(roomId);
|
||||||
|
@ -1618,24 +1651,242 @@ describe("Read receipts", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("in threads", () => {
|
describe("in threads", () => {
|
||||||
// One of the following two must be right:
|
it("Redacting the threaded message pointed to by my receipt leaves the room read", () => {
|
||||||
it.skip("Redacting the threaded message pointed to by my receipt leaves the room read", () => {});
|
// Given I have some threads
|
||||||
it.skip("Redacting a threaded message after it was read makes the room unread", () => {});
|
goTo(room1);
|
||||||
|
receiveMessages(room2, [
|
||||||
|
"Root",
|
||||||
|
threadedOff("Root", "ThreadMsg1"),
|
||||||
|
threadedOff("Root", "ThreadMsg2"),
|
||||||
|
"Root2",
|
||||||
|
threadedOff("Root2", "Root2->A"),
|
||||||
|
]);
|
||||||
|
assertUnread(room2, 5);
|
||||||
|
|
||||||
it.skip("Reading an unread thread after a redaction of the latest message makes it read", () => {});
|
// And I have read them
|
||||||
it.skip("Reading an unread thread after a redaction of an older message makes it read", () => {});
|
goTo(room2);
|
||||||
it.skip("Marking an unread thread as read after a redaction makes it read", () => {});
|
assertUnreadThread("Root");
|
||||||
it.skip("Sending and redacting a message after marking the thread as read makes it unread", () => {});
|
openThread("Root");
|
||||||
it.skip("?? Redacting a message after marking the thread as read makes it unread", () => {});
|
assertUnreadLessThan(room2, 4);
|
||||||
it.skip("Reacting to a redacted message leaves the thread read", () => {});
|
openThread("Root2");
|
||||||
it.skip("Editing a redacted message leaves the thread read", () => {});
|
assertRead(room2);
|
||||||
|
closeThreadsPanel();
|
||||||
|
goTo(room1);
|
||||||
|
assertRead(room2);
|
||||||
|
|
||||||
|
// When the latest message in a thread is redacted
|
||||||
|
receiveMessages(room2, [redactionOf("ThreadMsg2")]);
|
||||||
|
|
||||||
|
// Then the room and thread are still read
|
||||||
|
assertStillRead(room2);
|
||||||
|
goTo(room2);
|
||||||
|
assertReadThread("Root");
|
||||||
|
});
|
||||||
|
|
||||||
|
// XXX: fails because the unread count is still 1 when it should be 0 (this is a genuine stuck unread case)
|
||||||
|
it.skip("Reading an unread thread after a redaction of the latest message makes it read", () => {
|
||||||
|
// Given an unread thread where the latest message was redacted
|
||||||
|
goTo(room1);
|
||||||
|
receiveMessages(room2, ["Root", threadedOff("Root", "ThreadMsg1"), threadedOff("Root", "ThreadMsg2")]);
|
||||||
|
assertUnread(room2, 3);
|
||||||
|
receiveMessages(room2, [redactionOf("ThreadMsg2")]);
|
||||||
|
assertUnread(room2, 2);
|
||||||
|
goTo(room2);
|
||||||
|
assertUnreadThread("Root");
|
||||||
|
|
||||||
|
// When I read the thread
|
||||||
|
openThread("Root");
|
||||||
|
assertRead(room2);
|
||||||
|
closeThreadsPanel();
|
||||||
|
goTo(room1);
|
||||||
|
|
||||||
|
// Then the thread is read
|
||||||
|
assertRead(room2);
|
||||||
|
goTo(room2);
|
||||||
|
assertReadThread("Root");
|
||||||
|
});
|
||||||
|
// XXX: fails because the unread count is still 1 when it should be 0
|
||||||
|
it.skip("Reading an unread thread after a redaction of the latest message makes it read after restart", () => {
|
||||||
|
// Given a redacted message is not counted in the unread count
|
||||||
|
goTo(room1);
|
||||||
|
receiveMessages(room2, ["Root", threadedOff("Root", "ThreadMsg1"), threadedOff("Root", "ThreadMsg2")]);
|
||||||
|
assertUnread(room2, 3);
|
||||||
|
receiveMessages(room2, [redactionOf("ThreadMsg2")]);
|
||||||
|
assertUnread(room2, 2);
|
||||||
|
goTo(room2);
|
||||||
|
assertUnreadThread("Root");
|
||||||
|
openThread("Root");
|
||||||
|
assertRead(room2);
|
||||||
|
closeThreadsPanel();
|
||||||
|
goTo(room1);
|
||||||
|
assertRead(room2);
|
||||||
|
goTo(room2);
|
||||||
|
assertReadThread("Root");
|
||||||
|
|
||||||
|
// When I restart
|
||||||
|
saveAndReload();
|
||||||
|
|
||||||
|
// Then the room is still read
|
||||||
|
assertRead(room2);
|
||||||
|
});
|
||||||
|
// XXX: fails because the unread count is still 1 when it should be 0
|
||||||
|
it.skip("Reading an unread thread after a redaction of an older message makes it read", () => {
|
||||||
|
// Given an unread thread where an older message was redacted
|
||||||
|
goTo(room1);
|
||||||
|
receiveMessages(room2, ["Root", threadedOff("Root", "ThreadMsg1"), threadedOff("Root", "ThreadMsg2")]);
|
||||||
|
assertUnread(room2, 3);
|
||||||
|
receiveMessages(room2, [redactionOf("ThreadMsg1")]);
|
||||||
|
assertUnread(room2, 2);
|
||||||
|
goTo(room2);
|
||||||
|
assertUnreadThread("Root");
|
||||||
|
|
||||||
|
// When I read the thread
|
||||||
|
openThread("Root");
|
||||||
|
assertRead(room2);
|
||||||
|
closeThreadsPanel();
|
||||||
|
goTo(room1);
|
||||||
|
|
||||||
|
// Then the thread is read
|
||||||
|
assertRead(room2);
|
||||||
|
goTo(room2);
|
||||||
|
assertReadThread("Root");
|
||||||
|
});
|
||||||
|
// XXX: fails because the room has an unread dot after I marked it as read
|
||||||
|
it.skip("Marking an unread thread as read after a redaction makes it read", () => {
|
||||||
|
// Given an unread thread where an older message was redacted
|
||||||
|
goTo(room1);
|
||||||
|
receiveMessages(room2, ["Root", threadedOff("Root", "ThreadMsg1"), threadedOff("Root", "ThreadMsg2")]);
|
||||||
|
assertUnread(room2, 3);
|
||||||
|
receiveMessages(room2, [redactionOf("ThreadMsg1")]);
|
||||||
|
assertUnread(room2, 2);
|
||||||
|
|
||||||
|
// When I mark the room as read
|
||||||
|
markAsRead(room2);
|
||||||
|
assertRead(room2);
|
||||||
|
|
||||||
|
// Then the thread is read
|
||||||
|
assertRead(room2);
|
||||||
|
goTo(room2);
|
||||||
|
assertReadThread("Root");
|
||||||
|
});
|
||||||
|
// XXX: fails because the room has an unread dot after I marked it as read
|
||||||
|
it.skip("Sending and redacting a message after marking the thread as read leaves it read", () => {
|
||||||
|
// Given a thread exists and is marked as read
|
||||||
|
goTo(room1);
|
||||||
|
receiveMessages(room2, ["Root", threadedOff("Root", "ThreadMsg1"), threadedOff("Root", "ThreadMsg2")]);
|
||||||
|
assertUnread(room2, 3);
|
||||||
|
markAsRead(room2);
|
||||||
|
assertRead(room2);
|
||||||
|
|
||||||
|
// When I send and redact a message
|
||||||
|
receiveMessages(room2, [threadedOff("Root", "Msg3")]);
|
||||||
|
assertUnread(room2, 1);
|
||||||
|
receiveMessages(room2, [redactionOf("Msg3")]);
|
||||||
|
|
||||||
|
// Then the room and thread are read
|
||||||
|
assertRead(room2);
|
||||||
|
goTo(room2);
|
||||||
|
assertReadThread("Root");
|
||||||
|
});
|
||||||
|
// XXX: fails because the room has an unread dot after I marked it as read
|
||||||
|
it.skip("Redacting a message after marking the thread as read leaves it read", () => {
|
||||||
|
// Given a thread exists and is marked as read
|
||||||
|
goTo(room1);
|
||||||
|
receiveMessages(room2, ["Root", threadedOff("Root", "ThreadMsg1"), threadedOff("Root", "ThreadMsg2")]);
|
||||||
|
assertUnread(room2, 3);
|
||||||
|
markAsRead(room2);
|
||||||
|
assertRead(room2);
|
||||||
|
|
||||||
|
// When I redact a message
|
||||||
|
receiveMessages(room2, [redactionOf("ThreadMsg1")]);
|
||||||
|
|
||||||
|
// Then the room and thread are read
|
||||||
|
assertRead(room2);
|
||||||
|
goTo(room2);
|
||||||
|
assertReadThread("Root");
|
||||||
|
});
|
||||||
|
// TODO: Doesn't work because the test setup can't (yet) find the ID of a redacted message
|
||||||
|
it.skip("Reacting to a redacted message leaves the thread read", () => {
|
||||||
|
// Given a message in a thread was redacted and everything is read
|
||||||
|
goTo(room1);
|
||||||
|
receiveMessages(room2, ["Root", threadedOff("Root", "Msg2"), threadedOff("Root", "Msg3")]);
|
||||||
|
receiveMessages(room2, [redactionOf("Msg2")]);
|
||||||
|
assertUnread(room2, 2);
|
||||||
|
goTo(room2);
|
||||||
|
assertUnread(room2, 1);
|
||||||
|
openThread("Root");
|
||||||
|
assertRead(room2);
|
||||||
|
goTo(room1);
|
||||||
|
|
||||||
|
// When we receive a reaction to the redacted event
|
||||||
|
// TODO: doesn't work yet because we need to be able to look up
|
||||||
|
// the ID of Msg2 even though it has now disappeared from the
|
||||||
|
// timeline.
|
||||||
|
receiveMessages(room2, [reactionTo(room2, "Msg2")]);
|
||||||
|
|
||||||
|
// Then the room is unread
|
||||||
|
assertStillRead(room2);
|
||||||
|
});
|
||||||
|
// TODO: Doesn't work because the test setup can't (yet) find the ID of a redacted message
|
||||||
|
it.skip("Editing a redacted message leaves the thread read", () => {
|
||||||
|
// Given a message in a thread was redacted and everything is read
|
||||||
|
goTo(room1);
|
||||||
|
receiveMessages(room2, ["Root", threadedOff("Root", "Msg2"), threadedOff("Root", "Msg3")]);
|
||||||
|
receiveMessages(room2, [redactionOf("Msg2")]);
|
||||||
|
assertUnread(room2, 2);
|
||||||
|
goTo(room2);
|
||||||
|
assertUnread(room2, 1);
|
||||||
|
openThread("Root");
|
||||||
|
assertRead(room2);
|
||||||
|
goTo(room1);
|
||||||
|
|
||||||
|
// When we receive an edit of the redacted message
|
||||||
|
// TODO: doesn't work yet because we need to be able to look up
|
||||||
|
// the ID of Msg2 even though it has now disappeared from the
|
||||||
|
// timeline.
|
||||||
|
receiveMessages(room2, [editOf("Msg2", "New Msg2")]);
|
||||||
|
|
||||||
|
// Then the room is unread
|
||||||
|
assertStillRead(room2);
|
||||||
|
});
|
||||||
|
|
||||||
it.skip("?? Reading a reaction to a redacted message marks the thread as read", () => {});
|
it.skip("?? Reading a reaction to a redacted message marks the thread as read", () => {});
|
||||||
it.skip("?? Reading an edit of a redacted message marks the thread as read", () => {});
|
it.skip("?? Reading an edit of a redacted message marks the thread as read", () => {});
|
||||||
it.skip("Reading a reply to a redacted message marks the thread as read", () => {});
|
it.skip("Reading a reply to a redacted message marks the thread as read", () => {});
|
||||||
|
it.skip("Reading a thread root when its only message has been redacted leaves the room read", () => {});
|
||||||
|
|
||||||
it.skip("A thread with an unread redaction is still unread after restart", () => {});
|
it.skip("A thread with an unread redaction is still unread after restart", () => {});
|
||||||
it.skip("A thread with a read redaction is still read after restart", () => {});
|
it("A thread with a read redaction is still read after restart", () => {
|
||||||
|
// Given my receipt points at a redacted thread message
|
||||||
|
goTo(room1);
|
||||||
|
receiveMessages(room2, [
|
||||||
|
"Root",
|
||||||
|
threadedOff("Root", "ThreadMsg1"),
|
||||||
|
threadedOff("Root", "ThreadMsg2"),
|
||||||
|
"Root2",
|
||||||
|
threadedOff("Root2", "Root2->A"),
|
||||||
|
]);
|
||||||
|
assertUnread(room2, 5);
|
||||||
|
goTo(room2);
|
||||||
|
assertUnreadThread("Root");
|
||||||
|
openThread("Root");
|
||||||
|
assertUnreadLessThan(room2, 4);
|
||||||
|
openThread("Root2");
|
||||||
|
assertRead(room2);
|
||||||
|
closeThreadsPanel();
|
||||||
|
goTo(room1);
|
||||||
|
assertRead(room2);
|
||||||
|
receiveMessages(room2, [redactionOf("ThreadMsg2")]);
|
||||||
|
assertStillRead(room2);
|
||||||
|
goTo(room2);
|
||||||
|
assertReadThread("Root");
|
||||||
|
|
||||||
|
// When I restart
|
||||||
|
saveAndReload();
|
||||||
|
|
||||||
|
// Then the room is still read
|
||||||
|
assertRead(room2);
|
||||||
|
});
|
||||||
it.skip("A thread with an unread reply to a redacted message is still unread after restart", () => {});
|
it.skip("A thread with an unread reply to a redacted message is still unread after restart", () => {});
|
||||||
it.skip("A thread with a read replt to a redacted message is still read after restart", () => {});
|
it.skip("A thread with a read replt to a redacted message is still read after restart", () => {});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue