diff --git a/cypress/e2e/toasts/analytics-toast.spec.ts b/cypress/e2e/toasts/analytics-toast.spec.ts
deleted file mode 100644
index 4cc8baa838..0000000000
--- a/cypress/e2e/toasts/analytics-toast.spec.ts
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
-Copyright 2022 The Matrix.org Foundation C.I.C.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-///
-
-import { HomeserverInstance } from "../../plugins/utils/homeserver";
-import Chainable = Cypress.Chainable;
-
-function assertNoToasts(): void {
- cy.get(".mx_Toast_toast").should("not.exist");
-}
-
-function getToast(expectedTitle: string): Chainable {
- return cy.contains(".mx_Toast_toast h2", expectedTitle).should("exist").closest(".mx_Toast_toast");
-}
-
-function acceptToast(expectedTitle: string): void {
- getToast(expectedTitle).within(() => {
- cy.get(".mx_Toast_buttons .mx_AccessibleButton_kind_primary").click();
- });
-}
-
-function rejectToast(expectedTitle: string): void {
- getToast(expectedTitle).within(() => {
- cy.get(".mx_Toast_buttons .mx_AccessibleButton_kind_danger_outline").click();
- });
-}
-
-describe("Analytics Toast", () => {
- let homeserver: HomeserverInstance;
-
- afterEach(() => {
- cy.stopHomeserver(homeserver);
- });
-
- it("should not show an analytics toast if config has nothing about posthog", () => {
- cy.intercept("/config.json?cachebuster=*", (req) => {
- req.continue((res) => {
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- const { posthog, ...body } = res.body;
- res.send(200, body);
- });
- });
-
- cy.startHomeserver("default").then((data) => {
- homeserver = data;
- cy.initTestUser(homeserver, "Tod");
- });
-
- rejectToast("Notifications");
- assertNoToasts();
- });
-
- describe("with posthog enabled", () => {
- beforeEach(() => {
- cy.intercept("/config.json?cachebuster=*", (req) => {
- req.continue((res) => {
- res.send(200, {
- ...res.body,
- posthog: {
- project_api_key: "foo",
- api_host: "bar",
- },
- });
- });
- });
-
- cy.startHomeserver("default").then((data) => {
- homeserver = data;
- cy.initTestUser(homeserver, "Tod");
- rejectToast("Notifications");
- });
- });
-
- it("should show an analytics toast which can be accepted", () => {
- acceptToast("Help improve Element");
- assertNoToasts();
- });
-
- it("should show an analytics toast which can be rejected", () => {
- rejectToast("Help improve Element");
- assertNoToasts();
- });
- });
-});
diff --git a/playwright/e2e/toasts/analytics-toast.spec.ts b/playwright/e2e/toasts/analytics-toast.spec.ts
new file mode 100644
index 0000000000..2ce2f82962
--- /dev/null
+++ b/playwright/e2e/toasts/analytics-toast.spec.ts
@@ -0,0 +1,53 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { test } from "../../element-web-test";
+
+test.describe("Analytics Toast", () => {
+ test.use({
+ displayName: "Tod",
+ });
+
+ test("should not show an analytics toast if config has nothing about posthog", async ({ user, toasts }) => {
+ await toasts.rejectToast("Notifications");
+ await toasts.assertNoToasts();
+ });
+
+ test.describe("with posthog enabled", () => {
+ test.use({
+ config: {
+ posthog: {
+ project_api_key: "foo",
+ api_host: "bar",
+ },
+ },
+ });
+
+ test.beforeEach(async ({ user, toasts }) => {
+ await toasts.rejectToast("Notifications");
+ });
+
+ test("should show an analytics toast which can be accepted", async ({ user, toasts }) => {
+ await toasts.acceptToast("Help improve Element");
+ await toasts.assertNoToasts();
+ });
+
+ test("should show an analytics toast which can be rejected", async ({ user, toasts }) => {
+ await toasts.rejectToast("Help improve Element");
+ await toasts.assertNoToasts();
+ });
+ });
+});
diff --git a/playwright/element-web-test.ts b/playwright/element-web-test.ts
index 51cb003489..ee1ae67f3a 100644
--- a/playwright/element-web-test.ts
+++ b/playwright/element-web-test.ts
@@ -24,6 +24,7 @@ import { Credentials, HomeserverInstance, StartHomeserverOpts } from "./plugins/
import { Synapse } from "./plugins/synapse";
import { Instance } from "./plugins/mailhog";
import { OAuthServer } from "./plugins/oauth_server";
+import { Toasts } from "./pages/toasts";
const CONFIG_JSON: Partial = {
// This is deliberately quite a minimal config.json, so that we can test that the default settings
@@ -60,6 +61,7 @@ export const test = base.extend<
};
displayName?: string;
mailhog?: { api: mailhog.API; instance: Instance };
+ toasts: Toasts;
}
>({
crypto: ["legacy", { option: true }],
@@ -147,6 +149,10 @@ export const test = base.extend<
expect(results.violations).toEqual([]);
}),
+
+ toasts: async ({ page }, use) => {
+ await use(new Toasts(page));
+ },
});
test.use({});
diff --git a/playwright/pages/toasts.ts b/playwright/pages/toasts.ts
new file mode 100644
index 0000000000..0785f33c23
--- /dev/null
+++ b/playwright/pages/toasts.ts
@@ -0,0 +1,60 @@
+/*
+Copyright 2023 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { Page, expect, Locator } from "@playwright/test";
+
+export class Toasts {
+ public constructor(private readonly page: Page) {}
+
+ /**
+ * Assert that a toast with the given title exists, and return it
+ *
+ * @param expectedTitle - Expected title of the toast
+ * @returns the Locator for the matching toast
+ */
+ public async getToast(expectedTitle: string): Promise {
+ const toast = this.page.locator(".mx_Toast_toast", { hasText: expectedTitle }).first();
+ await expect(toast).toBeVisible();
+ return toast;
+ }
+
+ /**
+ * Assert that no toasts exist
+ */
+ public async assertNoToasts(): Promise {
+ await expect(this.page.locator(".mx_Toast_toast")).not.toBeVisible();
+ }
+
+ /**
+ * Accept a toast with the given title, only works for the first toast in the stack
+ *
+ * @param expectedTitle - Expected title of the toast
+ */
+ public async acceptToast(expectedTitle: string): Promise {
+ const toast = await this.getToast(expectedTitle);
+ await toast.locator(".mx_Toast_buttons .mx_AccessibleButton_kind_primary").click();
+ }
+
+ /**
+ * Reject a toast with the given title, only works for the first toast in the stack
+ *
+ * @param expectedTitle - Expected title of the toast
+ */
+ public async rejectToast(expectedTitle: string): Promise {
+ const toast = await this.getToast(expectedTitle);
+ await toast.locator(".mx_Toast_buttons .mx_AccessibleButton_kind_danger_outline").click();
+ }
+}