From cd429874dbfd9e78f7b77d181a938a1619d22b6b Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 26 Mar 2026 12:30:54 +0100 Subject: [PATCH] Reference files in Playwright more reliably (#32935) Without assuming the cwd --- .../e2e/audio-player/audio-player.spec.ts | 38 +++++++++---------- .../e2e/file-upload/image-upload.spec.ts | 3 +- .../playwright/e2e/messages/messages.spec.ts | 4 +- .../e2e/modules/custom-component.spec.ts | 6 +-- .../web/playwright/e2e/modules/loader.spec.ts | 3 +- .../e2e/right-panel/file-panel.spec.ts | 17 +++++---- .../account-user-settings-tab.spec.ts | 3 +- apps/web/playwright/e2e/spaces/spaces.spec.ts | 11 +++--- .../timeline/media-preview-settings.spec.ts | 4 +- .../playwright/e2e/timeline/timeline.spec.ts | 11 +++--- .../playwright/e2e/voip/element-call.spec.ts | 5 ++- .../playwright/e2e/widgets/stickers.spec.ts | 5 +-- .../homeserver/synapse/consentHomeserver.ts | 8 ++-- apps/web/playwright/sample-files/index.ts | 32 ++++++++++++++++ 14 files changed, 93 insertions(+), 57 deletions(-) create mode 100644 apps/web/playwright/sample-files/index.ts diff --git a/apps/web/playwright/e2e/audio-player/audio-player.spec.ts b/apps/web/playwright/e2e/audio-player/audio-player.spec.ts index b442be2b92..f042b07993 100644 --- a/apps/web/playwright/e2e/audio-player/audio-player.spec.ts +++ b/apps/web/playwright/e2e/audio-player/audio-player.spec.ts @@ -12,6 +12,7 @@ import { test, expect } from "../../element-web-test"; import { SettingLevel } from "../../../src/settings/SettingLevel"; import { Layout } from "../../../src/settings/enums/Layout"; import { type ElementAppPage } from "../../pages/ElementAppPage"; +import { getSampleFilePath } from "../../sample-files"; // Find and click "Reply" button const clickButtonReply = async (tile: Locator) => { @@ -28,9 +29,11 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => { displayName: "Hanako", }); - const uploadFile = async (page: Page, file: string) => { + const uploadFile = async (page: Page, sampleFile: string) => { // Upload a file from the message composer - await page.locator(".mx_MessageComposer_actions input[type='file']").setInputFiles(file); + await page + .locator(".mx_MessageComposer_actions input[type='file']") + .setInputFiles(getSampleFilePath(sampleFile)); // Find and click primary "Upload" button await page.locator(".mx_Dialog").getByRole("button", { name: "Upload" }).click(); @@ -41,12 +44,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => { "Your message was sent", ); // wait for the tile to finish loading - await expect( - page - .getByTestId("audio-player-name") - .last() - .filter({ hasText: file.split("/").at(-1) }), - ).toBeVisible(); + await expect(page.getByTestId("audio-player-name").last().filter({ hasText: sampleFile })).toBeVisible(); }; const scrollToBottomOfTimeline = async (page: Page) => { @@ -158,7 +156,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => { }); test("should be correctly rendered - light theme", { tag: "@screenshot" }, async ({ page, app }) => { - await uploadFile(page, "playwright/sample-files/1sec-long-name-audio-file.ogg"); + await uploadFile(page, "1sec-long-name-audio-file.ogg"); await takeSnapshots(page, app, "Selected EventTile of audio player (light theme)"); }); @@ -166,7 +164,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => { "should be correctly rendered - light theme with monospace font", { tag: "@screenshot" }, async ({ page, app }) => { - await uploadFile(page, "playwright/sample-files/1sec-long-name-audio-file.ogg"); + await uploadFile(page, "1sec-long-name-audio-file.ogg"); await takeSnapshots(page, app, "Selected EventTile of audio player (light theme, monospace font)", true); // Enable monospace }, @@ -183,7 +181,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => { await app.closeDialog(); - await uploadFile(page, "playwright/sample-files/1sec-long-name-audio-file.ogg"); + await uploadFile(page, "1sec-long-name-audio-file.ogg"); await takeSnapshots(page, app, "Selected EventTile of audio player (high contrast)"); }); @@ -192,13 +190,13 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => { // Enable dark theme await app.settings.setValue("theme", null, SettingLevel.ACCOUNT, "dark"); - await uploadFile(page, "playwright/sample-files/1sec-long-name-audio-file.ogg"); + await uploadFile(page, "1sec-long-name-audio-file.ogg"); await takeSnapshots(page, app, "Selected EventTile of audio player (dark theme)"); }); test("should play an audio file", async ({ page, app }) => { - await uploadFile(page, "playwright/sample-files/1sec.ogg"); + await uploadFile(page, "1sec.ogg"); // Assert that the audio player is rendered const container = page.locator(".mx_EventTile_last").getByRole("region", { name: "Audio player" }); @@ -220,7 +218,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => { }); test("should support downloading an audio file", async ({ page, app }) => { - await uploadFile(page, "playwright/sample-files/1sec.ogg"); + await uploadFile(page, "1sec.ogg"); const downloadPromise = page.waitForEvent("download"); @@ -238,7 +236,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => { "should support replying to audio file with another audio file", { tag: "@screenshot" }, async ({ page, app }) => { - await uploadFile(page, "playwright/sample-files/1sec.ogg"); + await uploadFile(page, "1sec.ogg"); // Assert the audio player is rendered await expect(page.getByRole("region", { name: "Audio player" })).toBeVisible(); @@ -248,7 +246,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => { await clickButtonReply(tile); // Reply to the player with another audio file - await uploadFile(page, "playwright/sample-files/1sec.ogg"); + await uploadFile(page, "1sec.ogg"); // Assert that the audio player is rendered await expect(tile.getByRole("region", { name: "Audio player" })).toBeVisible(); @@ -273,7 +271,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => { const tile = page.locator(".mx_EventTile_last"); - await uploadFile(page, "playwright/sample-files/upload-first.ogg"); + await uploadFile(page, "upload-first.ogg"); // Assert that the audio player is rendered await expect( @@ -283,7 +281,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => { await clickButtonReply(tile); // Reply to the player with another audio file - await uploadFile(page, "playwright/sample-files/upload-second.ogg"); + await uploadFile(page, "upload-second.ogg"); // Assert that the audio player is rendered await expect( @@ -293,7 +291,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => { await clickButtonReply(tile); // Reply to the player with yet another audio file to create a reply chain - await uploadFile(page, "playwright/sample-files/upload-third.ogg"); + await uploadFile(page, "upload-third.ogg"); // Assert that the audio player is rendered await expect(tile.getByRole("region", { name: "Audio player" })).toBeVisible(); @@ -325,7 +323,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => { ); test("should be rendered, play, and support replying on a thread", async ({ page, app }) => { - await uploadFile(page, "playwright/sample-files/1sec-long-name-audio-file.ogg"); + await uploadFile(page, "1sec-long-name-audio-file.ogg"); // On the main timeline const messageList = page.locator(".mx_RoomView_MessageList"); diff --git a/apps/web/playwright/e2e/file-upload/image-upload.spec.ts b/apps/web/playwright/e2e/file-upload/image-upload.spec.ts index ad445ab1d9..45ce44df5c 100644 --- a/apps/web/playwright/e2e/file-upload/image-upload.spec.ts +++ b/apps/web/playwright/e2e/file-upload/image-upload.spec.ts @@ -7,6 +7,7 @@ Please see LICENSE files in the repository root for full details. */ import { test, expect } from "../../element-web-test"; +import { getSampleFilePath } from "../../sample-files"; test.describe("Image Upload", () => { test.use({ @@ -28,7 +29,7 @@ test.describe("Image Upload", () => { test("should show image preview when uploading an image", { tag: "@screenshot" }, async ({ page, app }) => { await page .locator(".mx_MessageComposer_actions input[type='file']") - .setInputFiles("playwright/sample-files/riot.png"); + .setInputFiles(getSampleFilePath("riot.png")); await expect(page.getByRole("button", { name: "Upload" })).toBeEnabled(); await expect(page.getByRole("button", { name: "Close dialog" })).toBeEnabled(); diff --git a/apps/web/playwright/e2e/messages/messages.spec.ts b/apps/web/playwright/e2e/messages/messages.spec.ts index 4224737595..67af9edb42 100644 --- a/apps/web/playwright/e2e/messages/messages.spec.ts +++ b/apps/web/playwright/e2e/messages/messages.spec.ts @@ -9,11 +9,11 @@ Please see LICENSE files in the repository root for full details. /* See readme.md for tips on writing these tests. */ import { type Locator, type Page } from "@playwright/test"; -import { readFileSync } from "node:fs"; import { test, expect } from "../../element-web-test"; +import { readSampleFileSync } from "../../sample-files"; -const MEDIA_FILE = readFileSync("playwright/sample-files/riot.png"); +const MEDIA_FILE = readSampleFileSync("riot.png", null); async function waitForMessageSentStatus(msgTile: Locator): Promise { await expect(msgTile.getByRole("status")).toHaveAccessibleName("Your message was sent"); diff --git a/apps/web/playwright/e2e/modules/custom-component.spec.ts b/apps/web/playwright/e2e/modules/custom-component.spec.ts index d8f4d4646d..5d2dc34aef 100644 --- a/apps/web/playwright/e2e/modules/custom-component.spec.ts +++ b/apps/web/playwright/e2e/modules/custom-component.spec.ts @@ -6,9 +6,9 @@ Please see LICENSE files in the repository root for full details. */ import { type Page } from "@playwright/test"; -import fs from "node:fs"; import { test, expect } from "../../element-web-test"; +import { getSampleFilePath, readSampleFileSync } from "../../sample-files"; const screenshotOptions = (page: Page) => ({ // Hide the jump to bottom button in the timeline to avoid flakiness @@ -26,7 +26,7 @@ const screenshotOptions = (page: Page) => ({ `, }); -const IMAGE_FILE = fs.readFileSync("playwright/sample-files/element.png"); +const IMAGE_FILE = readSampleFileSync("element.png", null); test.describe("Custom Component API", () => { test.use({ @@ -36,7 +36,7 @@ test.describe("Custom Component API", () => { }, page: async ({ page }, use) => { await page.route("/modules/custom-component-module.js", async (route) => { - await route.fulfill({ path: "playwright/sample-files/custom-component-module.js" }); + await route.fulfill({ path: getSampleFilePath("custom-component-module.js") }); }); await use(page); }, diff --git a/apps/web/playwright/e2e/modules/loader.spec.ts b/apps/web/playwright/e2e/modules/loader.spec.ts index 52c7a02988..fe9c2f60f4 100644 --- a/apps/web/playwright/e2e/modules/loader.spec.ts +++ b/apps/web/playwright/e2e/modules/loader.spec.ts @@ -6,6 +6,7 @@ Please see LICENSE files in the repository root for full details. */ import { test, expect } from "../../element-web-test"; +import { getSampleFilePath } from "../../sample-files"; test.describe("Module loading", () => { test.use({ @@ -20,7 +21,7 @@ test.describe("Module loading", () => { }, page: async ({ page }, use) => { await page.route("/modules/example-module.js", async (route) => { - await route.fulfill({ path: "playwright/sample-files/example-module.js" }); + await route.fulfill({ path: getSampleFilePath("example-module.js") }); }); await use(page); }, diff --git a/apps/web/playwright/e2e/right-panel/file-panel.spec.ts b/apps/web/playwright/e2e/right-panel/file-panel.spec.ts index dd3f3f4409..2fcb6d43ed 100644 --- a/apps/web/playwright/e2e/right-panel/file-panel.spec.ts +++ b/apps/web/playwright/e2e/right-panel/file-panel.spec.ts @@ -11,13 +11,14 @@ import { type Page } from "@playwright/test"; import { test, expect } from "../../element-web-test"; import { viewRoomSummaryByName } from "./utils"; import { isDendrite } from "../../plugins/homeserver/dendrite"; +import { getSampleFilePath } from "../../sample-files"; const ROOM_NAME = "Test room"; const NAME = "Alice"; -async function uploadFile(page: Page, file: string) { +async function uploadFile(page: Page, sampleFile: string) { // Upload a file from the message composer - await page.locator(".mx_MessageComposer_actions input[type='file']").setInputFiles(file); + await page.locator(".mx_MessageComposer_actions input[type='file']").setInputFiles(getSampleFilePath(sampleFile)); await page.locator(".mx_Dialog").getByRole("button", { name: "Upload" }).click(); @@ -53,9 +54,9 @@ test.describe("FilePanel", () => { test("should list tiles on the panel", { tag: "@screenshot" }, async ({ page }) => { // Upload multiple files - await uploadFile(page, "playwright/sample-files/riot.png"); // Image - await uploadFile(page, "playwright/sample-files/1sec.ogg"); // Audio - await uploadFile(page, "playwright/sample-files/matrix-org-client-versions.json"); // JSON + await uploadFile(page, "riot.png"); // Image + await uploadFile(page, "1sec.ogg"); // Audio + await uploadFile(page, "matrix-org-client-versions.json"); // JSON const roomViewBody = page.locator(".mx_RoomView_body"); // Assert that all of the file were uploaded and rendered @@ -137,7 +138,7 @@ test.describe("FilePanel", () => { test("should render the audio player and play the audio file on the panel", async ({ page }) => { // Upload an image file - await uploadFile(page, "playwright/sample-files/1sec.ogg"); + await uploadFile(page, "1sec.ogg"); const audioBody = page.getByTestId("right-panel").getByRole("region", { name: "Audio player" }); @@ -170,7 +171,7 @@ test.describe("FilePanel", () => { const size = "1.12 KB"; // actual file size in kibibytes (1024 bytes) // Upload a file - await uploadFile(page, "playwright/sample-files/matrix-org-client-versions.json"); + await uploadFile(page, "matrix-org-client-versions.json"); const tile = page.locator(".mx_FilePanel .mx_EventTile"); // Assert that the file size is displayed in kibibytes, not kilobytes (1000 bytes) @@ -184,7 +185,7 @@ test.describe("FilePanel", () => { test("should download an image via the link on the panel", async ({ page, context }) => { // Upload an image file - await uploadFile(page, "playwright/sample-files/riot.png"); + await uploadFile(page, "riot.png"); // Detect the image file on the panel const imageBody = page.locator( diff --git a/apps/web/playwright/e2e/settings/account-user-settings-tab.spec.ts b/apps/web/playwright/e2e/settings/account-user-settings-tab.spec.ts index df011bdc4e..07c3a9592d 100644 --- a/apps/web/playwright/e2e/settings/account-user-settings-tab.spec.ts +++ b/apps/web/playwright/e2e/settings/account-user-settings-tab.spec.ts @@ -7,6 +7,7 @@ Please see LICENSE files in the repository root for full details. */ import { test, expect } from "../../element-web-test"; +import { getSampleFilePath } from "../../sample-files"; const USER_NAME = "Bob"; const USER_NAME_NEW = "Alice"; @@ -85,7 +86,7 @@ test.describe("Account user settings tab", () => { test("should support adding and removing a profile picture", async ({ uut, page }) => { const profileSettings = uut.locator(".mx_UserProfileSettings"); // Upload a picture - await profileSettings.getByAltText("Upload").setInputFiles("playwright/sample-files/riot.png"); + await profileSettings.getByAltText("Upload").setInputFiles(getSampleFilePath("riot.png")); // Image should be visible await expect(profileSettings.locator(".mx_AvatarSetting_avatar img")).toBeVisible(); diff --git a/apps/web/playwright/e2e/spaces/spaces.spec.ts b/apps/web/playwright/e2e/spaces/spaces.spec.ts index f528c4b0b5..72b7873920 100644 --- a/apps/web/playwright/e2e/spaces/spaces.spec.ts +++ b/apps/web/playwright/e2e/spaces/spaces.spec.ts @@ -12,6 +12,7 @@ import type { Preset, ICreateRoomOpts } from "matrix-js-sdk/src/matrix"; import { type ElementAppPage } from "../../pages/ElementAppPage"; import { isDendrite } from "../../plugins/homeserver/dendrite"; import { UIFeature } from "../../../src/settings/UIFeature"; +import { getSampleFilePath } from "../../sample-files"; async function openSpaceCreateMenu(page: Page): Promise { await page.getByRole("button", { name: "Create a space" }).click(); @@ -74,7 +75,7 @@ test.describe("Spaces", () => { await contextMenu .locator('.mx_SpaceBasicSettings_avatarContainer input[type="file"]') - .setInputFiles("playwright/sample-files/riot.png"); + .setInputFiles(getSampleFilePath("riot.png")); await contextMenu.getByRole("textbox", { name: "Name" }).fill("Let's have a Riot"); await expect(contextMenu.getByRole("textbox", { name: "Address" })).toHaveValue("lets-have-a-riot"); await contextMenu @@ -108,7 +109,7 @@ test.describe("Spaces", () => { await menu .locator('.mx_SpaceBasicSettings_avatarContainer input[type="file"]') - .setInputFiles("playwright/sample-files/riot.png"); + .setInputFiles(getSampleFilePath("riot.png")); await menu.getByRole("textbox", { name: "Name" }).fill("This is not a Riot"); await expect(menu.getByRole("textbox", { name: "Address" })).not.toBeVisible(); await menu.getByRole("textbox", { name: "Description" }).fill("This is a private space of mourning Riot.im..."); @@ -154,7 +155,7 @@ test.describe("Spaces", () => { await menu .locator('.mx_SpaceBasicSettings_avatarContainer input[type="file"]') - .setInputFiles("playwright/sample-files/riot.png"); + .setInputFiles(getSampleFilePath("riot.png")); await expect(menu.getByRole("textbox", { name: "Address" })).not.toBeVisible(); await menu.getByRole("textbox", { name: "Description" }).fill("This is a personal space to mourn Riot.im..."); await menu.getByRole("textbox", { name: "Name" }).fill("This is my Riot"); @@ -188,7 +189,7 @@ test.describe("Spaces", () => { await menu .locator('.mx_SpaceBasicSettings_avatarContainer input[type="file"]') - .setInputFiles("playwright/sample-files/riot.png"); + .setInputFiles(getSampleFilePath("riot.png")); await expect(menu.getByRole("textbox", { name: "Address" })).not.toBeVisible(); await menu .getByRole("textbox", { name: "Description" }) @@ -406,7 +407,7 @@ test.describe("Spaces", () => { const menu = await openSpaceCreateMenu(page); await menu .locator('.mx_SpaceBasicSettings_avatarContainer input[type="file"]') - .setInputFiles("playwright/sample-files/riot.png"); + .setInputFiles(getSampleFilePath("riot.png")); await menu.getByRole("textbox", { name: "Name" }).fill("This is a private space"); await expect(menu.getByRole("textbox", { name: "Address" })).not.toBeVisible(); await menu diff --git a/apps/web/playwright/e2e/timeline/media-preview-settings.spec.ts b/apps/web/playwright/e2e/timeline/media-preview-settings.spec.ts index 617aa08c09..f88312f682 100644 --- a/apps/web/playwright/e2e/timeline/media-preview-settings.spec.ts +++ b/apps/web/playwright/e2e/timeline/media-preview-settings.spec.ts @@ -5,12 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import * as fs from "node:fs"; import { type EventType, type MsgType, type RoomJoinRulesEventContent } from "matrix-js-sdk/src/types"; import { test, expect } from "../../element-web-test"; +import { readSampleFileSync } from "../../sample-files"; -const MEDIA_FILE = fs.readFileSync("playwright/sample-files/riot.png"); +const MEDIA_FILE = readSampleFileSync("riot.png", null); test.describe("Media preview settings", () => { test.use({ diff --git a/apps/web/playwright/e2e/timeline/timeline.spec.ts b/apps/web/playwright/e2e/timeline/timeline.spec.ts index aaffffa76d..8a1c51b45f 100644 --- a/apps/web/playwright/e2e/timeline/timeline.spec.ts +++ b/apps/web/playwright/e2e/timeline/timeline.spec.ts @@ -6,8 +6,6 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import * as fs from "node:fs"; - import type { Locator, Page } from "@playwright/test"; import type { ISendEventResponse, EventType, MsgType } from "matrix-js-sdk/src/matrix"; import { test, expect } from "../../element-web-test"; @@ -16,6 +14,7 @@ import { Layout } from "../../../src/settings/enums/Layout"; import { type Client } from "../../pages/client"; import { type ElementAppPage } from "../../pages/ElementAppPage"; import { Bot } from "../../pages/bot"; +import { getSampleFilePath, readSampleFileSync } from "../../sample-files"; // The avatar size used in the timeline const AVATAR_SIZE = 30; @@ -23,12 +22,12 @@ const AVATAR_SIZE = 30; const AVATAR_RESIZE_METHOD = "crop"; const ROOM_NAME = "Test room"; -const OLD_AVATAR = fs.readFileSync("playwright/sample-files/riot.png"); -const NEW_AVATAR = fs.readFileSync("playwright/sample-files/element.png"); +const OLD_AVATAR = readSampleFileSync("riot.png", null); +const NEW_AVATAR = readSampleFileSync("element.png", null); const OLD_NAME = "Alan"; const NEW_NAME = "Alan (away)"; -const VIDEO_FILE = fs.readFileSync("playwright/sample-files/5secvid.webm"); +const VIDEO_FILE = readSampleFileSync("5secvid.webm", null); const getEventTilesWithBodies = (page: Page): Locator => { return page.locator(".mx_EventTile").filter({ has: page.locator(".mx_EventTile_body") }); @@ -765,7 +764,7 @@ test.describe("Timeline", () => { // Upload a file from the message composer await page .locator(".mx_MessageComposer_actions input[type='file']") - .setInputFiles("playwright/sample-files/matrix-org-client-versions.json"); + .setInputFiles(getSampleFilePath("matrix-org-client-versions.json")); // Click "Upload" button await page.locator(".mx_Dialog").getByRole("button", { name: "Upload" }).click(); diff --git a/apps/web/playwright/e2e/voip/element-call.spec.ts b/apps/web/playwright/e2e/voip/element-call.spec.ts index 813d9a0601..b68a4d6b4c 100644 --- a/apps/web/playwright/e2e/voip/element-call.spec.ts +++ b/apps/web/playwright/e2e/voip/element-call.spec.ts @@ -15,13 +15,14 @@ import { test, expect } from "../../element-web-test"; import type { Credentials } from "../../plugins/homeserver"; import { Bot } from "../../pages/bot"; import { isDendrite } from "../../plugins/homeserver/dendrite"; +import { readSampleFile } from "../../sample-files"; // Load a copy of our fake Element Call app, and the latest widget API. // The fake call app does *just* enough to convince Element Web that a call is ongoing // and functions like PiP work. It does not actually do anything though, to limit the // surface we test. const widgetApi = readFile(fileURLToPath(import.meta.resolve("matrix-widget-api/dist/api.min.js")), "utf-8"); -const fakeCallClient = readFile("playwright/sample-files/fake-element-call.html", "utf-8"); +const fakeCallClient = readSampleFile("fake-element-call.html"); function assertCommonCallParameters( url: URLSearchParams, @@ -615,7 +616,7 @@ test.describe("Element Call", () => { }, }); - const fakeCallClientSend = readFile("playwright/sample-files/fake-element-call-with-send.html", "utf-8"); + const fakeCallClientSend = readSampleFile("fake-element-call-with-send.html"); let charlie: Bot; test.use({ diff --git a/apps/web/playwright/e2e/widgets/stickers.spec.ts b/apps/web/playwright/e2e/widgets/stickers.spec.ts index 79ae4cca0d..8ae1f4b0fb 100644 --- a/apps/web/playwright/e2e/widgets/stickers.spec.ts +++ b/apps/web/playwright/e2e/widgets/stickers.spec.ts @@ -6,20 +6,19 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import * as fs from "node:fs"; - import type { Page } from "@playwright/test"; import { test, expect } from "../../element-web-test"; import { type ElementAppPage } from "../../pages/ElementAppPage"; import { type Credentials } from "../../plugins/homeserver"; import type { UserWidget } from "../../../src/utils/WidgetUtils-types.ts"; +import { readSampleFileSync } from "../../sample-files"; const STICKER_PICKER_WIDGET_ID = "fake-sticker-picker"; const STICKER_PICKER_WIDGET_NAME = "Fake Stickers"; const STICKER_NAME = "Test Sticker"; const ROOM_NAME_1 = "Sticker Test"; const ROOM_NAME_2 = "Sticker Test Two"; -const STICKER_IMAGE = fs.readFileSync("playwright/sample-files/riot.png"); +const STICKER_IMAGE = readSampleFileSync("riot.png", null); function getStickerMessage(contentUri: string, mimetype: string): string { return JSON.stringify({ diff --git a/apps/web/playwright/plugins/homeserver/synapse/consentHomeserver.ts b/apps/web/playwright/plugins/homeserver/synapse/consentHomeserver.ts index 0dfc0aa735..97bfd60d4e 100644 --- a/apps/web/playwright/plugins/homeserver/synapse/consentHomeserver.ts +++ b/apps/web/playwright/plugins/homeserver/synapse/consentHomeserver.ts @@ -7,16 +7,18 @@ Please see LICENSE files in the repository root for full details. */ import { type SynapseContainer } from "@element-hq/element-web-playwright-common/lib/testcontainers/index.js"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; import { type Fixtures } from "../../../element-web-test.ts"; +const __dirname = dirname(fileURLToPath(import.meta.url)); + export const consentHomeserver: Fixtures = { _homeserver: [ async ({ _homeserver: container, mailpit }, use) => { (container as SynapseContainer) - .withCopyDirectoriesToContainer([ - { source: "playwright/plugins/homeserver/synapse/res", target: "/data/res" }, - ]) + .withCopyDirectoriesToContainer([{ source: join(__dirname, "res"), target: "/data/res" }]) .withSmtpServer(mailpit) .withConfig({ user_consent: { diff --git a/apps/web/playwright/sample-files/index.ts b/apps/web/playwright/sample-files/index.ts new file mode 100644 index 0000000000..786e5be6a4 --- /dev/null +++ b/apps/web/playwright/sample-files/index.ts @@ -0,0 +1,32 @@ +/* +Copyright 2026 Element Creations Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE files in the repository root for full details. +*/ + +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { readFile } from "node:fs/promises"; +import { readFileSync } from "node:fs"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +export function getSampleFilePath(file: string): string { + return join(__dirname, file); +} + +export function readSampleFile(file: string, encoding: null): Promise; +export function readSampleFile(file: string, encoding?: BufferEncoding): Promise; +export function readSampleFile( + file: string, + encoding: BufferEncoding | null = "utf-8", +): Promise { + return readFile(getSampleFilePath(file), encoding); +} + +export function readSampleFileSync(file: string, encoding: null): NonSharedBuffer; +export function readSampleFileSync(file: string, encoding?: BufferEncoding): string; +export function readSampleFileSync(file: string, encoding: BufferEncoding | null = "utf-8"): NonSharedBuffer | string { + return readFileSync(getSampleFilePath(file), encoding); +}