From 42253a7ae59306fb5ac2bb6afef45c3e3c5947b6 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 30 Jul 2026 10:07:03 +0100 Subject: [PATCH] Make apps/web/playwright comply with strict mode (#34403) * Make apps/web/playwright comply with strict mode Otherwise it sometimes fails to compile matrix-js-sdk as strict mode & noImplicitAny both impact how overloads are asserted * Iterate --- .../accessibility/keyboard-navigation.spec.ts | 4 +- .../e2e/audio-player/audio-player.spec.ts | 4 +- .../e2e/chat-export/html-export.spec.ts | 7 ++- .../web/playwright/e2e/composer/CIDER.spec.ts | 4 +- apps/web/playwright/e2e/composer/RTE.spec.ts | 14 ++--- .../playwright/e2e/crypto/backups-mas.spec.ts | 4 +- apps/web/playwright/e2e/crypto/crypto.spec.ts | 22 +++---- .../e2e/crypto/dehydration-mas.spec.ts | 2 +- .../playwright/e2e/crypto/dehydration.spec.ts | 12 ++-- .../e2e/crypto/device-verification.spec.ts | 18 +++--- .../e2e/crypto/event-shields.spec.ts | 8 +-- .../e2e/crypto/invisible-crypto.spec.ts | 4 +- .../playwright/e2e/crypto/migration.spec.ts | 8 +-- apps/web/playwright/e2e/crypto/toasts.spec.ts | 8 +-- .../e2e/crypto/user-verification.spec.ts | 14 ++--- apps/web/playwright/e2e/crypto/utils.ts | 34 ++++++----- .../playwright/e2e/editing/editing.spec.ts | 2 +- .../e2e/feedback/rageshakes.spec.ts | 2 +- .../forgot-password/forgot-password.spec.ts | 6 +- .../e2e/integration-manager/kick.spec.ts | 45 ++++++++++---- .../e2e/invite/invite-dialog.spec.ts | 8 +-- .../e2e/lazy-loading/lazy-loading.spec.ts | 12 ++-- .../room-list-collapse.spec.ts | 18 +++--- .../room-list-filter-sort.spec.ts | 10 ++-- .../room-list-sections.spec.ts | 8 +-- .../room-list-unread-toast.spec.ts | 6 +- .../room-list-panel/room-list.spec.ts | 14 ++--- .../playwright/e2e/links/permalinks.spec.ts | 12 ++-- .../e2e/login/login-consent.spec.ts | 8 +-- .../e2e/login/logout_redirect_url.spec.ts | 2 +- .../playwright/e2e/login/soft_logout.spec.ts | 2 +- apps/web/playwright/e2e/login/utils.ts | 8 +-- apps/web/playwright/e2e/oidc/index.ts | 4 +- .../playwright/e2e/oidc/oidc-native.spec.ts | 6 +- .../one-to-one-chat/one-to-one-chat.spec.ts | 6 +- .../playwright/e2e/pinned-messages/index.ts | 4 +- .../playwright/e2e/polls/pollHistory.spec.ts | 2 +- apps/web/playwright/e2e/polls/polls.spec.ts | 26 ++++---- .../playwright/e2e/presence/presence.spec.ts | 4 +- .../e2e/read-receipts/high-level.spec.ts | 15 +++-- .../web/playwright/e2e/read-receipts/index.ts | 60 ++++++++----------- .../e2e/read-receipts/read-receipts.spec.ts | 10 ++-- .../e2e/read-receipts/room-list-order.spec.ts | 4 +- .../web/playwright/e2e/register/email.spec.ts | 2 +- .../e2e/retention/retention-global.spec.ts | 2 +- .../e2e/retention/retention.spec.ts | 6 +- .../e2e/right-panel/right-panel.spec.ts | 2 +- .../e2e/room-directory/room-directory.spec.ts | 2 +- apps/web/playwright/e2e/room/invites.spec.ts | 2 +- .../e2e/room/room-status-bar.spec.ts | 4 +- apps/web/playwright/e2e/room/room.spec.ts | 4 +- .../e2e/room_options/marked_unread.spec.ts | 2 +- .../e2e/settings/device-management.spec.ts | 2 +- .../encryption-user-tab/advanced.spec.ts | 4 +- .../encryption-tab.spec.ts | 7 ++- .../e2e/settings/encryption-user-tab/index.ts | 2 +- .../encryption-user-tab/recovery.spec.ts | 5 +- .../general-room-settings-tab.spec.ts | 2 +- .../e2e/sliding-sync/sliding-sync.spec.ts | 4 +- apps/web/playwright/e2e/spaces/spaces.spec.ts | 4 +- .../spaces/threads-activity-centre/index.ts | 26 +++----- .../e2e/spotlight/spotlight.spec.ts | 52 ++++++++-------- .../playwright/e2e/threads/threads.spec.ts | 4 +- .../e2e/timeline/event-list-summary.spec.ts | 40 ++++++------- .../playwright/e2e/timeline/timeline.spec.ts | 12 ++-- .../e2e/user-menu/user-menu.spec.ts | 2 +- .../e2e/user-view/user-view.spec.ts | 6 +- apps/web/playwright/e2e/utils.ts | 2 +- .../playwright/e2e/voip/element-call.spec.ts | 44 +++++++------- .../web/playwright/e2e/widgets/events.spec.ts | 2 +- apps/web/playwright/e2e/widgets/jitsi.spec.ts | 2 +- .../web/playwright/e2e/widgets/layout.spec.ts | 8 +-- .../e2e/widgets/widget-pip-close.spec.ts | 6 +- apps/web/playwright/element-web-test.ts | 4 +- apps/web/playwright/pages/ElementAppPage.ts | 10 ++-- apps/web/playwright/pages/Spotlight.ts | 2 +- apps/web/playwright/pages/bot.ts | 6 +- apps/web/playwright/pages/client.ts | 22 +++---- apps/web/playwright/pages/crypto.ts | 4 +- apps/web/playwright/pages/timeline.ts | 4 +- .../synapse/legacyOAuthHomeserver.ts | 4 +- .../playwright/plugins/oauth_server/index.ts | 4 +- apps/web/playwright/tsconfig.json | 4 +- apps/web/src/@types/matrix-js-sdk.d.ts | 4 +- 84 files changed, 413 insertions(+), 388 deletions(-) diff --git a/apps/web/playwright/e2e/accessibility/keyboard-navigation.spec.ts b/apps/web/playwright/e2e/accessibility/keyboard-navigation.spec.ts index c77ff7e343..edd7b37ea8 100644 --- a/apps/web/playwright/e2e/accessibility/keyboard-navigation.spec.ts +++ b/apps/web/playwright/e2e/accessibility/keyboard-navigation.spec.ts @@ -65,7 +65,7 @@ test.describe("Landmark navigation tests", () => { await cli.invite(bobRoom.room_id, bob); }, { - bob: bob.credentials.userId, + bob: bob.credentials!.userId, }, ); @@ -118,7 +118,7 @@ test.describe("Landmark navigation tests", () => { await cli.invite(bobRoom.room_id, bob); }, { - bob: bob.credentials.userId, + bob: bob.credentials!.userId, }, ); diff --git a/apps/web/playwright/e2e/audio-player/audio-player.spec.ts b/apps/web/playwright/e2e/audio-player/audio-player.spec.ts index d4a28f9411..e20791ae94 100644 --- a/apps/web/playwright/e2e/audio-player/audio-player.spec.ts +++ b/apps/web/playwright/e2e/audio-player/audio-player.spec.ts @@ -313,7 +313,9 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => { await expect(tile.locator(".mx_ReplyChain")).toHaveCount(2); // Assert that one line contains the user name - await expect(tile.locator(".mx_ReplyChain .mx_ReplyTile_sender").getByText(user.displayName)).toBeVisible(); + await expect( + tile.locator(".mx_ReplyChain .mx_ReplyTile_sender").getByText(user.displayName!), + ).toBeVisible(); // Assert that the other line contains the file button await expect(tile.locator(".mx_ReplyChain .mx_MFileBody")).toBeVisible(); diff --git a/apps/web/playwright/e2e/chat-export/html-export.spec.ts b/apps/web/playwright/e2e/chat-export/html-export.spec.ts index aed032b09b..1436ef59c5 100644 --- a/apps/web/playwright/e2e/chat-export/html-export.spec.ts +++ b/apps/web/playwright/e2e/chat-export/html-export.spec.ts @@ -99,9 +99,12 @@ test.describe("HTML Export", () => { // Send a bunch of messages to populate the room for (let i = 1; i < 10; i++) { - const respone = await app.client.sendMessage(room.roomId, { body: `Testing ${i}`, msgtype: "m.text" }); + const response = await app.client.sendMessage(room!.roomId, { + body: `Testing ${i}`, + msgtype: "m.text", + }); if (i == 1) { - await app.client.reactToMessage(room.roomId, null, respone.event_id, "🙃"); + await app.client.reactToMessage(room!.roomId, null, response.event_id, "🙃"); } } diff --git a/apps/web/playwright/e2e/composer/CIDER.spec.ts b/apps/web/playwright/e2e/composer/CIDER.spec.ts index d50b24f3a0..9629e63c9e 100644 --- a/apps/web/playwright/e2e/composer/CIDER.spec.ts +++ b/apps/web/playwright/e2e/composer/CIDER.spec.ts @@ -184,7 +184,7 @@ test.describe("Composer", () => { // Set up a private room so we have another user to mention await app.client.createRoom({ is_direct: true, - invite: [bot.credentials.userId], + invite: [bot.credentials!.userId], }); await app.viewRoomByName("Bob"); @@ -194,7 +194,7 @@ test.describe("Composer", () => { // Note that we include the user ID here as the room tile is also an 'option' role // with text 'Bob' - await page.getByRole("option", { name: `Bob ${bot.credentials.userId}` }).click(); + await page.getByRole("option", { name: `Bob ${bot.credentials!.userId}` }).click(); await expect(composer.getByText("Bob")).toBeVisible(); await expect(composer).toMatchScreenshot("mention.png"); await composer.press("Enter"); diff --git a/apps/web/playwright/e2e/composer/RTE.spec.ts b/apps/web/playwright/e2e/composer/RTE.spec.ts index a2f0990907..e9ba8aaa32 100644 --- a/apps/web/playwright/e2e/composer/RTE.spec.ts +++ b/apps/web/playwright/e2e/composer/RTE.spec.ts @@ -100,7 +100,7 @@ test.describe("Composer", () => { // Set up a private room so we have another user to mention await app.client.createRoom({ is_direct: true, - invite: [bob.credentials.userId], + invite: [bob.credentials!.userId], }); await app.viewRoomByName("Bob"); @@ -113,11 +113,11 @@ test.describe("Composer", () => { await expect(page.getByTestId("autocomplete-wrapper")).toBeEmpty(); // Entering the first letter of the other user's name opens the autocomplete... - await page.getByRole("textbox").pressSequentially(bob.credentials.displayName.slice(0, 1)); + await page.getByRole("textbox").pressSequentially(bob.credentials!.displayName!.slice(0, 1)); // ...with the other user name visible, and clicking that username... - await page.getByTestId("autocomplete-wrapper").getByText(bob.credentials.displayName).click(); + await page.getByTestId("autocomplete-wrapper").getByText(bob.credentials!.displayName!).click(); // ...inserts the username into the composer - const pill = page.getByRole("textbox").getByText(bob.credentials.displayName, { exact: false }); + const pill = page.getByRole("textbox").getByText(bob.credentials!.displayName!, { exact: false }); await expect(pill).toHaveAttribute("contenteditable", "false"); await expect(pill).toHaveAttribute("data-mention-type", "user"); @@ -125,7 +125,7 @@ test.describe("Composer", () => { await page.getByRole("button", { name: "Send message" }).click(); // Typing an @, then other user's name, then trailing space closes the autocomplete - await page.getByRole("textbox").pressSequentially(`@${bob.credentials.displayName} `); + await page.getByRole("textbox").pressSequentially(`@${bob.credentials!.displayName!} `); await expect(page.getByTestId("autocomplete-wrapper")).toBeEmpty(); // Send the message to clear the composer @@ -134,7 +134,7 @@ test.describe("Composer", () => { // Moving the cursor back to an "incomplete" mention opens the autocomplete await page .getByRole("textbox") - .pressSequentially(`initial text @${bob.credentials.displayName.slice(0, 1)} abc`); + .pressSequentially(`initial text @${bob.credentials!.displayName!.slice(0, 1)} abc`); await expect(page.getByTestId("autocomplete-wrapper")).toBeEmpty(); // Move the cursor left by 4 to put it to: `@B| abc`, check autocomplete displays await page.getByRole("textbox").press("ArrowLeft"); @@ -145,7 +145,7 @@ test.describe("Composer", () => { // Selecting the autocomplete option using Enter inserts it into the composer await page.getByRole("textbox").press("Enter"); - const pill2 = page.getByRole("textbox").getByText(bob.credentials.displayName, { exact: false }); + const pill2 = page.getByRole("textbox").getByText(bob.credentials!.displayName!, { exact: false }); await expect(pill2).toHaveAttribute("contenteditable", "false"); await expect(pill2).toHaveAttribute("data-mention-type", "user"); }); diff --git a/apps/web/playwright/e2e/crypto/backups-mas.spec.ts b/apps/web/playwright/e2e/crypto/backups-mas.spec.ts index 477ca2a42f..3768c51e4d 100644 --- a/apps/web/playwright/e2e/crypto/backups-mas.spec.ts +++ b/apps/web/playwright/e2e/crypto/backups-mas.spec.ts @@ -89,13 +89,13 @@ test.describe("Key backup reset from elsewhere", () => { await page.getByRole("textbox", { name: "Name" }).fill("test room"); await page.getByRole("button", { name: "Create room" }).click(); - const accessToken = await page.evaluate(() => window.mxMatrixClientPeg.get().getAccessToken()); + const accessToken = await page.evaluate(() => window.mxMatrixClientPeg.get().getAccessToken()!); const csAPI = new TestClientServerAPI(request, homeserver, accessToken); const backupInfo = await csAPI.getCurrentBackupInfo(); - await csAPI.deleteBackupVersion(backupInfo.version); + await csAPI.deleteBackupVersion(backupInfo!.version); await page.getByRole("textbox", { name: "Send a message…" }).fill("/discardsession"); await page.getByRole("button", { name: "Send message" }).click(); diff --git a/apps/web/playwright/e2e/crypto/crypto.spec.ts b/apps/web/playwright/e2e/crypto/crypto.spec.ts index f446611799..88872052f2 100644 --- a/apps/web/playwright/e2e/crypto/crypto.spec.ts +++ b/apps/web/playwright/e2e/crypto/crypto.spec.ts @@ -25,8 +25,8 @@ const checkDMRoom = async (page: Page) => { const startDMWithBob = async (page: Page, bob: Bot) => { await page.getByRole("navigation", { name: "Room list" }).getByRole("button", { name: "New conversation" }).click(); await page.getByRole("menuitem", { name: "Start chat" }).click(); - await page.getByTestId("invite-dialog-input").fill(bob.credentials.userId); - await page.getByRole("option", { name: bob.credentials.displayName }).click(); + await page.getByTestId("invite-dialog-input").fill(bob.credentials!.userId); + await page.getByRole("option", { name: bob.credentials!.displayName! }).click(); await expect(page.getByTestId("invite-dialog-input-wrapper").getByText("Bob")).toBeVisible(); await page.getByRole("button", { name: "Go" }).click(); @@ -82,14 +82,14 @@ test.describe("Cryptography", function () { * @param keyType */ async function verifyKey(app: ElementAppPage, keyType: "master" | "self_signing" | "user_signing") { - const accountData: { encrypted: Record> } = await app.client.evaluate( + const accountData = await app.client.evaluate( (cli, keyType) => cli.getAccountDataFromServer(`m.cross_signing.${keyType}`), keyType, ); - expect(accountData.encrypted).toBeDefined(); - const keys = Object.keys(accountData.encrypted); - const key = accountData.encrypted[keys[0]]; + expect(accountData?.encrypted).toBeDefined(); + const keys = Object.keys(accountData!.encrypted); + const key = accountData!.encrypted[keys[0]]; expect(key.ciphertext).toBeDefined(); expect(key.iv).toBeDefined(); expect(key.mac).toBeDefined(); @@ -119,9 +119,9 @@ test.describe("Cryptography", function () { async function fetchMasterKey() { return await test.step("Fetch master key from server", async () => { const k = await app.client.evaluate(async (cli) => { - const userId = cli.getUserId(); + const userId = cli.getSafeUserId(); const keys = await cli.downloadKeysForUsers([userId]); - return Object.values(keys.master_keys[userId].keys)[0]; + return Object.values(keys.master_keys![userId].keys)[0]; }); console.log(`fetchMasterKey: ${k}`); return k; @@ -138,7 +138,7 @@ test.describe("Cryptography", function () { await encryptionTab.getByRole("button", { name: "Continue" }).click(); // Enter the password - await page.getByPlaceholder("Password").fill(aliceCredentials.password); + await page.getByPlaceholder("Password").fill(aliceCredentials.password!); await page.getByRole("button", { name: "Continue" }).click(); await expect(async () => { @@ -163,7 +163,7 @@ test.describe("Cryptography", function () { await encryptionTab.getByRole("button", { name: "Continue" }).click(); // Enter the password - await page.getByPlaceholder("Password").fill(aliceCredentials.password); + await page.getByPlaceholder("Password").fill(aliceCredentials.password!); await page.getByRole("button", { name: "Continue" }).click(); // Key storage should now be enabled @@ -209,7 +209,7 @@ test.describe("Cryptography", function () { await autoJoin(bob); // we need to have a room with the other user present, so we can open the verification panel - await createSharedRoomWithUser(app, bob.credentials.userId); + await createSharedRoomWithUser(app, bob.credentials!.userId); await verify(app, bob); }); }); diff --git a/apps/web/playwright/e2e/crypto/dehydration-mas.spec.ts b/apps/web/playwright/e2e/crypto/dehydration-mas.spec.ts index 5678936f92..fded708df3 100644 --- a/apps/web/playwright/e2e/crypto/dehydration-mas.spec.ts +++ b/apps/web/playwright/e2e/crypto/dehydration-mas.spec.ts @@ -46,7 +46,7 @@ test.describe("Device dehydration, on a MAS-enabled homeserver", () => { await autoJoin(bob); // Create an encrypted room, and wait for Bob to join it. - const testRoomId = await createSharedEncryptedRoomWithUser(app, bob.credentials.userId); + 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); diff --git a/apps/web/playwright/e2e/crypto/dehydration.spec.ts b/apps/web/playwright/e2e/crypto/dehydration.spec.ts index 6ebbb388e7..24ee94129b 100644 --- a/apps/web/playwright/e2e/crypto/dehydration.spec.ts +++ b/apps/web/playwright/e2e/crypto/dehydration.spec.ts @@ -77,7 +77,7 @@ test.describe("Dehydration", () => { // Set up cross-signing and recovery const { botClient } = await createBot(page, homeserver, credentials); // ... and dehydration - await botClient.evaluate(async (client) => await client.getCrypto().startDehydration()); + await botClient.evaluate(async (client) => await client.getCrypto()!.startDehydration()); const initialDehydratedDeviceIds = await getDehydratedDeviceIds(botClient); expect(initialDehydratedDeviceIds.length).toBe(1); @@ -93,7 +93,7 @@ test.describe("Dehydration", () => { page.getByRole("heading", { name: "Are you sure you want to reset your digital identity?" }), ).toBeVisible(); await page.getByRole("button", { name: "Continue", exact: true }).click(); - await page.getByPlaceholder("Password").fill(credentials.password); + await page.getByPlaceholder("Password").fill(credentials.password!); await page.getByRole("button", { name: "Continue" }).click(); // And set up recovery @@ -141,7 +141,7 @@ test.describe("Dehydration", () => { await autoJoin(bob); // create an encrypted room, and wait for Bob to join it. - const testRoomId = await createSharedEncryptedRoomWithUser(app, bob.credentials.userId); + 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); @@ -171,9 +171,9 @@ test.describe("Dehydration", () => { async function getDehydratedDeviceIds(client: Client): Promise { return await client.evaluate(async (client) => { - const userId = client.getUserId(); - const devices = await client.getCrypto().getUserDeviceInfo([userId]); - return Array.from(devices.get(userId).values()) + const userId = client.getSafeUserId(); + const devices = await client.getCrypto()!.getUserDeviceInfo([userId]); + return Array.from(devices.get(userId)!.values()) .filter((d) => d.dehydrated) .map((d) => d.deviceId); }); diff --git a/apps/web/playwright/e2e/crypto/device-verification.spec.ts b/apps/web/playwright/e2e/crypto/device-verification.spec.ts index 1500b5771d..eff50f72c1 100644 --- a/apps/web/playwright/e2e/crypto/device-verification.spec.ts +++ b/apps/web/playwright/e2e/crypto/device-verification.spec.ts @@ -169,8 +169,8 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => { await app.client.evaluate(async (cli, aliceBotCredentials) => { const deviceStatus = await cli .getCrypto()! - .getDeviceVerificationStatus(aliceBotCredentials.userId, aliceBotCredentials.deviceId); - if (!deviceStatus.isVerified()) { + .getDeviceVerificationStatus(aliceBotCredentials!.userId, aliceBotCredentials!.deviceId); + if (!deviceStatus!.isVerified()) { throw new Error("Bot device was not verified after QR code verification"); } }, aliceBotClient.credentials); @@ -193,14 +193,14 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => { ); test("Verify device with Recovery Key during login", async ({ page, app, credentials, homeserver }) => { - const recoveryKey = (await aliceBotClient.getRecoveryKey()).encodedPrivateKey; + const recoveryKey = (await aliceBotClient.getRecoveryKey()).encodedPrivateKey!; await logIntoElement(page, credentials); await enterRecoveryKeyAndCheckVerified(page, app, recoveryKey); }); test("Verify device with Recovery Key from settings", async ({ page, app, credentials }) => { - const recoveryKey = (await aliceBotClient.getRecoveryKey()).encodedPrivateKey; + const recoveryKey = (await aliceBotClient.getRecoveryKey()).encodedPrivateKey!; await logIntoElement(page, credentials); @@ -277,7 +277,7 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => { await authPage.getByRole("button", { name: "I'll verify later" }).click(); await page.waitForSelector(".mx_MatrixChat"); - const elementDeviceId = await page.evaluate(() => window.mxMatrixClientPeg.get().getDeviceId()); + const elementDeviceId = await page.evaluate(() => window.mxMatrixClientPeg.get().getDeviceId()!); /* Create an encrypted room so the "Verify this device" toast appears */ await app.client.createRoom({ @@ -301,7 +301,7 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => { /* Check the toast for the incoming request */ const toast = await getToast(page, "Verification requested"); // it should contain the device ID of the requesting device - await expect(toast.getByText(`${aliceBotClient.credentials.deviceId} from `)).toBeVisible(); + await expect(toast.getByText(`${aliceBotClient.credentials!.deviceId} from `)).toBeVisible(); // Accept await toast.getByRole("button", { name: "Start verification" }).click(); @@ -311,7 +311,7 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => { /* on the bot side, wait for the verifier to exist ... */ const verifier = await awaitVerifier(botVerificationRequest); // ... confirm ... - void botVerificationRequest.evaluate((verificationRequest) => verificationRequest.verifier.verify()); + void botVerificationRequest.evaluate((verificationRequest) => verificationRequest.verifier!.verify()); // ... and then check the emoji match await doTwoWaySasVerification(page, verifier); @@ -337,7 +337,7 @@ async function readQrCode(base: Locator) { >(async (img) => { // draw the image on a canvas const myCanvas = new OffscreenCanvas(img.width, img.height); - const ctx = myCanvas.getContext("2d"); + const ctx = myCanvas.getContext("2d")!; ctx.drawImage(img, 0, 0); // read the image data @@ -352,5 +352,5 @@ async function readQrCode(base: Locator) { // now we can decode the QR code. const result = jsQR(new Uint8ClampedArray(imageData.buffer), imageData.width, imageData.height); - return new Uint8Array(result.binaryData); + return new Uint8Array(result!.binaryData); } diff --git a/apps/web/playwright/e2e/crypto/event-shields.spec.ts b/apps/web/playwright/e2e/crypto/event-shields.spec.ts index a610a98a64..e25bcf3b73 100644 --- a/apps/web/playwright/e2e/crypto/event-shields.spec.ts +++ b/apps/web/playwright/e2e/crypto/event-shields.spec.ts @@ -40,7 +40,7 @@ test.describe("Cryptography", function () { await autoJoin(bob); // create an encrypted room, and wait for Bob to join it. - testRoomId = await createSharedEncryptedRoomWithUser(app, bob.credentials.userId); + 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); @@ -128,7 +128,7 @@ test.describe("Cryptography", function () { await bobSecondDevice.evaluate((cli) => cli.logout(true)); // wait for the logout to propagate. - await waitForDevices(app, bob.credentials.userId, 1); + await waitForDevices(app, bob.credentials!.userId, 1); // close and reopen the room, to get the shield to update. await app.viewRoomByName("Bob"); @@ -245,7 +245,7 @@ test.describe("Cryptography", function () { // Workaround for https://github.com/element-hq/element-web/issues/28640: // make sure that Alice has seen Bob's identity before she goes offline. We do this by opening // his user info. - await waitForDevices(app, bob.credentials.userId, 1); + await waitForDevices(app, bob.credentials!.userId, 1); // Our app is blocked from syncing while Bob sends his messages. await app.client.network.goOffline(); @@ -286,7 +286,7 @@ test.describe("Cryptography", function () { // Bob logs in a new device and resets cross-signing const bobSecondDevice = await createSecondBotDevice(page, homeserver, bob); - await bootstrapCrossSigningForClient(await bobSecondDevice.prepareClient(), bob.credentials, true); + await bootstrapCrossSigningForClient(await bobSecondDevice.prepareClient(), bob.credentials!, true); /* should show an error for a message from a previously verified device */ await bobSecondDevice.sendMessage(testRoomId, "test encrypted from user that was previously verified"); diff --git a/apps/web/playwright/e2e/crypto/invisible-crypto.spec.ts b/apps/web/playwright/e2e/crypto/invisible-crypto.spec.ts index d5aeba63cc..86b6d205ec 100644 --- a/apps/web/playwright/e2e/crypto/invisible-crypto.spec.ts +++ b/apps/web/playwright/e2e/crypto/invisible-crypto.spec.ts @@ -29,14 +29,14 @@ test.describe("Invisible cryptography", () => { await autoJoin(bob); // create an encrypted room - const testRoomId = await createSharedEncryptedRoomWithUser(app, bob.credentials.userId); + const testRoomId = await createSharedEncryptedRoomWithUser(app, bob.credentials!.userId); // Verify Bob await verify(app, bob); // Bob logs in a new device and resets cross-signing const bobSecondDevice = await createSecondBotDevice(page, homeserver, bob); - await bootstrapCrossSigningForClient(await bobSecondDevice.prepareClient(), bob.credentials, true); + await bootstrapCrossSigningForClient(await bobSecondDevice.prepareClient(), bob.credentials!, true); /* should show an error for a message from a previously verified device */ await bobSecondDevice.sendMessage(testRoomId, "test encrypted from user that was previously verified"); diff --git a/apps/web/playwright/e2e/crypto/migration.spec.ts b/apps/web/playwright/e2e/crypto/migration.spec.ts index 191568c29c..7fb00ef41c 100644 --- a/apps/web/playwright/e2e/crypto/migration.spec.ts +++ b/apps/web/playwright/e2e/crypto/migration.spec.ts @@ -41,8 +41,8 @@ test.describe("migration", { tag: "@no-webkit" }, function () { // When the progress bar first loads, it should have a high max (one per megolm session to import), and // a relatively low value. const progressBar = page.getByRole("progressbar"); - const initialProgress = parseFloat(await progressBar.getAttribute("value")); - const initialMax = parseFloat(await progressBar.getAttribute("max")); + const initialProgress = parseFloat((await progressBar.getAttribute("value"))!); + const initialMax = parseFloat((await progressBar.getAttribute("max"))!); expect(initialMax).toBeGreaterThan(4000); expect(initialProgress).toBeGreaterThanOrEqual(0); expect(initialProgress).toBeLessThanOrEqual(500); @@ -53,8 +53,8 @@ test.describe("migration", { tag: "@no-webkit" }, function () { async () => { const progressBar = page.getByRole("progressbar"); return ( - (parseFloat(await progressBar.getAttribute("value")) * 100.0) / - parseFloat(await progressBar.getAttribute("max")) + (parseFloat((await progressBar.getAttribute("value"))!) * 100.0) / + parseFloat((await progressBar.getAttribute("max"))!) ); }, { timeout: 60000 }, diff --git a/apps/web/playwright/e2e/crypto/toasts.spec.ts b/apps/web/playwright/e2e/crypto/toasts.spec.ts index c23ba8ea71..58c029c33b 100644 --- a/apps/web/playwright/e2e/crypto/toasts.spec.ts +++ b/apps/web/playwright/e2e/crypto/toasts.spec.ts @@ -30,7 +30,7 @@ test.describe("Key storage out of sync toast", () => { recoveryKey = res.recoveryKey; await logIntoElement(page, credentials); - await verifyAfterLogin(page, recoveryKey.encodedPrivateKey); + await verifyAfterLogin(page, recoveryKey.encodedPrivateKey!); await deleteCachedSecrets(page); }); @@ -43,7 +43,7 @@ test.describe("Key storage out of sync toast", () => { await page.getByRole("button", { name: "Enter recovery key" }).click(); - await page.getByRole("textbox", { name: "Recovery Key" }).fill(recoveryKey.encodedPrivateKey); + await page.getByRole("textbox", { name: "Recovery Key" }).fill(recoveryKey.encodedPrivateKey!); await page.getByRole("button", { name: "Continue" }).click(); await expect(page.getByRole("button", { name: "Enter recovery key" })).not.toBeVisible(); @@ -63,7 +63,7 @@ test.describe("Key storage out of sync toast", () => { }); test.describe("'Turn on key storage' toast", () => { - let botClient: Bot | undefined; + let botClient: Bot; test.beforeEach(async ({ page, homeserver, credentials }) => { // Set up all crypto stuff. Key storage defaults to on. @@ -73,7 +73,7 @@ test.describe("'Turn on key storage' toast", () => { botClient = res.botClient; await logIntoElement(page, credentials); - await verifyAfterLogin(page, recoveryKey.encodedPrivateKey); + await verifyAfterLogin(page, recoveryKey.encodedPrivateKey!); // We won't be prompted for crypto setup unless we have an e2e room, so make one await page diff --git a/apps/web/playwright/e2e/crypto/user-verification.spec.ts b/apps/web/playwright/e2e/crypto/user-verification.spec.ts index 68379e3801..f4cc78dfd5 100644 --- a/apps/web/playwright/e2e/crypto/user-verification.spec.ts +++ b/apps/web/playwright/e2e/crypto/user-verification.spec.ts @@ -39,7 +39,7 @@ test.describe("User verification", () => { user: aliceCredentials, room: { roomId: dmRoomId }, }) => { - await waitForDevices(app, bob.credentials.userId, 1); + await waitForDevices(app, bob.credentials!.userId, 1); await expect(page.getByRole("button", { name: "Avatar" })).toBeVisible(); const avatar = page.getByRole("button", { name: "Avatar" }); await avatar.click(); @@ -47,14 +47,14 @@ test.describe("User verification", () => { // once Alice has joined, Bob starts the verification const bobVerificationRequest = await bob.evaluateHandle( async (client, { dmRoomId, aliceCredentials }) => { - const room = client.getRoom(dmRoomId); + const room = client.getRoom(dmRoomId)!; while (room.getMember(aliceCredentials.userId)?.membership !== "join") { await new Promise((resolve) => { room.once(window.matrixcs.RoomStateEvent.Members, resolve); }); } - return client.getCrypto().requestVerificationDM(aliceCredentials.userId, dmRoomId); + return client.getCrypto()!.requestVerificationDM(aliceCredentials.userId, dmRoomId); }, { dmRoomId, aliceCredentials }, ); @@ -62,7 +62,7 @@ test.describe("User verification", () => { // there should also be a toast const toast = await getToast(page, "Verification requested"); // it should contain the details of the requesting user - await expect(toast.getByText(`Bob (${bob.credentials.userId})`)).toBeVisible(); + await expect(toast.getByText(`Bob (${bob.credentials!.userId})`)).toBeVisible(); // Accept await toast.getByRole("button", { name: "Verify User" }).click(); @@ -93,7 +93,7 @@ test.describe("User verification", () => { user: aliceCredentials, room: { roomId: dmRoomId }, }) => { - await waitForDevices(app, bob.credentials.userId, 1); + await waitForDevices(app, bob.credentials!.userId, 1); await expect(page.getByRole("button", { name: "Avatar" })).toBeVisible(); const avatar = page.getByRole("button", { name: "Avatar" }); await avatar.click(); @@ -101,14 +101,14 @@ test.describe("User verification", () => { // once Alice has joined, Bob starts the verification const bobVerificationRequest = await bob.evaluateHandle( async (client, { dmRoomId, aliceCredentials }) => { - const room = client.getRoom(dmRoomId); + const room = client.getRoom(dmRoomId)!; while (room.getMember(aliceCredentials.userId)?.membership !== "join") { await new Promise((resolve) => { room.once(window.matrixcs.RoomStateEvent.Members, resolve); }); } - return client.getCrypto().requestVerificationDM(aliceCredentials.userId, dmRoomId); + return client.getCrypto()!.requestVerificationDM(aliceCredentials.userId, dmRoomId); }, { dmRoomId, aliceCredentials }, ); diff --git a/apps/web/playwright/e2e/crypto/utils.ts b/apps/web/playwright/e2e/crypto/utils.ts index be86a1aa1e..194a10bf22 100644 --- a/apps/web/playwright/e2e/crypto/utils.ts +++ b/apps/web/playwright/e2e/crypto/utils.ts @@ -51,7 +51,7 @@ export async function createBot( botClient.setCredentials(credentials); // Backup is prepared in the background. Poll until it is ready. const botClientHandle = await botClient.prepareClient(); - let expectedBackupVersion: string; + let expectedBackupVersion: string | null; await expect .poll(async () => { expectedBackupVersion = await botClientHandle.evaluate((cli) => @@ -63,7 +63,7 @@ export async function createBot( const recoveryKey = await botClient.getRecoveryKey(); - return { botClient, recoveryKey, expectedBackupVersion }; + return { botClient, recoveryKey, expectedBackupVersion: expectedBackupVersion! }; } /** @@ -98,13 +98,15 @@ export async function waitForVerificationRequest(client: Client): Promise): Promise { return verifier.evaluate((verifier) => { const event = verifier.getShowSasCallbacks(); - if (event) return event.sas.emoji; + if (event) { + return event.sas.emoji!; + } return new Promise((resolve) => { const onShowSas = (event: ShowSasCallbacks) => { verifier.off("show_sas" as VerifierEvent, onShowSas); void event.confirm(); - resolve(event.sas.emoji); + resolve(event.sas.emoji!); }; verifier.on("show_sas" as VerifierEvent, onShowSas); @@ -117,24 +119,24 @@ export function handleSasVerification(verifier: JSHandle): Promise { const { userId, deviceId, keys } = await app.client.evaluate(async (cli: MatrixClient) => { - const deviceId = cli.getDeviceId(); - const userId = cli.getUserId(); + const deviceId = cli.getDeviceId()!; + const userId = cli.getSafeUserId(); const keys = await cli.downloadKeysForUsers([userId]); return { userId, deviceId, keys }; }); // there should be three cross-signing keys - expect(keys.master_keys[userId]).toHaveProperty("keys"); - expect(keys.self_signing_keys[userId]).toHaveProperty("keys"); - expect(keys.user_signing_keys[userId]).toHaveProperty("keys"); + expect(keys.master_keys![userId]).toHaveProperty("keys"); + expect(keys.self_signing_keys![userId]).toHaveProperty("keys"); + expect(keys.user_signing_keys![userId]).toHaveProperty("keys"); // and the device should be signed by the self-signing key - const selfSigningKeyId = Object.keys(keys.self_signing_keys[userId].keys)[0]; + const selfSigningKeyId = Object.keys(keys.self_signing_keys![userId].keys)[0]; expect(keys.device_keys[userId][deviceId]).toBeDefined(); - const myDeviceSignatures = keys.device_keys[userId][deviceId].signatures[userId]; + const myDeviceSignatures = keys.device_keys[userId][deviceId].signatures![userId]; expect(myDeviceSignatures[selfSigningKeyId]).toBeDefined(); } @@ -190,7 +192,7 @@ export async function checkDeviceIsConnectedKeyBackup( // We have a key backup expect(backupInfo).toBeDefined(); // The key backup version is as expected - expect(backupInfo.version).toBe(expectedBackupVersion); + expect(backupInfo!.version).toBe(expectedBackupVersion); // The active backup version is as expected expect(activeBackupVersion).toBe(expectedBackupVersion); // The backup key is stored in 4S @@ -211,7 +213,7 @@ export async function logIntoElement(page: Page, credentials: Credentials) { await page.goto("/#/login"); await page.getByRole("textbox", { name: "Username" }).fill(credentials.userId); - await page.getByPlaceholder("Password").fill(credentials.password); + await page.getByPlaceholder("Password").fill(credentials.password!); await page.getByRole("button", { name: "Sign in" }).click(); } @@ -379,7 +381,7 @@ export async function completeCreateSecretStorageDialog( // the step is quite quick, and playwright can miss it, so we can't test for it. if (opts && Object.hasOwn(opts, "accountPassword")) { await expect(currentDialogLocator.getByRole("heading", { name: "Setting up keys" })).toBeVisible(); - await page.getByPlaceholder("Password").fill(opts!.accountPassword); + await page.getByPlaceholder("Password").fill(opts!.accountPassword!); await currentDialogLocator.getByRole("button", { name: "Continue" }).click(); } @@ -595,7 +597,7 @@ export async function createSecondBotDevice(page: Page, homeserver: HomeserverIn bootstrapSecretStorage: false, bootstrapCrossSigning: false, }); - bobSecondDevice.setCredentials(await homeserver.loginUser(bob.credentials.userId, bob.credentials.password)); + bobSecondDevice.setCredentials(await homeserver.loginUser(bob.credentials!.userId, bob.credentials!.password!)); await bobSecondDevice.prepareClient(); return bobSecondDevice; } @@ -638,7 +640,7 @@ export async function waitForDevices( for (let i = 0; i < 10; ++i) { const userDeviceMap = await cli.getCrypto()?.getUserDeviceInfo([userId], true); const deviceMap = userDeviceMap?.get(userId); - if (deviceMap.size === expectedNumberOfDevices) return true; + if (deviceMap?.size === expectedNumberOfDevices) return true; await new Promise((r) => setTimeout(r, 500)); } return false; diff --git a/apps/web/playwright/e2e/editing/editing.spec.ts b/apps/web/playwright/e2e/editing/editing.spec.ts index 9b0efecb26..8b8180c77b 100644 --- a/apps/web/playwright/e2e/editing/editing.spec.ts +++ b/apps/web/playwright/e2e/editing/editing.spec.ts @@ -362,7 +362,7 @@ test.describe("Editing", () => { const messageTile = page.locator(`[data-event-id="${originalEventId}"]`); // at this point, the edit event should still be unknown const timeline = await app.client.evaluate( - (cli, { testRoomId, editEventId }) => cli.getRoom(testRoomId).getTimelineForEvent(editEventId), + (cli, { testRoomId, editEventId }) => cli.getRoom(testRoomId)!.getTimelineForEvent(editEventId), { testRoomId, editEventId }, ); expect(timeline).toBeNull(); diff --git a/apps/web/playwright/e2e/feedback/rageshakes.spec.ts b/apps/web/playwright/e2e/feedback/rageshakes.spec.ts index 58476f04ac..9fae568c82 100644 --- a/apps/web/playwright/e2e/feedback/rageshakes.spec.ts +++ b/apps/web/playwright/e2e/feedback/rageshakes.spec.ts @@ -94,7 +94,7 @@ test.describe("Rageshakes", () => { if (request.method() !== "POST") { throw Error("Expected POST"); } - const fields = formDataParser(request.postData(), await request.headerValue("Content-Type")); + const fields = formDataParser(request.postData()!, await request.headerValue("Content-Type")); expect(fields.text).toEqual( "These are some notes\n\nIssue: https://github.com/element-hq/element-web/12345", ); diff --git a/apps/web/playwright/e2e/forgot-password/forgot-password.spec.ts b/apps/web/playwright/e2e/forgot-password/forgot-password.spec.ts index e692975958..1b9dad290c 100644 --- a/apps/web/playwright/e2e/forgot-password/forgot-password.spec.ts +++ b/apps/web/playwright/e2e/forgot-password/forgot-password.spec.ts @@ -56,7 +56,7 @@ test.describe("Forgot Password", () => { "renders email verification dialog properly", { tag: "@screenshot" }, async ({ page, homeserver, credentials }) => { - const user = await homeserver.registerUser(credentials.username, credentials.password); + const user = await homeserver.registerUser(credentials.username, credentials.password!); await homeserver.setThreepid(user.userId, "email", email); @@ -73,8 +73,8 @@ test.describe("Forgot Password", () => { await page.getByRole("button", { name: "Next" }).click(); - await page.getByRole("textbox", { name: "New Password", exact: true }).fill(credentials.password); - await page.getByRole("textbox", { name: "Confirm new password", exact: true }).fill(credentials.password); + await page.getByRole("textbox", { name: "New Password", exact: true }).fill(credentials.password!); + await page.getByRole("textbox", { name: "Confirm new password", exact: true }).fill(credentials.password!); await page.getByRole("button", { name: "Reset password" }).click(); diff --git a/apps/web/playwright/e2e/integration-manager/kick.spec.ts b/apps/web/playwright/e2e/integration-manager/kick.spec.ts index 152b19e542..e41d95d2bb 100644 --- a/apps/web/playwright/e2e/integration-manager/kick.spec.ts +++ b/apps/web/playwright/e2e/integration-manager/kick.spec.ts @@ -148,18 +148,23 @@ test.describe("Integration Manager: Kick", () => { test("should kick the target", async ({ page, app, bot: targetUser, room }) => { await app.viewRoomByName(ROOM_NAME); - await app.client.inviteUser(room.roomId, targetUser.credentials.userId); + await app.client.inviteUser(room.roomId, targetUser.credentials!.userId); await expect(page.getByText(`${BOT_DISPLAY_NAME} joined the room`)).toBeVisible(); await openIntegrationManager(app); - await sendActionFromIntegrationManager(page, integrationManagerUrl, room.roomId, targetUser.credentials.userId); + await sendActionFromIntegrationManager( + page, + integrationManagerUrl, + room.roomId, + targetUser.credentials!.userId, + ); await closeIntegrationManager(page, integrationManagerUrl); await expectKickedMessage(page, true); }); test("should not kick the target if lacking permissions", async ({ page, app, user, bot: targetUser, room }) => { await app.viewRoomByName(ROOM_NAME); - await app.client.inviteUser(room.roomId, targetUser.credentials.userId); + await app.client.inviteUser(room.roomId, targetUser.credentials!.userId); await expect(page.getByText(`${BOT_DISPLAY_NAME} joined the room`)).toBeVisible(); await app.client.sendStateEvent(room.roomId, "m.room.power_levels", { @@ -170,31 +175,46 @@ test.describe("Integration Manager: Kick", () => { }); await openIntegrationManager(app); - await sendActionFromIntegrationManager(page, integrationManagerUrl, room.roomId, targetUser.credentials.userId); + await sendActionFromIntegrationManager( + page, + integrationManagerUrl, + room.roomId, + targetUser.credentials!.userId, + ); await closeIntegrationManager(page, integrationManagerUrl); await expectKickedMessage(page, false); }); test("should no-op if the target already left", async ({ page, app, bot: targetUser, room }) => { await app.viewRoomByName(ROOM_NAME); - await app.client.inviteUser(room.roomId, targetUser.credentials.userId); + await app.client.inviteUser(room.roomId, targetUser.credentials!.userId); await expect(page.getByText(`${BOT_DISPLAY_NAME} joined the room`)).toBeVisible(); await targetUser.leave(room.roomId); await openIntegrationManager(app); - await sendActionFromIntegrationManager(page, integrationManagerUrl, room.roomId, targetUser.credentials.userId); + await sendActionFromIntegrationManager( + page, + integrationManagerUrl, + room.roomId, + targetUser.credentials!.userId, + ); await closeIntegrationManager(page, integrationManagerUrl); await expectKickedMessage(page, false); }); test("should no-op if the target was banned", async ({ page, app, bot: targetUser, room }) => { await app.viewRoomByName(ROOM_NAME); - await app.client.inviteUser(room.roomId, targetUser.credentials.userId); + await app.client.inviteUser(room.roomId, targetUser.credentials!.userId); await expect(page.getByText(`${BOT_DISPLAY_NAME} joined the room`)).toBeVisible(); - await app.client.ban(room.roomId, targetUser.credentials.userId); + await app.client.ban(room.roomId, targetUser.credentials!.userId); await openIntegrationManager(app); - await sendActionFromIntegrationManager(page, integrationManagerUrl, room.roomId, targetUser.credentials.userId); + await sendActionFromIntegrationManager( + page, + integrationManagerUrl, + room.roomId, + targetUser.credentials!.userId, + ); await closeIntegrationManager(page, integrationManagerUrl); await expectKickedMessage(page, false); }); @@ -203,7 +223,12 @@ test.describe("Integration Manager: Kick", () => { await app.viewRoomByName(ROOM_NAME); await openIntegrationManager(app); - await sendActionFromIntegrationManager(page, integrationManagerUrl, room.roomId, targetUser.credentials.userId); + await sendActionFromIntegrationManager( + page, + integrationManagerUrl, + room.roomId, + targetUser.credentials!.userId, + ); await closeIntegrationManager(page, integrationManagerUrl); await expectKickedMessage(page, false); }); diff --git a/apps/web/playwright/e2e/invite/invite-dialog.spec.ts b/apps/web/playwright/e2e/invite/invite-dialog.spec.ts index 080a7f21fb..ea518d588d 100644 --- a/apps/web/playwright/e2e/invite/invite-dialog.spec.ts +++ b/apps/web/playwright/e2e/invite/invite-dialog.spec.ts @@ -55,13 +55,13 @@ test.describe("Invite dialog", function () { await expect(other.locator(".mx_InviteDialog_identityServer")).not.toBeVisible(); - await other.getByTestId("invite-dialog-input").fill(bot.credentials.userId); + await other.getByTestId("invite-dialog-input").fill(bot.credentials!.userId); // Assert that notification about identity servers appears after typing userId await expect(other.locator(".mx_InviteDialog_identityServer")).toBeVisible(); // Assert that the bot id is rendered properly - await expect(other.getByRole("option", { name: botName }).getByText(bot.credentials.userId)).toBeVisible(); + await expect(other.getByRole("option", { name: botName }).getByText(bot.credentials!.userId)).toBeVisible(); await other.getByRole("option", { name: botName }).click(); @@ -112,9 +112,9 @@ test.describe("Invite dialog", function () { // Take a snapshot of the invite dialog await expect(page.locator(".mx_Dialog")).toMatchScreenshot("invite-dialog-dm-without-user.png"); - await other.getByTestId("invite-dialog-input").fill(bot.credentials.userId); + await other.getByTestId("invite-dialog-input").fill(bot.credentials!.userId); - await expect(other.getByRole("option", { name: botName }).getByText(bot.credentials.userId)).toBeVisible(); + await expect(other.getByRole("option", { name: botName }).getByText(bot.credentials!.userId)).toBeVisible(); await other.getByRole("option", { name: botName }).click(); await expect(other.getByTestId("invite-dialog-input-wrapper").getByText(botName)).toBeVisible(); diff --git a/apps/web/playwright/e2e/lazy-loading/lazy-loading.spec.ts b/apps/web/playwright/e2e/lazy-loading/lazy-loading.spec.ts index f6f098a079..7d286b27d4 100644 --- a/apps/web/playwright/e2e/lazy-loading/lazy-loading.spec.ts +++ b/apps/web/playwright/e2e/lazy-loading/lazy-loading.spec.ts @@ -80,8 +80,12 @@ test.describe("Lazy Loading", () => { async function checkPaginatedDisplayNames(app: ElementAppPage, charlies: Bot[]) { await app.timeline.scrollToTop(); for (const charly of charlies) { - await expect(await app.timeline.findEventTile(charly.credentials.displayName, charlyMsg1)).toBeAttached(); - await expect(await app.timeline.findEventTile(charly.credentials.displayName, charlyMsg2)).toBeAttached(); + await expect( + (await app.timeline.findEventTile(charly.credentials!.displayName!, charlyMsg1))!, + ).toBeAttached(); + await expect( + (await app.timeline.findEventTile(charly.credentials!.displayName!, charlyMsg2))!, + ).toBeAttached(); } } @@ -99,13 +103,13 @@ test.describe("Lazy Loading", () => { await expect(getMemberInMemberlist(page, "Alice")).toBeAttached(); await expect(getMemberInMemberlist(page, "Bob")).toBeAttached(); for (const charly of charlies) { - await expect(getMemberInMemberlist(page, charly.credentials.displayName)).toBeAttached(); + await expect(getMemberInMemberlist(page, charly.credentials!.displayName!)).toBeAttached(); } } async function checkMemberListLacksCharlies(page: Page, charlies: Bot[]) { for (const charly of charlies) { - await expect(getMemberInMemberlist(page, charly.credentials.displayName)).not.toBeAttached(); + await expect(getMemberInMemberlist(page, charly.credentials!.displayName!)).not.toBeAttached(); } } diff --git a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-collapse.spec.ts b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-collapse.spec.ts index 1649cdc5c6..977b0ffa24 100644 --- a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-collapse.spec.ts +++ b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-collapse.spec.ts @@ -33,8 +33,8 @@ test.describe("Collapsible Room list", () => { const boundingBox = await leftPanelLocator.boundingBox(); // Move mouse 2px to the right of the left-panel, this should be region that the user drags to resize the panel. - const mouseX = boundingBox.x + boundingBox.width + 2; - const mouseY = boundingBox.y + boundingBox.height / 2; + const mouseX = boundingBox!.x + boundingBox!.width + 2; + const mouseY = boundingBox!.y + boundingBox!.height / 2; await page.mouse.move(mouseX, mouseY); await page.mouse.down(); @@ -50,12 +50,12 @@ test.describe("Collapsible Room list", () => { // Contract the panel let previousBoundingBox = await resize(page, -50); let currentBoundingBox = await leftPanelLocator.boundingBox(); - expect(currentBoundingBox.width).toBeCloseTo(previousBoundingBox.width - 50, 0); + expect(currentBoundingBox!.width).toBeCloseTo(previousBoundingBox!.width - 50, 0); // Expand the panel previousBoundingBox = await resize(page, 30); currentBoundingBox = await leftPanelLocator.boundingBox(); - expect(currentBoundingBox.width).toBeCloseTo(previousBoundingBox.width + 30, 0); + expect(currentBoundingBox!.width).toBeCloseTo(previousBoundingBox!.width + 30, 0); }); test( @@ -67,7 +67,7 @@ test.describe("Collapsible Room list", () => { // Collapse the panel await resize(page, -300); let currentBoundingBox = await leftPanelLocator.boundingBox(); - expect(currentBoundingBox.width).toStrictEqual(0); + expect(currentBoundingBox!.width).toStrictEqual(0); // Expect te separator to be shown const separator = page.getByRole("separator", { name: "Click or drag to expand" }); @@ -77,19 +77,19 @@ test.describe("Collapsible Room list", () => { // Should be possible to expand by clicking on the separator await separator.click(); currentBoundingBox = await leftPanelLocator.boundingBox(); - expect(currentBoundingBox.width).toBeGreaterThan(365); + expect(currentBoundingBox!.width).toBeGreaterThan(365); // Collapse the panel again await resize(page, -300); // Check that the panel can be expanded by dragging the separator const separatorBoundingBox = await separator.boundingBox(); - const mouseX = separatorBoundingBox.x + separatorBoundingBox.width / 2; - const mouseY = separatorBoundingBox.y + separatorBoundingBox.height / 2; + const mouseX = separatorBoundingBox!.x + separatorBoundingBox!.width / 2; + const mouseY = separatorBoundingBox!.y + separatorBoundingBox!.height / 2; await page.mouse.move(mouseX, mouseY); await page.mouse.down(); await page.mouse.move(mouseX + 400, mouseY); - expect(currentBoundingBox.width).toBeGreaterThan(365); + expect(currentBoundingBox!.width).toBeGreaterThan(365); }, ); }); diff --git a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-filter-sort.spec.ts b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-filter-sort.spec.ts index 12afa1cc6b..4488d66cc8 100644 --- a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-filter-sort.spec.ts +++ b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-filter-sort.spec.ts @@ -48,7 +48,7 @@ test.describe("Room list filters and sort", () => { We will also send a simple message in this room. */ const oldRoomId = await app.client.createRoom({ name: "Old Room" }); - await app.client.inviteUser(oldRoomId, bot.credentials.userId); + await app.client.inviteUser(oldRoomId, bot.credentials!.userId); await bot.joinRoom(oldRoomId); const response = await app.client.sendMessage(oldRoomId, "Hello!"); @@ -99,8 +99,8 @@ test.describe("Room list filters and sort", () => { }); test.describe("Room list", () => { - let unReadDmId: string | undefined; - let unReadRoomId: string | undefined; + let unReadDmId: string; + let unReadRoomId: string; test.beforeEach(async ({ page, app, bot, user }) => { await app.client.createRoom({ name: "empty room" }); @@ -114,7 +114,7 @@ test.describe("Room list filters and sort", () => { await bot.sendMessage(unReadDmId, "I am a robot. Beep."); unReadRoomId = await app.client.createRoom({ name: "unread room" }); - await app.client.inviteUser(unReadRoomId, bot.credentials.userId); + await app.client.inviteUser(unReadRoomId, bot.credentials!.userId); await bot.joinRoom(unReadRoomId); await bot.sendMessage(unReadRoomId, "I am a robot. Beep."); @@ -135,7 +135,7 @@ test.describe("Room list filters and sort", () => { }); const mentionRoomId = await app.client.createRoom({ name: "room with mention" }); - await app.client.inviteUser(mentionRoomId, bot.credentials.userId); + await app.client.inviteUser(mentionRoomId, bot.credentials!.userId); await bot.joinRoom(mentionRoomId); const clientBot = await bot.prepareClient(); diff --git a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-sections.spec.ts b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-sections.spec.ts index 88e15ed9bc..5e36ff01a2 100644 --- a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-sections.spec.ts +++ b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-sections.spec.ts @@ -364,7 +364,7 @@ test.describe("Room list sections", () => { const roomList = getRoomList(page); // Invite the bot and have it send a message to generate an unread - await app.client.inviteUser(favouriteId, bot.credentials.userId); + await app.client.inviteUser(favouriteId, bot.credentials!.userId); await bot.joinRoom(favouriteId); await bot.sendMessage(favouriteId, "Hello from bot!"); @@ -391,7 +391,7 @@ test.describe("Room list sections", () => { // A room with a mention, landing in the Chats section const mentionId = await app.client.createRoom({ name: "mention room" }); - await app.client.inviteUser(mentionId, bot.credentials.userId); + await app.client.inviteUser(mentionId, bot.credentials!.userId); await bot.joinRoom(mentionId); const clientBot = await bot.prepareClient(); await clientBot.evaluate( @@ -464,13 +464,13 @@ test.describe("Room list sections", () => { await app.client.evaluate(async (client, roomId) => { await client.setRoomTag(roomId, "m.favourite"); }, favouriteId); - await app.client.inviteUser(favouriteId, bot.credentials.userId); + await app.client.inviteUser(favouriteId, bot.credentials!.userId); await bot.joinRoom(favouriteId); await bot.sendMessage(favouriteId, "Hello from favourite!"); // Create a regular room with unread messages const regularId = await app.client.createRoom({ name: "regular with unread" }); - await app.client.inviteUser(regularId, bot.credentials.userId); + await app.client.inviteUser(regularId, bot.credentials!.userId); await bot.joinRoom(regularId); await bot.sendMessage(regularId, "Hello from regular!"); diff --git a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-unread-toast.spec.ts b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-unread-toast.spec.ts index d469bae40e..d4bb2a4e1f 100644 --- a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-unread-toast.spec.ts +++ b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-unread-toast.spec.ts @@ -62,7 +62,7 @@ test.describe("Room list unread activity toast", () => { // A room with a real notification count, named so it sorts to the very bottom under A-Z. const targetId = await app.client.createRoom({ name: "zzz unread room" }); - await app.client.inviteUser(targetId, bot.credentials.userId); + await app.client.inviteUser(targetId, bot.credentials!.userId); await bot.joinRoom(targetId); // Enough filler rooms to push the target well below the visible area. @@ -100,7 +100,7 @@ test.describe("Room list unread activity toast", () => { // The target's unread state will only ever be an activity dot, never a notification count: set it // to "@mentions & keywords" so a plain (non-mention) message produces activity rather than a count. const targetId = await app.client.createRoom({ name: "zzz activity room" }); - await app.client.inviteUser(targetId, bot.credentials.userId); + await app.client.inviteUser(targetId, bot.credentials!.userId); await bot.joinRoom(targetId); await app.viewRoomById(targetId); @@ -148,7 +148,7 @@ test.describe("Room list unread activity toast", () => { // A regular (Chats) room with a notification count. const notifyId = await app.client.createRoom({ name: "chats notify room" }); - await app.client.inviteUser(notifyId, bot.credentials.userId); + await app.client.inviteUser(notifyId, bot.credentials!.userId); await bot.joinRoom(notifyId); // A favourite room so the list renders in section mode from the start. diff --git a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list.spec.ts b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list.spec.ts index 2a84ea8280..a0135d725a 100644 --- a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list.spec.ts +++ b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list.spec.ts @@ -192,7 +192,7 @@ test.describe("Room list", () => { const roomListView = getRoomList(page); const roomId = await app.client.createRoom({ name: "1 notification" }); - await app.client.inviteUser(roomId, bot.credentials.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); await bot.joinRoom(roomId); await bot.sendMessage(roomId, "I am a robot. Beep."); @@ -396,7 +396,7 @@ test.describe("Room list", () => { const roomListView = getRoomList(page); const roomId = await app.client.createRoom({ name: "2 notifications" }); - await app.client.inviteUser(roomId, bot.credentials.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); await bot.joinRoom(roomId); await bot.sendMessage(roomId, "I am a robot. Beep."); @@ -412,7 +412,7 @@ test.describe("Room list", () => { const roomListView = getRoomList(page); const roomId = await app.client.createRoom({ name: "mention" }); - await app.client.inviteUser(roomId, bot.credentials.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); await bot.joinRoom(roomId); const clientBot = await bot.prepareClient(); @@ -445,7 +445,7 @@ test.describe("Room list", () => { // focus the user menu to avoid to have hover decoration await page.getByRole("button", { name: "User menu" }).focus(); - await app.client.inviteUser(roomId, bot.credentials.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); await bot.joinRoom(roomId); await bot.sendMessage(roomId, "I am a robot. Beep."); @@ -483,7 +483,7 @@ test.describe("Room list", () => { const otherRoomId = await app.client.createRoom({ name: "other room" }); const roomId = await app.client.createRoom({ name: "activity" }); - await app.client.inviteUser(roomId, bot.credentials.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); await bot.joinRoom(roomId); await app.viewRoomById(roomId); @@ -510,7 +510,7 @@ test.describe("Room list", () => { const roomListView = getRoomList(page); const roomId = await app.client.createRoom({ name: "mark as unread" }); - await app.client.inviteUser(roomId, bot.credentials.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); await bot.joinRoom(roomId); const room = roomListView.getByRole("option", { name: "mark as unread" }); @@ -527,7 +527,7 @@ test.describe("Room list", () => { const roomListView = getRoomList(page); const roomId = await app.client.createRoom({ name: "silent" }); - await app.client.inviteUser(roomId, bot.credentials.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); await bot.joinRoom(roomId); await app.viewRoomById(roomId); diff --git a/apps/web/playwright/e2e/links/permalinks.spec.ts b/apps/web/playwright/e2e/links/permalinks.spec.ts index cd1aa5c42e..6463475608 100644 --- a/apps/web/playwright/e2e/links/permalinks.spec.ts +++ b/apps/web/playwright/e2e/links/permalinks.spec.ts @@ -38,8 +38,8 @@ test.describe("permalinks", () => { await app.viewRoomByName(room1Name); - await app.client.inviteUser(room1Id, bob.credentials.userId); - await app.client.inviteUser(room2Id, charlotte.credentials.userId); + await app.client.inviteUser(room1Id, bob.credentials!.userId); + await app.client.inviteUser(room2Id, charlotte.credentials!.userId); await app.client.sendMessage(room1Id, "At room mention: @room"); @@ -65,11 +65,11 @@ test.describe("permalinks", () => { await app.client.sendMessage( room1Id, - `Permalink to a user in the room: ${permalinkPrefix}${bob.credentials.userId}`, + `Permalink to a user in the room: ${permalinkPrefix}${bob.credentials!.userId}`, ); await app.client.sendMessage( room1Id, - `Permalink to a user in another room: ${permalinkPrefix}${charlotte.credentials.userId}`, + `Permalink to a user in another room: ${permalinkPrefix}${charlotte.credentials!.userId}`, ); await app.client.sendMessage( room1Id, @@ -117,14 +117,14 @@ test.describe("triple-click message selection", () => { await bot.prepareClient(); const roomId = await app.client.createRoom({ name: "Test Room" }); - await app.client.inviteUser(roomId, bot.credentials.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); await app.viewRoomByName("Test Room"); // Send a message with user and room pills await app.client.sendMessage( roomId, `Testing triple-click message selection. ` + - `User: ${permalinkPrefix}${bot.credentials.userId}, ` + + `User: ${permalinkPrefix}${bot.credentials!.userId}, ` + `Room: ${permalinkPrefix}${roomId}, ` + `Message: ${permalinkPrefix}${roomId}/$dummy-event, ` + `and @room mention.`, diff --git a/apps/web/playwright/e2e/login/login-consent.spec.ts b/apps/web/playwright/e2e/login/login-consent.spec.ts index 094e73f8b2..f9aa7442dc 100644 --- a/apps/web/playwright/e2e/login/login-consent.spec.ts +++ b/apps/web/playwright/e2e/login/login-consent.spec.ts @@ -75,7 +75,7 @@ async function login(page: Page, homeserver: HomeserverInstance, credentials: Cr await selectHomeserver(page, homeserver.baseUrl); await page.getByRole("textbox", { name: "Username" }).fill(credentials.username); - await page.getByPlaceholder("Password").fill(credentials.password); + await page.getByPlaceholder("Password").fill(credentials.password!); await page.getByRole("button", { name: "Sign in" }).click(); } @@ -152,7 +152,7 @@ test.describe("Login", () => { await expect(axe).toHaveNoViolations(); await page.getByRole("textbox", { name: "Username" }).fill(credentials.username); - await page.getByPlaceholder("Password").fill(credentials.password); + await page.getByPlaceholder("Password").fill(credentials.password!); await page.getByRole("button", { name: "Sign in" }).click(); await expect(page).toHaveURL(/\/#\/home$/); @@ -323,7 +323,7 @@ test.describe("Login", () => { // Finally we actually continue await page.getByRole("button", { name: "Continue" }).click(); - await page.getByPlaceholder("Password").fill(credentials.password); + await page.getByPlaceholder("Password").fill(credentials.password!); await page.getByRole("button", { name: "Continue" }).click(); // We end up at the Home screen @@ -336,7 +336,7 @@ test.describe("Login", () => { test.describe("logout", () => { test("should go to welcome page on logout", async ({ page, user }) => { await page.getByRole("button", { name: "User menu" }).click(); - await expect(page.getByText(user.displayName, { exact: true })).toBeVisible(); + await expect(page.getByText(user.displayName!, { exact: true })).toBeVisible(); // Allow the outstanding requests queue to settle before logging out await page.waitForTimeout(2000); diff --git a/apps/web/playwright/e2e/login/logout_redirect_url.spec.ts b/apps/web/playwright/e2e/login/logout_redirect_url.spec.ts index ab83394a0d..1da1917dcb 100644 --- a/apps/web/playwright/e2e/login/logout_redirect_url.spec.ts +++ b/apps/web/playwright/e2e/login/logout_redirect_url.spec.ts @@ -24,7 +24,7 @@ test.use({ test.describe("logout with logout_redirect_url", () => { test("should respect logout_redirect_url", async ({ page, user }) => { await page.getByRole("button", { name: "User menu" }).click(); - await expect(page.getByText(user.displayName, { exact: true })).toBeVisible(); + await expect(page.getByText(user.displayName!, { exact: true })).toBeVisible(); // give a change for the outstanding requests queue to settle before logging out await page.waitForTimeout(2000); diff --git a/apps/web/playwright/e2e/login/soft_logout.spec.ts b/apps/web/playwright/e2e/login/soft_logout.spec.ts index 2c9325e757..23293c67bd 100644 --- a/apps/web/playwright/e2e/login/soft_logout.spec.ts +++ b/apps/web/playwright/e2e/login/soft_logout.spec.ts @@ -26,7 +26,7 @@ test.describe("Soft logout with password user", () => { test("shows the soft-logout page when a request fails, and allows a re-login", async ({ page, user }) => { await interceptRequestsWithSoftLogout(page, user); await expect(page.getByText("You're signed out")).toBeVisible(); - await page.getByPlaceholder("Password").fill(user.password); + await page.getByPlaceholder("Password").fill(user.password!); await page.getByPlaceholder("Password").press("Enter"); // back to the welcome page diff --git a/apps/web/playwright/e2e/login/utils.ts b/apps/web/playwright/e2e/login/utils.ts index e9ff05bb69..82681bfe55 100644 --- a/apps/web/playwright/e2e/login/utils.ts +++ b/apps/web/playwright/e2e/login/utils.ts @@ -52,13 +52,13 @@ export async function doTokenRegistration( return page.evaluate(() => ({ homeserverBaseUrl: window.mxMatrixClientPeg.get().getHomeserverUrl(), - accessToken: window.mxMatrixClientPeg.get().getAccessToken(), - userId: window.mxMatrixClientPeg.get().getUserId(), - deviceId: window.mxMatrixClientPeg.get().getDeviceId(), + accessToken: window.mxMatrixClientPeg.get().getAccessToken()!, + userId: window.mxMatrixClientPeg.get().getSafeUserId(), + deviceId: window.mxMatrixClientPeg.get().getDeviceId()!, homeServer: window.mxMatrixClientPeg.get().getHomeserverUrl(), password: null, displayName: "Alice", - username: window.mxMatrixClientPeg.get().getUserIdLocalpart(), + username: window.mxMatrixClientPeg.get().getUserIdLocalpart()!, })); } diff --git a/apps/web/playwright/e2e/oidc/index.ts b/apps/web/playwright/e2e/oidc/index.ts index 2cc6d48176..37838acf21 100644 --- a/apps/web/playwright/e2e/oidc/index.ts +++ b/apps/web/playwright/e2e/oidc/index.ts @@ -30,12 +30,12 @@ export async function registerAccountMas( await page.getByRole("textbox", { name: "Confirm Password" }).fill(password); await page.getByRole("button", { name: "Continue" }).click(); - let code: string; + let code!: string; await expect(async () => { const messages = await mailpit.listMessages(); expect(messages.messages[0].To[0].Address).toEqual(email); const text = await mailpit.renderMessageText(messages.messages[0].ID); - [, code] = text.match(/Your verification code to confirm this email address is: (\d{6})/); + [, code] = text.match(/Your verification code to confirm this email address is: (\d{6})/)!; }).toPass(); await page.getByRole("textbox", { name: "6-digit code" }).fill(code); diff --git a/apps/web/playwright/e2e/oidc/oidc-native.spec.ts b/apps/web/playwright/e2e/oidc/oidc-native.spec.ts index 0e54411e58..dd797f9d6a 100644 --- a/apps/web/playwright/e2e/oidc/oidc-native.spec.ts +++ b/apps/web/playwright/e2e/oidc/oidc-native.spec.ts @@ -29,7 +29,7 @@ test.describe("OIDC Native", { tag: ["@no-firefox", "@no-webkit"] }, () => { }, testInfo) => { await page.clock.install(); - const tokenUri = `${mas.baseUrl}/oauth2/token`; + const tokenUri = `${mas!.baseUrl}/oauth2/token`; const tokenApiPromise = page.waitForRequest( (request) => request.url() === tokenUri && request.postDataJSON()["grant_type"] === "authorization_code", ); @@ -66,7 +66,7 @@ test.describe("OIDC Native", { tag: ["@no-firefox", "@no-webkit"] }, () => { await newPage.close(); // Assert logging out revokes both tokens - const revokeUri = `${mas.baseUrl}/oauth2/revoke`; + const revokeUri = `${mas!.baseUrl}/oauth2/revoke`; const revokeAccessTokenPromise = page.waitForRequest( (request) => request.url() === revokeUri && request.postDataJSON()["token_type_hint"] === "access_token", ); @@ -95,7 +95,7 @@ test.describe("OIDC Native", { tag: ["@no-firefox", "@no-webkit"] }, () => { await expect(page.getByText("Welcome")).toBeVisible(); await page.goto("about:blank"); - const result = await mas.manage("kill-sessions", userId); + const result = await mas!.manage("kill-sessions", userId); expect(result.output).toContain("Ended 1 active OAuth 2.0 session"); await page.goto("http://localhost:8080"); diff --git a/apps/web/playwright/e2e/one-to-one-chat/one-to-one-chat.spec.ts b/apps/web/playwright/e2e/one-to-one-chat/one-to-one-chat.spec.ts index 6ad69deba9..312084c895 100644 --- a/apps/web/playwright/e2e/one-to-one-chat/one-to-one-chat.spec.ts +++ b/apps/web/playwright/e2e/one-to-one-chat/one-to-one-chat.spec.ts @@ -12,7 +12,7 @@ import { type Credentials } from "../../plugins/homeserver"; import { isDendrite } from "../../plugins/homeserver/dendrite"; const test = base.extend<{ - user2?: Credentials; + user2: Credentials; }>({}); test.describe("1:1 chat room", () => { @@ -38,12 +38,12 @@ test.describe("1:1 chat room", () => { // wait till the room was left await expect( - page.getByRole("group", { name: "Rooms" }).locator(".mx_RoomTile").getByText(user2.displayName), + page.getByRole("group", { name: "Rooms" }).locator(".mx_RoomTile").getByText(user2.displayName!), ).not.toBeVisible(); await page.waitForTimeout(500); // avoid race condition with routing // open new 1:1 chat room await page.goto(`/#/user/${user2.userId}?action=chat`); - await expect(page.locator(".mx_RoomHeader_heading").getByText(user2.displayName)).toBeVisible(); + await expect(page.locator(".mx_RoomHeader_heading").getByText(user2.displayName!)).toBeVisible(); }); }); diff --git a/apps/web/playwright/e2e/pinned-messages/index.ts b/apps/web/playwright/e2e/pinned-messages/index.ts index 793dc1b45e..c3a326be32 100644 --- a/apps/web/playwright/e2e/pinned-messages/index.ts +++ b/apps/web/playwright/e2e/pinned-messages/index.ts @@ -19,7 +19,7 @@ type RoomRef = { name: string; roomId: string }; * Set up for pinned message tests. */ export const test = base.extend<{ - room1Name?: string; + room1Name: string; room1: { name: string; roomId: string }; util: Helpers; }>({ @@ -28,7 +28,7 @@ export const test = base.extend<{ room1Name: "Room 1", room1: async ({ room1Name: name, app, user, bot }, use) => { - const roomId = await app.client.createRoom({ name, invite: [bot.credentials.userId] }); + const roomId = await app.client.createRoom({ name, invite: [bot.credentials!.userId] }); await bot.awaitRoomMembership(roomId); await use({ name, roomId }); }, diff --git a/apps/web/playwright/e2e/polls/pollHistory.spec.ts b/apps/web/playwright/e2e/polls/pollHistory.spec.ts index 4f2adff40d..71271a3986 100644 --- a/apps/web/playwright/e2e/polls/pollHistory.spec.ts +++ b/apps/web/playwright/e2e/polls/pollHistory.spec.ts @@ -95,7 +95,7 @@ test.describe("Poll history", () => { const roomId = await app.client.createRoom({}); - await app.client.inviteUser(roomId, bot.credentials.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); await page.goto("/#/room/" + roomId); // wait until Bob joined await expect(page.getByText("BotBob joined the room")).toBeAttached(); diff --git a/apps/web/playwright/e2e/polls/polls.spec.ts b/apps/web/playwright/e2e/polls/polls.spec.ts index f10b46f209..9452b2f9f0 100644 --- a/apps/web/playwright/e2e/polls/polls.spec.ts +++ b/apps/web/playwright/e2e/polls/polls.spec.ts @@ -98,7 +98,7 @@ test.describe("Polls", () => { test("should be creatable and votable", { tag: "@screenshot" }, async ({ page, app, bot, user }) => { const roomId: string = await app.client.createRoom({}); - await app.client.inviteUser(roomId, bot.credentials.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); await page.goto("/#/room/" + roomId); // wait until Bob joined await expect(page.getByText("BotBob joined the room")).toBeAttached(); @@ -116,10 +116,10 @@ test.describe("Polls", () => { await createPoll(page, pollParams); // Wait for message to send, get its ID and save as @pollId - const pollId = await page + const pollId = (await page .locator(".mx_RoomView_body .mx_EventTile[data-scroll-tokens]") .filter({ hasText: pollParams.title }) - .getAttribute("data-scroll-tokens"); + .getAttribute("data-scroll-tokens"))!; await expect(getPollTile(page, pollId)).toMatchScreenshot("Polls_Timeline_tile_no_votes.png", { css: ` .mx_MessageTimestamp { @@ -162,7 +162,7 @@ test.describe("Polls", () => { test("should be editable from context menu if no votes have been cast", async ({ page, app, user, bot }) => { const roomId: string = await app.client.createRoom({}); - await app.client.inviteUser(roomId, bot.credentials.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); await page.goto("/#/room/" + roomId); const locator = await app.openMessageComposerOptions(); @@ -175,10 +175,10 @@ test.describe("Polls", () => { await createPoll(page, pollParams); // Wait for message to send, get its ID and save as @pollId - const pollId = await page + const pollId = (await page .locator(".mx_RoomView_body .mx_EventTile[data-scroll-tokens]") .filter({ hasText: pollParams.title }) - .getAttribute("data-scroll-tokens"); + .getAttribute("data-scroll-tokens"))!; // Open context menu await getPollTile(page, pollId).click({ button: "right" }); @@ -192,7 +192,7 @@ test.describe("Polls", () => { test("should not be editable from context menu if votes have been cast", async ({ page, app, user, bot }) => { const roomId: string = await app.client.createRoom({}); - await app.client.inviteUser(roomId, bot.credentials.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); await page.goto("/#/room/" + roomId); const locator = await app.openMessageComposerOptions(); @@ -205,10 +205,10 @@ test.describe("Polls", () => { await createPoll(page, pollParams); // Wait for message to send, get its ID and save as @pollId - const pollId = await page + const pollId = (await page .locator(".mx_RoomView_body .mx_EventTile[data-scroll-tokens]") .filter({ hasText: pollParams.title }) - .getAttribute("data-scroll-tokens"); + .getAttribute("data-scroll-tokens"))!; // Bot votes 'Maybe' in the poll await botVoteForOption(page, bot, roomId, pollId, pollParams.options[2]); @@ -234,8 +234,8 @@ test.describe("Polls", () => { await botCharlie.prepareClient(); const roomId: string = await app.client.createRoom({}); - await app.client.inviteUser(roomId, bot.credentials.userId); - await app.client.inviteUser(roomId, botCharlie.credentials.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); + await app.client.inviteUser(roomId, botCharlie.credentials!.userId); await page.goto("/#/room/" + roomId); // wait until the bots joined @@ -253,10 +253,10 @@ test.describe("Polls", () => { await createPoll(page, pollParams); // Wait for message to send, get its ID and save as @pollId - const pollId = await page + const pollId = (await page .locator(".mx_RoomView_body .mx_EventTile[data-scroll-tokens]") .filter({ hasText: pollParams.title }) - .getAttribute("data-scroll-tokens"); + .getAttribute("data-scroll-tokens"))!; // Bob starts thread on the poll await bot.sendMessage( diff --git a/apps/web/playwright/e2e/presence/presence.spec.ts b/apps/web/playwright/e2e/presence/presence.spec.ts index 684fd8a5bf..b451d307e2 100644 --- a/apps/web/playwright/e2e/presence/presence.spec.ts +++ b/apps/web/playwright/e2e/presence/presence.spec.ts @@ -18,7 +18,7 @@ test.describe("Presence tests", () => { // This is failing on CI (https://github.com/element-hq/element-web/issues/27270) // but not locally, so debugging this is going to be tricky. Let's disable it for now. test.skip("renders unreachable presence state correctly", async ({ page, app, user, bot: bob }) => { - await app.client.createRoom({ name: "My Room", invite: [bob.credentials.userId] }); + await app.client.createRoom({ name: "My Room", invite: [bob.credentials!.userId] }); await app.viewRoomByName("My Room"); await bob.evaluate(async (client) => { @@ -36,7 +36,7 @@ test.describe("Presence tests", () => { events: [ { type: "m.presence", - sender: bob.credentials.userId, + sender: bob.credentials!.userId, content: { presence: "io.element.unreachable", currently_active: false, diff --git a/apps/web/playwright/e2e/read-receipts/high-level.spec.ts b/apps/web/playwright/e2e/read-receipts/high-level.spec.ts index a723928c57..d3d2e5765c 100644 --- a/apps/web/playwright/e2e/read-receipts/high-level.spec.ts +++ b/apps/web/playwright/e2e/read-receipts/high-level.spec.ts @@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details. /* See readme.md for tips on writing these tests. */ -import { customEvent, many, test } from "."; +import { many, test } from "."; import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Read receipts", { tag: "@mergequeue" }, () => { @@ -20,6 +20,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => { roomAlpha: room1, roomBeta: room2, util, + msg, }) => { await util.goTo(room1); await util.assertRead(room2); @@ -29,13 +30,14 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => { await util.markAsRead(room2); await util.assertRead(room2); - await util.receiveMessages(room2, [customEvent("org.custom.event", { body: "foobar" })]); + await util.receiveMessages(room2, [msg.customEvent("org.custom.event", { body: "foobar" })]); await util.assertRead(room2); }); test("Sending an important event after unimportant ones makes the room unread", async ({ roomAlpha: room1, roomBeta: room2, util, + msg, }) => { // Given We have read the important messages await util.goTo(room1); @@ -47,7 +49,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => { await util.goTo(room1); // When we receive unimportant messages - await util.receiveMessages(room2, [customEvent("org.custom.event", { body: "foobar" })]); + await util.receiveMessages(room2, [msg.customEvent("org.custom.event", { body: "foobar" })]); // Then the room is still read await util.assertStillRead(room2); @@ -62,6 +64,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => { roomAlpha: room1, roomBeta: room2, util, + msg, }) => { // Display room 1 await util.goTo(room1); @@ -71,9 +74,9 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => { // We received 3 unimportant messages to room2 await util.receiveMessages(room2, [ - customEvent("org.custom.event", { body: "foobar1" }), - customEvent("org.custom.event", { body: "foobar2" }), - customEvent("org.custom.event", { body: "foobar3" }), + msg.customEvent("org.custom.event", { body: "foobar1" }), + msg.customEvent("org.custom.event", { body: "foobar2" }), + msg.customEvent("org.custom.event", { body: "foobar3" }), ]); // The room 2 is still read diff --git a/apps/web/playwright/e2e/read-receipts/index.ts b/apps/web/playwright/e2e/read-receipts/index.ts index ee8cbb0667..1df837a236 100644 --- a/apps/web/playwright/e2e/read-receipts/index.ts +++ b/apps/web/playwright/e2e/read-receipts/index.ts @@ -23,9 +23,9 @@ type RoomRef = { name: string; roomId: string }; * - Invite the bot to both rooms and ensure that it has joined */ export const test = base.extend<{ - roomAlphaName?: string; + roomAlphaName: string; roomAlpha: RoomRef; - roomBetaName?: string; + roomBetaName: string; roomBeta: RoomRef; msg: MessageBuilder; util: Helpers; @@ -35,13 +35,13 @@ export const test = base.extend<{ roomAlphaName: "Room Alpha", roomAlpha: async ({ roomAlphaName: name, app, user, bot }, use) => { - const roomId = await app.client.createRoom({ name, invite: [bot.credentials.userId] }); + const roomId = await app.client.createRoom({ name, invite: [bot.credentials!.userId] }); await bot.awaitRoomMembership(roomId); await use({ name, roomId }); }, roomBetaName: "Room Beta", roomBeta: async ({ roomBetaName: name, app, user, bot }, use) => { - const roomId = await app.client.createRoom({ name, invite: [bot.credentials.userId] }); + const roomId = await app.client.createRoom({ name, invite: [bot.credentials!.userId] }); await bot.awaitRoomMembership(roomId); await use({ name, roomId }); }, @@ -159,7 +159,7 @@ export class MessageBuilder { ev.getRelation()?.rel_type === "m.thread" ? { rel_type: "m.thread", - event_id: ev.getRelation().event_id, + event_id: ev.getRelation()!.event_id, } : {}; @@ -222,11 +222,11 @@ export class MessageBuilder { public async performAction(bot: Bot, room: JSHandle): Promise { const ev = await this.messageFinder.getMessage(room, targetMessage, true); const { id, threadId } = await ev.evaluate((ev) => ({ - id: ev.getId(), + id: ev.getId()!, threadId: !ev.isThreadRoot ? ev.threadRootId : undefined, })); const roomId = await room.evaluate((room) => room.roomId); - await bot.reactToMessage(roomId, threadId, id, reaction); + await bot.reactToMessage(roomId, threadId ?? null, id, reaction); } })(this); } @@ -240,11 +240,11 @@ export class MessageBuilder { public async performAction(bot: Bot, room: JSHandle): Promise { const ev = await this.messageFinder.getMessage(room, targetMessage, true); const { id, threadId } = await ev.evaluate((ev) => ({ - id: ev.getId(), + id: ev.getId()!, threadId: !ev.isThreadRoot ? ev.threadRootId : undefined, })); const roomId = await room.evaluate((room) => room.roomId); - await bot.redactEvent(roomId, threadId, id); + await bot.redactEvent(roomId, threadId!, id); } })(this); } @@ -286,6 +286,20 @@ export class MessageBuilder { { event }, ); } + + /** + * BotActionSpec to send a custom event + * @param eventType - the type of the event to send + * @param content - the event content to send + */ + customEvent(eventType: string, content: Record): BotActionSpec { + return new (class extends BotActionSpec { + public async performAction(cli: Client, room: JSHandle): Promise { + const roomId = await room.evaluate((room) => room.roomId); + await cli.sendEvent(roomId, null, eventType, content); + } + })(this); + } } /** @@ -295,11 +309,7 @@ export class MessageBuilder { * MessageBuilder.replyTo} which creates a reply based on a previous message. */ export abstract class MessageContentSpec { - messageFinder: MessageBuilder | null; - - constructor(messageFinder: MessageBuilder = null) { - this.messageFinder = messageFinder; - } + constructor(public readonly messageFinder: MessageBuilder) {} public abstract getContent(room: JSHandle): Promise>; } @@ -312,11 +322,7 @@ export abstract class MessageContentSpec { * MessageBuilder.redactionOf} which redacts the message we are referring to. */ export abstract class BotActionSpec { - messageFinder: MessageBuilder | null; - - constructor(messageFinder: MessageBuilder = null) { - this.messageFinder = messageFinder; - } + constructor(public readonly messageFinder: MessageBuilder) {} public abstract performAction(client: Client, room: JSHandle): Promise; } @@ -542,7 +548,7 @@ class Helpers { async findRoomById(roomId: string): Promise> { return this.app.client.evaluateHandle((cli, roomId) => { - return cli.getRooms().find((r) => r.roomId === roomId); + return cli.getRooms().find((r) => r.roomId === roomId)!; }, roomId); } @@ -614,20 +620,6 @@ class Helpers { } } -/** - * BotActionSpec to send a custom event - * @param eventType - the type of the event to send - * @param content - the event content to send - */ -export function customEvent(eventType: string, content: Record): BotActionSpec { - return new (class extends BotActionSpec { - public async performAction(cli: Client, room: JSHandle): Promise { - const roomId = await room.evaluate((room) => room.roomId); - await cli.sendEvent(roomId, null, eventType, content); - } - })(); -} - /** * Generate strings with the supplied prefix, suffixed with numbers. * diff --git a/apps/web/playwright/e2e/read-receipts/read-receipts.spec.ts b/apps/web/playwright/e2e/read-receipts/read-receipts.spec.ts index dbb6fd4d8e..627eb1e3c7 100644 --- a/apps/web/playwright/e2e/read-receipts/read-receipts.spec.ts +++ b/apps/web/playwright/e2e/read-receipts/read-receipts.spec.ts @@ -64,7 +64,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => { const sendThreadedReadReceipt = async ( app: ElementAppPage, eventResponse: ISendEventResponse, - threadRootEventResponse: ISendEventResponse = undefined, + threadRootEventResponse?: ISendEventResponse, ) => { await app.client.sendReadReceipt( await fakeEventFromSent(app, eventResponse, threadRootEventResponse?.event_id), @@ -93,10 +93,10 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => { */ selectedRoomId = await app.client.createRoom({ name: selectedRoomName }); // Invite the bot to Other room - otherRoomId = await app.client.createRoom({ name: otherRoomName, invite: [bot.credentials.userId] }); + otherRoomId = await app.client.createRoom({ name: otherRoomName, invite: [bot.credentials!.userId] }); await page.goto(`/#/room/${otherRoomId}`); - await expect(page.getByText(`${bot.credentials.displayName} joined the room`)).toBeVisible(); + await expect(page.getByText(`${bot.credentials!.displayName} joined the room`)).toBeVisible(); // Then go into Selected room await page.goto(`/#/room/${selectedRoomId}`); @@ -287,7 +287,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => { sendMessageResponses.push(await sendMessage(bot, i)); } - const lastMessageId = sendMessageResponses.at(-1).event_id; + const lastMessageId = sendMessageResponses.at(-1)!.event_id; const uriEncodedLastMessageId = encodeURIComponent(lastMessageId); // wait until all messages have been received @@ -330,7 +330,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => { const readMarkersRequest2 = await readMarkersRequestPromise2; expect(readMarkersRequest2.postDataJSON()).toEqual({ - ["m.fully_read"]: sendMessageResponses.at(-1).event_id, + ["m.fully_read"]: sendMessageResponses.at(-1)!.event_id, }); }); }); diff --git a/apps/web/playwright/e2e/read-receipts/room-list-order.spec.ts b/apps/web/playwright/e2e/read-receipts/room-list-order.spec.ts index c13730107c..fdfd64083f 100644 --- a/apps/web/playwright/e2e/read-receipts/room-list-order.spec.ts +++ b/apps/web/playwright/e2e/read-receipts/room-list-order.spec.ts @@ -22,7 +22,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => { bot, }) => { // Create a third room to navigate to - const room3Id = await app.client.createRoom({ name: "Room Gamma", invite: [bot.credentials.userId] }); + const room3Id = await app.client.createRoom({ name: "Room Gamma", invite: [bot.credentials!.userId] }); await bot.awaitRoomMembership(room3Id); const room3 = { name: "Room Gamma", roomId: room3Id }; @@ -51,7 +51,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => { bot, }) => { // Create a third room to navigate to - const room3Id = await app.client.createRoom({ name: "Room Gamma", invite: [bot.credentials.userId] }); + const room3Id = await app.client.createRoom({ name: "Room Gamma", invite: [bot.credentials!.userId] }); await bot.awaitRoomMembership(room3Id); const room3 = { name: "Room Gamma", roomId: room3Id }; diff --git a/apps/web/playwright/e2e/register/email.spec.ts b/apps/web/playwright/e2e/register/email.spec.ts index bf8a2157f5..a629266954 100644 --- a/apps/web/playwright/e2e/register/email.spec.ts +++ b/apps/web/playwright/e2e/register/email.spec.ts @@ -55,7 +55,7 @@ test.describe("Email Registration", async () => { expect(messages.messages).toHaveLength(1); expect(messages.messages[0].To[0].Address).toEqual("alice@email.com"); const text = await mailpitClient.renderMessageText(messages.messages[0].ID); - const [emailLink] = text.match(/http.+/); + const [emailLink] = text.match(/http.+/)!; await request.get(emailLink); // "Click" the link in the email await expect(page.getByText("Welcome alice")).toBeVisible(); diff --git a/apps/web/playwright/e2e/retention/retention-global.spec.ts b/apps/web/playwright/e2e/retention/retention-global.spec.ts index 3ff37ce49a..d158771f4a 100644 --- a/apps/web/playwright/e2e/retention/retention-global.spec.ts +++ b/apps/web/playwright/e2e/retention/retention-global.spec.ts @@ -46,7 +46,7 @@ test.describe("global retention rules", () => { test("should apply", async ({ app, bot, page }) => { const roomId = await app.client.createRoom({ name: "Test", - invite: [bot.credentials.userId], + invite: [bot.credentials!.userId], }); await checkRetentionInRoom({ app, bot, page }, roomId); }); diff --git a/apps/web/playwright/e2e/retention/retention.spec.ts b/apps/web/playwright/e2e/retention/retention.spec.ts index 9988e57412..40048b9a5a 100644 --- a/apps/web/playwright/e2e/retention/retention.spec.ts +++ b/apps/web/playwright/e2e/retention/retention.spec.ts @@ -46,7 +46,7 @@ test.describe("Retention", () => { test("should apply retention to a bunch of messages", async ({ app, homeserver, page, user, bot }) => { const roomId = await app.client.createRoom({ name: "Test", - invite: [bot.credentials.userId], + invite: [bot.credentials!.userId], initial_state: [ { state_key: "", @@ -66,7 +66,7 @@ test.describe("Retention", () => { test("retention rules should apply after restart", async ({ app, bot, page }) => { const roomId = await app.client.createRoom({ name: "Test", - invite: [bot.credentials.userId], + invite: [bot.credentials!.userId], }); await bot.joinRoom(roomId); await app.viewRoomByName("Test"); @@ -102,7 +102,7 @@ test.describe("Retention", () => { const currentTime = new Date(); const roomId = await app.client.createRoom({ name: "Test", - invite: [bot.credentials.userId], + invite: [bot.credentials!.userId], initial_state: [ { state_key: "", diff --git a/apps/web/playwright/e2e/right-panel/right-panel.spec.ts b/apps/web/playwright/e2e/right-panel/right-panel.spec.ts index fade4afdd2..b7d396a538 100644 --- a/apps/web/playwright/e2e/right-panel/right-panel.spec.ts +++ b/apps/web/playwright/e2e/right-panel/right-panel.spec.ts @@ -147,7 +147,7 @@ test.describe("RightPanel", () => { async ({ page, homeserver, app }) => { const bobLongName = new Bot(page, homeserver, { displayName: LONG_NAME }); await bobLongName.prepareClient(); - await app.client.inviteUser(testRoomId, bobLongName.credentials.userId); + await app.client.inviteUser(testRoomId, bobLongName.credentials!.userId); await bobLongName.joinRoom(testRoomId); await viewRoomSummaryByName(page, app, ROOM_NAME); diff --git a/apps/web/playwright/e2e/room-directory/room-directory.spec.ts b/apps/web/playwright/e2e/room-directory/room-directory.spec.ts index f14cd83475..d9fa7860ae 100644 --- a/apps/web/playwright/e2e/room-directory/room-directory.spec.ts +++ b/apps/web/playwright/e2e/room-directory/room-directory.spec.ts @@ -51,7 +51,7 @@ test.describe("Room Directory", () => { const resp = await bot.publicRooms({}); expect(resp.total_room_count_estimate).toBeGreaterThanOrEqual(1); - expect(resp.chunk).toHaveLength(resp.total_room_count_estimate); + expect(resp.chunk).toHaveLength(resp.total_room_count_estimate!); expect(resp.chunk.find((r) => r.room_id === roomId)).toBeTruthy(); }, ); diff --git a/apps/web/playwright/e2e/room/invites.spec.ts b/apps/web/playwright/e2e/room/invites.spec.ts index 9312b24445..a1cc70874e 100644 --- a/apps/web/playwright/e2e/room/invites.spec.ts +++ b/apps/web/playwright/e2e/room/invites.spec.ts @@ -68,7 +68,7 @@ test.describe("Invites", () => { await app.settings.openUserSettings("Security & Privacy"); const ignoredUsersList = page.getByRole("list", { name: "Ignored users" }); await ignoredUsersList.scrollIntoViewIfNeeded(); - await expect(ignoredUsersList.getByRole("listitem", { name: bot.credentials.userId })).toBeVisible(); + await expect(ignoredUsersList.getByRole("listitem", { name: bot.credentials!.userId })).toBeVisible(); }, ); }); diff --git a/apps/web/playwright/e2e/room/room-status-bar.spec.ts b/apps/web/playwright/e2e/room/room-status-bar.spec.ts index 99c738d210..55cfd8471b 100644 --- a/apps/web/playwright/e2e/room/room-status-bar.spec.ts +++ b/apps/web/playwright/e2e/room/room-status-bar.spec.ts @@ -161,9 +161,9 @@ test.describe("Room Status Bar", () => { }); const other = page.locator(".mx_InviteDialog_other"); - await other.getByTestId("invite-dialog-input").fill(bot.credentials.userId); + await other.getByTestId("invite-dialog-input").fill(bot.credentials!.userId); await expect( - other.getByRole("option", { name: "Alice" }).getByText(bot.credentials.userId), + other.getByRole("option", { name: "Alice" }).getByText(bot.credentials!.userId), ).toBeVisible(); await other.getByRole("option", { name: "Alice" }).click(); await other.getByRole("button", { name: "Go" }).click(); diff --git a/apps/web/playwright/e2e/room/room.spec.ts b/apps/web/playwright/e2e/room/room.spec.ts index 6181333e87..ba1ddadff8 100644 --- a/apps/web/playwright/e2e/room/room.spec.ts +++ b/apps/web/playwright/e2e/room/room.spec.ts @@ -34,8 +34,8 @@ test.describe("Room Directory", () => { }); }, { - bob: bob.credentials.userId, - charlie: charlie.credentials.userId, + bob: bob.credentials!.userId, + charlie: charlie.credentials!.userId, }, ); diff --git a/apps/web/playwright/e2e/room_options/marked_unread.spec.ts b/apps/web/playwright/e2e/room_options/marked_unread.spec.ts index cad26f6286..dffdfe3412 100644 --- a/apps/web/playwright/e2e/room_options/marked_unread.spec.ts +++ b/apps/web/playwright/e2e/room_options/marked_unread.spec.ts @@ -31,7 +31,7 @@ test.describe("Mark as Unread", () => { const dummyRoomId = await app.client.createRoom({ name: "Room of no consequence", }); - await app.client.inviteUser(roomId, bot.credentials.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); await bot.joinRoom(roomId); await bot.sendMessage(roomId, "I am a robot. Beep."); diff --git a/apps/web/playwright/e2e/settings/device-management.spec.ts b/apps/web/playwright/e2e/settings/device-management.spec.ts index c2e2855fc2..fa6752ea24 100644 --- a/apps/web/playwright/e2e/settings/device-management.spec.ts +++ b/apps/web/playwright/e2e/settings/device-management.spec.ts @@ -19,7 +19,7 @@ test.describe("Device manager", () => { test.beforeEach(async ({ homeserver, user }) => { // create 3 extra sessions to manage for (let i = 0; i < 3; i++) { - await homeserver.loginUser(user.userId, user.password); + await homeserver.loginUser(user.userId, user.password!); } }); diff --git a/apps/web/playwright/e2e/settings/encryption-user-tab/advanced.spec.ts b/apps/web/playwright/e2e/settings/encryption-user-tab/advanced.spec.ts index 0167a321b7..ba0f1e6c1d 100644 --- a/apps/web/playwright/e2e/settings/encryption-user-tab/advanced.spec.ts +++ b/apps/web/playwright/e2e/settings/encryption-user-tab/advanced.spec.ts @@ -21,7 +21,7 @@ test.describe("Advanced section in Encryption tab", () => { const section = util.getEncryptionDetailsSection(); const deviceId = await page.evaluate(() => window.mxMatrixClientPeg.get().getDeviceId()); - await expect(section.getByText(deviceId)).toBeVisible(); + await expect(section.getByText(deviceId!)).toBeVisible(); await expect(section).toMatchScreenshot("encryption-details.png", { mask: [section.getByTestId("deviceId"), section.getByTestId("sessionKey")], @@ -59,7 +59,7 @@ test.describe("Advanced section in Encryption tab", () => { // Fill password dialog and validate const dialog = page.locator(".mx_InteractiveAuthDialog"); - await dialog.getByRole("textbox", { name: "Password" }).fill(credentials.password); + await dialog.getByRole("textbox", { name: "Password" }).fill(credentials.password!); await dialog.getByRole("button", { name: "Continue" }).click(); await expect(section.getByRole("button", { name: "Reset cryptographic identity" })).toBeVisible(); diff --git a/apps/web/playwright/e2e/settings/encryption-user-tab/encryption-tab.spec.ts b/apps/web/playwright/e2e/settings/encryption-user-tab/encryption-tab.spec.ts index 3f5383ae30..5257ca0e0d 100644 --- a/apps/web/playwright/e2e/settings/encryption-user-tab/encryption-tab.spec.ts +++ b/apps/web/playwright/e2e/settings/encryption-user-tab/encryption-tab.spec.ts @@ -26,6 +26,7 @@ test.describe("Encryption tab", () => { test.beforeEach(async ({ page, homeserver, credentials }) => { // The bot bootstraps cross-signing, creates a key backup and sets up a recovery key const botCredentials = { ...credentials }; + // @ts-expect-error delete botCredentials.accessToken; // use a new login for the bot const res = await createBot(page, homeserver, botCredentials); recoveryKey = res.recoveryKey; @@ -71,7 +72,7 @@ test.describe("Encryption tab", () => { "should prompt to enter the recovery key when the secrets are not cached locally", { tag: "@screenshot" }, async ({ page, app, util }) => { - await verifySession(app, recoveryKey.encodedPrivateKey); + await verifySession(app, recoveryKey.encodedPrivateKey!); // We need to delete the cached secrets await deleteCachedSecrets(page); @@ -104,7 +105,7 @@ test.describe("Encryption tab", () => { app, util, }) => { - await verifySession(app, recoveryKey.encodedPrivateKey); + await verifySession(app, recoveryKey.encodedPrivateKey!); // We need to delete the cached secrets await deleteCachedSecrets(page); @@ -120,7 +121,7 @@ test.describe("Encryption tab", () => { }); test("should warn before turning off key storage", { tag: "@screenshot" }, async ({ page, app, util }) => { - await verifySession(app, recoveryKey.encodedPrivateKey); + await verifySession(app, recoveryKey.encodedPrivateKey!); await util.openEncryptionTab(); await page.getByRole("switch", { name: "Allow key storage" }).click(); diff --git a/apps/web/playwright/e2e/settings/encryption-user-tab/index.ts b/apps/web/playwright/e2e/settings/encryption-user-tab/index.ts index 3d180047a1..a2b6f8eee7 100644 --- a/apps/web/playwright/e2e/settings/encryption-user-tab/index.ts +++ b/apps/web/playwright/e2e/settings/encryption-user-tab/index.ts @@ -55,7 +55,7 @@ class Helpers { async enterRecoveryKey(recoveryKey: GeneratedSecretStorageKey) { // Fill the recovery key const dialog = this.page.locator(".mx_Dialog"); - await dialog.getByRole("textbox").fill(recoveryKey.encodedPrivateKey); + await dialog.getByRole("textbox").fill(recoveryKey.encodedPrivateKey!); await dialog.getByRole("button", { name: "Continue" }).click(); } diff --git a/apps/web/playwright/e2e/settings/encryption-user-tab/recovery.spec.ts b/apps/web/playwright/e2e/settings/encryption-user-tab/recovery.spec.ts index 84dedecb53..3f5a4b5f05 100644 --- a/apps/web/playwright/e2e/settings/encryption-user-tab/recovery.spec.ts +++ b/apps/web/playwright/e2e/settings/encryption-user-tab/recovery.spec.ts @@ -18,6 +18,7 @@ test.describe("Recovery section in Encryption tab", () => { test.beforeEach(async ({ page, homeserver, credentials }) => { // The bot bootstraps cross-signing, creates a key backup and sets up a recovery key const botCredentials = { ...credentials }; + // @ts-expect-error delete botCredentials.accessToken; // use a new login for the bot const res = await createBot(page, homeserver, botCredentials); recoveryKey = res.recoveryKey; @@ -27,7 +28,7 @@ test.describe("Recovery section in Encryption tab", () => { "should change the recovery key", { tag: ["@screenshot", "@no-webkit"] }, async ({ page, app, homeserver, credentials, util, context }) => { - await verifySession(app, recoveryKey.encodedPrivateKey); + await verifySession(app, recoveryKey.encodedPrivateKey!); const dialog = await util.openEncryptionTab(); // The user can only change the recovery key @@ -54,7 +55,7 @@ test.describe("Recovery section in Encryption tab", () => { ); test("should setup the recovery key", { tag: ["@screenshot", "@no-webkit"] }, async ({ page, app, util }) => { - await verifySession(app, recoveryKey.encodedPrivateKey); + await verifySession(app, recoveryKey.encodedPrivateKey!); await util.removeSecretStorageDefaultKeyId(); // The key backup is deleted and the user needs to set it up diff --git a/apps/web/playwright/e2e/settings/general-room-settings-tab.spec.ts b/apps/web/playwright/e2e/settings/general-room-settings-tab.spec.ts index e3f0963b59..a8d0fe6f98 100644 --- a/apps/web/playwright/e2e/settings/general-room-settings-tab.spec.ts +++ b/apps/web/playwright/e2e/settings/general-room-settings-tab.spec.ts @@ -54,6 +54,6 @@ test.describe("General room settings tab", () => { const dialogBoundingBox = await page.locator(".mx_Dialog").boundingBox(); const inputBoundingBox = await settings.locator("#canonicalAlias").boundingBox(); // Assert that the width of the select element is less than that of .mx_Dialog div. - expect(inputBoundingBox.width).toBeLessThan(dialogBoundingBox.width); + expect(inputBoundingBox!.width).toBeLessThan(dialogBoundingBox!.width); }); }); diff --git a/apps/web/playwright/e2e/sliding-sync/sliding-sync.spec.ts b/apps/web/playwright/e2e/sliding-sync/sliding-sync.spec.ts index 1b8862bf71..952d2f22ea 100644 --- a/apps/web/playwright/e2e/sliding-sync/sliding-sync.spec.ts +++ b/apps/web/playwright/e2e/sliding-sync/sliding-sync.spec.ts @@ -25,7 +25,7 @@ const test = base.extend<{ joinedBot: async ({ app, bot, testRoom }, use) => { const roomId = testRoom.roomId; await bot.prepareClient(); - const bobUserId = await bot.evaluate((client) => client.getUserId()); + const bobUserId = await bot.evaluate((client) => client.getSafeUserId()); await app.client.evaluate( async (client, { bobUserId, roomId }) => { await client.invite(roomId, bobUserId); @@ -230,7 +230,7 @@ test.describe("Sliding Sync", () => { joinedBot: bot, testRoom, }) => { - const clientUserId = await app.client.evaluate((client) => client.getUserId()); + const clientUserId = await app.client.evaluate((client) => client.getSafeUserId()); // invite bot into 3 rooms: // - roomJoin: will join this room diff --git a/apps/web/playwright/e2e/spaces/spaces.spec.ts b/apps/web/playwright/e2e/spaces/spaces.spec.ts index b1ce9eb36e..3bcd244a7e 100644 --- a/apps/web/playwright/e2e/spaces/spaces.spec.ts +++ b/apps/web/playwright/e2e/spaces/spaces.spec.ts @@ -48,7 +48,7 @@ function spaceChildInitialState( serverName: string, roomId: string, order?: string, -): ICreateRoomOpts["initial_state"]["0"] { +): NonNullable[number] { return { type: "m.space.child", state_key: roomId, @@ -240,7 +240,7 @@ test.describe("Spaces", () => { await shareDialog.getByRole("button", { name: "Invite people" }).click(); const otherSection = page.locator(".mx_InviteDialog_other"); - await otherSection.getByRole("textbox").fill(bot.credentials.userId); + await otherSection.getByRole("textbox").fill(bot.credentials!.userId); await otherSection.getByRole("button", { name: "Invite" }).click(); await expect(page.locator(".mx_InviteDialog_other")).not.toBeVisible(); diff --git a/apps/web/playwright/e2e/spaces/threads-activity-centre/index.ts b/apps/web/playwright/e2e/spaces/threads-activity-centre/index.ts index c4781c1c27..3b51347673 100644 --- a/apps/web/playwright/e2e/spaces/threads-activity-centre/index.ts +++ b/apps/web/playwright/e2e/spaces/threads-activity-centre/index.ts @@ -25,9 +25,9 @@ type RoomRef = { name: string; roomId: string }; * - Invite the bot to both rooms and ensure that it has joined */ export const test = base.extend<{ - room1Name?: string; + room1Name: string; room1: { name: string; roomId: string }; - room2Name?: string; + room2Name: string; room2: { name: string; roomId: string }; msg: MessageBuilder; util: Helpers; @@ -39,7 +39,7 @@ export const test = base.extend<{ room1: async ({ room1Name: name, app, user, bot }, use) => { const roomId = await app.client.createRoom({ name, - invite: [bot.credentials.userId], + invite: [bot.credentials!.userId], preset: "public_chat" as Preset, }); await bot.awaitRoomMembership(roomId); @@ -47,12 +47,12 @@ export const test = base.extend<{ }, room2Name: "Room 2", room2: async ({ room2Name: name, app, user, bot }, use) => { - const roomId = await app.client.createRoom({ name, invite: [bot.credentials.userId] }); + const roomId = await app.client.createRoom({ name, invite: [bot.credentials!.userId] }); await bot.awaitRoomMembership(roomId); await use({ name, roomId }); }, msg: async ({ page, app, util }, use) => { - await use(new MessageBuilder(page, app, util)); + await use(new MessageBuilder()); }, util: async ({ room1, room2, page, app, bot }, use) => { await use(new Helpers(page, app, bot)); @@ -70,12 +70,6 @@ export const test = base.extend<{ * which finds a message and then constructs a reply to it. */ export class MessageBuilder { - constructor( - private page: Page, - private app: ElementAppPage, - private helpers: Helpers, - ) {} - /** * Map of message content -> event. */ @@ -164,11 +158,7 @@ export class MessageBuilder { * MessageBuilder.replyTo} which creates a reply based on a previous message. */ export abstract class MessageContentSpec { - messageFinder: MessageBuilder | null; - - constructor(messageFinder: MessageBuilder = null) { - this.messageFinder = messageFinder; - } + constructor(public readonly messageFinder: MessageBuilder) {} public abstract getContent(room: JSHandle): Promise>; } @@ -230,9 +220,9 @@ export class Helpers { await expect(this.page.locator(".mx_ThreadView_timelinePanelWrapper")).toBeVisible(); } - async findRoomById(roomId: string): Promise> { + async findRoomById(roomId: string): Promise> { return this.app.client.evaluateHandle((cli, roomId) => { - return cli.getRooms().find((r) => r.roomId === roomId); + return cli.getRooms().find((r) => r.roomId === roomId)!; }, roomId); } diff --git a/apps/web/playwright/e2e/spotlight/spotlight.spec.ts b/apps/web/playwright/e2e/spotlight/spotlight.spec.ts index d2caf93d9f..df865bc067 100644 --- a/apps/web/playwright/e2e/spotlight/spotlight.spec.ts +++ b/apps/web/playwright/e2e/spotlight/spotlight.spec.ts @@ -97,8 +97,8 @@ test.describe("Spotlight", () => { test.beforeEach(async ({ page, user, bot1, bot2, room1, room2, room3 }) => { await bot1.joinRoom(room1.roomId); - await bot2.inviteUser(room2.roomId, bot1.credentials.userId); - await bot2.inviteUser(room3.roomId, bot1.credentials.userId); + await bot2.inviteUser(room2.roomId, bot1.credentials!.userId); + await bot2.inviteUser(room3.roomId, bot1.credentials!.userId); await page.goto(`/#/room/${room1.roomId}`); await expect(page.locator(".mx_RoomSublist_skeletonUI")).not.toBeAttached(); @@ -215,12 +215,12 @@ test.describe("Spotlight", () => { const spotlight = await app.openSpotlight(); await page.waitForTimeout(500); // wait for the dialog to settle await spotlight.filter(Filter.People); - await spotlight.search(bot1.credentials.displayName); + await spotlight.search(bot1.credentials!.displayName!); const resultLocator = spotlight.results; await expect(resultLocator).toHaveCount(1); - await expect(resultLocator.first()).toContainText(bot1.credentials.displayName); + await expect(resultLocator.first()).toContainText(bot1.credentials!.displayName!); await resultLocator.first().click(); - await expect(roomHeaderName(page)).toHaveText(bot1.credentials.displayName); + await expect(roomHeaderName(page)).toHaveText(bot1.credentials!.displayName!); }); /** @@ -234,30 +234,30 @@ test.describe("Spotlight", () => { const spotlight = await app.openSpotlight(); await page.waitForTimeout(500); // wait for the dialog to settle await spotlight.filter(Filter.People); - await spotlight.search(bot2.credentials.displayName); + await spotlight.search(bot2.credentials!.displayName!); const resultLocator = spotlight.results; await expect(resultLocator).toHaveCount(1); - await expect(resultLocator.first()).toContainText(bot2.credentials.displayName); + await expect(resultLocator.first()).toContainText(bot2.credentials!.displayName!); await resultLocator.first().click(); - await expect(roomHeaderName(page)).toHaveText(bot2.credentials.displayName); + await expect(roomHeaderName(page)).toHaveText(bot2.credentials!.displayName!); }); test("should find group DMs by usernames or user ids", async ({ page, app, bot1, bot2, room1 }) => { // First we want to share a room with both bots to ensure we’ve got their usernames cached - await app.client.inviteUser(room1.roomId, bot2.credentials.userId); + await app.client.inviteUser(room1.roomId, bot2.credentials!.userId); // Starting a DM with ByteBot (will be turned into a group dm later) let spotlight = await app.openSpotlight(); await page.waitForTimeout(500); // wait for the dialog to settle await spotlight.filter(Filter.People); - await spotlight.search(bot2.credentials.displayName); + await spotlight.search(bot2.credentials!.displayName!); let resultLocator = spotlight.results; await expect(resultLocator).toHaveCount(1); - await expect(resultLocator.first()).toContainText(bot2.credentials.displayName); + await expect(resultLocator.first()).toContainText(bot2.credentials!.displayName!); await resultLocator.first().click(); // Send first message to actually start DM - await expect(roomHeaderName(page)).toHaveText(bot2.credentials.displayName); + await expect(roomHeaderName(page)).toHaveText(bot2.credentials!.displayName!); const locator = page.getByRole("textbox", { name: "Send a message…" }); await locator.fill("Hey!"); await locator.press("Enter"); @@ -265,7 +265,7 @@ test.describe("Spotlight", () => { // Assert DM exists by checking for the first message and the room being in the room list await expect(page.locator(".mx_EventTile_body").filter({ hasText: "Hey!" })).toBeAttached({ timeout: 3000 }); await expect( - page.getByTestId("room-list").getByRole("option", { name: `Open room ${bot2.credentials.displayName}` }), + page.getByTestId("room-list").getByRole("option", { name: `Open room ${bot2.credentials!.displayName}` }), ).toBeVisible(); // Invite BotBob into existing DM with ByteBot @@ -273,11 +273,11 @@ test.describe("Spotlight", () => { const map = client .getAccountData("m.direct" as keyof AccountDataEvents) ?.getContent>(); - return map[userId] ?? []; - }, bot2.credentials.userId); + return map?.[userId] ?? []; + }, bot2.credentials!.userId); expect(dmRooms).toHaveLength(1); - const groupDmName = await app.client.evaluate((client, id) => client.getRoom(id).name, dmRooms[0]); - await app.client.inviteUser(dmRooms[0], bot1.credentials.userId); + const groupDmName = await app.client.evaluate((client, id) => client.getRoom(id)!.name, dmRooms[0]); + await app.client.inviteUser(dmRooms[0], bot1.credentials!.userId); await expect(roomHeaderName(page).first()).toContainText(groupDmName); await expect( page.getByTestId("room-list").getByRole("option", { name: `Open room ${groupDmName}` }), @@ -286,7 +286,7 @@ test.describe("Spotlight", () => { // Search for BotBob by id, should return group DM and user spotlight = await app.openSpotlight(); await spotlight.filter(Filter.People); - await spotlight.search(bot1.credentials.userId); + await spotlight.search(bot1.credentials!.userId); await page.waitForTimeout(1000); // wait for the dialog to settle resultLocator = spotlight.results; await expect(resultLocator).toHaveCount(2); @@ -299,7 +299,7 @@ test.describe("Spotlight", () => { // Search for ByteBot by id, should return group DM and user spotlight = await app.openSpotlight(); await spotlight.filter(Filter.People); - await spotlight.search(bot2.credentials.userId); + await spotlight.search(bot2.credentials!.userId); await page.waitForTimeout(1000); // wait for the dialog to settle resultLocator = spotlight.results; await expect(resultLocator).toHaveCount(2); @@ -324,11 +324,11 @@ test.describe("Spotlight", () => { // We search for user ID to trigger the profile lookup within the dialog. for (let i = 0; i < 2; i++) { console.log("Iteration: " + i); - await spotlight.search(bot1.credentials.userId); + await spotlight.search(bot1.credentials!.userId); await page.waitForTimeout(1000); // wait for the dialog to settle const resultLocator = spotlight.results; await expect(resultLocator).toHaveCount(1); - await expect(resultLocator.first()).toContainText(bot1.credentials.userId); + await expect(resultLocator.first()).toContainText(bot1.credentials!.userId); } }); @@ -336,12 +336,12 @@ test.describe("Spotlight", () => { const spotlight = await app.openSpotlight(); await page.waitForTimeout(500); // wait for the dialog to settle await spotlight.filter(Filter.People); - await spotlight.search(bot2.credentials.displayName); + await spotlight.search(bot2.credentials!.displayName!); await page.waitForTimeout(3000); // wait for the dialog to settle const resultLocator = spotlight.results; await expect(resultLocator).toHaveCount(1); - await expect(resultLocator.first()).toContainText(bot2.credentials.displayName); + await expect(resultLocator.first()).toContainText(bot2.credentials!.displayName!); await expect(spotlight.dialog.locator("#mx_SpotlightDialog_button_startGroupChat")).toContainText( "Start a group chat", @@ -351,17 +351,17 @@ test.describe("Spotlight", () => { }); test("should close spotlight after starting a DM", async ({ page, app, bot1 }) => { - await startDM(app, page, bot1.credentials.displayName); + await startDM(app, page, bot1.credentials!.displayName!); await expect(page.locator(".mx_SpotlightDialog")).toHaveCount(0); }); test("should show the same user only once", async ({ page, app, bot1 }) => { - await startDM(app, page, bot1.credentials.displayName); + await startDM(app, page, bot1.credentials!.displayName!); await page.goto("/#/home"); const spotlight = await app.openSpotlight(); await page.waitForTimeout(500); // wait for the dialog to settle await spotlight.filter(Filter.People); - await spotlight.search(bot1.credentials.displayName); + await spotlight.search(bot1.credentials!.displayName!); await page.waitForTimeout(3000); // wait for the dialog to settle await expect(spotlight.dialog.locator(".mx_Spinner")).not.toBeAttached(); const resultLocator = spotlight.results; diff --git a/apps/web/playwright/e2e/threads/threads.spec.ts b/apps/web/playwright/e2e/threads/threads.spec.ts index 1ace1c4499..75bda6d407 100644 --- a/apps/web/playwright/e2e/threads/threads.spec.ts +++ b/apps/web/playwright/e2e/threads/threads.spec.ts @@ -29,7 +29,7 @@ test.describe("Threads", () => { test("should be usable for a conversation", { tag: "@screenshot" }, async ({ page, app, bot }) => { const roomId = await app.client.createRoom({}); - await app.client.inviteUser(roomId, bot.credentials.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); await bot.joinRoom(roomId); await page.goto("/#/room/" + roomId); @@ -436,7 +436,7 @@ test.describe("Threads", () => { { tag: ["@screenshot", "@no-firefox"] }, async ({ page, app, bot }) => { const roomId = await app.client.createRoom({}); - await app.client.inviteUser(roomId, bot.credentials.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); await bot.joinRoom(roomId); await page.goto("/#/room/" + roomId); diff --git a/apps/web/playwright/e2e/timeline/event-list-summary.spec.ts b/apps/web/playwright/e2e/timeline/event-list-summary.spec.ts index 442966c2aa..c628df6d06 100644 --- a/apps/web/playwright/e2e/timeline/event-list-summary.spec.ts +++ b/apps/web/playwright/e2e/timeline/event-list-summary.spec.ts @@ -60,7 +60,7 @@ test.describe("Event List Summary", () => { await app.client.sendMessage(roomId, "Saying something"); // When we ban the bot - await app.client.ban(roomId, bot.credentials.userId); + await app.client.ban(roomId, bot.credentials!.userId); // Then we say that, but the name is hidden await expect( @@ -92,8 +92,8 @@ test.describe("Event List Summary", () => { ).toBeVisible(); // When we perform multiple actions on it - await app.client.kick(roomId, bot.credentials.userId); - await app.client.inviteUser(roomId, bot.credentials.userId); + await app.client.kick(roomId, bot.credentials!.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); await bot.joinRoom(roomId); // Then those actions are gathered into a single summary @@ -126,9 +126,9 @@ test.describe("Event List Summary", () => { ).toBeVisible(); // When we perform multiple actions on it, including a ban - await app.client.ban(roomId, bot.credentials.userId); - await app.client.unban(roomId, bot.credentials.userId); - await app.client.inviteUser(roomId, bot.credentials.userId); + await app.client.ban(roomId, bot.credentials!.userId); + await app.client.unban(roomId, bot.credentials!.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); await bot.joinRoom(roomId); // Then those actions are gathered into a single summary, with the name hidden @@ -158,7 +158,7 @@ test.describe("Event List Summary", () => { autoAcceptInvites: false, }); await bot2.prepareClient(); - await app.client.inviteUser(roomId, bot2.credentials.userId); + await app.client.inviteUser(roomId, bot2.credentials!.userId); await app.client.sendMessage(roomId, "I invited MyBot2..."); await bot.joinRoom(roomId); await bot2.joinRoom(roomId); @@ -169,10 +169,10 @@ test.describe("Event List Summary", () => { ).toBeVisible(); // When we perform multiple actions on both bots - await app.client.kick(roomId, bot.credentials.userId); - await app.client.kick(roomId, bot2.credentials.userId); - await app.client.inviteUser(roomId, bot.credentials.userId); - await app.client.inviteUser(roomId, bot2.credentials.userId); + await app.client.kick(roomId, bot.credentials!.userId); + await app.client.kick(roomId, bot2.credentials!.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); + await app.client.inviteUser(roomId, bot2.credentials!.userId); await bot.joinRoom(roomId); await bot2.joinRoom(roomId); @@ -227,7 +227,7 @@ test.describe("Event List Summary", () => { autoAcceptInvites: false, }); await bot2.prepareClient(); - await app.client.inviteUser(roomId, bot2.credentials.userId); + await app.client.inviteUser(roomId, bot2.credentials!.userId); await app.client.sendMessage(roomId, "I invited MyBot2..."); await bot.joinRoom(roomId); await bot2.joinRoom(roomId); @@ -238,11 +238,11 @@ test.describe("Event List Summary", () => { ).toBeVisible(); // When we ban bot1 but not bot2 - await app.client.ban(roomId, bot.credentials.userId); - await app.client.unban(roomId, bot.credentials.userId); - await app.client.kick(roomId, bot2.credentials.userId); - await app.client.inviteUser(roomId, bot.credentials.userId); - await app.client.inviteUser(roomId, bot2.credentials.userId); + await app.client.ban(roomId, bot.credentials!.userId); + await app.client.unban(roomId, bot.credentials!.userId); + await app.client.kick(roomId, bot2.credentials!.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); + await app.client.inviteUser(roomId, bot2.credentials!.userId); await bot.joinRoom(roomId); await bot2.joinRoom(roomId); @@ -318,7 +318,7 @@ async function setupRoom(app: ElementAppPage, homeserver: StartedHomeserverConta autoAcceptInvites: false, }); await bot.prepareClient(); - await app.client.inviteUser(roomId, bot.credentials.userId); + await app.client.inviteUser(roomId, bot.credentials!.userId); await app.client.sendMessage(roomId, "I invited MyBot..."); return { bot, roomId }; @@ -336,11 +336,11 @@ async function replaceBotIds(page: Page, bot: Bot, bot2?: Bot) { const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT); while (walker.nextNode()) { const node = walker.currentNode; - node.textContent = node.textContent.replaceAll(bot1UserId, "<>"); + node.textContent = node.textContent!.replaceAll(bot1UserId, "<>"); node.textContent = node.textContent.replaceAll(bot2UserId, "<>"); } } }, - [bot.credentials.userId, bot2?.credentials?.userId ?? "no_bot_2_to_replace"], + [bot.credentials!.userId, bot2?.credentials?.userId ?? "no_bot_2_to_replace"], ); } diff --git a/apps/web/playwright/e2e/timeline/timeline.spec.ts b/apps/web/playwright/e2e/timeline/timeline.spec.ts index 64ca9e07b2..42cf5adf98 100644 --- a/apps/web/playwright/e2e/timeline/timeline.spec.ts +++ b/apps/web/playwright/e2e/timeline/timeline.spec.ts @@ -48,7 +48,7 @@ const expectAvatar = async (cli: Client, e: Locator, avatarUrl: string): Promise }, { avatarUrl, size, resizeMethod: AVATAR_RESIZE_METHOD }, ); - await expect(e.locator(".mx_BaseAvatar img")).toHaveAttribute("src", url); + await expect(e.locator(".mx_BaseAvatar img")).toHaveAttribute("src", url!); }; const sendEvent = async (client: Client, roomId: string, html = false): Promise => { @@ -917,7 +917,7 @@ test.describe("Timeline", () => { const bot = new Bot(page, homeserver, {}); await bot.prepareClient(); - await app.client.inviteUser(room.roomId, bot.credentials.userId); + await app.client.inviteUser(room.roomId, bot.credentials!.userId); await sendImage(bot, room.roomId, NEW_AVATAR); await app.timeline.scrollToBottom(); @@ -936,7 +936,7 @@ test.describe("Timeline", () => { const bot = new Bot(page, homeserver, {}); await bot.prepareClient(); - await app.client.inviteUser(room.roomId, bot.credentials.userId); + await app.client.inviteUser(room.roomId, bot.credentials!.userId); const upload = await bot.uploadContent(VIDEO_FILE, { name: "bbb.webm", type: "video/webm" }); await bot.sendEvent(room.roomId, null, "m.room.message" as EventType, { @@ -970,7 +970,7 @@ test.describe("Timeline", () => { autoAcceptInvites: false, }); await bot.prepareClient(); - await app.client.inviteUser(room.roomId, bot.credentials.userId); + await app.client.inviteUser(room.roomId, bot.credentials!.userId); await bot.joinRoom(room.roomId); await bot.sendMessage(room.roomId, messageFromSender); @@ -1100,7 +1100,7 @@ test.describe("Timeline", () => { autoAcceptInvites: false, }); await bot.prepareClient(); - await app.client.inviteUser(room.roomId, bot.credentials.userId); + await app.client.inviteUser(room.roomId, bot.credentials!.userId); await bot.joinRoom(room.roomId); // Make sure the bot joined the room @@ -1228,7 +1228,7 @@ test.describe("Timeline", () => { // Create another room with a long name, invite the bot, and open the room const testRoomId = await app.client.createRoom({ name: LONG_STRING }); - await app.client.inviteUser(testRoomId, bot.credentials.userId); + await app.client.inviteUser(testRoomId, bot.credentials!.userId); await bot.joinRoom(testRoomId); await page.goto(`/#/room/${testRoomId}`); diff --git a/apps/web/playwright/e2e/user-menu/user-menu.spec.ts b/apps/web/playwright/e2e/user-menu/user-menu.spec.ts index cfc4757c15..7a0c661e2d 100644 --- a/apps/web/playwright/e2e/user-menu/user-menu.spec.ts +++ b/apps/web/playwright/e2e/user-menu/user-menu.spec.ts @@ -25,7 +25,7 @@ test.describe("User Menu", () => { await page.getByRole("button", { name: "User menu", exact: true }).click(); const menu = page.getByRole("menu"); - await expect(menu.getByText(user.displayName)).toBeVisible(); + await expect(menu.getByText(user.displayName!)).toBeVisible(); await expect(menu.getByText(user.userId)).toBeVisible(); await expect(menu).toMatchScreenshot("user-menu.png", screenshotOptions(page)); }); diff --git a/apps/web/playwright/e2e/user-view/user-view.spec.ts b/apps/web/playwright/e2e/user-view/user-view.spec.ts index e09d8a1593..28799b6796 100644 --- a/apps/web/playwright/e2e/user-view/user-view.spec.ts +++ b/apps/web/playwright/e2e/user-view/user-view.spec.ts @@ -15,10 +15,12 @@ test.describe("UserView", () => { }); test("should render the user view as expected", { tag: "@screenshot" }, async ({ page, homeserver, user, bot }) => { - await page.goto(`/#/user/${bot.credentials.userId}`); + await page.goto(`/#/user/${bot.credentials!.userId}`); const rightPanel = page.locator("#mx_RightPanel"); - await expect(rightPanel.getByRole("heading", { name: bot.credentials.displayName, exact: true })).toBeVisible(); + await expect( + rightPanel.getByRole("heading", { name: bot.credentials!.displayName, exact: true }), + ).toBeVisible(); await expect(rightPanel).toMatchScreenshot("user-info.png", { mask: [page.locator(".mx_UserInfo_profile_mxid")], css: ` diff --git a/apps/web/playwright/e2e/utils.ts b/apps/web/playwright/e2e/utils.ts index 6c30bf1856..3024f56f06 100644 --- a/apps/web/playwright/e2e/utils.ts +++ b/apps/web/playwright/e2e/utils.ts @@ -40,7 +40,7 @@ export async function waitForRoom( await client.evaluateHandle( (matrixClient, { roomId, predicateId }) => { return new Promise((resolve) => { - const room = matrixClient.getRoom(roomId); + const room = matrixClient.getRoom(roomId)!; if ((window)[predicateId](room)) { resolve(room); diff --git a/apps/web/playwright/e2e/voip/element-call.spec.ts b/apps/web/playwright/e2e/voip/element-call.spec.ts index c3194c7337..9a798773f7 100644 --- a/apps/web/playwright/e2e/voip/element-call.spec.ts +++ b/apps/web/playwright/e2e/voip/element-call.spec.ts @@ -63,7 +63,7 @@ async function sendRTCState(bot: Bot, roomId: string, notification?: "ring" | "n }, "scope": "m.room", }, - `_@${bot.credentials.userId}_OiDFxsZrjz_m.call`, + `_@${bot.credentials!.userId}_OiDFxsZrjz_m.call`, ); if (!notification) { return; @@ -140,7 +140,7 @@ test.describe("Element Call", () => { await charlie.prepareClient(); const roomId = await app.client.createRoom({ name: "TestRoom", - invite: [bot.credentials.userId, charlie.credentials.userId], + invite: [bot.credentials!.userId, charlie.credentials!.userId], }); await use({ roomId }); }, @@ -155,7 +155,7 @@ test.describe("Element Call", () => { const frameUrlStr = await page.locator("iframe").getAttribute("src"); expect(frameUrlStr).toBeDefined(); // Ensure we set the correct parameters for ECall. - const url = new URL(frameUrlStr); + const url = new URL(frameUrlStr!); const hash = new URLSearchParams(url.hash.slice(1)); assertCommonCallParameters(url.searchParams, hash, user, room); expect(hash.get("intent")).toEqual("start_call"); @@ -180,7 +180,7 @@ test.describe("Element Call", () => { const frameUrlStr = await page.locator("iframe").getAttribute("src"); expect(frameUrlStr).toBeDefined(); - const url = new URL(frameUrlStr); + const url = new URL(frameUrlStr!); const hash = new URLSearchParams(url.hash.slice(1)); assertCommonCallParameters(url.searchParams, hash, user, room); expect(hash.get("intent")).toEqual("start_call"); @@ -192,7 +192,7 @@ test.describe("Element Call", () => { await app.viewRoomById(room.roomId); // Allow bob to create a call await expect(page.getByText("Bob and one other were invited and joined")).toBeVisible(); - await app.client.setPowerLevel(room.roomId, bot.credentials.userId, 50); + await app.client.setPowerLevel(room.roomId, bot.credentials!.userId, 50); // Fake a start of a call await sendRTCState(bot, room.roomId, undefined, callType === "voice" ? "audio" : "video"); const button = page.getByTestId("join-call-button"); @@ -205,7 +205,7 @@ test.describe("Element Call", () => { await button.click(); const frameUrlStr = await page.locator("iframe").getAttribute("src"); expect(frameUrlStr).toBeDefined(); - const url = new URL(frameUrlStr); + const url = new URL(frameUrlStr!); const hash = new URLSearchParams(url.hash.slice(1)); assertCommonCallParameters(url.searchParams, hash, user, room); @@ -237,7 +237,7 @@ test.describe("Element Call", () => { await app.viewRoomById(room.roomId); // Allow bob to create a call await expect(page.getByText("Bob and one other were invited and joined")).toBeVisible(); - await app.client.setPowerLevel(room.roomId, bot.credentials.userId, 50); + await app.client.setPowerLevel(room.roomId, bot.credentials!.userId, 50); // Fake a start of a call await sendRTCState(bot, room.roomId, "notification", "video"); const toast = page.locator(".mx_Toast_toast"); @@ -255,7 +255,7 @@ test.describe("Element Call", () => { await button.click(); const frameUrlStr = await page.locator("iframe").getAttribute("src"); expect(frameUrlStr).toBeDefined(); - const url = new URL(frameUrlStr); + const url = new URL(frameUrlStr!); const hash = new URLSearchParams(url.hash.slice(1)); assertCommonCallParameters(url.searchParams, hash, user, room); @@ -272,7 +272,7 @@ test.describe("Element Call", () => { await app.viewRoomById(room.roomId); // Allow bob to create a call await expect(page.getByText("Bob and one other were invited and joined")).toBeVisible(); - await app.client.setPowerLevel(room.roomId, bot.credentials.userId, 50); + await app.client.setPowerLevel(room.roomId, bot.credentials!.userId, 50); // Fake a start of a call await sendRTCState(bot, room.roomId, "notification", "audio"); const toast = page.locator(".mx_Toast_toast"); @@ -284,7 +284,7 @@ test.describe("Element Call", () => { await button.click(); const frameUrlStr = await page.locator("iframe").getAttribute("src"); expect(frameUrlStr).toBeDefined(); - const url = new URL(frameUrlStr); + const url = new URL(frameUrlStr!); const hash = new URLSearchParams(url.hash.slice(1)); assertCommonCallParameters(url.searchParams, hash, user, room); @@ -299,11 +299,11 @@ test.describe("Element Call", () => { room: async ({ page, app, user, bot }, use) => { const roomId = await app.client.createRoom({ preset: "trusted_private_chat" as Preset.TrustedPrivateChat, - invite: [bot.credentials.userId], + invite: [bot.credentials!.userId], }); await bot.awaitRoomMembership(roomId); await app.client.setAccountData("m.direct" as EventType.Direct, { - [bot.credentials.userId]: [roomId], + [bot.credentials!.userId]: [roomId], }); await use({ roomId }); }, @@ -318,7 +318,7 @@ test.describe("Element Call", () => { const frameUrlStr = await page.locator("iframe").getAttribute("src"); expect(frameUrlStr).toBeDefined(); - const url = new URL(frameUrlStr); + const url = new URL(frameUrlStr!); const hash = new URLSearchParams(url.hash.slice(1)); assertCommonCallParameters(url.searchParams, hash, user, room); expect(hash.get("intent")).toEqual("start_call_dm"); @@ -336,7 +336,7 @@ test.describe("Element Call", () => { const frameUrlStr = await page.locator("iframe").getAttribute("src"); expect(frameUrlStr).toBeDefined(); - const url = new URL(frameUrlStr); + const url = new URL(frameUrlStr!); const hash = new URLSearchParams(url.hash.slice(1)); assertCommonCallParameters(url.searchParams, hash, user, room); expect(hash.get("intent")).toEqual("start_call_dm"); @@ -370,7 +370,7 @@ test.describe("Element Call", () => { await button.click(); const frameUrlStr = await page.locator("iframe").getAttribute("src"); expect(frameUrlStr).toBeDefined(); - const url = new URL(frameUrlStr); + const url = new URL(frameUrlStr!); const hash = new URLSearchParams(url.hash.slice(1)); assertCommonCallParameters(url.searchParams, hash, user, room); @@ -410,7 +410,7 @@ test.describe("Element Call", () => { await button.click(); const frameUrlStr = await page.locator("iframe").getAttribute("src"); expect(frameUrlStr).toBeDefined(); - const url = new URL(frameUrlStr); + const url = new URL(frameUrlStr!); const hash = new URLSearchParams(url.hash.slice(1)); assertCommonCallParameters(url.searchParams, hash, user, room); @@ -444,7 +444,7 @@ test.describe("Element Call", () => { await button.click(); const frameUrlStr = await page.locator("iframe").getAttribute("src"); expect(frameUrlStr).toBeDefined(); - const url = new URL(frameUrlStr); + const url = new URL(frameUrlStr!); const hash = new URLSearchParams(url.hash.slice(1)); assertCommonCallParameters(url.searchParams, hash, user, room); @@ -477,7 +477,7 @@ test.describe("Element Call", () => { const frameUrlStr = await page.locator("iframe").getAttribute("src"); expect(frameUrlStr).toBeDefined(); // Ensure we set the correct parameters for ECall. - const url = new URL(frameUrlStr); + const url = new URL(frameUrlStr!); const hash = new URLSearchParams(url.hash.slice(1)); assertCommonCallParameters(url.searchParams, hash, user, { roomId }); expect(hash.get("intent")).toEqual("join_existing"); @@ -494,7 +494,7 @@ test.describe("Element Call", () => { await charlie.prepareClient(); const roomId = await app.client.createRoom({ name: "TestRoom", - invite: [bot.credentials.userId, charlie.credentials.userId], + invite: [bot.credentials!.userId, charlie.credentials!.userId], }); await app.client.createRoom({ name: "OtherRoom", @@ -514,7 +514,7 @@ test.describe("Element Call", () => { const iframe = page.locator("iframe"); await expect(iframe).toBeVisible(); const frameUrlStr = await page.locator("iframe").getAttribute("src"); - const callFrame = page.frame({ url: frameUrlStr }); + const callFrame = page.frame({ url: frameUrlStr! })!; await callFrame.getByRole("button", { name: "Join Call" }).click(); await expect(callFrame.getByText("In call", { exact: true })).toBeVisible(); @@ -608,7 +608,7 @@ test.describe("Element Call", () => { }) => { await app.viewRoomById(room.roomId); await expect(page.getByText("Bob and one other were invited and joined")).toBeVisible(); - await app.client.setPowerLevel(room.roomId, bot.credentials.userId, 50); + await app.client.setPowerLevel(room.roomId, bot.credentials!.userId, 50); await sendRTCState(bot, room.roomId); await openAndJoinCall(page, true); @@ -654,7 +654,7 @@ test.describe("Element Call", () => { await charlie.prepareClient(); const roomId = await app.client.createRoom({ name: "VideoRoom", - invite: [bot.credentials.userId, charlie.credentials.userId], + invite: [bot.credentials!.userId, charlie.credentials!.userId], creation_content: { type: "org.matrix.msc3417.call", }, diff --git a/apps/web/playwright/e2e/widgets/events.spec.ts b/apps/web/playwright/e2e/widgets/events.spec.ts index 7553ec4b46..cbb942cfd0 100644 --- a/apps/web/playwright/e2e/widgets/events.spec.ts +++ b/apps/web/playwright/e2e/widgets/events.spec.ts @@ -75,7 +75,7 @@ test.describe("Widget Events", () => { }) => { const roomId = await app.client.createRoom({ name: ROOM_NAME, - invite: [bot.credentials.userId], + invite: [bot.credentials!.userId], }); // setup widget via state event diff --git a/apps/web/playwright/e2e/widgets/jitsi.spec.ts b/apps/web/playwright/e2e/widgets/jitsi.spec.ts index fc269c506b..406d7eac33 100644 --- a/apps/web/playwright/e2e/widgets/jitsi.spec.ts +++ b/apps/web/playwright/e2e/widgets/jitsi.spec.ts @@ -30,7 +30,7 @@ test.describe("Jitsi Calls", () => { test("should be able to pop out a jitsi widget", async ({ page, app, bot, bot2, context }) => { const roomId = await app.client.createRoom({ name: ROOM_NAME, - invite: [bot.credentials.userId, bot2.credentials.userId], + invite: [bot.credentials!.userId, bot2.credentials!.userId], }); await bot.joinRoom(roomId); diff --git a/apps/web/playwright/e2e/widgets/layout.spec.ts b/apps/web/playwright/e2e/widgets/layout.spec.ts index 61332aecb4..d58beb9390 100644 --- a/apps/web/playwright/e2e/widgets/layout.spec.ts +++ b/apps/web/playwright/e2e/widgets/layout.spec.ts @@ -76,19 +76,19 @@ test.describe("Widget Layout", () => { test("manually resize the height of the top container layout", async ({ page }) => { const iframe = page.locator('iframe[title="widget"]'); - expect((await iframe.boundingBox()).height).toBeLessThan(250); + expect((await iframe.boundingBox())!.height).toBeLessThan(250); await page.locator(".mx_AppsDrawer_resizer_container_handle").hover(); await page.mouse.down(); await page.mouse.move(0, 550); await page.mouse.up(); - expect((await iframe.boundingBox()).height).toBeGreaterThan(400); + expect((await iframe.boundingBox())!.height).toBeGreaterThan(400); }); test("programmatically resize the height of the top container layout", async ({ page, app }) => { const iframe = page.locator('iframe[title="widget"]'); - expect((await iframe.boundingBox()).height).toBeLessThan(250); + expect((await iframe.boundingBox())!.height).toBeLessThan(250); await app.client.sendStateEvent( roomId, @@ -106,6 +106,6 @@ test.describe("Widget Layout", () => { "", ); - await expect.poll(async () => (await iframe.boundingBox()).height).toBeGreaterThan(400); + await expect.poll(async () => (await iframe.boundingBox())!.height).toBeGreaterThan(400); }); }); diff --git a/apps/web/playwright/e2e/widgets/widget-pip-close.spec.ts b/apps/web/playwright/e2e/widgets/widget-pip-close.spec.ts index f2b01f5263..17780b81c2 100644 --- a/apps/web/playwright/e2e/widgets/widget-pip-close.spec.ts +++ b/apps/web/playwright/e2e/widgets/widget-pip-close.spec.ts @@ -56,7 +56,7 @@ async function waitForRoomWidget(client: Client, widgetId: string, roomId: strin } } - const room = matrixClient.getRoom(roomId); + const room = matrixClient.getRoom(roomId)!; const startingWidgetEvents = room.currentState.getStateEvents("im.vector.modular.widgets"); if (eventsInIntendedState(startingWidgetEvents)) { @@ -97,14 +97,14 @@ test.describe("Widget PIP", () => { test(`should be closed on ${userRemove}`, async ({ page, app, bot, user }) => { const roomId = await app.client.createRoom({ name: ROOM_NAME, - invite: [bot.credentials.userId], + invite: [bot.credentials!.userId], }); // sets bot to Admin and user to Moderator await app.client.sendStateEvent(roomId, "m.room.power_levels", { users: { [user.userId]: 50, - [bot.credentials.userId]: 100, + [bot.credentials!.userId]: 100, }, }); diff --git a/apps/web/playwright/element-web-test.ts b/apps/web/playwright/element-web-test.ts index c3e242de9b..d2c4755139 100644 --- a/apps/web/playwright/element-web-test.ts +++ b/apps/web/playwright/element-web-test.ts @@ -44,8 +44,8 @@ export interface TestFixtures extends BaseTestFixtures { app: ElementAppPage; crypto: Crypto; - room?: { roomId: string }; - uut?: Locator; // Unit Under Test, useful place to refer a prepared locator + room: { roomId: string }; + uut: Locator; // Unit Under Test, useful place to refer a prepared locator botCreateOpts: CreateBotOpts; bot: Bot; webserver: Webserver; diff --git a/apps/web/playwright/pages/ElementAppPage.ts b/apps/web/playwright/pages/ElementAppPage.ts index 4cd8ff0f76..3c7d66a950 100644 --- a/apps/web/playwright/pages/ElementAppPage.ts +++ b/apps/web/playwright/pages/ElementAppPage.ts @@ -210,7 +210,7 @@ export class ElementAppPage { const dataTransfer = await this.page.evaluateHandle( async ([buffer, name, type]) => { const dt = new DataTransfer(); - const file = new File([Uint8Array.fromBase64(buffer)], name, { + const file = new File([Uint8Array.fromBase64!(buffer)], name, { type, }); dt.items.add(file); @@ -241,7 +241,7 @@ export class ElementAppPage { await composer.evaluate( async (element, [buffer, name, type]) => { const clipboardData = new DataTransfer(); - const file = new File([Uint8Array.fromBase64(buffer)], name, { + const file = new File([Uint8Array.fromBase64!(buffer)], name, { type, }); clipboardData.items.add(file); @@ -404,12 +404,12 @@ export class ElementAppPage { const boundingRectangle = await separator.boundingBox(); // Place the cursor in the center of the separator - const centerX = boundingRectangle.x + boundingRectangle.width / 2; - await this.page.mouse.move(centerX, boundingRectangle.y); + const centerX = boundingRectangle!.x + boundingRectangle!.width / 2; + await this.page.mouse.move(centerX, boundingRectangle!.y); // Drag the cursor by delta pixels await this.page.mouse.down(); - await this.page.mouse.move(centerX + delta, boundingRectangle.y); + await this.page.mouse.move(centerX + delta, boundingRectangle!.y); await this.page.mouse.up(); } } diff --git a/apps/web/playwright/pages/Spotlight.ts b/apps/web/playwright/pages/Spotlight.ts index 5f3c8ef6b9..4b08d6e3bb 100644 --- a/apps/web/playwright/pages/Spotlight.ts +++ b/apps/web/playwright/pages/Spotlight.ts @@ -15,7 +15,7 @@ export enum Filter { } export class Spotlight { - private root: Locator; + private root!: Locator; constructor(private page: Page) {} diff --git a/apps/web/playwright/pages/bot.ts b/apps/web/playwright/pages/bot.ts index 0df531020c..1e5a9bb3c9 100644 --- a/apps/web/playwright/pages/bot.ts +++ b/apps/web/playwright/pages/bot.ts @@ -63,7 +63,7 @@ type ExtendedMatrixClient = MatrixClient & { __playwright_recovery_key: Generate export class Bot extends Client { public credentials?: CredentialsOptionalAccessToken; - private handlePromise: Promise>; + private handlePromise?: Promise>; constructor( page: Page, @@ -192,7 +192,7 @@ export class Bot extends Client { type: "m.id.user", user: credentials.userId, }, - password: credentials.password, + password: credentials.password ?? undefined, }); credentials.accessToken = loginResponse.access_token; @@ -252,7 +252,7 @@ export class Bot extends Client { if (this.opts.bootstrapSecretStorage) { await clientHandle.evaluate(async (cli, usePassphrase) => { const passphrase = usePassphrase ? "new passphrase" : undefined; - const recoveryKey = await cli.getCrypto().createRecoveryKeyFromPassphrase(passphrase); + const recoveryKey = await cli.getCrypto()!.createRecoveryKeyFromPassphrase(passphrase); Object.assign(cli, { __playwright_recovery_key: recoveryKey }); await cli.getCrypto()!.bootstrapSecretStorage({ diff --git a/apps/web/playwright/pages/client.ts b/apps/web/playwright/pages/client.ts index 4c063cc09e..d95577c5fd 100644 --- a/apps/web/playwright/pages/client.ts +++ b/apps/web/playwright/pages/client.ts @@ -60,7 +60,7 @@ export type PageFunctionOn = string | ((on: On, arg2: Unboxed export class Client { public network: Network; - protected client: JSHandle; + protected client: JSHandle | null = null; protected getClientHandle(): Promise> { return this.page.evaluateHandle(() => window.mxMatrixClientPeg.get()); @@ -93,8 +93,8 @@ export class Client { arg?: any, ): Promise; public async evaluate(fn: (client: MatrixClient) => T, arg?: any): Promise { - await this.prepareClient(); - return this.client.evaluate(fn, arg); + const client = await this.prepareClient(); + return client.evaluate(fn, arg); } public evaluateHandle( @@ -106,8 +106,8 @@ export class Client { arg?: any, ): Promise>; public async evaluateHandle(fn: (client: MatrixClient) => T, arg?: any): Promise> { - await this.prepareClient(); - return this.client.evaluateHandle(fn, arg); + const client = await this.prepareClient(); + return client.evaluateHandle(fn, arg); } /** @@ -248,7 +248,7 @@ export class Client { const client = await this.prepareClient(); return client.evaluate( async (client, { roomName }) => { - const room = client.getRooms().find((r) => r.getDefaultRoomName(client.getUserId()) === roomName); + const room = client.getRooms().find((r) => r.getDefaultRoomName(client.getSafeUserId()) === roomName); if (room) { await client.joinRoom(room.roomId); return room.roomId; @@ -268,7 +268,7 @@ export class Client { await this.page.waitForResponse(async (response) => { const accessToken = await this.evaluate((client) => client.getAccessToken()); const authHeader = await response.request().headerValue("authorization"); - return response.url().includes("/sync") && authHeader.includes(accessToken); + return response.url().includes("/sync") && !!accessToken && !!authHeader?.includes(accessToken); }); } @@ -392,11 +392,11 @@ export class Client { event: JSHandle, receiptType?: ReceiptType, unthreaded?: boolean, - ): Promise { + ): Promise { const client = await this.prepareClient(); return client.evaluate( - (client, { event, receiptType, unthreaded }) => { - return client.sendReadReceipt(event, receiptType, unthreaded); + async (client, { event, receiptType, unthreaded }) => { + await client.sendReadReceipt(event, receiptType, unthreaded); }, { event, receiptType, unthreaded }, ); @@ -555,7 +555,7 @@ export function bootstrapCrossSigningForClient( ) { return client.evaluate( async (client, { credentials, resetKeys }) => { - await client.getCrypto().bootstrapCrossSigning({ + await client.getCrypto()!.bootstrapCrossSigning({ authUploadDeviceSigningKeys: async (func) => { await func({ type: "m.login.password", diff --git a/apps/web/playwright/pages/crypto.ts b/apps/web/playwright/pages/crypto.ts index c882040987..b0737541eb 100644 --- a/apps/web/playwright/pages/crypto.ts +++ b/apps/web/playwright/pages/crypto.ts @@ -22,8 +22,8 @@ export class Crypto { */ public async assertDeviceIsCrossSigned(): Promise { const { userId, deviceId, accessToken } = await this.page.evaluate(() => ({ - userId: window.mxMatrixClientPeg.get().getUserId(), - deviceId: window.mxMatrixClientPeg.get().getDeviceId(), + userId: window.mxMatrixClientPeg.get().getSafeUserId(), + deviceId: window.mxMatrixClientPeg.get().getDeviceId()!, accessToken: window.mxMatrixClientPeg.get().getAccessToken(), })); diff --git a/apps/web/playwright/pages/timeline.ts b/apps/web/playwright/pages/timeline.ts index ca9965a63e..0aa52bc66a 100644 --- a/apps/web/playwright/pages/timeline.ts +++ b/apps/web/playwright/pages/timeline.ts @@ -28,9 +28,9 @@ export class Timeline { } // Find the event tile matching the given sender & body - async findEventTile(sender: string, body: string): Promise { + async findEventTile(sender: string, body: string): Promise { const locators = await this.page.locator(".mx_RoomView_MessageList .mx_EventTile").all(); - let latestSender: string; + let latestSender: string | undefined; for (const locator of locators) { const displayName = locator.locator(".mx_DisambiguatedProfile_displayName"); if (await displayName.count()) { diff --git a/apps/web/playwright/plugins/homeserver/synapse/legacyOAuthHomeserver.ts b/apps/web/playwright/plugins/homeserver/synapse/legacyOAuthHomeserver.ts index abdd0624e7..f792d6d8f5 100644 --- a/apps/web/playwright/plugins/homeserver/synapse/legacyOAuthHomeserver.ts +++ b/apps/web/playwright/plugins/homeserver/synapse/legacyOAuthHomeserver.ts @@ -22,12 +22,12 @@ export const legacyOAuthHomeserver: Fixtures = { ], context: async ({ homeserverType, context, oAuthServer }, use, testInfo) => { testInfo.skip(homeserverType !== "synapse", "does not yet support OIDC"); - oAuthServer.onTestStarted(testInfo); + oAuthServer!.onTestStarted(testInfo); await use(context); }, _homeserver: [ async ({ oAuthServer, _homeserver: homeserver }, use) => { - const port = oAuthServer.start(); + const port = oAuthServer!.start(); await TestContainers.exposeHostPorts(port); homeserver.withConfig({ oidc_providers: [ diff --git a/apps/web/playwright/plugins/oauth_server/index.ts b/apps/web/playwright/plugins/oauth_server/index.ts index 16aad2f027..274973810b 100644 --- a/apps/web/playwright/plugins/oauth_server/index.ts +++ b/apps/web/playwright/plugins/oauth_server/index.ts @@ -69,8 +69,8 @@ export class OAuthServer { public stop(): void { console.log("Stopping OAuth server"); - const address = this.server.address() as AddressInfo; - this.server.close(); + const address = this.server!.address() as AddressInfo; + this.server!.close(); console.log(`Stopped OAuth server at ${address.address}:${address.port}`); } } diff --git a/apps/web/playwright/tsconfig.json b/apps/web/playwright/tsconfig.json index 00f45c0505..a1a5e25ffe 100644 --- a/apps/web/playwright/tsconfig.json +++ b/apps/web/playwright/tsconfig.json @@ -8,8 +8,8 @@ "moduleResolution": "bundler", "module": "ESNext", "allowImportingTsExtensions": true, - "strictNullChecks": false, - "noImplicitAny": false, + "strict": true, + "noUnusedLocals": true, "types": ["node"], "noEmit": true }, diff --git a/apps/web/src/@types/matrix-js-sdk.d.ts b/apps/web/src/@types/matrix-js-sdk.d.ts index 5930ad33ff..09be4eb31e 100644 --- a/apps/web/src/@types/matrix-js-sdk.d.ts +++ b/apps/web/src/@types/matrix-js-sdk.d.ts @@ -11,7 +11,7 @@ import type { BLURHASH_FIELD } from "../utils/image-media"; import type { JitsiCallMemberEventType, JitsiCallMemberContent } from "../call-types"; import type { ILayoutStateEvent, WIDGET_LAYOUT_EVENT_TYPE } from "../stores/widgets/types"; import type { EncryptedFile } from "matrix-js-sdk/src/types"; -import type { EmptyObject } from "matrix-js-sdk/src/matrix"; +import type { EmptyObject, IContent } from "matrix-js-sdk/src/matrix"; import type { DeviceClientInformation } from "../utils/device/types.ts"; import type { UserWidget } from "../utils/WidgetUtils-types.ts"; import { type MediaPreviewConfig } from "./media_preview.ts"; @@ -49,7 +49,7 @@ declare module "matrix-js-sdk/src/types" { "m.room.plumbing": { status: string; }; - "m.room.bot.options": unknown; + "m.room.bot.options": IContent; } export interface TimelineEvents {