Playwright test for device rehydration (#34091)
* Device dehydration tests: use common util for recovery setup We have a utility method for setting up the recovery key, so let's use it. * Factor out shared method for creating encrypted rooms * Playwright test for device dehydration Add a playwright test to check that this stuff actually works.
This commit is contained in:
@@ -8,7 +8,15 @@ Please see LICENSE files in the repository root for full details.
|
||||
|
||||
import { test, expect } from "../../element-web-test";
|
||||
import { isDendrite } from "../../plugins/homeserver/dendrite";
|
||||
import { createBot, logIntoElement } from "./utils.ts";
|
||||
import {
|
||||
autoJoin,
|
||||
createBot,
|
||||
createSharedEncryptedRoomWithUser,
|
||||
enableKeyBackup,
|
||||
logIntoElement,
|
||||
logIntoElementAndVerify,
|
||||
logOutOfElement,
|
||||
} from "./utils.ts";
|
||||
import { type Client } from "../../pages/client.ts";
|
||||
import { type ElementAppPage } from "../../pages/ElementAppPage.ts";
|
||||
|
||||
@@ -40,15 +48,10 @@ test.describe("Dehydration", () => {
|
||||
await settings.getByRole("button", { name: "Verify this device" }).click();
|
||||
await page.getByRole("button", { name: "Can't confirm?" }).click();
|
||||
await page.getByRole("button", { name: "Continue" }).click();
|
||||
await app.closeDialog();
|
||||
|
||||
// Set up recovery
|
||||
await page.getByRole("button", { name: "Get recovery key" }).click();
|
||||
await page.getByRole("button", { name: "Continue" }).click();
|
||||
const recoveryKey = await page.getByTestId("recoveryKey").innerText();
|
||||
await page.getByRole("button", { name: "Continue" }).click();
|
||||
await page.getByRole("textbox").fill(recoveryKey);
|
||||
await page.getByRole("button", { name: "Finish set up" }).click();
|
||||
await page.getByRole("button", { name: "Close" }).click();
|
||||
await enableKeyBackup(app);
|
||||
|
||||
await expectDehydratedDeviceEnabled(app);
|
||||
|
||||
@@ -61,28 +64,7 @@ test.describe("Dehydration", () => {
|
||||
|
||||
test("'Get recovery key' creates dehydrated device", async ({ app, credentials, page }) => {
|
||||
await logIntoElement(page, credentials);
|
||||
|
||||
const settingsDialogLocator = await app.settings.openUserSettings("Encryption");
|
||||
await settingsDialogLocator.getByRole("button", { name: "Get recovery key" }).click();
|
||||
|
||||
// First it displays an informative panel about the recovery key
|
||||
await expect(settingsDialogLocator.getByRole("heading", { name: "Get recovery key" })).toBeVisible();
|
||||
await settingsDialogLocator.getByRole("button", { name: "Continue" }).click();
|
||||
|
||||
// Next, it displays the new recovery key. We click on the copy button.
|
||||
await expect(settingsDialogLocator.getByText("Save your recovery key somewhere safe")).toBeVisible();
|
||||
await settingsDialogLocator.getByRole("button", { name: "Copy" }).click();
|
||||
const recoveryKey = await app.getClipboard();
|
||||
await settingsDialogLocator.getByRole("button", { name: "Continue" }).click();
|
||||
|
||||
await expect(
|
||||
settingsDialogLocator.getByText("Enter your recovery key to confirm", { exact: true }),
|
||||
).toBeVisible();
|
||||
await settingsDialogLocator.getByRole("textbox").fill(recoveryKey);
|
||||
await settingsDialogLocator.getByRole("button", { name: "Finish set up" }).click();
|
||||
|
||||
await app.settings.closeDialog();
|
||||
|
||||
await enableKeyBackup(app);
|
||||
await expectDehydratedDeviceEnabled(app);
|
||||
});
|
||||
|
||||
@@ -115,13 +97,7 @@ test.describe("Dehydration", () => {
|
||||
await page.getByRole("button", { name: "Continue" }).click();
|
||||
|
||||
// And set up recovery
|
||||
const settings = await app.settings.openUserSettings("Encryption");
|
||||
await settings.getByRole("button", { name: "Get recovery key" }).click();
|
||||
await settings.getByRole("button", { name: "Continue" }).click();
|
||||
const recoveryKey = await settings.getByTestId("recoveryKey").innerText();
|
||||
await settings.getByRole("button", { name: "Continue" }).click();
|
||||
await settings.getByRole("textbox").fill(recoveryKey);
|
||||
await settings.getByRole("button", { name: "Finish set up" }).click();
|
||||
await enableKeyBackup(app);
|
||||
|
||||
// There should be a brand new dehydrated device
|
||||
await expectDehydratedDeviceEnabled(app);
|
||||
@@ -132,34 +108,54 @@ test.describe("Dehydration", () => {
|
||||
|
||||
// Create a dehydrated device by setting up recovery (see "'Set up
|
||||
// recovery' creates dehydrated device" test above)
|
||||
const settingsDialogLocator = await app.settings.openUserSettings("Encryption");
|
||||
await settingsDialogLocator.getByRole("button", { name: "Get recovery key" }).click();
|
||||
|
||||
// First it displays an informative panel about the recovery key
|
||||
await expect(settingsDialogLocator.getByRole("heading", { name: "Get recovery key" })).toBeVisible();
|
||||
await settingsDialogLocator.getByRole("button", { name: "Continue" }).click();
|
||||
|
||||
// Next, it displays the new recovery key. We click on the copy button.
|
||||
await expect(settingsDialogLocator.getByText("Save your recovery key somewhere safe")).toBeVisible();
|
||||
await settingsDialogLocator.getByRole("button", { name: "Copy" }).click();
|
||||
const recoveryKey = await app.getClipboard();
|
||||
await settingsDialogLocator.getByRole("button", { name: "Continue" }).click();
|
||||
|
||||
await expect(
|
||||
settingsDialogLocator.getByText("Enter your recovery key to confirm", { exact: true }),
|
||||
).toBeVisible();
|
||||
await settingsDialogLocator.getByRole("textbox").fill(recoveryKey);
|
||||
await settingsDialogLocator.getByRole("button", { name: "Finish set up" }).click();
|
||||
|
||||
await enableKeyBackup(app);
|
||||
await expectDehydratedDeviceEnabled(app);
|
||||
|
||||
// After recovery is set up, we reset our cryptographic identity, which
|
||||
// should drop the dehydrated device.
|
||||
const settingsDialogLocator = await app.settings.openUserSettings("Encryption");
|
||||
await settingsDialogLocator.getByRole("button", { name: "Reset cryptographic identity" }).click();
|
||||
await settingsDialogLocator.getByRole("button", { name: "Continue" }).click();
|
||||
|
||||
await expectDehydratedDeviceDisabled(app);
|
||||
});
|
||||
|
||||
test("Can read messages sent while logged out", async ({ page, user: credentials, app, bot: bob }) => {
|
||||
const recoveryKey =
|
||||
await test.step("Alice sets up cross-signing and recovery => a dehydrated device is created", async () => {
|
||||
// Create an identity, then set up recovery, to create a dehydrated device.
|
||||
await app.client.bootstrapCrossSigning(credentials);
|
||||
const recoveryKey = await enableKeyBackup(app);
|
||||
|
||||
await expectDehydratedDeviceEnabled(app);
|
||||
return recoveryKey;
|
||||
});
|
||||
|
||||
const testRoomId = await test.step("Bob and Alice make a shared room", async () => {
|
||||
await autoJoin(bob);
|
||||
|
||||
// create an encrypted room, and wait for Bob to join it.
|
||||
const testRoomId = await createSharedEncryptedRoomWithUser(app, bob.credentials.userId);
|
||||
|
||||
// Even though Alice has seen Bob's join event, Bob may not have done so yet. Wait for the sync to arrive.
|
||||
await bob.awaitRoomMembership(testRoomId);
|
||||
return testRoomId;
|
||||
});
|
||||
|
||||
await test.step("Alice logs out", async () => {
|
||||
await logOutOfElement(page);
|
||||
});
|
||||
|
||||
await test.step("Bob sends a message", async () => {
|
||||
await bob.sendMessage(testRoomId, "test encrypted 1");
|
||||
});
|
||||
|
||||
await test.step("Alice logs back in, and should be able to view Bob's message", async () => {
|
||||
await logIntoElementAndVerify(page, credentials, recoveryKey);
|
||||
await app.viewRoomById(testRoomId);
|
||||
await expect(page.getByText("test encrypted 1")).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
async function getDehydratedDeviceIds(client: Client): Promise<string[]> {
|
||||
|
||||
Reference in New Issue
Block a user