-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Expand file tree
/
Copy pathhistory-sharing.spec.ts
More file actions
156 lines (129 loc) · 7.38 KB
/
history-sharing.spec.ts
File metadata and controls
156 lines (129 loc) · 7.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { createNewInstance } from "@element-hq/element-web-playwright-common";
import { expect, test } from "../../element-web-test";
import { ElementAppPage } from "../../pages/ElementAppPage";
import { createRoom, sendMessageInCurrentRoom } from "./utils";
test.use({
displayName: "Alice",
labsFlags: ["feature_share_history_on_invite"],
});
/** Tests for MSC4268: encrypted history sharing */
test.describe("History sharing", function () {
test(
"We should share history when sending invites",
{ tag: "@screenshot" },
async (
{ labsFlags, browser, page: alicePage, user: aliceCredentials, app: aliceElementApp, homeserver },
testInfo,
) => {
// In this test, Alice creates an encrypted room and sends an event;
// we then invite Bob, and ensure Bob can see the content.
await aliceElementApp.client.bootstrapCrossSigning(aliceCredentials);
// Register a second user, and open it in a second instance of the app
const bobCredentials = await homeserver.registerUser(`user_${testInfo.testId}_bob`, "password", "Bob");
const bobPage = await createNewInstance(browser, bobCredentials, {}, labsFlags);
const bobElementApp = new ElementAppPage(bobPage);
await bobElementApp.client.bootstrapCrossSigning(bobCredentials);
// Create the room and send a message
await createRoom(alicePage, "TestRoom", true);
// The default history visibility for private rooms is "invited",
// so we need to change it to "shared" to ensure Bob can see the message when he joins.
const roomId = await aliceElementApp.getCurrentRoomIdFromUrl();
await aliceElementApp.client.sendStateEvent(roomId, "m.room.history_visibility", {
history_visibility: "shared",
});
await sendMessageInCurrentRoom(alicePage, "A message from Alice");
// Send the invite to Bob
await aliceElementApp.inviteUserToCurrentRoom(bobCredentials.userId, { confirmUnknownUser: true });
// Bob accepts the invite
await bobPage.getByRole("option", { name: "TestRoom" }).click();
await bobPage.getByRole("button", { name: "Accept" }).click();
// Bob should now be able to decrypt the event
await expect(bobPage.getByText("A message from Alice")).toBeVisible();
// Exclude message timestamps and RR avatars from the screenshot. Bob sometimes sees Alice's RR on the
// previous event, which is surprising but not what we're testing here.
const mask = [bobPage.locator(".mx_MessageTimestamp"), bobPage.locator(".mx_ReadReceiptGroup_container")];
await expect(bobPage.locator(".mx_RoomView_body")).toMatchScreenshot("shared-history-invite-accepted.png", {
mask,
});
},
);
test("Messages sent when we believed the room history was unshared should not be visible", async ({
labsFlags,
browser,
page: alicePage,
user: aliceCredentials,
app: aliceElementApp,
homeserver,
}, testInfo) => {
test.setTimeout(60000);
// In this test:
// 1. Alice creates an encrypted room with Bob.
// 2. She sets the history visibility to "shared", but Bob doesn't receive the memo
// 3. Bob sends a message
// 4. Alice invites Charlie
// 5. Charlie can't see the message.
await aliceElementApp.client.bootstrapCrossSigning(aliceCredentials);
await createRoom(alicePage, "TestRoom", true);
// Register a second user, and open it in a second instance of the app
const bobCredentials = await homeserver.registerUser(`user_${testInfo.testId}_bob`, "password", "Bob");
const bobPage = await createNewInstance(browser, bobCredentials, {}, labsFlags);
const bobElementApp = new ElementAppPage(bobPage);
await bobElementApp.client.bootstrapCrossSigning(bobCredentials);
// ... and a third
const charlieCredentials = await homeserver.registerUser(
`user_${testInfo.testId}_charlie`,
"password",
"Charlie",
);
const charliePage = await createNewInstance(browser, charlieCredentials, {}, labsFlags);
const charlieElementApp = new ElementAppPage(charliePage);
await charlieElementApp.client.bootstrapCrossSigning(charlieCredentials);
// Alice invites Bob, and Bob accepts
const roomId = await aliceElementApp.getCurrentRoomIdFromUrl();
await aliceElementApp.inviteUserToCurrentRoom(bobCredentials.userId, { confirmUnknownUser: true });
await bobPage.getByRole("option", { name: "TestRoom" }).click();
await bobPage.getByRole("button", { name: "Accept" }).click();
// The room now defaults to "invited" history visibility, so we need to set it to "shared" first
await aliceElementApp.client.sendStateEvent(roomId, "m.room.history_visibility", {
history_visibility: "shared",
});
await expect(bobPage.getByText("Alice made future room history visible to all room members.")).toBeVisible();
// Bob sends a message with "shared" visibility
await sendMessageInCurrentRoom(bobPage, "Message1: 'shared' visibility");
await expect(alicePage.getByText("Message1")).toBeVisible();
// Alice sets the history visibility to "joined"
await aliceElementApp.client.sendStateEvent(roomId, "m.room.history_visibility", {
history_visibility: "joined",
});
await expect(
bobPage.getByText(
"Alice made future room history visible to all room members, from the point they joined.",
),
).toBeVisible();
// Bob stops syncing, and sends a message with "joined" visibility.
// (Stopping syncing *before* sending the message means that the active sync will be flushed by sending the
// message, so that Alice's change to the history viz below won't be seen by Bob.)
await bobPage.route(`**/sync*`, (route) => route.fulfill({}));
await sendMessageInCurrentRoom(bobPage, "Message2: 'joined' visibility");
await expect(alicePage.getByText("Message2")).toBeVisible();
// Alice changes the history viz, but Bob doesn't receive the memo
await aliceElementApp.client.sendStateEvent(roomId, "m.room.history_visibility", {
history_visibility: "shared",
});
await sendMessageInCurrentRoom(bobPage, "Message3: 'shared' visibility, but Bob thinks it is still 'joined'");
// Alice now invites Charlie
await aliceElementApp.inviteUserToCurrentRoom(charlieCredentials.userId, { confirmUnknownUser: true });
await charliePage.getByRole("option", { name: "TestRoom" }).click();
await charliePage.getByRole("button", { name: "Accept" }).click();
// Message1 should be visible
// Message2 should be invisible
// Message3 should be undecryptable
await expect(charliePage.getByText("Message1")).toBeVisible();
await expect(charliePage.getByText("You don't have access to this message")).toBeVisible();
});
});