Run only the browser in docker for storybook screenshots (#32489)

* Remove old screenshots

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Add experimental playwright-screenshots.sh utility and use it for shared-components `test:storybook:update`

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Tidy up

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate based on review

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski
2026-02-13 10:20:16 +00:00
committed by GitHub
parent d7ca3dbd1d
commit b3b6574638
15 changed files with 203 additions and 26 deletions

View File

@@ -0,0 +1,13 @@
ARG PLAYWRIGHT_VERSION
FROM mcr.microsoft.com/playwright:v${PLAYWRIGHT_VERSION}-noble
WORKDIR /work
# fonts-dejavu is needed for the same RTL rendering as on CI
RUN apt-get update && apt-get -y install docker.io fonts-dejavu
# Install the matching playwright runtime, the docker image only includes browsers
RUN npm i -g playwright@${PLAYWRIGHT_VERSION}
COPY docker-entrypoint.sh /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]

View File

@@ -0,0 +1,22 @@
# @element-hq/element-web-playwright-common
Set of Playwright utilities to make it easier to write tests for Element Web, Element Web Modules & Element Desktop.
# This is a partial clone of https://github.com/element-hq/element-modules/tree/main/packages/element-web-playwright-common
In the future the rest of the package will be brought into this monorepo, for now it serves as an experimental alternative to https://github.com/element-hq/element-modules/pull/188
## Releases
The API is versioned using semver, with the major version incremented for breaking changes.
## Copyright & License
Copyright (c) 2026 Element Creations Ltd
This software is multi licensed by Element Creations Ltd (Element). It can be used either:
(1) for free under the terms of the GNU Affero General Public License (as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version); OR
(2) under the terms of a paid-for Element Commercial License agreement between you and Element (the terms of which may vary depending on what you and Element have agreed to).
Unless required by applicable law or agreed to in writing, software distributed under the Licenses is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Licenses for the specific language governing permissions and limitations under the Licenses.

View File

@@ -0,0 +1,4 @@
#!/bin/bash
# We use npm here as we used `npm i -g` to install playwright in the Dockerfile
npm exec -- playwright run-server --port "$PORT" --host 0.0.0.0

View File

@@ -0,0 +1,21 @@
{
"name": "@element-hq/element-web-playwright-common-local",
"type": "module",
"version": "3.0.0",
"license": "SEE LICENSE IN README.md",
"repository": {
"type": "git",
"url": "git+https://github.com/element-hq/element-web.git",
"directory": "packages/playwright-common"
},
"author": "element-hq",
"engines": {
"node": ">=20.0.0"
},
"bin": {
"playwright-screenshots": "playwright-screenshots.sh"
},
"devDependencies": {
"wait-on": "^9.0.4"
}
}

View File

@@ -0,0 +1,36 @@
#!/bin/bash
set -e
# Handle symlinks here as we tend to be executed as an npm binary
SCRIPT_PATH=$(readlink -f "$0")
SCRIPT_DIR=$(dirname "$SCRIPT_PATH")
IMAGE_NAME="element-web-playwright-server"
WS_PORT=3000
# Check the playwright version
PW_VERSION=$(npm exec --silent -- playwright --version | gcut -d" " -f2)
echo "Building $IMAGE_NAME:$PW_VERSION image in $SCRIPT_DIR"
# Build the image
docker build -t "$IMAGE_NAME" --build-arg "PLAYWRIGHT_VERSION=$PW_VERSION" "$SCRIPT_DIR"
# Start the playwright-server in docker
CONTAINER=$(docker run --network=host --rm -d -e PORT="$WS_PORT" "$IMAGE_NAME")
# Set up an exit trap to clean up the docker container
clean_up() {
ARG=$?
echo "Stopping playwright-server"
docker stop "$CONTAINER" > /dev/null
exit $ARG
}
trap clean_up EXIT
# Wait for playwright-server to be ready
echo "Waiting for playwright-server"
pnpm wait-on "tcp:$WS_PORT"
# Run the test we were given, setting PW_TEST_CONNECT_WS_ENDPOINT accordingly
echo "Running '$@'"
PW_TEST_CONNECT_WS_ENDPOINT="http://localhost:$WS_PORT" "$@"

View File

