/* Copyright 2025 New Vector Ltd. SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE files in the repository root for full details. */ import { defineConfig, devices, type Project } from "@playwright/test"; import fs, { globSync } from "node:fs"; import path, { dirname } from "node:path"; import { fileURLToPath } from "node:url"; import type { Options } from "./playwright/element-web-test.ts"; const __dirname = dirname(fileURLToPath(import.meta.url)); const chromeProject = { ...devices["Desktop Chrome"], channel: "chromium", permissions: ["clipboard-write", "clipboard-read", "microphone"], launchOptions: { args: ["--use-fake-ui-for-media-stream", "--use-fake-device-for-media-stream", "--mute-audio"], }, connectOptions: process.env.PW_TEST_CONNECT_WS_ENDPOINT ? { wsEndpoint: process.env.PW_TEST_CONNECT_WS_ENDPOINT, exposeNetwork: "", } : undefined, }; /** We assume that all modules will have the following directory structure: └── modules/ └── my-module/ ├── e2e/ │ ├── test-1.spec.ts │ └── test-2.spec.ts └── package.json The following code maps each such module (my-module in the example above) to a separate playwright project. */ const projects: Project[] = []; // Get all the directories that hold playwright tests const moduleTestDirectories = globSync("*/e2e", { cwd: __dirname }).map((d) => path.join(__dirname, d)); // Process each directory for (const testDirectory of moduleTestDirectories) { // Based on the directory structure, the parent directory of the test directory holds package.json. const moduleDirectory = path.join(testDirectory, ".."); // Get module name from package.json const packageJson = JSON.parse(fs.readFileSync(path.join(moduleDirectory, "package.json"), "utf-8")); const MODULE_PREFIX = "@element-hq/element-web-module-"; const name = packageJson.name.startsWith(MODULE_PREFIX) ? packageJson.name.slice(MODULE_PREFIX.length) : packageJson.name; // Create playwright project projects.push({ name, use: { ...chromeProject, moduleDir: moduleDirectory, }, testDir: testDirectory, snapshotDir: `${testDirectory}/snapshots`, outputDir: `${testDirectory}/_results`, }); } const baseURL = process.env["BASE_URL"] ?? "http://localhost:8080"; export default defineConfig({ projects, use: { viewport: { width: 1280, height: 720 }, ignoreHTTPSErrors: true, video: "retain-on-failure", baseURL, trace: "on-first-retry", }, webServer: { command: process.env.WEBAPP_PATH ? `npx serve -p 8080 -L ${process.env.WEBAPP_PATH}` : "docker run --rm -p 8080:80 ghcr.io/element-hq/element-web:develop", url: `${baseURL}/config.json`, reuseExistingServer: true, timeout: (process.env.CI ? 30 : 120) * 1000, }, workers: 1, retries: process.env.CI ? 2 : 0, reporter: process.env.CI ? [["list"], ["blob"], ["github"]] : [["list"], ["html", { outputFolder: "playwright-html-report" }]], // When running the browser in docker, set the platform to `linux` as that is the platform where the browser is running snapshotPathTemplate: `{snapshotDir}/{testFilePath}/{arg}-${process.env.PW_TEST_CONNECT_WS_ENDPOINT ? "linux" : "{platform}"}{ext}`, forbidOnly: !!process.env.CI, });