Browse Source

Make knip happier (#32721)

Signed-off-by: Michael Telatynski <[email protected]>
Michael Telatynski 1 day ago
parent
commit
32037b0135

+ 5 - 2
.github/workflows/end-to-end-tests.yaml

@@ -160,11 +160,13 @@ jobs:
 
             - name: Install Playwright browsers
               if: steps.playwright-cache.outputs.cache-hit != 'true'
+              working-directory: apps/web
               run: pnpm playwright install --with-deps --no-shell
 
             - name: Install system dependencies for WebKit
               # Some WebKit dependencies seem to lay outside the cache and will need to be installed separately
               if: matrix.project == 'WebKit' && steps.playwright-cache.outputs.cache-hit == 'true'
+              working-directory: apps/web
               run: pnpm playwright install-deps webkit
 
             # We skip tests tagged with @mergequeue when running on PRs, but run them in MQ and everywhere else
@@ -223,12 +225,13 @@ jobs:
               uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8
               with:
                   pattern: all-blob-reports-*
-                  path: all-blob-reports
+                  path: apps/web/all-blob-reports
                   merge-multiple: true
 
             - name: Merge into HTML Report
               if: inputs.skip != true
-              run: pnpm playwright merge-reports --reporter=html,./apps/web/playwright/flaky-reporter.ts,@element-hq/element-web-playwright-common/lib/stale-screenshot-reporter.js ./all-blob-reports
+              working-directory: apps/web
+              run: pnpm playwright merge-reports --reporter=html,./playwright/flaky-reporter.ts,@element-hq/element-web-playwright-common/lib/stale-screenshot-reporter.js ./all-blob-reports
               env:
                   # Only pass creds to the flaky-reporter on main branch runs
                   GITHUB_TOKEN: ${{ github.ref_name == 'develop' && secrets.ELEMENT_BOT_TOKEN || '' }}

+ 0 - 3
.husky/pre-commit

@@ -1,4 +1 @@
-#!/usr/bin/env sh
-. "$(dirname "$0")/_/husky.sh"
-
 npx lint-staged --concurrent false

+ 1 - 1
.lintstagedrc

@@ -1,3 +1,3 @@
 {
-    "*": "prettier --write"
+    "*": "prettier --write --ignore-unknown"
 }

+ 1 - 1
apps/web/.lintstagedrc

@@ -1,5 +1,5 @@
 {
-    "*": "prettier --write",
+    "*": "prettier --write --ignore-unknown",
     "src/**/*.(ts|tsx)": ["eslint --fix"],
     "scripts/**/*.(ts|tsx)": ["eslint --fix"],
     "module_system/**/*.(ts|tsx)": ["eslint --fix"],

+ 3 - 0
apps/web/jest.config.ts

@@ -17,6 +17,9 @@ const config: Config = {
         // This is needed to be able to load dual CJS/ESM WASM packages e.g. rust crypto & matrix-wywiwyg
         customExportConditions: ["browser", "node"],
     },
+    transform: {
+        "\\.[jt]sx?$": "babel-jest",
+    },
     testMatch: ["<rootDir>/test/**/*-test.[tj]s?(x)"],
     globalSetup: "<rootDir>/test/globalSetup.ts",
     setupFiles: ["jest-canvas-mock", "web-streams-polyfill/polyfill"],

+ 1 - 1
apps/web/package.json

@@ -129,7 +129,6 @@
         "@babel/preset-env": "^7.12.11",
         "@babel/preset-react": "^7.12.10",
         "@babel/preset-typescript": "^7.12.7",
-        "@babel/runtime": "^7.12.5",
         "@casualbot/jest-sonar-reporter": "2.5.0",
         "@element-hq/element-call-embedded": "0.16.3",
         "@element-hq/element-web-playwright-common": "catalog:",
@@ -210,6 +209,7 @@
         "matrix-web-i18n": "catalog:",
         "mini-css-extract-plugin": "2.10.0",
         "modernizr": "^3.12.0",
+        "playwright-core": "catalog:",
         "postcss": "8.5.6",
         "postcss-easings": "4.0.0",
         "postcss-hexrgba": "2.1.0",

+ 3 - 3
apps/web/project.json

@@ -34,9 +34,9 @@
             "executor": "nx:run-commands",
             "options": {
                 "commands": [
-                    "tsc --noEmit --project ./tsconfig.module_system.json",
-                    "tsc --noEmit",
-                    "tsc --noEmit -p playwright"
+                    "pnpm tsc --noEmit --project ./tsconfig.module_system.json",
+                    "pnpm tsc --noEmit",
+                    "pnpm tsc --noEmit -p playwright"
                 ],
                 "parallel": false,
                 "cwd": "apps/web"

+ 0 - 9
apps/web/res/css/shared.pcss

@@ -1,9 +0,0 @@
-/*
- * Copyright 2025 New Vector 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 url("@vector-im/compound-design-tokens/assets/web/css/compound-design-tokens.css") layer(compound);
-@import url("@vector-im/compound-web/dist/style.css");

+ 1 - 0
apps/web/src/components/views/elements/InfoTooltip.tsx

@@ -15,6 +15,7 @@ import { ErrorSolidIcon, InfoIcon } from "@vector-im/compound-design-tokens/asse
 import { _t } from "../../../languageHandler";
 
 export enum InfoTooltipKind {
+    /** @knipignore */
     Info = "info",
     Warning = "warning",
 }

+ 4 - 1
apps/web/src/hooks/useTimeout.ts

@@ -10,7 +10,10 @@ import { useEffect, useRef, useState } from "react";
 
 type Handler = () => void;
 
-// Hook to simplify timeouts in functional components
+/**
+ * Hook to simplify timeouts in functional components
+ * @knipignore
+ */
 export const useTimeout = (handler: Handler, timeoutMs: number): void => {
     // Create a ref that stores handler
     const savedHandler = useRef<Handler>(undefined);

+ 3 - 4
apps/web/src/vector/jitsi/index.ts

@@ -33,6 +33,9 @@ import { SnakedObject } from "../../utils/SnakedObject";
 import { ElementWidgetCapabilities } from "../../stores/widgets/ElementWidgetCapabilities";
 import { getVectorConfig } from "../getconfig";
 
+// We have to trick webpack into loading our CSS for us.
+import "./index.pcss";
+
 interface Config extends _Config {
     // Jitsi's types are missing these fields
     prejoinConfig?: {
@@ -61,10 +64,6 @@ interface ExternalAPIOptions extends _ExternalAPIOptions {
     lang?: string;
 }
 
-// We have to trick webpack into loading our CSS for us.
-// eslint-disable-next-line @typescript-eslint/no-require-imports
-require("./index.pcss");
-
 const JITSI_OPENIDTOKEN_JWT_AUTH = "openidtoken-jwt";
 
 // Dev note: we use raw JS without many dependencies to reduce bundle size.

+ 21 - 54
knip.ts

@@ -1,29 +1,17 @@
 import { KnipConfig } from "knip";
 
+// Specify this as knip loads config files which may conditionally add reporters, e.g. `@casualbot/jest-sonar-reporter'
+process.env.GITHUB_ACTIONS = "1";
+
 export default {
     workspaces: {
-        "packages/shared-components": {
-            entry: ["src/index.ts"],
-            ignoreBinaries: [
-                // False positives
-                "vite",
-                "typedoc",
-            ],
+        "packages/shared-components": {},
+        "packages/playwright-common": {
             ignoreDependencies: [
-                // We import this in some tests, transitive dep of @playwright/test
-                "playwright-core",
-                // False positives
-                "@testing-library/jest-dom",
-                "@vitejs/plugin-react",
-                "expect",
-                "vitest-browser-react",
-                "vitest-sonar-reporter",
+                // Used in playwright-screenshots.sh
+                "wait-on",
             ],
         },
-        "packages/playwright-common": {
-            entry: ["playwright-screenshots.sh"],
-            ignoreDependencies: ["@playwright/test", "wait-on"],
-        },
         "apps/web": {
             entry: [
                 "src/serviceworker/index.ts",
@@ -35,26 +23,13 @@ export default {
                 "test/**",
                 "res/decoder-ring/**",
                 "res/jitsi_external_api.min.js",
+                "res/themes/*/css/*.pcss",
             ],
             ignore: [
                 // Keep for now
                 "src/hooks/useLocalStorageState.ts",
-                "src/hooks/useTimeout.ts",
-                "src/components/views/elements/InfoTooltip.tsx",
-                "src/components/views/elements/StyledCheckbox.tsx",
-            ],
-            ignoreBinaries: [
-                // False positive
-                "webpack-dev-server",
             ],
             ignoreDependencies: [
-                // Used by jest
-                "babel-jest",
-                // Used by babel
-                "@babel/runtime",
-                "@babel/plugin-transform-class-properties",
-                // Referenced in PCSS
-                "github-markdown-css",
                 // False positive
                 "sw.js",
                 // Used by webpack
@@ -62,11 +37,6 @@ export default {
                 "util",
                 // Embedded into webapp
                 "@element-hq/element-call-embedded",
-                // False-positive jest dep
-                "vitest-environment-jest-fixed-jsdom",
-
-                // We import this in some tests, transitive dep of @playwright/test
-                "playwright-core",
 
                 // Used by matrix-js-sdk, which means we have to include them as a
                 // dependency so that // we can run `tsc` (since we import the typescript
@@ -78,25 +48,22 @@ export default {
         },
         ".": {
             entry: ["scripts/**", "docs/**"],
-            ignoreBinaries: ["lint:types", "lint:js", "lint:style"],
-            ignoreDependencies: [
-                // Required for `action-validator`
-                "@action-validator/*",
-                // Used for git pre-commit hooks
-                "husky",
-            ],
         },
     },
-    ignoreBinaries: [
-        // False positives
-        "playwright",
-        "build:storybook",
-        "test:storybook",
-        "test:unit",
-        "vendor:jitsi",
-    ],
     ignoreExportsUsedInFile: true,
+    compilers: {
+        pcss: (text: string) =>
+            [...text.matchAll(/(?<=@)import[^;]+/g)]
+                .map(([line]) => {
+                    if (line.startsWith("import url(")) {
+                        return line.replace("url(", "").slice(0, -1);
+                    }
+                    return line;
+                })
+                .join("\n"),
+    },
     nx: {
-        config: ["nx.json", "project.json", "{apps,packages,modules}/**/project.json", "package.json"],
+        config: ["{nx,package,project}.json", "{apps,packages,modules}/**/{package,project}.json"],
     },
+    tags: ["-knipignore"],
 } satisfies KnipConfig;

+ 4 - 3
package.json

@@ -16,8 +16,9 @@
         "lint": "pnpm -r lint:types && pnpm lint:prettier && pnpm -r lint:js && pnpm -r lint:style && pnpm lint:workflows && pnpm lint:knip",
         "lint:prettier": "prettier --check .",
         "lint:prettier-fix": "prettier --log-level=warn --write .",
-        "lint:workflows": "find .github/workflows -type f \\( -iname '*.yaml' -o -iname '*.yml' \\) | xargs -I {} sh -c 'echo \"Linting {}\"; action-validator \"{}\"'",
+        "lint:workflows": "find .github/workflows -type f \\( -iname '*.yaml' -o -iname '*.yml' \\) -print -exec action-validator {} ';'",
         "lint:knip": "knip",
+        "install:git-hooks": "husky",
         "postinstall": "node scripts/pnpm-link.ts"
     },
     "resolutions": {
@@ -35,7 +36,6 @@
         "qs": "6.15.0",
         "serialize-javascript": "7.0.3"
     },
-    "dependencies": {},
     "devDependencies": {
         "@action-validator/cli": "^0.6.0",
         "@action-validator/core": "^0.6.0",
@@ -71,7 +71,8 @@
             "await-lock": "patches/await-lock.patch",
             "jest-fixed-jsdom": "patches/jest-fixed-jsdom.patch",
             "jsdom": "patches/jsdom.patch",
-            "rollup": "patches/rollup.patch"
+            "rollup": "patches/rollup.patch",
+            "knip": "patches/knip.patch"
         },
         "peerDependencyRules": {
             "allowedVersions": {

+ 0 - 1
packages/playwright-common/package.json

@@ -16,7 +16,6 @@
         "playwright-screenshots-experimental": "playwright-screenshots.sh"
     },
     "devDependencies": {
-        "@playwright/test": "catalog:",
         "wait-on": "^9.0.4"
     }
 }

+ 5 - 4
packages/playwright-common/playwright-screenshots.sh

@@ -2,11 +2,12 @@
 
 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")
+
 function build_image() {
     local IMAGE_NAME="$1"
-    # Handle symlinks here as we tend to be executed as an npm binary
-    local SCRIPT_PATH=$(readlink -f "$0")
-    local SCRIPT_DIR=$(dirname "$SCRIPT_PATH")
 
     echo "Building $IMAGE_NAME image in $SCRIPT_DIR"
     docker build -t "$IMAGE_NAME" --build-arg "PLAYWRIGHT_VERSION=${IMAGE_NAME#*:}" "$SCRIPT_DIR"
@@ -34,7 +35,7 @@ trap clean_up EXIT
 
 # Wait for playwright-server to be ready
 echo "Waiting for playwright-server"
-pnpm wait-on "tcp:$WS_PORT"
+pnpm --dir "$SCRIPT_DIR" wait-on "tcp:$WS_PORT"
 
 # Run the test we were given, setting PW_TEST_CONNECT_WS_ENDPOINT accordingly
 echo "Running '$@'"

+ 0 - 5
packages/shared-components/package.json

@@ -76,7 +76,6 @@
         "@storybook/react-vite": "^10.0.7",
         "@stylistic/eslint-plugin": "^5.7.0",
         "@testing-library/dom": "^10.4.1",
-        "@testing-library/jest-dom": "^6.9.1",
         "@testing-library/react": "^16.3.2",
         "@testing-library/user-event": "^14.6.1",
         "@types/counterpart": "^0.18.4",
@@ -86,10 +85,8 @@
         "@typescript-eslint/eslint-plugin": "^8.53.1",
         "@typescript-eslint/parser": "^8.53.1",
         "@vector-im/compound-web": "catalog:",
-        "@vitejs/plugin-react": "^5.1.2",
         "@vitest/browser-playwright": "^4.0.17",
         "@vitest/coverage-v8": "^4.0.17",
-        "@vitest/ui": "^4.0.17",
         "eslint": "8",
         "eslint-config-google": "^0.14.0",
         "eslint-config-prettier": "^10.1.8",
@@ -102,7 +99,6 @@
         "eslint-plugin-react-hooks": "^7.0.1",
         "eslint-plugin-storybook": "^10.0.7",
         "eslint-plugin-unicorn": "^56.0.0",
-        "expect": "^30.2.0",
         "prettier": "^3.6.2",
         "storybook": "^10.0.7",
         "storybook-addon-vis": "^3.1.2",
@@ -114,7 +110,6 @@
         "vite-plugin-dts": "^4.5.4",
         "vite-plugin-node-polyfills": "^0.25.0",
         "vitest": "^4.0.18",
-        "vitest-browser-react": "^2.0.2",
         "vitest-sonar-reporter": "^3.0.0"
     },
     "engines": {

+ 2 - 5
packages/shared-components/vitest.config.ts

@@ -5,19 +5,16 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
 Please see LICENSE files in the repository root for full details.
 */
 
-/// <reference types="@vitest/browser-playwright" />
-
 import { defineConfig } from "vitest/config";
 import path from "node:path";
 import { fileURLToPath } from "node:url";
 import { storybookTest } from "@storybook/addon-vitest/vitest-plugin";
 import { storybookVis } from "storybook-addon-vis/vitest-plugin";
-import { playwright } from "@vitest/browser-playwright";
+import { playwright, PlaywrightProviderOptions } from "@vitest/browser-playwright";
 import { nodePolyfills } from "vite-plugin-node-polyfills";
 import { InlineConfig } from "vite";
 import { Reporter } from "vitest/reporters";
 import { env } from "process";
-import { BrowserContextOptions } from "playwright-core";
 
 const dirname = typeof __dirname !== "undefined" ? __dirname : path.dirname(fileURLToPath(import.meta.url));
 
@@ -61,7 +58,7 @@ if (env["GITHUB_ACTIONS"] !== undefined) {
     }
 }
 
-const commonContextOptions: Omit<BrowserContextOptions, "ignoreHTTPSErrors" | "serviceWorkers"> = {
+const commonContextOptions: PlaywrightProviderOptions["contextOptions"] = {
     reducedMotion: "reduce",
     // Force consistent font rendering
     colorScheme: "light",

+ 93 - 0
patches/knip.patch

@@ -0,0 +1,93 @@
+diff --git a/dist/binaries/bash-parser.js b/dist/binaries/bash-parser.js
+index 7e8c465e4fcf156988edd35ac725f8159edc5a87..ab28395084c77ed8922a3fa882daaff89f1e65fd 100644
+--- a/dist/binaries/bash-parser.js
++++ b/dist/binaries/bash-parser.js
+@@ -49,6 +49,16 @@ export const getDependenciesFromScript = (script, options) => {
+                 if (definedFunctions.has(binary))
+                     return [];
+                 const args = node.suffix?.map(arg => arg.text) ?? [];
++                if (binary === "find" && args.includes("-exec")) {
++                    const i = args.indexOf("-exec");
++                    const [execCmd, ...execArgs] = node.suffix.slice(i + 1, -1);
++                    return getDependenciesFromNodes([{
++                        type: "Command",
++                        name: execCmd,
++                        suffix: execArgs,
++                    }]);
++                    return (commandExpansions.flatMap(expansion => getDependenciesFromNodes(expansion.commandAST.commands)) ?? []);
++                }
+                 if (['!', 'test'].includes(binary))
+                     return fromArgs(args);
+                 const fromNodeOptions = node.prefix
+diff --git a/dist/plugins/babel/index.js b/dist/plugins/babel/index.js
+index 4772fcda2ab92dfc80b248e91dc5c3894920d075..3b34f9c3439b6576f07959abf42f37c0418c2fc5 100644
+--- a/dist/plugins/babel/index.js
++++ b/dist/plugins/babel/index.js
+@@ -9,15 +9,23 @@ const config = ['babel.config.{json,js,cjs,mjs,cts,ts}', '.babelrc.{json,js,cjs,
+ const getName = (value) => [Array.isArray(value) ? value[0] : value].filter(name => typeof name === 'string');
+ export const getDependenciesFromConfig = (config) => {
+     const presets = config.presets?.flatMap(getName).map(name => resolveName(name, 'preset')) ?? [];
++    const presetIncludes = config.presets?.filter(preset => Array.isArray(preset) && typeof preset[1] === "object").flatMap(preset => preset[1]?.include ?? []).map(name => resolveName(name, 'plugin')) ?? [];
+     const plugins = config.plugins?.flatMap(getName).map(name => resolveName(name, 'plugin')) ?? [];
+     const nested = config.env ? Object.values(config.env).flatMap(getDependenciesFromConfig) : [];
+     const overrides = config.overrides ? [config.overrides].flat().flatMap(getDependenciesFromConfig) : [];
+-    return compact([
++    const deps = [
+         ...presets.map(id => toDeferResolve(id)),
++        ...presetIncludes.map(id => toDeferResolve(id)),
+         ...plugins.map(id => toDeferResolve(id)),
+         ...nested,
+         ...overrides,
+-    ]);
++    ];
++
++    if (deps.find(dep => dep.specifier === "@babel/plugin-transform-runtime")) {
++        deps.push(toDeferResolve("@babel/runtime"));
++    }
++
++    return compact(deps);
+ };
+ const resolveConfig = async (config) => {
+     if (typeof config === 'function')
+diff --git a/dist/plugins/nx/index.js b/dist/plugins/nx/index.js
+index 43bd253a3bcae4e9f8cb05be0db09b0b14598000..415479489f30cfcc9d57557a7fab02babdf12030 100644
+--- a/dist/plugins/nx/index.js
++++ b/dist/plugins/nx/index.js
+@@ -34,18 +34,18 @@ const resolveConfig = async (localConfig, options) => {
+         .map(target => target?.executor)
+         .filter(executor => executor && !executor.startsWith('.'))
+         .map(executor => executor?.split(':')[0]);
+-    const scripts = targets
++    const inputs = targets
+         .filter(target => target.executor === 'nx:run-commands' || target.command)
+         .flatMap(target => {
++        let commands = [];
+         if (target.command)
+-            return [target.command];
++            commands = [target.command];
+         if (target.options?.command)
+-            return [target.options.command];
++            commands = [target.options.command];
+         if (target.options?.commands)
+-            return target.options.commands.map(commandConfig => typeof commandConfig === 'string' ? commandConfig : commandConfig.command);
+-        return [];
++            commands = target.options.commands.map(commandConfig => typeof commandConfig === 'string' ? commandConfig : commandConfig.command);
++        return options.getInputsFromScripts(commands, { cwd: target.options?.cwd });
+     });
+-    const inputs = options.getInputsFromScripts(scripts);
+     const configInputs = targets.flatMap(target => {
+         const opts = target.options;
+         if (!opts)
+diff --git a/dist/typescript/pragmas/custom.js b/dist/typescript/pragmas/custom.js
+index f913d03560252b9161c11f0371f1a68198ed78bd..7ac5cc43b1fff9eec9b7b59d48c5871fb8403eb4 100644
+--- a/dist/typescript/pragmas/custom.js
++++ b/dist/typescript/pragmas/custom.js
+@@ -2,7 +2,7 @@ import { IMPORT_FLAGS } from '../../constants.js';
+ import { getEnvSpecifier } from '../../plugins/vitest/helpers.js';
+ import { isAbsolute, isInternal } from '../../util/path.js';
+ import { getLeadingComments, stripQuotes } from '../ast-helpers.js';
+-const VITEST_ENV = /@(vitest|jest)-environment\s+(\S+)/g;
++const VITEST_ENV = /@(vitest)-environment\s+(\S+)/g;
+ export const collectCustomImports = (sourceFile) => {
+     const comments = getLeadingComments(sourceFile);
+     if (!comments.length)

+ 18 - 99
pnpm-lock.yaml

@@ -27,6 +27,9 @@ catalogs:
     matrix-web-i18n:
       specifier: 3.6.0
       version: 3.6.0
+    playwright-core:
+      specifier: 1.58.2
+      version: 1.58.2
     react:
       specifier: ^19.0.0
       version: 19.2.4
@@ -73,6 +76,9 @@ patchedDependencies:
   jsdom:
     hash: 040623e87b1c8b676c2a705513c0276c0704dd1b23fc3a1bb77cde8128b64b5f
     path: patches/jsdom.patch
+  knip:
+    hash: 5f6aaaa07ba1cb3f8934c51e130a6d5aaf7cca32b398cb57dfdb313c387bfff1
+    path: patches/knip.patch
   linkify-html:
     hash: 1761c1eabe25d9fae83f74f27a20b3d24515840a4a8747bb04828df46bcfdea2
     path: patches/linkify-html.patch
@@ -113,7 +119,7 @@ importers:
         version: 9.1.7
       knip:
         specifier: ^5.36.2
-        version: 5.85.0(@types/[email protected])([email protected])
+        version: 5.85.0(patch_hash=5f6aaaa07ba1cb3f8934c51e130a6d5aaf7cca32b398cb57dfdb313c387bfff1)(@types/[email protected])([email protected])
       lint-staged:
         specifier: ^16.0.0
         version: 16.3.0
@@ -284,7 +290,7 @@ importers:
         version: 1.0.3
       matrix-js-sdk:
         specifier: github:matrix-org/matrix-js-sdk#develop
-        version: https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/c7cd5570d32f7c3556c0f82bbe2eb97f78a9418c
+        version: https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/5d0e2efaf32c00cc71e0259078f289c4180a9338
       matrix-widget-api:
         specifier: ^1.17.0
         version: 1.17.0
@@ -649,6 +655,9 @@ importers:
       modernizr:
         specifier: ^3.12.0
         version: 3.13.1
+      playwright-core:
+        specifier: 'catalog:'
+        version: 1.58.2
       postcss:
         specifier: 8.5.6
         version: 8.5.6
@@ -745,9 +754,6 @@ importers:
 
   packages/playwright-common:
     devDependencies:
-      '@playwright/test':
-        specifier: 'catalog:'
-        version: 1.58.2
       wait-on:
         specifier: ^9.0.4
         version: 9.0.4
@@ -824,9 +830,6 @@ importers:
       '@testing-library/dom':
         specifier: ^10.4.1
         version: 10.4.1
-      '@testing-library/jest-dom':
-        specifier: ^6.9.1
-        version: 6.9.1
       '@testing-library/react':
         specifier: ^16.3.2
         version: 16.3.2(@testing-library/[email protected])(@types/[email protected](@types/[email protected]))(@types/[email protected])([email protected]([email protected]))([email protected])
@@ -854,18 +857,12 @@ importers:
       '@vector-im/compound-web':
         specifier: 'catalog:'
         version: 8.4.0(@fontsource/[email protected])(@fontsource/[email protected])(@types/[email protected](@types/[email protected]))(@types/[email protected])(@vector-im/[email protected](@types/[email protected])([email protected]))([email protected]([email protected]))([email protected])
-      '@vitejs/plugin-react':
-        specifier: ^5.1.2
-        version: 5.1.4([email protected](@types/[email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])([email protected]))
       '@vitest/browser-playwright':
         specifier: ^4.0.17
         version: 4.0.18([email protected])([email protected](@types/[email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])([email protected]))([email protected])
       '@vitest/coverage-v8':
         specifier: ^4.0.17
         version: 4.0.18(@vitest/[email protected]([email protected](@types/[email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])([email protected]))([email protected]))([email protected])
-      '@vitest/ui':
-        specifier: ^4.0.17
-        version: 4.0.18([email protected])
       eslint:
         specifier: '8'
         version: 8.57.1
@@ -902,9 +899,6 @@ importers:
       eslint-plugin-unicorn:
         specifier: ^56.0.0
         version: 56.0.1([email protected])
-      expect:
-        specifier: ^30.2.0
-        version: 30.2.0
       prettier:
         specifier: ^3.6.2
         version: 3.8.1
@@ -938,9 +932,6 @@ importers:
       vitest:
         specifier: ^4.0.18
         version: 4.0.18(@opentelemetry/[email protected])(@types/[email protected])(@vitest/[email protected])(@vitest/[email protected])([email protected])([email protected](patch_hash=040623e87b1c8b676c2a705513c0276c0704dd1b23fc3a1bb77cde8128b64b5f))([email protected]([email protected]))([email protected])([email protected])([email protected])
-      vitest-browser-react:
-        specifier: ^2.0.2
-        version: 2.0.5(@types/[email protected](@types/[email protected]))(@types/[email protected])([email protected]([email protected]))([email protected])([email protected])
       vitest-sonar-reporter:
         specifier: ^3.0.0
         version: 3.0.0([email protected])
@@ -1519,18 +1510,6 @@ packages:
     peerDependencies:
       '@babel/core': ^7.0.0-0
 
-  '@babel/[email protected]':
-    resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
-
-  '@babel/[email protected]':
-    resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
-
   '@babel/[email protected]':
     resolution: {integrity: sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==}
     engines: {node: '>=6.9.0'}
@@ -3565,9 +3544,6 @@ packages:
     resolution: {integrity: sha512-2FK1hF93Fuf1laSdfiEmJvSJPVIDHEUTz68D3Fi9s0IZrrpaEcj6pTFBTbYvsgC5du4ogrtf5re7yMMvrKNgkw==}
     engines: {node: ^20.9.0 || ^22.11.0 || ^24, pnpm: ^10.0.0}
 
-  '@rolldown/[email protected]':
-    resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==}
-
   '@rollup/[email protected]':
     resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==}
     engines: {node: '>=14.0.0'}
@@ -4586,12 +4562,6 @@ packages:
     bundledDependencies:
       - '@vector-im/matrix-wysiwyg-wasm'
 
-  '@vitejs/[email protected]':
-    resolution: {integrity: sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA==}
-    engines: {node: ^20.19.0 || >=22.12.0}
-    peerDependencies:
-      vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
-
   '@vitest/[email protected]':
     resolution: {integrity: sha512-gfajTHVCiwpxRj1qh0Sh/5bbGLG4F/ZH/V9xvFVoFddpITfMta9YGow0W6ZpTTORv2vdJuz9TnrNSmjKvpOf4g==}
     peerDependencies:
@@ -7846,8 +7816,8 @@ packages:
   [email protected]:
     resolution: {integrity: sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==}
 
-  matrix-js-sdk@https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/c7cd5570d32f7c3556c0f82bbe2eb97f78a9418c:
-    resolution: {tarball: https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/c7cd5570d32f7c3556c0f82bbe2eb97f78a9418c}
+  matrix-js-sdk@https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/5d0e2efaf32c00cc71e0259078f289c4180a9338:
+    resolution: {tarball: https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/5d0e2efaf32c00cc71e0259078f289c4180a9338}
     version: 41.0.0
     engines: {node: '>=22.0.0'}
 
@@ -9105,10 +9075,6 @@ packages:
       react-native:
         optional: true
 
-  [email protected]:
-    resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==}
-    engines: {node: '>=0.10.0'}
-
   [email protected]:
     resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==}
     engines: {node: '>=10'}
@@ -10384,20 +10350,6 @@ packages:
       yaml:
         optional: true
 
-  [email protected]:
-    resolution: {integrity: sha512-YODQX8mHTJCyKNVYTWJrLEYrUtw+QfLl78owgvuE7C5ydgmGBq6v5s4jK2w6wdPhIZsN9PpV1rQbmAevWJjO9g==}
-    peerDependencies:
-      '@types/react': ^19.2.10
-      '@types/react-dom': ^19.2.3
-      react: ^18.0.0 || ^19.0.0
-      react-dom: ^18.0.0 || ^19.0.0
-      vitest: ^4.0.0
-    peerDependenciesMeta:
-      '@types/react':
-        optional: true
-      '@types/react-dom':
-        optional: true
-
   [email protected]:
     resolution: {integrity: sha512-wEYILWeax3hMUNMLMJzZ0dwtasy/YKAZz5/pyqK+0tyETjNBhtdrWiRLZc6OktOMZJk2YPlpjSOB/qqldAlvMQ==}
     peerDependencies:
@@ -11420,16 +11372,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/[email protected](@babel/[email protected])':
-    dependencies:
-      '@babel/core': 7.29.0
-      '@babel/helper-plugin-utils': 7.28.6
-
-  '@babel/[email protected](@babel/[email protected])':
-    dependencies:
-      '@babel/core': 7.29.0
-      '@babel/helper-plugin-utils': 7.28.6
-
   '@babel/[email protected](@babel/[email protected])':
     dependencies:
       '@babel/core': 7.29.0
@@ -13721,8 +13663,6 @@ snapshots:
 
   '@renovatebot/[email protected]': {}
 
-  '@rolldown/[email protected]': {}
-
   '@rollup/[email protected]([email protected](patch_hash=603340e49399c6044e41a3998891667387d5ec1acbd38d4e5862f2ba3ef58de8))':
     dependencies:
       '@rollup/pluginutils': 5.3.0([email protected](patch_hash=603340e49399c6044e41a3998891667387d5ec1acbd38d4e5862f2ba3ef58de8))
@@ -14761,18 +14701,6 @@ snapshots:
     dependencies:
       react: 19.2.4
 
-  '@vitejs/[email protected]([email protected](@types/[email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])([email protected]))':
-    dependencies:
-      '@babel/core': 7.29.0
-      '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/[email protected])
-      '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/[email protected])
-      '@rolldown/pluginutils': 1.0.0-rc.3
-      '@types/babel__core': 7.20.5
-      react-refresh: 0.18.0
-      vite: 7.3.1(@types/[email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])([email protected])
-    transitivePeerDependencies:
-      - supports-color
-
   '@vitest/[email protected]([email protected])([email protected](@types/[email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])([email protected]))([email protected])':
     dependencies:
       '@vitest/browser': 4.0.18([email protected](@types/[email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])([email protected]))([email protected])
@@ -14879,6 +14807,7 @@ snapshots:
       tinyglobby: 0.2.15
       tinyrainbow: 3.0.3
       vitest: 4.0.18(@opentelemetry/[email protected])(@types/[email protected])(@vitest/[email protected])(@vitest/[email protected])([email protected])([email protected](patch_hash=040623e87b1c8b676c2a705513c0276c0704dd1b23fc3a1bb77cde8128b64b5f))([email protected]([email protected]))([email protected])([email protected])([email protected])
+    optional: true
 
   '@vitest/[email protected]':
     dependencies:
@@ -17178,7 +17107,8 @@ snapshots:
 
   [email protected]: {}
 
-  [email protected]: {}
+  [email protected]:
+    optional: true
 
   [email protected]:
     dependencies:
@@ -18537,7 +18467,7 @@ snapshots:
 
   [email protected]: {}
 
-  [email protected](@types/[email protected])([email protected]):
+  [email protected](patch_hash=5f6aaaa07ba1cb3f8934c51e130a6d5aaf7cca32b398cb57dfdb313c387bfff1)(@types/[email protected])([email protected]):
     dependencies:
       '@nodelib/fs.walk': 1.2.8
       '@types/node': 22.19.13
@@ -18779,7 +18709,7 @@ snapshots:
 
   [email protected]: {}
 
-  matrix-js-sdk@https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/c7cd5570d32f7c3556c0f82bbe2eb97f78a9418c:
+  matrix-js-sdk@https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/5d0e2efaf32c00cc71e0259078f289c4180a9338:
     dependencies:
       '@babel/runtime': 7.28.6
       '@matrix-org/matrix-sdk-crypto-wasm': 17.1.0
@@ -20189,8 +20119,6 @@ snapshots:
     optionalDependencies:
       react-dom: 19.2.4([email protected])
 
-  [email protected]: {}
-
   [email protected](@types/[email protected])([email protected]):
     dependencies:
       react: 19.2.4
@@ -21724,15 +21652,6 @@ snapshots:
       tsx: 4.21.0
       yaml: 2.8.2
 
-  [email protected](@types/[email protected](@types/[email protected]))(@types/[email protected])([email protected]([email protected]))([email protected])([email protected]):
-    dependencies:
-      react: 19.2.4
-      react-dom: 19.2.4([email protected])
-      vitest: 4.0.18(@opentelemetry/[email protected])(@types/[email protected])(@vitest/[email protected])(@vitest/[email protected])([email protected])([email protected](patch_hash=040623e87b1c8b676c2a705513c0276c0704dd1b23fc3a1bb77cde8128b64b5f))([email protected]([email protected]))([email protected])([email protected])([email protected])
-    optionalDependencies:
-      '@types/react': 19.2.10
-      '@types/react-dom': 19.2.3(@types/[email protected])
-
   [email protected](@vitest/[email protected])(@vitest/[email protected]([email protected](@types/[email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])([email protected]))([email protected]))([email protected])([email protected]):
     dependencies:
       '@vitest/browser': 4.0.18([email protected](@types/[email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])([email protected]))([email protected])

+ 1 - 0
pnpm-workspace.yaml

@@ -15,6 +15,7 @@ catalog:
     # playwright
     "@element-hq/element-web-playwright-common": 2.2.7
     "@playwright/test": 1.58.2
+    "playwright-core": 1.58.2
     # Module API
     "@element-hq/element-web-module-api": 1.10.0
     # Compound