@element-hq/element-web-playwright-common 2.4.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.
- package/Dockerfile +14 -8
- package/README.md +2 -2
- package/docker-entrypoint.sh +1 -8
- package/lib/expect/axe.d.ts +1 -1
- package/lib/expect/axe.d.ts.map +1 -1
- package/lib/expect/screenshot.d.ts +1 -1
- package/lib/expect/screenshot.d.ts.map +1 -1
- package/lib/fixtures/axe.d.ts +2 -2
- package/lib/fixtures/axe.d.ts.map +1 -1
- package/lib/fixtures/services.d.ts.map +1 -1
- package/lib/fixtures/services.js +2 -22
- package/lib/fixtures/toasts.d.ts +64 -0
- package/lib/fixtures/toasts.d.ts.map +1 -0
- package/lib/fixtures/toasts.js +97 -0
- package/lib/fixtures/user.d.ts +13 -2
- package/lib/fixtures/user.d.ts.map +1 -1
- package/lib/fixtures/user.js +4 -1
- package/lib/flaky-reporter.d.ts +24 -0
- package/lib/flaky-reporter.d.ts.map +1 -0
- package/lib/flaky-reporter.js +153 -0
- package/lib/index.d.ts +11 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/stale-screenshot-reporter.d.ts +1 -0
- package/lib/stale-screenshot-reporter.d.ts.map +1 -1
- package/lib/stale-screenshot-reporter.js +9 -4
- package/lib/testcontainers/index.d.ts +2 -1
- package/lib/testcontainers/index.d.ts.map +1 -1
- package/lib/testcontainers/index.js +2 -1
- package/lib/testcontainers/mas.d.ts +5 -2
- package/lib/testcontainers/mas.d.ts.map +1 -1
- package/lib/testcontainers/mas.js +14 -2
- package/lib/testcontainers/postgres.d.ts +5 -0
- package/lib/testcontainers/postgres.d.ts.map +1 -0
- package/lib/testcontainers/postgres.js +31 -0
- package/lib/testcontainers/synapse.d.ts +6 -0
- package/lib/testcontainers/synapse.d.ts.map +1 -1
- package/lib/testcontainers/synapse.js +17 -1
- package/package.json +10 -11
- package/playwright-screenshots.sh +33 -126
- package/project.json +44 -0
- package/src/fixtures/services.ts +3 -22
- package/src/fixtures/toasts.ts +109 -0
- package/src/fixtures/user.ts +4 -1
- package/src/flaky-reporter.ts +188 -0
- package/src/stale-screenshot-reporter.ts +9 -5
- package/src/testcontainers/index.ts +2 -0
- package/src/testcontainers/mas.ts +21 -0
- package/src/testcontainers/postgres.ts +40 -0
- package/src/testcontainers/synapse.ts +24 -1
- package/tsconfig.json +8 -3
|
@@ -5,6 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
|
|
5
5
|
Please see LICENSE files in the repository root for full details.
|
|
6
6
|
*/
|
|
7
7
|
export { PostgreSqlContainer, StartedPostgreSqlContainer } from "@testcontainers/postgresql";
|
|
8
|
+
export { makePostgres } from "./postgres.js";
|
|
8
9
|
export { SynapseContainer, StartedSynapseContainer } from "./synapse.js";
|
|
9
|
-
export { MatrixAuthenticationServiceContainer, StartedMatrixAuthenticationServiceContainer, } from "./mas.js";
|
|
10
|
+
export { MatrixAuthenticationServiceContainer, StartedMatrixAuthenticationServiceContainer, makeMas, } from "./mas.js";
|
|
10
11
|
export { MailpitContainer, StartedMailpitContainer } from "./mailpit.js";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { AbstractStartedContainer, GenericContainer, type StartedTestContainer, type ExecResult } from "testcontainers";
|
|
1
|
+
import { AbstractStartedContainer, GenericContainer, type StartedTestContainer, type ExecResult, type StartedNetwork } from "testcontainers";
|
|
2
2
|
import { type StartedPostgreSqlContainer } from "@testcontainers/postgresql";
|
|
3
3
|
import { type Credentials } from "../utils/api.js";
|
|
4
4
|
import type { RootConfig as MasConfig } from "./mas-config.js";
|
|
5
|
+
import type { Logger } from "../utils/logger.js";
|
|
5
6
|
export { type MasConfig };
|
|
6
7
|
/**
|
|
7
8
|
* A container running the Matrix Authentication Service.
|
|
@@ -29,8 +30,9 @@ export declare class MatrixAuthenticationServiceContainer extends GenericContain
|
|
|
29
30
|
export declare class StartedMatrixAuthenticationServiceContainer extends AbstractStartedContainer {
|
|
30
31
|
readonly baseUrl: string;
|
|
31
32
|
private readonly args;
|
|
33
|
+
readonly sharedSecret: string;
|
|
32
34
|
private adminTokenPromise?;
|
|
33
|
-
constructor(container: StartedTestContainer, baseUrl: string, args: string[]);
|
|
35
|
+
constructor(container: StartedTestContainer, baseUrl: string, args: string[], sharedSecret: string);
|
|
34
36
|
/**
|
|
35
37
|
* Retrieves a valid HS admin token
|
|
36
38
|
*/
|
|
@@ -55,4 +57,5 @@ export declare class StartedMatrixAuthenticationServiceContainer extends Abstrac
|
|
|
55
57
|
*/
|
|
56
58
|
setThreepid(username: string, medium: string, address: string): Promise<void>;
|
|
57
59
|
}
|
|
60
|
+
export declare function makeMas(postgres: StartedPostgreSqlContainer, network: StartedNetwork, logger: Logger, config: Partial<MasConfig>, name?: string): Promise<StartedMatrixAuthenticationServiceContainer>;
|
|
58
61
|
//# sourceMappingURL=mas.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mas.d.ts","sourceRoot":"","sources":["../../src/testcontainers/mas.ts"],"names":[],"mappings":"AAOA,OAAO,EACH,wBAAwB,EACxB,gBAAgB,EAChB,KAAK,oBAAoB,EAEzB,KAAK,UAAU,
|
|
1
|
+
{"version":3,"file":"mas.d.ts","sourceRoot":"","sources":["../../src/testcontainers/mas.ts"],"names":[],"mappings":"AAOA,OAAO,EACH,wBAAwB,EACxB,gBAAgB,EAChB,KAAK,oBAAoB,EAEzB,KAAK,UAAU,EACf,KAAK,cAAc,EACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,KAAK,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAK7E,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAKnD,OAAO,KAAK,EAAE,UAAU,IAAI,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO,EAAE,KAAK,SAAS,EAAE,CAAC;AAmH1B;;;;;GAKG;AACH,qBAAa,oCAAqC,SAAQ,gBAAgB;IACtE,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAiC;gBAGlD,EAAE,EAAE,0BAA0B,EAC9B,KAAK,GAAE,MAAkE;IAgB7E;;;OAGG;IACI,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI;IAQnD;;OAEG;IACmB,KAAK,IAAI,OAAO,CAAC,2CAA2C,CAAC;CA2BtF;AAED;;GAEG;AACH,qBAAa,2CAA4C,SAAQ,wBAAwB;aAKjE,OAAO,EAAE,MAAM;IAC/B,OAAO,CAAC,QAAQ,CAAC,IAAI;aACL,YAAY,EAAE,MAAM;IANxC,OAAO,CAAC,iBAAiB,CAAC,CAAkB;gBAGxC,SAAS,EAAE,oBAAoB,EACf,OAAO,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAAE,EACf,YAAY,EAAE,MAAM;IAKxC;;OAEG;IACU,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAYhC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;YAQ1D,kBAAkB;YAgClB,6BAA6B;YAmB7B,oBAAoB;IAoBlC;;;;;;OAMG;IACU,YAAY,CACrB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAC;IAIlD;;;;;OAKG;IACU,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAO7F;AAED,wBAAsB,OAAO,CACzB,QAAQ,EAAE,0BAA0B,EACpC,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,EAC1B,IAAI,SAAQ,GACb,OAAO,CAAC,2CAA2C,CAAC,CAQtD"}
|
|
@@ -132,6 +132,7 @@ export class MatrixAuthenticationServiceContainer extends GenericContainer {
|
|
|
132
132
|
constructor(db, image = "ghcr.io/element-hq/matrix-authentication-service:latest") {
|
|
133
133
|
super(image);
|
|
134
134
|
const initialConfig = deepCopy(DEFAULT_CONFIG);
|
|
135
|
+
initialConfig.database.host = db.getHostname();
|
|
135
136
|
initialConfig.database.username = db.getUsername();
|
|
136
137
|
initialConfig.database.password = db.getPassword();
|
|
137
138
|
this.config = initialConfig;
|
|
@@ -170,7 +171,7 @@ export class MatrixAuthenticationServiceContainer extends GenericContainer {
|
|
|
170
171
|
content: YAML.stringify(this.config),
|
|
171
172
|
},
|
|
172
173
|
]);
|
|
173
|
-
return new StartedMatrixAuthenticationServiceContainer(await super.start(), `http://localhost:${port}`, this.args);
|
|
174
|
+
return new StartedMatrixAuthenticationServiceContainer(await super.start(), `http://localhost:${port}`, this.args, this.config.matrix.secret);
|
|
174
175
|
}
|
|
175
176
|
}
|
|
176
177
|
/**
|
|
@@ -179,11 +180,13 @@ export class MatrixAuthenticationServiceContainer extends GenericContainer {
|
|
|
179
180
|
export class StartedMatrixAuthenticationServiceContainer extends AbstractStartedContainer {
|
|
180
181
|
baseUrl;
|
|
181
182
|
args;
|
|
183
|
+
sharedSecret;
|
|
182
184
|
adminTokenPromise;
|
|
183
|
-
constructor(container, baseUrl, args) {
|
|
185
|
+
constructor(container, baseUrl, args, sharedSecret) {
|
|
184
186
|
super(container);
|
|
185
187
|
this.baseUrl = baseUrl;
|
|
186
188
|
this.args = args;
|
|
189
|
+
this.sharedSecret = sharedSecret;
|
|
187
190
|
}
|
|
188
191
|
/**
|
|
189
192
|
* Retrieves a valid HS admin token
|
|
@@ -265,3 +268,12 @@ export class StartedMatrixAuthenticationServiceContainer extends AbstractStarted
|
|
|
265
268
|
await this.manage("add-email", username, address);
|
|
266
269
|
}
|
|
267
270
|
}
|
|
271
|
+
export async function makeMas(postgres, network, logger, config, name = "mas") {
|
|
272
|
+
const container = await new MatrixAuthenticationServiceContainer(postgres)
|
|
273
|
+
.withNetwork(network)
|
|
274
|
+
.withNetworkAliases(name)
|
|
275
|
+
.withLogConsumer(logger.getConsumer(name))
|
|
276
|
+
.withConfig(config)
|
|
277
|
+
.start();
|
|
278
|
+
return container;
|
|
279
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type StartedPostgreSqlContainer } from "@testcontainers/postgresql";
|
|
2
|
+
import { type StartedNetwork } from "testcontainers";
|
|
3
|
+
import { type Logger } from "../utils/logger.js";
|
|
4
|
+
export declare function makePostgres(network: StartedNetwork, logger: Logger, name?: string): Promise<StartedPostgreSqlContainer>;
|
|
5
|
+
//# sourceMappingURL=postgres.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/testcontainers/postgres.ts"],"names":[],"mappings":"AAOA,OAAO,EAAuB,KAAK,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAClG,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAEjD,wBAAsB,YAAY,CAC9B,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,MAAM,EACd,IAAI,SAAa,GAClB,OAAO,CAAC,0BAA0B,CAAC,CAuBrC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2026 Element Creations Ltd.
|
|
3
|
+
|
|
4
|
+
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
|
5
|
+
Please see LICENSE files in the repository root for full details.
|
|
6
|
+
*/
|
|
7
|
+
import { PostgreSqlContainer } from "@testcontainers/postgresql";
|
|
8
|
+
export async function makePostgres(network, logger, name = "postgres") {
|
|
9
|
+
const container = await new PostgreSqlContainer("postgres:13.3-alpine")
|
|
10
|
+
.withNetwork(network)
|
|
11
|
+
.withNetworkAliases(name)
|
|
12
|
+
.withLogConsumer(logger.getConsumer(name))
|
|
13
|
+
.withTmpFs({
|
|
14
|
+
"/dev/shm/pgdata/data": "",
|
|
15
|
+
})
|
|
16
|
+
.withEnvironment({
|
|
17
|
+
PG_DATA: "/dev/shm/pgdata/data",
|
|
18
|
+
})
|
|
19
|
+
.withCommand([
|
|
20
|
+
"-c",
|
|
21
|
+
"shared_buffers=128MB",
|
|
22
|
+
"-c",
|
|
23
|
+
`fsync=off`,
|
|
24
|
+
"-c",
|
|
25
|
+
`synchronous_commit=off`,
|
|
26
|
+
"-c",
|
|
27
|
+
"full_page_writes=off",
|
|
28
|
+
])
|
|
29
|
+
.start();
|
|
30
|
+
return container;
|
|
31
|
+
}
|
|
@@ -153,6 +153,12 @@ declare const DEFAULT_CONFIG: {
|
|
|
153
153
|
module: string;
|
|
154
154
|
config?: Record<string, unknown>;
|
|
155
155
|
}>;
|
|
156
|
+
matrix_authentication_service: undefined | {
|
|
157
|
+
enabled?: boolean;
|
|
158
|
+
endpoint?: string;
|
|
159
|
+
secret?: string | null;
|
|
160
|
+
secret_path?: string | null;
|
|
161
|
+
};
|
|
156
162
|
};
|
|
157
163
|
/**
|
|
158
164
|
* Incomplete type describing the configuration for a Synapse homeserver
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"synapse.d.ts","sourceRoot":"","sources":["../../src/testcontainers/synapse.ts"],"names":[],"mappings":"AAOA,OAAO,EACH,wBAAwB,EACxB,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EAE5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAQzE,OAAO,EAAE,KAAK,mBAAmB,EAAE,KAAK,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACrG,OAAO,EAAE,KAAK,2CAA2C,EAAE,MAAM,UAAU,CAAC;AAC5E,OAAO,EAAE,GAAG,EAAE,eAAe,EAAa,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACpF,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAE5D,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WA+GV,SAAS,GACT;QACI,aAAa,EAAE,OAAO,CAAC;QACvB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,0BAA0B,EAAE,KAAK,CAAC;QAClC,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,mBAAmB,EAAE,MAAM,CAAC;QAC5B,mBAAmB,EAAE,OAAO,CAAC;QAC7B,eAAe,EAAE,MAAM,CAAC;KAC3B;kBAED,SAAS,GACT;QACI,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC;QAChB,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/C,4BAA4B,EAAE,OAAO,CAAC;QACtC,kBAAkB,EAAE,MAAM,CAAC;QAC3B,uBAAuB,EAAE,OAAO,CAAC;KACpC;oBAED,SAAS,GACT;QACI,qBAAqB,EAAE,MAAM,CAAC;QAC9B,wBAAwB,EAAE,MAAM,CAAC;QACjC,sBAAsB,EAAE,MAAM,CAAC;QAC/B,SAAS,EAAE,MAAM,CAAC;KACrB;;2BAEsB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBAE9C,SAAS,GACT;QACI,UAAU,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAC,CAAC;KAChE;;;;;;;;;;aAQQ,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"synapse.d.ts","sourceRoot":"","sources":["../../src/testcontainers/synapse.ts"],"names":[],"mappings":"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"}
|
|
@@ -136,6 +136,7 @@ const DEFAULT_CONFIG = {
|
|
|
136
136
|
},
|
|
137
137
|
room_list_publication_rules: [{ action: "allow" }],
|
|
138
138
|
modules: [],
|
|
139
|
+
matrix_authentication_service: undefined,
|
|
139
140
|
};
|
|
140
141
|
/**
|
|
141
142
|
* A Synapse testcontainer
|
|
@@ -217,7 +218,22 @@ export class SynapseContainer extends GenericContainer {
|
|
|
217
218
|
return this;
|
|
218
219
|
}
|
|
219
220
|
withMatrixAuthenticationService(mas) {
|
|
220
|
-
|
|
221
|
+
if (mas) {
|
|
222
|
+
this.mas = mas;
|
|
223
|
+
this.withConfig({
|
|
224
|
+
matrix_authentication_service: {
|
|
225
|
+
enabled: true,
|
|
226
|
+
endpoint: `http://${mas.getHostname()}:8080/`,
|
|
227
|
+
secret: mas.sharedSecret,
|
|
228
|
+
},
|
|
229
|
+
// Must be disabled when using MAS.
|
|
230
|
+
password_config: {
|
|
231
|
+
enabled: false,
|
|
232
|
+
},
|
|
233
|
+
// Must be disabled when using MAS.
|
|
234
|
+
enable_registration: false,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
221
237
|
return this;
|
|
222
238
|
}
|
|
223
239
|
async start() {
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@element-hq/element-web-playwright-common",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "3.1.0",
|
|
5
5
|
"license": "SEE LICENSE IN README.md",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/element-hq/element-
|
|
9
|
-
"directory": "packages/
|
|
8
|
+
"url": "git+https://github.com/element-hq/element-web.git",
|
|
9
|
+
"directory": "packages/playwright-common"
|
|
10
10
|
},
|
|
11
11
|
"author": "element-hq",
|
|
12
12
|
"engines": {
|
|
@@ -18,15 +18,14 @@
|
|
|
18
18
|
"playwright-screenshots": "playwright-screenshots.sh"
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
|
-
"
|
|
22
|
-
"lint:types": "
|
|
23
|
-
"lint:codestyle": "echo 'handled by lint:eslint'",
|
|
24
|
-
"test": "echo No tests for @element-hq/element-web-playwright-common"
|
|
21
|
+
"prepack": "nx build:playwright",
|
|
22
|
+
"lint:types": "nx lint:types"
|
|
25
23
|
},
|
|
26
24
|
"devDependencies": {
|
|
27
|
-
"@element-hq/element-web-module-api": "
|
|
25
|
+
"@element-hq/element-web-module-api": "workspace:*",
|
|
28
26
|
"@types/lodash-es": "^4.17.12",
|
|
29
|
-
"typescript": "^5.8.2"
|
|
27
|
+
"typescript": "^5.8.2",
|
|
28
|
+
"wait-on": "^9.0.4"
|
|
30
29
|
},
|
|
31
30
|
"dependencies": {
|
|
32
31
|
"@axe-core/playwright": "^4.10.1",
|
|
@@ -40,7 +39,7 @@
|
|
|
40
39
|
},
|
|
41
40
|
"peerDependencies": {
|
|
42
41
|
"@element-hq/element-web-module-api": "*",
|
|
43
|
-
"@playwright/test": "
|
|
44
|
-
"playwright-core": "
|
|
42
|
+
"@playwright/test": "catalog:",
|
|
43
|
+
"playwright-core": "catalog:"
|
|
45
44
|
}
|
|
46
45
|
}
|
|
@@ -6,137 +6,44 @@ set -e
|
|
|
6
6
|
SCRIPT_PATH=$(readlink -f "$0")
|
|
7
7
|
SCRIPT_DIR=$(dirname "$SCRIPT_PATH")
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
function build_image() {
|
|
10
|
+
local IMAGE_NAME="$1"
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
build_image() {
|
|
14
|
-
echo "Building $IMAGE_NAME image in $SCRIPT_DIR"
|
|
15
|
-
|
|
16
|
-
# Check the playwright version
|
|
17
|
-
PM=$(cat package.json | jq -r '.packageManager')
|
|
18
|
-
if [[ $PM == "pnpm@"* ]]; then
|
|
19
|
-
PW_VERSION=$(pnpm list @playwright/test --depth=0 --json | jq -r '.[].devDependencies["@playwright/test"].version')
|
|
20
|
-
else
|
|
21
|
-
PW_VERSION=$(yarn list --pattern @playwright/test --depth=0 --json --non-interactive --no-progress | jq -r '.data.trees[].name | split("@") | last')
|
|
22
|
-
fi
|
|
23
|
-
echo "with Playwright version $PW_VERSION"
|
|
24
|
-
|
|
25
|
-
# Build image
|
|
26
|
-
docker build -t "$IMAGE_NAME" --build-arg "PLAYWRIGHT_VERSION=$PW_VERSION" "$SCRIPT_DIR"
|
|
12
|
+
echo "Building $IMAGE_NAME image in $SCRIPT_DIR"
|
|
13
|
+
docker build -t "$IMAGE_NAME" --build-arg "PLAYWRIGHT_VERSION=${IMAGE_NAME#*:}" "$SCRIPT_DIR"
|
|
27
14
|
}
|
|
28
15
|
|
|
29
|
-
|
|
30
|
-
case "$DOCKER_HOST" in
|
|
31
|
-
unix://*)
|
|
32
|
-
docker_sock="${DOCKER_HOST:7}"
|
|
33
|
-
;;
|
|
34
|
-
"")
|
|
35
|
-
docker_sock="/var/run/docker.sock"
|
|
36
|
-
;;
|
|
37
|
-
*)
|
|
38
|
-
echo "$0: unsupported DOCKER_HOST setting '${DOCKER_HOST}'" >&2
|
|
39
|
-
exit 1;
|
|
40
|
-
;;
|
|
41
|
-
esac
|
|
42
|
-
|
|
43
|
-
RUN_ARGS=(
|
|
44
|
-
--rm
|
|
45
|
-
--network host
|
|
46
|
-
# Pass BASE_URL and CI environment variables to the container
|
|
47
|
-
-e BASE_URL
|
|
48
|
-
-e CI
|
|
49
|
-
# Bind mount the working directory into the container
|
|
50
|
-
-v $(pwd):/work/
|
|
51
|
-
# Bind mount the docker socket so we can run docker commands from the container
|
|
52
|
-
-v "${docker_sock}":/var/run/docker.sock
|
|
53
|
-
# Bind mount /tmp so we can store temporary files
|
|
54
|
-
-v /tmp/:/tmp/
|
|
55
|
-
-it
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
DEFAULT_ARGS=(--grep @screenshot)
|
|
59
|
-
LINK_MODULES=true
|
|
60
|
-
|
|
61
|
-
# Some arguments to customise behaviour so the same script / image can be
|
|
62
|
-
# re-used for other screenshot generation.
|
|
63
|
-
while [[ $# -gt 0 ]]; do
|
|
64
|
-
case "$1" in
|
|
65
|
-
# Mounts a separate node_modules directory from a docker volume in the container.
|
|
66
|
-
# Must be used if executing something that requires native node modules
|
|
67
|
-
# It's a volume rather than a directory because otherwise things tend to start picking up
|
|
68
|
-
# files from it in the native environment and break.
|
|
69
|
-
--with-node-modules)
|
|
70
|
-
mount_param="type=volume,src=ew-docker-node-modules,dst=/work/node_modules"
|
|
71
|
-
# podman doesn't support `volume-nocopy`
|
|
72
|
-
if [ -z "$docker_is_podman" ]; then mount_param+=",volume-nocopy"; fi
|
|
73
|
-
RUN_ARGS+=(--mount "${mount_param}" -e YARN_INSTALL=true)
|
|
74
|
-
shift
|
|
75
|
-
;;
|
|
76
|
-
# Disables the automatic detection & linking of node_modules which can clash with developer tooling e.g. pnpm-link
|
|
77
|
-
--no-link-modules)
|
|
78
|
-
LINK_MODULES=false
|
|
79
|
-
shift
|
|
80
|
-
;;
|
|
81
|
-
# Sets a different entrypoint (in which case the default arguments to the script will be ignored)
|
|
82
|
-
--entrypoint)
|
|
83
|
-
shift
|
|
84
|
-
RUN_ARGS+=(--entrypoint "$1")
|
|
85
|
-
DEFAULT_ARGS=()
|
|
86
|
-
shift
|
|
87
|
-
;;
|
|
88
|
-
*)
|
|
89
|
-
break
|
|
90
|
-
;;
|
|
91
|
-
esac
|
|
92
|
-
done
|
|
93
|
-
|
|
94
|
-
build_image
|
|
16
|
+
WS_PORT=3000
|
|
95
17
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
SYMLINKS=$(find . -maxdepth 2 -type l -not -path "./.bin/*")
|
|
100
|
-
popd > /dev/null
|
|
101
|
-
for LINK in $SYMLINKS; do
|
|
102
|
-
TARGET=$(readlink -f "node_modules/$LINK") || true
|
|
103
|
-
if [ -d "$TARGET" ]; then
|
|
104
|
-
if [ -n "$docker_is_podman" ]; then
|
|
105
|
-
echo -e "\033[31m" >&2
|
|
106
|
-
cat <<'EOF' >&2
|
|
107
|
-
WARNING: `node_modules` contains symlinks, and the support for this in
|
|
108
|
-
`playwright-screenshots.sh` is broken under podman due to
|
|
109
|
-
https://github.com/containers/podman/issues/25947.
|
|
18
|
+
# Check the playwright version
|
|
19
|
+
PW_VERSION=$(pnpm --silent -- playwright --version | awk '{print $2}')
|
|
20
|
+
IMAGE_NAME="ghcr.io/element-hq/element-web/playwright-server:$PW_VERSION"
|
|
110
21
|
|
|
111
|
-
If
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
done
|
|
22
|
+
# If the image exists in the repository, pull it; otherwise, build it.
|
|
23
|
+
#
|
|
24
|
+
# (This explicit test gives the user clearer progress info than just
|
|
25
|
+
# `docker pull 2>/dev/null || build_image`.)
|
|
26
|
+
if docker manifest inspect "$IMAGE_NAME" &>/dev/null; then
|
|
27
|
+
docker pull "$IMAGE_NAME"
|
|
28
|
+
else
|
|
29
|
+
build_image "$IMAGE_NAME"
|
|
120
30
|
fi
|
|
121
31
|
|
|
122
|
-
#
|
|
123
|
-
|
|
124
|
-
#
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
#
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
# find the running Ryuk instance and connect to it rather than start a new one.
|
|
137
|
-
#
|
|
138
|
-
# [1] https://testcontainers.com/
|
|
139
|
-
# [2] https://github.com/testcontainers/moby-ryuk
|
|
140
|
-
docker run -d --rm --label org.testcontainers.ryuk=true -v "${docker_sock}":/var/run/docker.sock -p 8080 --name="playwright-ryuk" testcontainers/ryuk:0.14.0
|
|
32
|
+
# Start the playwright-server in docker
|
|
33
|
+
CONTAINER=$(docker run --network=host -v /tmp:/tmp --rm -d -e PORT="$WS_PORT" "$IMAGE_NAME")
|
|
34
|
+
# Set up an exit trap to clean up the docker container
|
|
35
|
+
clean_up() {
|
|
36
|
+
ARG=$?
|
|
37
|
+
echo "Stopping playwright-server"
|
|
38
|
+
docker stop "$CONTAINER" > /dev/null
|
|
39
|
+
exit $ARG
|
|
40
|
+
}
|
|
41
|
+
trap clean_up EXIT
|
|
42
|
+
|
|
43
|
+
# Wait for playwright-server to be ready
|
|
44
|
+
echo "Waiting for playwright-server"
|
|
45
|
+
pnpm --dir "$SCRIPT_DIR" exec wait-on "tcp:$WS_PORT"
|
|
141
46
|
|
|
142
|
-
|
|
47
|
+
# Run the test we were given, setting PW_TEST_CONNECT_WS_ENDPOINT accordingly
|
|
48
|
+
echo "Running '$@'"
|
|
49
|
+
PW_TEST_CONNECT_WS_ENDPOINT="http://localhost:$WS_PORT" "$@"
|
package/project.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
3
|
+
"projectType": "library",
|
|
4
|
+
"root": "packages/playwright-common",
|
|
5
|
+
"targets": {
|
|
6
|
+
"build:playwright": {
|
|
7
|
+
"cache": true,
|
|
8
|
+
"command": "tsc",
|
|
9
|
+
"inputs": ["src"],
|
|
10
|
+
"outputs": ["{projectRoot}/lib"],
|
|
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"]
|
|
18
|
+
},
|
|
19
|
+
"docker:prebuild": {
|
|
20
|
+
"cache": true,
|
|
21
|
+
"command": "echo PLAYWRIGHT_VERSION=$(pnpm --silent -- playwright --version | awk '{print $2}') > .env.docker:build",
|
|
22
|
+
"inputs": [{ "runtime": "pnpm --silent -- playwright --version" }],
|
|
23
|
+
"outputs": ["{projectRoot}/.env.docker:build"],
|
|
24
|
+
"options": { "cwd": "packages/playwright-common" }
|
|
25
|
+
},
|
|
26
|
+
"docker:build": {
|
|
27
|
+
"executor": "@nx-tools/nx-container:build",
|
|
28
|
+
"dependsOn": ["docker:prebuild"],
|
|
29
|
+
"options": {
|
|
30
|
+
"load": true,
|
|
31
|
+
"engine": "docker",
|
|
32
|
+
"platforms": ["linux/amd64", "linux/arm64"],
|
|
33
|
+
"provenance": "true",
|
|
34
|
+
"sbom": true,
|
|
35
|
+
"build-args": ["PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION"],
|
|
36
|
+
"context": "{projectRoot}",
|
|
37
|
+
"metadata": {
|
|
38
|
+
"images": ["ghcr.io/element-hq/element-web/playwright-server"],
|
|
39
|
+
"tags": ["type=ref,event=branch", "type=raw,enable={{is_default_branch}},value=$PLAYWRIGHT_VERSION"]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/fixtures/services.ts
CHANGED
|
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
|
|
7
7
|
|
|
8
8
|
import { type MailpitClient } from "mailpit-api";
|
|
9
9
|
import { Network, type StartedNetwork } from "testcontainers";
|
|
10
|
-
import {
|
|
10
|
+
import { type StartedPostgreSqlContainer } from "@testcontainers/postgresql";
|
|
11
11
|
|
|
12
12
|
import {
|
|
13
13
|
type SynapseConfig,
|
|
@@ -22,6 +22,7 @@ import { Logger } from "../utils/logger.js";
|
|
|
22
22
|
// We want to avoid using `mergeTests` in index.ts because it drops useful type information about the fixtures. Instead,
|
|
23
23
|
// we add `axe` into our fixture suite by using its `test` as a base, so that there is a linear hierarchy.
|
|
24
24
|
import { test as base } from "./axe.js";
|
|
25
|
+
import { makePostgres } from "../testcontainers/postgres.js";
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* Test-scoped fixtures available in the test
|
|
@@ -101,27 +102,7 @@ export const test = base.extend<TestFixtures, WorkerOptions & Services>({
|
|
|
101
102
|
],
|
|
102
103
|
postgres: [
|
|
103
104
|
async ({ logger, network }, use) => {
|
|
104
|
-
const container = await
|
|
105
|
-
.withNetwork(network)
|
|
106
|
-
.withNetworkAliases("postgres")
|
|
107
|
-
.withLogConsumer(logger.getConsumer("postgres"))
|
|
108
|
-
.withTmpFs({
|
|
109
|
-
"/dev/shm/pgdata/data": "",
|
|
110
|
-
})
|
|
111
|
-
.withEnvironment({
|
|
112
|
-
PG_DATA: "/dev/shm/pgdata/data",
|
|
113
|
-
})
|
|
114
|
-
.withCommand([
|
|
115
|
-
"-c",
|
|
116
|
-
"shared_buffers=128MB",
|
|
117
|
-
"-c",
|
|
118
|
-
`fsync=off`,
|
|
119
|
-
"-c",
|
|
120
|
-
`synchronous_commit=off`,
|
|
121
|
-
"-c",
|
|
122
|
-
"full_page_writes=off",
|
|
123
|
-
])
|
|
124
|
-
.start();
|
|
105
|
+
const container = await makePostgres(network, logger);
|
|
125
106
|
await use(container);
|
|
126
107
|
await container.stop();
|
|
127
108
|
},
|
|
@@ -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
|
+
}
|
package/src/fixtures/user.ts
CHANGED
|
@@ -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
|
-
|
|
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. */
|