@@ -40,7 +40,7 @@
"i18n:lint": "matrix-i18n-lint && prettier --log-level=silent --write src/i18n/strings/ --ignore-path /dev/null",
"test:unit": "vitest --project=unit",
"test:storybook": "pnpm build:doc && vitest --project=storybook",
"test:storybook:update": "cd ../.. && playwright-screenshots --entrypoint /work/packages/shared-components/scripts/storybook-screenshot-update.sh --with-node-modules --no-link-modules",
"test:storybook:update": "CI=1 pnpm playwright-screenshots pnpm vitest --run --update --project=storybook",
"build": "vite build",
"prepack": "pnpm run build",
"storybook": "storybook dev -p 6007",
@@ -63,7 +63,7 @@
"temporal-polyfill": "^0.3.0"
},
"devDependencies": {
"@element-hq/element-web-playwright-common": "catalog:",
"@element-hq/element-web-playwright-common-local": "workspace:*",
"@fetch-mock/vitest": "^0.2.18",
"@matrix-org/react-sdk-module-api": "^2.5.0",
"@playwright/test": "catalog:",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

View File

@@ -1,19 +0,0 @@
#!/bin/bash
#
# Update storybook screenshots
#
# This script should be used as the entrypoint parameter of the `playwright-screenshots` script. It
# installs the pnpm dependencies, and then runs `vitest --run --update --project=storybook` to update the storybook screenshots.
#
# It requires that `playwright-screenshots` is given the `--with-node-modules` parameter.
set -e
# First install dependencies. We have to do this within the playwright container rather than the host,
# because we have which must be built for the right architecture (and some environments use a VM
# to run docker containers, meaning that things inside a container use a different architecture than
# those on the host).
pnpm install --frozen-lockfile
# Now run the screenshot update, we set CI=1 to inform vis to update the real baselines
CI=1 pnpm --dir packages/shared-components test:storybook --run --update

View File

@@ -101,6 +101,8 @@ export default defineConfig({
storybookVis({
// 3px of difference allowed before marking as failed
failureThreshold: 3,
// When running in CI=1 mode, set the platform to `linux` as that is the platform where the browser-in-docker is running
snapshotRootDir: ({ ci, platform }) => `__vis__/${ci ? "linux" : platform}`,
}),
],
test: {
@@ -110,7 +112,16 @@ export default defineConfig({
headless: true,
provider: playwright({
contextOptions: commonContextOptions,
launchOptions: commonLaunchOptions,
launchOptions: process.env.PW_TEST_CONNECT_WS_ENDPOINT ? undefined : commonLaunchOptions,
connectOptions: process.env.PW_TEST_CONNECT_WS_ENDPOINT
? {
wsEndpoint: process.env.PW_TEST_CONNECT_WS_ENDPOINT,
exposeNetwork: "<loopback>",
headers: {
"x-playwright-launch-options": JSON.stringify(commonLaunchOptions),
},
}
: undefined,
}),
instances: [{ browser: "chromium" }],
},

97
pnpm-lock.yaml generated
View File

@@ -711,6 +711,12 @@ importers:
specifier: ^2.3.3
version: 2.8.2
packages/playwright-common:
devDependencies:
wait-on:
specifier: ^9.0.4
version: 9.0.4
packages/shared-components:
dependencies:
'@element-hq/element-web-module-api':
@@ -744,9 +750,9 @@ importers:
specifier: ^0.3.0
version: 0.3.0
devDependencies:
'@element-hq/element-web-playwright-common':
specifier: 'catalog:'
version: 2.2.7(@element-hq/element-web-module-api@1.9.0(@matrix-org/react-sdk-module-api@2.5.0(patch_hash=016146c9cc96e6363609d2b2ac0896ccef567882eb1d73b75a77b8a30929de96)(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(matrix-web-i18n@3.6.0)(react@19.2.4))(@playwright/test@1.58.1)(playwright-core@1.58.1)
'@element-hq/element-web-playwright-common-local':
specifier: workspace:*
version: link:../playwright-common
'@fetch-mock/vitest':
specifier: ^0.2.18
version: 0.2.18(vitest@4.0.18)
@@ -2268,6 +2274,26 @@ packages:
engines: {node: '>=6'}
hasBin: true
'@hapi/address@5.1.1':
resolution: {integrity: sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA==}
engines: {node: '>=14.0.0'}
'@hapi/formula@3.0.2':
resolution: {integrity: sha512-hY5YPNXzw1He7s0iqkRQi+uMGh383CGdyyIGYtB+W5N3KHPXoqychklvHhKCC9M3Xtv0OCs/IHw+r4dcHtBYWw==}
'@hapi/hoek@11.0.7':
resolution: {integrity: sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ==}
'@hapi/pinpoint@2.0.1':
resolution: {integrity: sha512-EKQmr16tM8s16vTT3cA5L0kZZcTMU5DUOZTuvpnY738m+jyP3JIUj+Mm1xc1rsLkGBQ/gVnfKYPwOmPg1tUR4Q==}
'@hapi/tlds@1.1.5':
resolution: {integrity: sha512-Vq/1gnIIsvFUpKlDdfrPd/ssHDpAyBP/baVukh3u2KSG2xoNjsnRNjQiPmuyPPGqsn1cqVWWhtZHfOBaLizFRQ==}
engines: {node: '>=14.0.0'}
'@hapi/topo@6.0.2':
resolution: {integrity: sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg==}
'@humanwhocodes/config-array@0.13.0':
resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==}
engines: {node: '>=10.10.0'}
@@ -4877,6 +4903,9 @@ packages:
axios@1.13.4:
resolution: {integrity: sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==}
axios@1.13.5:
resolution: {integrity: sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==}
axobject-query@4.1.0:
resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
engines: {node: '>= 0.4'}
@@ -7352,6 +7381,10 @@ packages:
jju@1.4.0:
resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
joi@18.0.2:
resolution: {integrity: sha512-RuCOQMIt78LWnktPoeBL0GErkNaJPTBGcYuyaBvUOQSpcpcLfWrHPPihYdOGbV5pam9VTWbeoF7TsGiHugcjGA==}
engines: {node: '>= 20'}
js-tokens@10.0.0:
resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==}
@@ -9195,6 +9228,9 @@ packages:
rw@1.3.3:
resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==}
rxjs@7.8.2:
resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==}
safe-array-concat@1.1.3:
resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
engines: {node: '>=0.4'}
@@ -10270,6 +10306,11 @@ packages:
resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
engines: {node: '>=18'}
wait-on@9.0.4:
resolution: {integrity: sha512-k8qrgfwrPVJXTeFY8tl6BxVHiclK11u72DVKhpybHfUL/K6KM4bdyK9EhIVYGytB5MJe/3lq4Tf0hrjM+pvJZQ==}
engines: {node: '>=20.0.0'}
hasBin: true
walk-up-path@4.0.0:
resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==}
engines: {node: 20 || >=22}
@@ -12068,6 +12109,22 @@ snapshots:
protobufjs: 7.5.4
yargs: 17.7.2
'@hapi/address@5.1.1':
dependencies:
'@hapi/hoek': 11.0.7
'@hapi/formula@3.0.2': {}
'@hapi/hoek@11.0.7': {}
'@hapi/pinpoint@2.0.1': {}
'@hapi/tlds@1.1.5': {}
'@hapi/topo@6.0.2':
dependencies:
'@hapi/hoek': 11.0.7
'@humanwhocodes/config-array@0.13.0':
dependencies:
'@humanwhocodes/object-schema': 2.0.3
@@ -15005,6 +15062,14 @@ snapshots:
transitivePeerDependencies:
- debug
axios@1.13.5:
dependencies:
follow-redirects: 1.15.11
form-data: 4.0.5
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
axobject-query@4.1.0: {}
b4a@1.7.3: {}
@@ -18068,6 +18133,16 @@ snapshots:
jju@1.4.0: {}
joi@18.0.2:
dependencies:
'@hapi/address': 5.1.1
'@hapi/formula': 3.0.2
'@hapi/hoek': 11.0.7
'@hapi/pinpoint': 2.0.1
'@hapi/tlds': 1.1.5
'@hapi/topo': 6.0.2
'@standard-schema/spec': 1.1.0
js-tokens@10.0.0: {}
js-tokens@4.0.0: {}
@@ -18368,7 +18443,7 @@ snapshots:
mailpit-api@1.7.0:
dependencies:
axios: 1.13.4
axios: 1.13.5
partysocket: 1.1.11
ws: 8.19.0
transitivePeerDependencies:
@@ -20141,6 +20216,10 @@ snapshots:
rw@1.3.3: {}
rxjs@7.8.2:
dependencies:
tslib: 2.8.1
safe-array-concat@1.1.3:
dependencies:
call-bind: 1.0.8
@@ -21436,6 +21515,16 @@ snapshots:
dependencies:
xml-name-validator: 5.0.0
wait-on@9.0.4:
dependencies:
axios: 1.13.5
joi: 18.0.2
lodash: 4.17.23
minimist: 1.2.8
rxjs: 7.8.2
transitivePeerDependencies:
- debug
walk-up-path@4.0.0: {}
walk@2.3.15: