@element-hq/element-web-playwright-common 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,64 @@
1
+ import { type Locator, type Page } from "@playwright/test";
2
+ export declare const test: import("playwright/test").TestType<import("playwright/test").PlaywrightTestArgs & import("playwright/test").PlaywrightTestOptions & {
3
+ axe: import("@axe-core/playwright").AxeBuilder;
4
+ } & import("./services.js").TestFixtures & {
5
+ /**
6
+ * Convenience functions for handling toasts.
7
+ */
8
+ toasts: Toasts;
9
+ }, import("playwright/test").PlaywrightWorkerArgs & import("playwright/test").PlaywrightWorkerOptions & import("./services.js").WorkerOptions & import("./services.js").Services>;
10
+ declare class Toasts {
11
+ readonly page: Page;
12
+ constructor(page: Page);
13
+ /**
14
+ * Assert that no toasts exist
15
+ */
16
+ assertNoToasts(): Promise<void>;
17
+ /**
18
+ * Assert that a toast with the given title exists, and return it
19
+ *
20
+ * @param title - Expected title of the toast
21
+ * @param timeout - Time to retry the assertion for in milliseconds.
22
+ * Defaults to `timeout` in `TestConfig.expect`.
23
+ * @returns the Locator for the matching toast
24
+ */
25
+ getToast(title: string, timeout?: number): Promise<Locator>;
26
+ /**
27
+ * Find a toast with the given title, if it exists.
28
+ *
29
+ * @param title - Title of the toast.
30
+ * @returns the Locator for the matching toast, or an empty locator if it
31
+ * doesn't exist.
32
+ */
33
+ getToastIfExists(title: string): Locator;
34
+ /**
35
+ * Accept a toast with the given title. Only works for the first toast in
36
+ * the stack.
37
+ *
38
+ * @param title - Expected title of the toast
39
+ */
40
+ acceptToast(title: string): Promise<void>;
41
+ /**
42
+ * Accept a toast with the given title, if it exists. Only works for the
43
+ * first toast in the stack.
44
+ *
45
+ * @param title - Title of the toast
46
+ */
47
+ acceptToastIfExists(title: string): Promise<void>;
48
+ /**
49
+ * Reject a toast with the given title. Only works for the first toast in
50
+ * the stack.
51
+ *
52
+ * @param title - Expected title of the toast
53
+ */
54
+ rejectToast(title: string): Promise<void>;
55
+ /**
56
+ * Reject a toast with the given title, if it exists. Only works for the
57
+ * first toast in the stack.
58
+ *
59
+ * @param title - Title of the toast
60
+ */
61
+ rejectToastIfExists(title: string): Promise<void>;
62
+ }
63
+ export {};
64
+ //# sourceMappingURL=toasts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toasts.d.ts","sourceRoot":"","sources":["../../src/fixtures/toasts.ts"],"names":[],"mappings":"AAOA,OAAO,EAAU,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAQnE,eAAO,MAAM,IAAI;;;IACb;;OAEG;YACK,MAAM;iLAMhB,CAAC;AAEH,cAAM,MAAM;aAC2B,IAAI,EAAE,IAAI;gBAAV,IAAI,EAAE,IAAI;IAE7C;;OAEG;IACU,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5C;;;;;;;OAOG;IACU,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMxE;;;;;;OAMG;IACI,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAI/C;;;;;OAKG;IACU,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAItD;;;;;OAKG;IACU,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO9D;;;;;OAKG;IACU,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKtD;;;;;OAKG;IACU,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAMjE"}
@@ -0,0 +1,97 @@
1
+ /*
2
+ * Copyright 2026 Element Creations Ltd.
3
+ *
4
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
5
+ * Please see LICENSE files in the repository root for full details.
6
+ */
7
+ import { expect } from "@playwright/test";
8
+ // We want to avoid using `mergeTests` in index.ts because it drops useful type
9
+ // information about the fixtures. Instead, we add `services` into our fixture
10
+ // suite by using its `test` as a base, so that there is a linear hierarchy.
11
+ import { test as base } from "./services.js";
12
+ // This fixture provides convenient handling of Element Web's toasts.
13
+ export const test = base.extend({
14
+ toasts: async ({ page }, use) => {
15
+ const toasts = new Toasts(page);
16
+ await use(toasts);
17
+ },
18
+ });
19
+ class Toasts {
20
+ page;
21
+ constructor(page) {
22
+ this.page = page;
23
+ }
24
+ /**
25
+ * Assert that no toasts exist
26
+ */
27
+ async assertNoToasts() {
28
+ await expect(this.page.locator(".mx_Toast_toast")).not.toBeVisible();
29
+ }
30
+ /**
31
+ * Assert that a toast with the given title exists, and return it
32
+ *
33
+ * @param title - Expected title of the toast
34
+ * @param timeout - Time to retry the assertion for in milliseconds.
35
+ * Defaults to `timeout` in `TestConfig.expect`.
36
+ * @returns the Locator for the matching toast
37
+ */
38
+ async getToast(title, timeout) {
39
+ const toast = this.getToastIfExists(title);
40
+ await expect(toast).toBeVisible({ timeout });
41
+ return toast;
42
+ }
43
+ /**
44
+ * Find a toast with the given title, if it exists.
45
+ *
46
+ * @param title - Title of the toast.
47
+ * @returns the Locator for the matching toast, or an empty locator if it
48
+ * doesn't exist.
49
+ */
50
+ getToastIfExists(title) {
51
+ return this.page.locator(".mx_Toast_toast", { hasText: title }).first();
52
+ }
53
+ /**
54
+ * Accept a toast with the given title. Only works for the first toast in
55
+ * the stack.
56
+ *
57
+ * @param title - Expected title of the toast
58
+ */
59
+ async acceptToast(title) {
60
+ const toast = await this.getToast(title);
61
+ await toast.locator('.mx_Toast_buttons button[data-kind="primary"]').click();
62
+ }
63
+ /**
64
+ * Accept a toast with the given title, if it exists. Only works for the
65
+ * first toast in the stack.
66
+ *
67
+ * @param title - Title of the toast
68
+ */
69
+ async acceptToastIfExists(title) {
70
+ const toast = this.getToastIfExists(title).locator('.mx_Toast_buttons button[data-kind="primary"]');
71
+ if ((await toast.count()) > 0) {
72
+ await toast.click();
73
+ }
74
+ }
75
+ /**
76
+ * Reject a toast with the given title. Only works for the first toast in
77
+ * the stack.
78
+ *
79
+ * @param title - Expected title of the toast
80
+ */
81
+ async rejectToast(title) {
82
+ const toast = await this.getToast(title);
83
+ await toast.locator('.mx_Toast_buttons button[data-kind="secondary"]').click();
84
+ }
85
+ /**
86
+ * Reject a toast with the given title, if it exists. Only works for the
87
+ * first toast in the stack.
88
+ *
89
+ * @param title - Title of the toast
90
+ */
91
+ async rejectToastIfExists(title) {
92
+ const toast = this.getToastIfExists(title).locator('.mx_Toast_buttons button[data-kind="secondary"]');
93
+ if ((await toast.count()) > 0) {
94
+ await toast.click();
95
+ }
96
+ }
97
+ }
@@ -5,6 +5,17 @@ export declare function populateLocalStorageWithCredentials(page: Page, credenti
5
5
  export declare const test: import("playwright/test").TestType<import("playwright/test").PlaywrightTestArgs & import("playwright/test").PlaywrightTestOptions & {
6
6
  axe: import("@axe-core/playwright").AxeBuilder;
7
7
  } & import("./services.js").TestFixtures & {
8
+ toasts: {
9
+ readonly page: Page;
10
+ assertNoToasts(): Promise<void>;
11
+ getToast(title: string, timeout?: number): Promise<import("playwright-core").Locator>;
12
+ getToastIfExists(title: string): import("playwright-core").Locator;
13
+ acceptToast(title: string): Promise<void>;
14
+ acceptToastIfExists(title: string): Promise<void>;
15
+ rejectToast(title: string): Promise<void>;
16
+ rejectToastIfExists(title: string): Promise<void>;
17
+ };
18
+ } & {
8
19
  /**
9
20
  * The displayname to use for the user registered in {@link #credentials}.
10
21
  *
@@ -1 +1 @@
1
- {"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../src/fixtures/user.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAI7C,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,0IAA0I;AAC1I,wBAAsB,mCAAmC,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,iBAuB7F;AAED,eAAO,MAAM,IAAI;;;IACb;;;;;OAKG;kBACW,MAAM;IAEpB;;;OAGG;iBACU,WAAW;IAExB;;;;;;OAMG;yBACkB,IAAI;IAEzB;;;;OAIG;UACG,WAAW;iLA+BnB,CAAC"}
1
+ {"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../src/fixtures/user.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAO7C,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,0IAA0I;AAC1I,wBAAsB,mCAAmC,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,iBAuB7F;AAED,eAAO,MAAM,IAAI;;;;;;;;;;;;;;IACb;;;;;OAKG;kBACW,MAAM;IAEpB;;;OAGG;iBACU,WAAW;IAExB;;;;;;OAMG;yBACkB,IAAI;IAEzB;;;;OAIG;UACG,WAAW;iLA+BnB,CAAC"}
@@ -6,7 +6,10 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
6
6
  Please see LICENSE files in the repository root for full details.
7
7
  */
8
8
  import { sample, uniqueId } from "lodash-es";
9
- import { test as base } from "./services.js";
9
+ // We want to avoid using `mergeTests` in index.ts because it drops useful type
10
+ // information about the fixtures. Instead, we add `toasts` into our fixture
11
+ // suite by using its `test` as a base, so that there is a linear hierarchy.
12
+ import { test as base } from "./toasts.js";
10
13
  /** Adds an initScript to the given page which will populate localStorage appropriately so that Element will use the given credentials. */
11
14
  export async function populateLocalStorageWithCredentials(page, credentials) {
12
15
  await page.addInitScript(({ credentials }) => {
package/lib/index.d.ts CHANGED
@@ -41,6 +41,17 @@ export interface TestFixtures {
41
41
  export declare const test: import("playwright/test").TestType<import("playwright/test").PlaywrightTestArgs & import("playwright/test").PlaywrightTestOptions & {
42
42
  axe: import("@axe-core/playwright").AxeBuilder;
43
43
  } & import("./fixtures/services.js").TestFixtures & {
44
+ toasts: {
45
+ readonly page: import("playwright-core").Page;
46
+ assertNoToasts(): Promise<void>;
47
+ getToast(title: string, timeout?: number): Promise<import("playwright-core").Locator>;
48
+ getToastIfExists(title: string): import("playwright-core").Locator;
49
+ acceptToast(title: string): Promise<void>;
50
+ acceptToastIfExists(title: string): Promise<void>;
51
+ rejectToast(title: string): Promise<void>;
52
+ rejectToastIfExists(title: string): Promise<void>;
53
+ };
54
+ } & {
44
55
  displayName?: string;
45
56
  credentials: import("./utils/api.js").Credentials;
46
57
  pageWithCredentials: import("playwright-core").Page;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,MAAM,IAAI,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAK/E,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AAEnC,OAAO,EAAE,mCAAmC,EAAE,MAAM,oBAAoB,CAAC;AAQzE,MAAM,WAAW,MAAO,SAAQ,UAAU;IACtC,qBAAqB,EAAE;QACnB,cAAc,CAAC,EAAE;YACb,QAAQ,EAAE,MAAM,CAAC;YACjB,WAAW,CAAC,EAAE,MAAM,CAAC;SACxB,CAAC;QACF,mBAAmB,CAAC,EAAE;YAClB,QAAQ,EAAE,MAAM,CAAC;YACjB,WAAW,CAAC,EAAE,MAAM,CAAC;SACxB,CAAC;KACL,CAAC;IACF,yBAAyB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpD,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAGD,eAAO,MAAM,WAAW,EAAE,OAAO,CAAC,MAAM,CAevC,CAAC;AAEF,MAAM,WAAW,YAAY;IACzB;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC;IAEpC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB;;;;;;;;OAQG;IACH,kBAAkB,EAAE,OAAO,CAAC;CAC/B;AAED,eAAO,MAAM,IAAI;;;;;;;kNAmBf,CAAC;AAEH,OAAO,EAAE,MAAM,EAAE,KAAK,wBAAwB,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,MAAM,IAAI,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAK/E,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AAEnC,OAAO,EAAE,mCAAmC,EAAE,MAAM,oBAAoB,CAAC;AAQzE,MAAM,WAAW,MAAO,SAAQ,UAAU;IACtC,qBAAqB,EAAE;QACnB,cAAc,CAAC,EAAE;YACb,QAAQ,EAAE,MAAM,CAAC;YACjB,WAAW,CAAC,EAAE,MAAM,CAAC;SACxB,CAAC;QACF,mBAAmB,CAAC,EAAE;YAClB,QAAQ,EAAE,MAAM,CAAC;YACjB,WAAW,CAAC,EAAE,MAAM,CAAC;SACxB,CAAC;KACL,CAAC;IACF,yBAAyB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpD,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAGD,eAAO,MAAM,WAAW,EAAE,OAAO,CAAC,MAAM,CAevC,CAAC;AAEF,MAAM,WAAW,YAAY;IACzB;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC;IAEpC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB;;;;;;;;OAQG;IACH,kBAAkB,EAAE,OAAO,CAAC;CAC/B;AAED,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;kNAmBf,CAAC;AAEH,OAAO,EAAE,MAAM,EAAE,KAAK,wBAAwB,EAAE,MAAM,mBAAmB,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@element-hq/element-web-playwright-common",
3
3
  "type": "module",
4
- "version": "3.0.0",
4
+ "version": "3.1.0",
5
5
  "license": "SEE LICENSE IN README.md",
6
6
  "repository": {
7
7
  "type": "git",
@@ -19,10 +19,10 @@
19
19
  },
20
20
  "scripts": {
21
21
  "prepack": "nx build:playwright",
22
- "lint:types": "tsc --noEmit"
22
+ "lint:types": "nx lint:types"
23
23
  },
24
24
  "devDependencies": {
25
- "@element-hq/element-web-module-api": "*",
25
+ "@element-hq/element-web-module-api": "workspace:*",
26
26
  "@types/lodash-es": "^4.17.12",
27
27
  "typescript": "^5.8.2",
28
28
  "wait-on": "^9.0.4"
package/project.json CHANGED
@@ -8,7 +8,13 @@
8
8
  "command": "tsc",
9
9
  "inputs": ["src"],
10
10
  "outputs": ["{projectRoot}/lib"],
11
- "options": { "cwd": "packages/playwright-common" }
11
+ "options": { "cwd": "packages/playwright-common" },
12
+ "dependsOn": ["^build"]
13
+ },
14
+ "lint:types": {
15
+ "command": "pnpm exec tsc --noEmit",
16
+ "options": { "cwd": "packages/playwright-common" },
17
+ "dependsOn": ["^build"]
12
18
  },
13
19
  "docker:prebuild": {
14
20
  "cache": true,
@@ -0,0 +1,109 @@
1
+ /*
2
+ * Copyright 2026 Element Creations Ltd.
3
+ *
4
+ * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
5
+ * Please see LICENSE files in the repository root for full details.
6
+ */
7
+
8
+ import { expect, type Locator, type Page } from "@playwright/test";
9
+
10
+ // We want to avoid using `mergeTests` in index.ts because it drops useful type
11
+ // information about the fixtures. Instead, we add `services` into our fixture
12
+ // suite by using its `test` as a base, so that there is a linear hierarchy.
13
+ import { test as base } from "./services.js";
14
+
15
+ // This fixture provides convenient handling of Element Web's toasts.
16
+ export const test = base.extend<{
17
+ /**
18
+ * Convenience functions for handling toasts.
19
+ */
20
+ toasts: Toasts;
21
+ }>({
22
+ toasts: async ({ page }, use) => {
23
+ const toasts = new Toasts(page);
24
+ await use(toasts);
25
+ },
26
+ });
27
+
28
+ class Toasts {
29
+ public constructor(public readonly page: Page) {}
30
+
31
+ /**
32
+ * Assert that no toasts exist
33
+ */
34
+ public async assertNoToasts(): Promise<void> {
35
+ await expect(this.page.locator(".mx_Toast_toast")).not.toBeVisible();
36
+ }
37
+
38
+ /**
39
+ * Assert that a toast with the given title exists, and return it
40
+ *
41
+ * @param title - Expected title of the toast
42
+ * @param timeout - Time to retry the assertion for in milliseconds.
43
+ * Defaults to `timeout` in `TestConfig.expect`.
44
+ * @returns the Locator for the matching toast
45
+ */
46
+ public async getToast(title: string, timeout?: number): Promise<Locator> {
47
+ const toast = this.getToastIfExists(title);
48
+ await expect(toast).toBeVisible({ timeout });
49
+ return toast;
50
+ }
51
+
52
+ /**
53
+ * Find a toast with the given title, if it exists.
54
+ *
55
+ * @param title - Title of the toast.
56
+ * @returns the Locator for the matching toast, or an empty locator if it
57
+ * doesn't exist.
58
+ */
59
+ public getToastIfExists(title: string): Locator {
60
+ return this.page.locator(".mx_Toast_toast", { hasText: title }).first();
61
+ }
62
+
63
+ /**
64
+ * Accept a toast with the given title. Only works for the first toast in
65
+ * the stack.
66
+ *
67
+ * @param title - Expected title of the toast
68
+ */
69
+ public async acceptToast(title: string): Promise<void> {
70
+ const toast = await this.getToast(title);
71
+ await toast.locator('.mx_Toast_buttons button[data-kind="primary"]').click();
72
+ }
73
+ /**
74
+ * Accept a toast with the given title, if it exists. Only works for the
75
+ * first toast in the stack.
76
+ *
77
+ * @param title - Title of the toast
78
+ */
79
+ public async acceptToastIfExists(title: string): Promise<void> {
80
+ const toast = this.getToastIfExists(title).locator('.mx_Toast_buttons button[data-kind="primary"]');
81
+ if ((await toast.count()) > 0) {
82
+ await toast.click();
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Reject a toast with the given title. Only works for the first toast in
88
+ * the stack.
89
+ *
90
+ * @param title - Expected title of the toast
91
+ */
92
+ public async rejectToast(title: string): Promise<void> {
93
+ const toast = await this.getToast(title);
94
+ await toast.locator('.mx_Toast_buttons button[data-kind="secondary"]').click();
95
+ }
96
+
97
+ /**
98
+ * Reject a toast with the given title, if it exists. Only works for the
99
+ * first toast in the stack.
100
+ *
101
+ * @param title - Title of the toast
102
+ */
103
+ public async rejectToastIfExists(title: string): Promise<void> {
104
+ const toast = this.getToastIfExists(title).locator('.mx_Toast_buttons button[data-kind="secondary"]');
105
+ if ((await toast.count()) > 0) {
106
+ await toast.click();
107
+ }
108
+ }
109
+ }
@@ -9,7 +9,10 @@ Please see LICENSE files in the repository root for full details.
9
9
  import { type Page } from "@playwright/test";
10
10
  import { sample, uniqueId } from "lodash-es";
11
11
 
12
- import { test as base } from "./services.js";
12
+ // We want to avoid using `mergeTests` in index.ts because it drops useful type
13
+ // information about the fixtures. Instead, we add `toasts` into our fixture
14
+ // suite by using its `test` as a base, so that there is a linear hierarchy.
15
+ import { test as base } from "./toasts.js";
13
16
  import { type Credentials } from "../utils/api.js";
14
17
 
15
18
  /** Adds an initScript to the given page which will populate localStorage appropriately so that Element will use the given credentials. */