@element-hq/element-web-playwright-common 1.0.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.
Files changed (96) hide show
  1. package/Dockerfile +9 -0
  2. package/README.md +28 -0
  3. package/lib/element-web-test.d.ts +26 -0
  4. package/lib/element-web-test.d.ts.map +1 -0
  5. package/lib/element-web-test.js +54 -0
  6. package/lib/expect/axe.d.ts +11 -0
  7. package/lib/expect/axe.d.ts.map +1 -0
  8. package/lib/expect/axe.js +22 -0
  9. package/lib/expect/index.d.ts +6 -0
  10. package/lib/expect/index.d.ts.map +1 -0
  11. package/lib/expect/index.js +10 -0
  12. package/lib/expect/screenshot.d.ts +14 -0
  13. package/lib/expect/screenshot.d.ts.map +1 -0
  14. package/lib/expect/screenshot.js +48 -0
  15. package/lib/expect/toHaveNoViolations.d.ts +11 -0
  16. package/lib/expect/toHaveNoViolations.d.ts.map +1 -0
  17. package/lib/expect/toHaveNoViolations.js +22 -0
  18. package/lib/expect/toMatchScreenshot.d.ts +13 -0
  19. package/lib/expect/toMatchScreenshot.d.ts.map +1 -0
  20. package/lib/expect/toMatchScreenshot.js +44 -0
  21. package/lib/expect/toPassAxeCheck.d.ts +7 -0
  22. package/lib/expect/toPassAxeCheck.d.ts.map +1 -0
  23. package/lib/expect/toPassAxeCheck.js +22 -0
  24. package/lib/fixtures/axe.d.ts +8 -0
  25. package/lib/fixtures/axe.d.ts.map +1 -0
  26. package/lib/fixtures/axe.js +15 -0
  27. package/lib/fixtures/index.d.ts +10 -0
  28. package/lib/fixtures/index.d.ts.map +1 -0
  29. package/lib/fixtures/index.js +10 -0
  30. package/lib/fixtures/services.d.ts +57 -0
  31. package/lib/fixtures/services.d.ts.map +1 -0
  32. package/lib/fixtures/services.js +114 -0
  33. package/lib/fixtures/user.d.ts +31 -0
  34. package/lib/fixtures/user.d.ts.map +1 -0
  35. package/lib/fixtures/user.js +47 -0
  36. package/lib/index.d.ts +35 -0
  37. package/lib/index.d.ts.map +1 -0
  38. package/lib/index.js +54 -0
  39. package/lib/logger.d.ts +10 -0
  40. package/lib/logger.d.ts.map +1 -0
  41. package/lib/logger.js +59 -0
  42. package/lib/playwright.d.ts +2 -0
  43. package/lib/playwright.d.ts.map +1 -0
  44. package/lib/playwright.js +1 -0
  45. package/lib/testcontainers/HomeserverContainer.d.ts +70 -0
  46. package/lib/testcontainers/HomeserverContainer.d.ts.map +1 -0
  47. package/lib/testcontainers/HomeserverContainer.js +7 -0
  48. package/lib/testcontainers/index.d.ts +5 -0
  49. package/lib/testcontainers/index.d.ts.map +1 -0
  50. package/lib/testcontainers/index.js +9 -0
  51. package/lib/testcontainers/mailpit.d.ts +33 -0
  52. package/lib/testcontainers/mailpit.d.ts.map +1 -0
  53. package/lib/testcontainers/mailpit.js +52 -0
  54. package/lib/testcontainers/mas.d.ts +182 -0
  55. package/lib/testcontainers/mas.d.ts.map +1 -0
  56. package/lib/testcontainers/mas.js +311 -0
  57. package/lib/testcontainers/synapse.d.ts +229 -0
  58. package/lib/testcontainers/synapse.d.ts.map +1 -0
  59. package/lib/testcontainers/synapse.js +383 -0
  60. package/lib/utils/api.d.ts +49 -0
  61. package/lib/utils/api.d.ts.map +1 -0
  62. package/lib/utils/api.js +73 -0
  63. package/lib/utils/logger.d.ts +25 -0
  64. package/lib/utils/logger.d.ts.map +1 -0
  65. package/lib/utils/logger.js +74 -0
  66. package/lib/utils/object.d.ts +8 -0
  67. package/lib/utils/object.d.ts.map +1 -0
  68. package/lib/utils/object.js +15 -0
  69. package/lib/utils/port.d.ts +5 -0
  70. package/lib/utils/port.d.ts.map +1 -0
  71. package/lib/utils/port.js +20 -0
  72. package/lib/utils/rand.d.ts +6 -0
  73. package/lib/utils/rand.d.ts.map +1 -0
  74. package/lib/utils/rand.js +15 -0
  75. package/package.json +30 -0
  76. package/playwright-screenshots.sh +53 -0
  77. package/src/@types/playwright-core.d.ts +12 -0
  78. package/src/expect/axe.ts +37 -0
  79. package/src/expect/index.ts +21 -0
  80. package/src/expect/screenshot.ts +79 -0
  81. package/src/fixtures/axe.ts +22 -0
  82. package/src/fixtures/index.ts +15 -0
  83. package/src/fixtures/services.ts +188 -0
  84. package/src/fixtures/user.ts +93 -0
  85. package/src/index.ts +92 -0
  86. package/src/testcontainers/HomeserverContainer.ts +87 -0
  87. package/src/testcontainers/index.ts +15 -0
  88. package/src/testcontainers/mailpit.ts +62 -0
  89. package/src/testcontainers/mas.ts +382 -0
  90. package/src/testcontainers/synapse.ts +493 -0
  91. package/src/utils/api.ts +113 -0
  92. package/src/utils/logger.ts +79 -0
  93. package/src/utils/object.ts +16 -0
  94. package/src/utils/port.ts +22 -0
  95. package/src/utils/rand.ts +17 -0
  96. package/tsconfig.json +10 -0
@@ -0,0 +1,31 @@
1
+ import { type Page } from "@playwright/test";
2
+ import { Credentials } from "../utils/api.js";
3
+ export declare const test: import("playwright/test").TestType<import("playwright/test").PlaywrightTestArgs & import("playwright/test").PlaywrightTestOptions & import("./services.js").TestFixtures & {
4
+ /**
5
+ * The displayname to use for the user registered in {@link #credentials}.
6
+ *
7
+ * To set it, call `test.use({ displayName: "myDisplayName" })` in the test file or `describe` block.
8
+ * See {@link https://playwright.dev/docs/api/class-test#test-use}.
9
+ */
10
+ displayName?: string;
11
+ /**
12
+ * A test fixture which registers a test user on the {@link #homeserver} and supplies the details
13
+ * of the registered user.
14
+ */
15
+ credentials: Credentials;
16
+ /**
17
+ * The same as {@link https://playwright.dev/docs/api/class-fixtures#fixtures-page|`page`},
18
+ * but adds an initScript which will populate localStorage with the user's details from
19
+ * {@link #credentials} and {@link #homeserver}.
20
+ *
21
+ * Similar to {@link #user}, but doesn't load the app.
22
+ */
23
+ pageWithCredentials: Page;
24
+ /**
25
+ * A (rather poorly-named) test fixture which registers a user per {@link #credentials}, stores
26
+ * the credentials into localStorage per {@link #homeserver}, and then loads the front page of the
27
+ * app.
28
+ */
29
+ user: Credentials;
30
+ }, import("playwright/test").PlaywrightWorkerArgs & import("playwright/test").PlaywrightWorkerOptions & import("./services.js").WorkerOptions & import("./services.js").Services>;
31
+ //# sourceMappingURL=user.d.ts.map
@@ -0,0 +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,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,eAAO,MAAM,IAAI;IACb;;;;;OAKG;kBACW,MAAM;IAEpB;;;OAGG;iBACU,WAAW;IAExB;;;;;;OAMG;yBACkB,IAAI;IAEzB;;;;OAIG;UACG,WAAW;iLAiDnB,CAAC"}
@@ -0,0 +1,47 @@
1
+ /*
2
+ Copyright 2024-2025 New Vector Ltd.
3
+ Copyright 2023 The Matrix.org Foundation C.I.C.
4
+
5
+ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
6
+ Please see LICENSE files in the repository root for full details.
7
+ */
8
+ import { sample, uniqueId } from "lodash-es";
9
+ import { test as base } from "./services.js";
10
+ export const test = base.extend({
11
+ displayName: undefined,
12
+ credentials: async ({ homeserver, displayName: testDisplayName }, use, testInfo) => {
13
+ const names = ["Alice", "Bob", "Charlie", "Daniel", "Eve", "Frank", "Grace", "Hannah", "Isaac", "Judy"];
14
+ const password = uniqueId("password_");
15
+ const displayName = testDisplayName ?? sample(names);
16
+ const credentials = await homeserver.registerUser(`user_${testInfo.testId}`, password, displayName);
17
+ console.log(`Registered test user ${credentials.userId} with displayname ${displayName}`);
18
+ await use({
19
+ ...credentials,
20
+ displayName,
21
+ });
22
+ },
23
+ pageWithCredentials: async ({ page, homeserver, credentials }, use) => {
24
+ await page.addInitScript(({ baseUrl, credentials }) => {
25
+ // Seed the localStorage with the required credentials
26
+ window.localStorage.setItem("mx_hs_url", baseUrl);
27
+ window.localStorage.setItem("mx_user_id", credentials.userId);
28
+ window.localStorage.setItem("mx_access_token", credentials.accessToken);
29
+ window.localStorage.setItem("mx_device_id", credentials.deviceId);
30
+ window.localStorage.setItem("mx_is_guest", "false");
31
+ window.localStorage.setItem("mx_has_pickle_key", "false");
32
+ window.localStorage.setItem("mx_has_access_token", "true");
33
+ window.localStorage.setItem("mx_local_settings", JSON.stringify({
34
+ // Retain any other settings which may have already been set
35
+ ...JSON.parse(window.localStorage.getItem("mx_local_settings") || "{}"),
36
+ // Ensure the language is set to a consistent value
37
+ language: "en",
38
+ }));
39
+ }, { baseUrl: homeserver.baseUrl, credentials });
40
+ await use(page);
41
+ },
42
+ user: async ({ pageWithCredentials: page, credentials }, use) => {
43
+ await page.goto("/");
44
+ await page.waitForSelector(".mx_MatrixChat", { timeout: 30000 });
45
+ await use(credentials);
46
+ },
47
+ });
package/lib/index.d.ts ADDED
@@ -0,0 +1,35 @@
1
+ import { type Config as BaseConfig } from "@element-hq/element-web-module-api";
2
+ export interface Config extends BaseConfig {
3
+ default_server_config: {
4
+ "m.homeserver"?: {
5
+ base_url: string;
6
+ server_name?: string;
7
+ };
8
+ "m.identity_server"?: {
9
+ base_url: string;
10
+ server_name?: string;
11
+ };
12
+ };
13
+ setting_defaults: Record<string, unknown>;
14
+ map_style_url?: string;
15
+ features: Record<string, boolean>;
16
+ modules?: string[];
17
+ }
18
+ export declare const CONFIG_JSON: Partial<Config>;
19
+ export interface TestFixtures {
20
+ /**
21
+ * The contents of the config.json to send when the client requests it.
22
+ */
23
+ config: Partial<typeof CONFIG_JSON>;
24
+ labsFlags: string[];
25
+ }
26
+ export declare const test: import("playwright/test").TestType<import("playwright/test").PlaywrightTestArgs & import("playwright/test").PlaywrightTestOptions & {
27
+ axe: import("@axe-core/playwright").AxeBuilder;
28
+ } & import("./fixtures/services.js").TestFixtures & {
29
+ displayName?: string;
30
+ credentials: import("./utils/api.js").Credentials;
31
+ pageWithCredentials: import("playwright-core").Page;
32
+ user: import("./utils/api.js").Credentials;
33
+ } & TestFixtures, import("playwright/test").PlaywrightWorkerArgs & import("playwright/test").PlaywrightWorkerOptions & import("./fixtures/services.js").WorkerOptions & import("./fixtures/services.js").Services>;
34
+ export { expect, type ToMatchScreenshotOptions } from "./expect/index.js";
35
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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;AAU/E,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,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;CACvB;AAED,eAAO,MAAM,IAAI;;;;;;;kNA2Bf,CAAC;AAEH,OAAO,EAAE,MAAM,EAAE,KAAK,wBAAwB,EAAE,MAAM,mBAAmB,CAAC"}
package/lib/index.js ADDED
@@ -0,0 +1,54 @@
1
+ /*
2
+ Copyright 2024-2025 New Vector Ltd.
3
+ Copyright 2023 The Matrix.org Foundation C.I.C.
4
+
5
+ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
6
+ Please see LICENSE files in the repository root for full details.
7
+ */
8
+ import { test as base } from "./fixtures/index.js";
9
+ // Enable experimental service worker support
10
+ // See https://playwright.dev/docs/service-workers-experimental#how-to-enable
11
+ process.env["PW_EXPERIMENTAL_SERVICE_WORKER_NETWORK_EVENTS"] = "1";
12
+ // This is deliberately quite a minimal config.json, so that we can test that the default settings actually work.
13
+ export const CONFIG_JSON = {
14
+ default_server_config: {},
15
+ // The default language is set here for test consistency
16
+ setting_defaults: {
17
+ language: "en-GB",
18
+ },
19
+ // the location tests want a map style url.
20
+ map_style_url: "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx",
21
+ features: {
22
+ // We don't want to go through the feature announcement during the e2e test
23
+ feature_release_announcement: false,
24
+ },
25
+ };
26
+ export const test = base.extend({
27
+ config: {}, // We merge this atop the default CONFIG_JSON in the page fixture to make extending it easier
28
+ labsFlags: [],
29
+ page: async ({ homeserver, context, page, config, labsFlags }, use) => {
30
+ await context.route(`http://localhost:8080/config.json*`, async (route) => {
31
+ const json = {
32
+ ...CONFIG_JSON,
33
+ ...config,
34
+ default_server_config: {
35
+ "m.homeserver": {
36
+ base_url: homeserver.baseUrl,
37
+ },
38
+ ...config.default_server_config,
39
+ },
40
+ };
41
+ json["features"] = {
42
+ ...json["features"],
43
+ // Enable the lab features
44
+ ...labsFlags.reduce((obj, flag) => {
45
+ obj[flag] = true;
46
+ return obj;
47
+ }, {}),
48
+ };
49
+ await route.fulfill({ json });
50
+ });
51
+ await use(page);
52
+ },
53
+ });
54
+ export { expect } from "./expect/index.js";
@@ -0,0 +1,10 @@
1
+ import { type BrowserContext, type TestInfo } from "@playwright/test";
2
+ import { type Readable } from "stream";
3
+ export declare class Logger {
4
+ private pages;
5
+ private logs;
6
+ getConsumer(container: string): (stream: Readable) => void;
7
+ onTestStarted(context: BrowserContext): Promise<void>;
8
+ onTestFinished(testInfo: TestInfo): Promise<void>;
9
+ }
10
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,cAAc,EAAa,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjF,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAGvC,qBAAa,MAAM;IACf,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,IAAI,CAA8B;IAEnC,WAAW,CAAC,SAAS,EAAE,MAAM,IAExB,QAAQ,QAAQ;IAUf,aAAa,CAAC,OAAO,EAAE,cAAc;IAyBrC,cAAc,CAAC,QAAQ,EAAE,QAAQ;CAWjD"}
package/lib/logger.js ADDED
@@ -0,0 +1,59 @@
1
+ /*
2
+ Copyright 2024 New Vector 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 stripAnsi from "strip-ansi";
8
+ export class Logger {
9
+ pages = [];
10
+ logs = {};
11
+ getConsumer(container) {
12
+ this.logs[container] = "";
13
+ return (stream) => {
14
+ stream.on("data", (chunk) => {
15
+ this.logs[container] += chunk.toString();
16
+ });
17
+ stream.on("err", (chunk) => {
18
+ this.logs[container] += "ERR " + chunk.toString();
19
+ });
20
+ };
21
+ }
22
+ async onTestStarted(context) {
23
+ this.pages = [];
24
+ for (const id in this.logs) {
25
+ if (id.startsWith("page-")) {
26
+ delete this.logs[id];
27
+ }
28
+ else {
29
+ this.logs[id] = "";
30
+ }
31
+ }
32
+ context.on("console", (msg) => {
33
+ const page = msg.page();
34
+ if (!page)
35
+ return;
36
+ let pageIdx = this.pages.indexOf(page);
37
+ if (pageIdx === -1) {
38
+ this.pages.push(page);
39
+ pageIdx = this.pages.length - 1;
40
+ this.logs[`page-${pageIdx}`] = `Console logs for page with URL: ${page.url()}\n\n`;
41
+ }
42
+ const type = msg.type();
43
+ const text = msg.text();
44
+ this.logs[`page-${pageIdx}`] += `${type}: ${text}\n`;
45
+ });
46
+ }
47
+ async onTestFinished(testInfo) {
48
+ if (testInfo.status !== "passed") {
49
+ for (const id in this.logs) {
50
+ if (!this.logs[id])
51
+ continue;
52
+ await testInfo.attach(id, {
53
+ body: stripAnsi(this.logs[id]),
54
+ contentType: "text/plain",
55
+ });
56
+ }
57
+ }
58
+ }
59
+ }
@@ -0,0 +1,2 @@
1
+ export * from "@playwright/test";
2
+ //# sourceMappingURL=playwright.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playwright.d.ts","sourceRoot":"","sources":["../src/playwright.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1 @@
1
+ export * from "@playwright/test";
@@ -0,0 +1,70 @@
1
+ import { type AbstractStartedContainer, type GenericContainer } from "testcontainers";
2
+ import { type APIRequestContext, type TestInfo } from "@playwright/test";
3
+ import { type StartedMatrixAuthenticationServiceContainer } from "./mas";
4
+ import { ClientServerApi, Credentials } from "../utils/api";
5
+ import { StartedMailpitContainer } from "./mailpit";
6
+ export interface HomeserverInstance {
7
+ readonly baseUrl: string;
8
+ readonly csApi: ClientServerApi;
9
+ /**
10
+ * Register a user on the given Homeserver using the shared registration secret.
11
+ * @param username the username of the user to register
12
+ * @param password the password of the user to register
13
+ * @param displayName optional display name to set on the newly registered user
14
+ */
15
+ registerUser(username: string, password: string, displayName?: string): Promise<Credentials>;
16
+ /**
17
+ * Logs into synapse with the given username/password
18
+ * @param userId login username
19
+ * @param password login password
20
+ */
21
+ loginUser(userId: string, password: string): Promise<Credentials>;
22
+ /**
23
+ * Sets a third party identifier for the given user. This only supports setting a single 3pid and will
24
+ * replace any others.
25
+ * @param userId The full ID of the user to edit (as returned from registerUser)
26
+ * @param medium The medium of the 3pid to set
27
+ * @param address The address of the 3pid to set
28
+ */
29
+ setThreepid(userId: string, medium: string, address: string): Promise<void>;
30
+ }
31
+ export interface HomeserverContainer<Config> extends GenericContainer {
32
+ /**
33
+ * Set a configuration field in the config
34
+ * @param key - the key to set
35
+ * @param value - the value to set
36
+ */
37
+ withConfigField<Key extends keyof Config>(key: Key, value: Config[Key]): this;
38
+ /**
39
+ * Merge a partial configuration into the config
40
+ * @param config - the partial configuration to merge
41
+ */
42
+ withConfig(config: Partial<Config>): this;
43
+ /**
44
+ * Set the SMTP server to use for sending emails
45
+ * @param mailpit - the mailpit container to use
46
+ */
47
+ withSmtpServer(mailpit: StartedMailpitContainer): this;
48
+ /**
49
+ * Set the MAS server to use for delegated auth
50
+ * @param mas - the MAS container to use
51
+ */
52
+ withMatrixAuthenticationService(mas?: StartedMatrixAuthenticationServiceContainer): this;
53
+ /**
54
+ * Start the container
55
+ */
56
+ start(): Promise<StartedHomeserverContainer>;
57
+ }
58
+ export interface StartedHomeserverContainer extends AbstractStartedContainer, HomeserverInstance {
59
+ /**
60
+ * Set the request context for the APIs
61
+ * @param request - the request context to set
62
+ */
63
+ setRequest(request: APIRequestContext): void;
64
+ /**
65
+ * Clean up the server to prevent rooms leaking between tests
66
+ * @param testInfo - the test info for the test that just finished
67
+ */
68
+ onTestFinished(testInfo: TestInfo): Promise<void>;
69
+ }
70
+ //# sourceMappingURL=HomeserverContainer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HomeserverContainer.d.ts","sourceRoot":"","sources":["../../src/testcontainers/HomeserverContainer.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,wBAAwB,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACtF,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEzE,OAAO,EAAE,KAAK,2CAA2C,EAAE,MAAM,OAAO,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AAEpD,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAEhC;;;;;OAKG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAE7F;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAElE;;;;;;OAMG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/E;AAED,MAAM,WAAW,mBAAmB,CAAC,MAAM,CAAE,SAAQ,gBAAgB;IACjE;;;;OAIG;IACH,eAAe,CAAC,GAAG,SAAS,MAAM,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IAE9E;;;OAGG;IACH,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAE1C;;;OAGG;IACH,cAAc,CAAC,OAAO,EAAE,uBAAuB,GAAG,IAAI,CAAC;IACvD;;;OAGG;IACH,+BAA+B,CAAC,GAAG,CAAC,EAAE,2CAA2C,GAAG,IAAI,CAAC;IAEzF;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,0BAA0B,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,0BAA2B,SAAQ,wBAAwB,EAAE,kBAAkB;IAC5F;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAE7C;;;OAGG;IACH,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrD"}
@@ -0,0 +1,7 @@
1
+ /*
2
+ Copyright 2024-2025 New Vector 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
+ export {};
@@ -0,0 +1,5 @@
1
+ export type { HomeserverInstance, HomeserverContainer, StartedHomeserverContainer } from "./HomeserverContainer.js";
2
+ export { type SynapseConfig, SynapseContainer, StartedSynapseContainer } from "./synapse.js";
3
+ export { type MasConfig, MatrixAuthenticationServiceContainer, StartedMatrixAuthenticationServiceContainer, } from "./mas.js";
4
+ export { MailpitClient, MailpitContainer, StartedMailpitContainer } from "./mailpit.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testcontainers/index.ts"],"names":[],"mappings":"AAOA,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACpH,OAAO,EAAE,KAAK,aAAa,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAC7F,OAAO,EACH,KAAK,SAAS,EACd,oCAAoC,EACpC,2CAA2C,GAC9C,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,9 @@
1
+ /*
2
+ Copyright 2025 New Vector 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
+ export { SynapseContainer, StartedSynapseContainer } from "./synapse.js";
8
+ export { MatrixAuthenticationServiceContainer, StartedMatrixAuthenticationServiceContainer, } from "./mas.js";
9
+ export { MailpitContainer, StartedMailpitContainer } from "./mailpit.js";
@@ -0,0 +1,33 @@
1
+ import { AbstractStartedContainer, GenericContainer, type StartedTestContainer } from "testcontainers";
2
+ import { MailpitClient } from "mailpit-api";
3
+ export type { MailpitClient };
4
+ /**
5
+ * A testcontainer for Mailpit.
6
+ *
7
+ * Exposes port 8025.
8
+ * Waits for listening ports.
9
+ * Disables SMTP authentication.
10
+ */
11
+ export declare class MailpitContainer extends GenericContainer {
12
+ constructor();
13
+ /**
14
+ * Start the Mailpit container.
15
+ */
16
+ start(): Promise<StartedMailpitContainer>;
17
+ }
18
+ /**
19
+ * A started Mailpit container.
20
+ */
21
+ export declare class StartedMailpitContainer extends AbstractStartedContainer {
22
+ readonly client: MailpitClient;
23
+ constructor(container: StartedTestContainer);
24
+ /**
25
+ * Get the hostname to use to connect to the Mailpit container from inside the docker network.
26
+ */
27
+ get internalHost(): string;
28
+ /**
29
+ * Get the port to use to connect to the Mailpit container from inside the docker network.
30
+ */
31
+ get internalSmtpPort(): number;
32
+ }
33
+ //# sourceMappingURL=mailpit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mailpit.d.ts","sourceRoot":"","sources":["../../src/testcontainers/mailpit.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,KAAK,oBAAoB,EAAQ,MAAM,gBAAgB,CAAC;AAC7G,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B;;;;;;GAMG;AACH,qBAAa,gBAAiB,SAAQ,gBAAgB;;IAUlD;;OAEG;IACmB,KAAK,IAAI,OAAO,CAAC,uBAAuB,CAAC;CAGlE;AAED;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,wBAAwB;IACjE,SAAgB,MAAM,EAAE,aAAa,CAAC;gBAEnB,SAAS,EAAE,oBAAoB;IAKlD;;OAEG;IACH,IAAW,YAAY,IAAI,MAAM,CAEhC;IAED;;OAEG;IACH,IAAW,gBAAgB,IAAI,MAAM,CAEpC;CACJ"}
@@ -0,0 +1,52 @@
1
+ /*
2
+ Copyright 2024-2025 New Vector 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 { AbstractStartedContainer, GenericContainer, Wait } from "testcontainers";
8
+ import { MailpitClient } from "mailpit-api";
9
+ /**
10
+ * A testcontainer for Mailpit.
11
+ *
12
+ * Exposes port 8025.
13
+ * Waits for listening ports.
14
+ * Disables SMTP authentication.
15
+ */
16
+ export class MailpitContainer extends GenericContainer {
17
+ constructor() {
18
+ super("axllent/mailpit:latest");
19
+ this.withExposedPorts(8025).withWaitStrategy(Wait.forListeningPorts()).withEnvironment({
20
+ MP_SMTP_AUTH_ALLOW_INSECURE: "true",
21
+ MP_SMTP_AUTH_ACCEPT_ANY: "true",
22
+ });
23
+ }
24
+ /**
25
+ * Start the Mailpit container.
26
+ */
27
+ async start() {
28
+ return new StartedMailpitContainer(await super.start());
29
+ }
30
+ }
31
+ /**
32
+ * A started Mailpit container.
33
+ */
34
+ export class StartedMailpitContainer extends AbstractStartedContainer {
35
+ client;
36
+ constructor(container) {
37
+ super(container);
38
+ this.client = new MailpitClient(`http://${container.getHost()}:${container.getMappedPort(8025)}`);
39
+ }
40
+ /**
41
+ * Get the hostname to use to connect to the Mailpit container from inside the docker network.
42
+ */
43
+ get internalHost() {
44
+ return "mailpit";
45
+ }
46
+ /**
47
+ * Get the port to use to connect to the Mailpit container from inside the docker network.
48
+ */
49
+ get internalSmtpPort() {
50
+ return 1025;
51
+ }
52
+ }
@@ -0,0 +1,182 @@
1
+ import { AbstractStartedContainer, GenericContainer, type StartedTestContainer } from "testcontainers";
2
+ import { type StartedPostgreSqlContainer } from "@testcontainers/postgresql";
3
+ import { type Credentials } from "../utils/api.js";
4
+ declare const DEFAULT_CONFIG: {
5
+ http: {
6
+ listeners: {
7
+ name: string;
8
+ resources: ({
9
+ name: string;
10
+ playground?: undefined;
11
+ path?: undefined;
12
+ } | {
13
+ name: string;
14
+ playground: boolean;
15
+ path?: undefined;
16
+ } | {
17
+ name: string;
18
+ path: string;
19
+ playground?: undefined;
20
+ })[];
21
+ binds: {
22
+ address: string;
23
+ }[];
24
+ proxy_protocol: boolean;
25
+ }[];
26
+ trusted_proxies: string[];
27
+ public_base: string;
28
+ issuer: string;
29
+ };
30
+ database: {
31
+ host: string;
32
+ port: number;
33
+ database: string;
34
+ username: string;
35
+ password: string;
36
+ max_connections: number;
37
+ min_connections: number;
38
+ connect_timeout: number;
39
+ idle_timeout: number;
40
+ max_lifetime: number;
41
+ };
42
+ telemetry: {
43
+ tracing: {
44
+ exporter: string;
45
+ propagators: never[];
46
+ };
47
+ metrics: {
48
+ exporter: string;
49
+ };
50
+ sentry: {
51
+ dsn: null;
52
+ };
53
+ };
54
+ templates: {
55
+ path: string;
56
+ assets_manifest: string;
57
+ translations_path: string;
58
+ };
59
+ email: {
60
+ from: string;
61
+ reply_to: string;
62
+ transport: string;
63
+ mode: string;
64
+ hostname: string;
65
+ port: number;
66
+ username: string;
67
+ password: string;
68
+ };
69
+ secrets: {
70
+ encryption: string;
71
+ keys: {
72
+ kid: string;
73
+ key: string;
74
+ }[];
75
+ };
76
+ passwords: {
77
+ enabled: boolean;
78
+ schemes: {
79
+ version: number;
80
+ algorithm: string;
81
+ }[];
82
+ minimum_complexity: number;
83
+ };
84
+ policy: {
85
+ wasm_module: string;
86
+ client_registration_entrypoint: string;
87
+ register_entrypoint: string;
88
+ authorization_grant_entrypoint: string;
89
+ password_entrypoint: string;
90
+ email_entrypoint: string;
91
+ data: {
92
+ client_registration: {
93
+ allow_insecure_uris: boolean;
94
+ allow_missing_contacts: boolean;
95
+ };
96
+ };
97
+ };
98
+ upstream_oauth2: {
99
+ providers: never[];
100
+ };
101
+ branding: {
102
+ service_name: null;
103
+ policy_uri: null;
104
+ tos_uri: null;
105
+ imprint: null;
106
+ logo_uri: null;
107
+ };
108
+ account: {
109
+ password_registration_enabled: boolean;
110
+ };
111
+ experimental: {
112
+ access_token_ttl: number;
113
+ compat_token_ttl: number;
114
+ };
115
+ rate_limiting: {
116
+ login: {
117
+ burst: number;
118
+ per_second: number;
119
+ };
120
+ registration: {
121
+ burst: number;
122
+ per_second: number;
123
+ };
124
+ };
125
+ };
126
+ /**
127
+ * Incomplete type for the MAS configuration.
128
+ */
129
+ export type MasConfig = typeof DEFAULT_CONFIG;
130
+ /**
131
+ * A container running the Matrix Authentication Service.
132
+ *
133
+ * Exposes the MAS API on port 8080 and the health check on port 8081.
134
+ * Waits for HTTP /health on port 8081 to be available.
135
+ */
136
+ export declare class MatrixAuthenticationServiceContainer extends GenericContainer {
137
+ private config;
138
+ private readonly args;
139
+ constructor(db: StartedPostgreSqlContainer);
140
+ /**
141
+ * Adds additional configuration to the MAS config.
142
+ * @param config - additional config fields to add
143
+ */
144
+ withConfig(config: object): this;
145
+ /**
146
+ * Starts the MAS container
147
+ */
148
+ start(): Promise<StartedMatrixAuthenticationServiceContainer>;
149
+ }
150
+ /**
151
+ * A started Matrix Authentication Service container.
152
+ */
153
+ export declare class StartedMatrixAuthenticationServiceContainer extends AbstractStartedContainer {
154
+ readonly baseUrl: string;
155
+ private readonly args;
156
+ private adminTokenPromise?;
157
+ constructor(container: StartedTestContainer, baseUrl: string, args: string[]);
158
+ /**
159
+ * Retrieves a valid HS admin token
160
+ */
161
+ getAdminToken(): Promise<string>;
162
+ private manage;
163
+ private manageRegisterUser;
164
+ private manageIssueCompatibilityToken;
165
+ private registerUserInternal;
166
+ /**
167
+ * Registers a user
168
+ * @param username - the username of the user to register
169
+ * @param password - the password of the user to register
170
+ * @param displayName - optional display name to set on the newly registered user
171
+ */
172
+ registerUser(username: string, password: string, displayName?: string): Promise<Credentials>;
173
+ /**
174
+ * Binds a 3pid
175
+ * @param username - the username of the user to bind the 3pid to
176
+ * @param medium - the medium of the 3pid to bind
177
+ * @param address - the address of the 3pid to bind
178
+ */
179
+ setThreepid(username: string, medium: string, address: string): Promise<void>;
180
+ }
181
+ export {};
182
+ //# sourceMappingURL=mas.d.ts.map
@@ -0,0 +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,EAG5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,KAAK,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAK7E,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8JnB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,OAAO,cAAc,CAAC;AAE9C;;;;;GAKG;AACH,qBAAa,oCAAqC,SAAQ,gBAAgB;IACtE,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAiC;gBAEnC,EAAE,EAAE,0BAA0B;IAcjD;;;OAGG;IACI,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAQvC;;OAEG;IACmB,KAAK,IAAI,OAAO,CAAC,2CAA2C,CAAC;CAuBtF;AAED;;GAEG;AACH,qBAAa,2CAA4C,SAAQ,wBAAwB;aAKjE,OAAO,EAAE,MAAM;IAC/B,OAAO,CAAC,QAAQ,CAAC,IAAI;IALzB,OAAO,CAAC,iBAAiB,CAAC,CAAkB;gBAGxC,SAAS,EAAE,oBAAoB,EACf,OAAO,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAAE;IAKnC;;OAEG;IACU,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;YAY/B,MAAM;YAQN,kBAAkB;YAgClB,6BAA6B;YAmB7B,oBAAoB;IAoBlC;;;;;OAKG;IACU,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAIzG;;;;;OAKG;IACU,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAO7F"}