From 2d7e659953b33635e3de82e29b2f3a02c2731c5e Mon Sep 17 00:00:00 2001 From: Glen Huang Date: Mon, 20 Oct 2025 19:00:05 +0800 Subject: [PATCH] ui: run storybook tests with nix --- pkgs/clan-app/shell.nix | 41 ++++++++----------- pkgs/clan-app/ui.nix | 18 ++++----- pkgs/clan-app/ui/package-lock.json | 16 ++++---- pkgs/clan-app/ui/package.json | 6 +-- pkgs/clan-app/ui/vite.config.ts | 40 ++++++++++++++++++- pkgs/clan-app/ui/vitest.config.ts | 63 ------------------------------ 6 files changed, 72 insertions(+), 112 deletions(-) delete mode 100644 pkgs/clan-app/ui/vitest.config.ts diff --git a/pkgs/clan-app/shell.nix b/pkgs/clan-app/shell.nix index 822c23aa6..4328b88db 100644 --- a/pkgs/clan-app/shell.nix +++ b/pkgs/clan-app/shell.nix @@ -12,7 +12,7 @@ fetchzip, process-compose, json2ts, - playwright-driver, + playwright, luakit, self', }: @@ -108,32 +108,23 @@ mkShell { export PC_CONFIG_FILES="$CLAN_CORE_PATH/pkgs/clan-app/process-compose.yaml" echo -e "${GREEN}To launch a qemu VM for testing, run:\n start-vm ${NC}" - '' - + - # todo darwin support needs some work - (lib.optionalString stdenv.hostPlatform.isLinux '' - # configure playwright for storybook snapshot testing - # we only want webkit as that matches what the app is rendered with - export PLAYWRIGHT_BROWSERS_PATH=${ - playwright-driver.browsers.override { - withFfmpeg = false; - withFirefox = false; - withWebkit = true; - withChromium = false; - withChromiumHeadlessShell = true; - } + # configure playwright for storybook snapshot testing + # we only want webkit as that matches what the app is rendered with + + export PLAYWRIGHT_BROWSERS_PATH=${ + playwright.browsers.override { + withFfmpeg = false; + withFirefox = false; + withWebkit = true; + withChromium = false; + withChromiumHeadlessShell = false; } + } - # stop playwright from trying to validate it has downloaded the necessary browsers - # we are providing them manually via nix + # stop playwright from trying to validate it has downloaded the necessary browsers + # we are providing them manually via nix - export PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS=true - - # playwright browser drivers are versioned e.g. webkit-2191 - # this helps us avoid having to update the playwright js dependency everytime we update nixpkgs and vice versa - # see vitest.config.js for corresponding launch configuration - - export PLAYWRIGHT_CHROMIUM_EXECUTABLE=$(find -L "$PLAYWRIGHT_BROWSERS_PATH" -type f -name "headless_shell") - ''); + export PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS=true + ''; } diff --git a/pkgs/clan-app/ui.nix b/pkgs/clan-app/ui.nix index d121f1dd6..503df0193 100644 --- a/pkgs/clan-app/ui.nix +++ b/pkgs/clan-app/ui.nix @@ -35,7 +35,7 @@ buildNpmPackage (finalAttrs: { # Something about passing orientation in any of the Form stories is causing the browser to crash # `npm run test-storybook-static` works fine in the devshell - passthru = rec { + passthru = { storybook = buildNpmPackage { pname = "${finalAttrs.pname}-storybook"; inherit (finalAttrs) @@ -50,22 +50,18 @@ buildNpmPackage (finalAttrs: { ps ]; - npmBuildScript = "test-storybook-static"; + npmBuildScript = "test-storybook"; env = { PLAYWRIGHT_BROWSERS_PATH = "${playwright-driver.browsers.override { - withChromiumHeadlessShell = true; + withFfmpeg = false; + withFirefox = false; + withWebkit = true; + withChromium = false; + withChromiumHeadlessShell = false; }}"; PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS = true; }; - - preBuild = finalAttrs.preBuild + '' - export PLAYWRIGHT_CHROMIUM_EXECUTABLE=$(find -L "$PLAYWRIGHT_BROWSERS_PATH" -type f -name "headless_shell") - ''; - - postBuild = '' - mv storybook-static $out - ''; }; }; }) diff --git a/pkgs/clan-app/ui/package-lock.json b/pkgs/clan-app/ui/package-lock.json index e4abc2ffd..87029e6c9 100644 --- a/pkgs/clan-app/ui/package-lock.json +++ b/pkgs/clan-app/ui/package-lock.json @@ -55,7 +55,7 @@ "jsdom": "^26.1.0", "knip": "^5.61.2", "markdown-to-jsx": "^7.7.10", - "playwright": "~1.55.1", + "playwright": "1.54.1", "postcss": "^8.4.38", "postcss-url": "^10.1.3", "prettier": "^3.2.5", @@ -7292,13 +7292,13 @@ } }, "node_modules/playwright": { - "version": "1.55.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.1.tgz", - "integrity": "sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==", + "version": "1.54.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.54.1.tgz", + "integrity": "sha512-peWpSwIBmSLi6aW2auvrUtf2DqY16YYcCMO8rTVx486jKmDTJg7UAhyrraP98GB8BoPURZP8+nxO7TSd4cPr5g==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.55.1" + "playwright-core": "1.54.1" }, "bin": { "playwright": "cli.js" @@ -7311,9 +7311,9 @@ } }, "node_modules/playwright-core": { - "version": "1.55.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.1.tgz", - "integrity": "sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==", + "version": "1.54.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.54.1.tgz", + "integrity": "sha512-Nbjs2zjj0htNhzgiy5wu+3w09YetDx5pkrpI/kZotDlDUaYk0HVA5xrBVPdow4SAUIlhgKcJeJg4GRKW6xHusA==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/pkgs/clan-app/ui/package.json b/pkgs/clan-app/ui/package.json index ea3b13955..fe421da8b 100644 --- a/pkgs/clan-app/ui/package.json +++ b/pkgs/clan-app/ui/package.json @@ -14,11 +14,9 @@ "vite": "vite", "storybook": "storybook", "knip": "knip --fix", - "storybook-build": "storybook build", "storybook-dev": "storybook dev -p 6006", "test-storybook": "vitest run --project storybook --reporter verbose", - "test-storybook-update-snapshots": "vitest run --project storybook --update", - "test-storybook-static": "npm run storybook-build && concurrently -k -s first -n 'SB,TEST' -c 'magenta,blue' 'http-server storybook-static -a 127.0.0.1 -p 6006 --silent' 'wait-on tcp:127.0.0.1:6006 && npm run test-storybook'" + "test-storybook-update-snapshots": "vitest run --project storybook --update" }, "license": "MIT", "devDependencies": { @@ -50,7 +48,7 @@ "jsdom": "^26.1.0", "knip": "^5.61.2", "markdown-to-jsx": "^7.7.10", - "playwright": "~1.55.1", + "playwright": "1.54.1", "postcss": "^8.4.38", "postcss-url": "^10.1.3", "prettier": "^3.2.5", diff --git a/pkgs/clan-app/ui/vite.config.ts b/pkgs/clan-app/ui/vite.config.ts index bf7272567..579b7ed82 100644 --- a/pkgs/clan-app/ui/vite.config.ts +++ b/pkgs/clan-app/ui/vite.config.ts @@ -5,6 +5,8 @@ import solidSvg from "vite-plugin-solid-svg"; import { patchCssModules } from "vite-css-modules"; import path from "node:path"; import { exec } from "child_process"; +// @ts-expect-error the type is a bit funky, but it's working +import { storybookTest } from "@storybook/addon-vitest/vitest-plugin"; // watch also clan-cli to catch api changes const clanCliDir = path.resolve(__dirname, "../../clan-cli"); @@ -12,7 +14,7 @@ const clanCliDir = path.resolve(__dirname, "../../clan-cli"); function regenPythonApiOnFileChange() { return { name: "run-python-script-on-change", - handleHotUpdate({}) { + handleHotUpdate() { exec("reload-python-api.sh", (err, stdout, stderr) => { if (err) { console.error(`reload-python-api.sh error:\n${stderr}`); @@ -67,4 +69,40 @@ export default defineConfig({ }, // assetsInlineLimit: 0, }, + test: { + projects: [ + { + test: { + name: "unit", + }, + }, + { + extends: path.resolve(__dirname, "vite.config.ts"), + plugins: [ + // The plugin will run tests for the stories defined in your Storybook config + // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest + storybookTest({ + configDir: path.resolve(__dirname, ".storybook"), + }), + ], + test: { + name: "storybook", + browser: { + // Enable browser-based testing for UI components + enabled: true, + headless: true, + provider: "playwright", + instances: [ + { + browser: "webkit", + }, + ], + }, + // This setup file applies Storybook project annotations for Vitest + // More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations + setupFiles: [".storybook/vitest.setup.ts"], + }, + }, + ], + }, }); diff --git a/pkgs/clan-app/ui/vitest.config.ts b/pkgs/clan-app/ui/vitest.config.ts deleted file mode 100644 index aa6cdd835..000000000 --- a/pkgs/clan-app/ui/vitest.config.ts +++ /dev/null @@ -1,63 +0,0 @@ -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -import solid from "vite-plugin-solid"; -import { defineConfig, mergeConfig } from "vitest/config"; -// @ts-expect-error the type is a bit funky, but it's working -import { storybookTest } from "@storybook/addon-vitest/vitest-plugin"; - -const dirname = - typeof __dirname !== "undefined" - ? __dirname - : path.dirname(fileURLToPath(import.meta.url)); - -import viteConfig from "./vite.config"; - -const browser = process.env.BROWSER || "chromium"; - -export default mergeConfig( - viteConfig, - defineConfig({ - plugins: [solid()], - test: { - projects: [ - { - test: { - name: "unit", - }, - }, - { - extends: path.join(dirname, "vite.config.ts"), - plugins: [ - // The plugin will run tests for the stories defined in your Storybook config - // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest - storybookTest({ - configDir: path.join(dirname, ".storybook"), - }), - ], - test: { - name: "storybook", - browser: { - // Enable browser-based testing for UI components - enabled: true, - headless: true, - provider: "playwright", - instances: [ - { - browser: "chromium", - launch: { - // we specify this explicitly to avoid the version matching that playwright tries to do - executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE, - }, - }, - ], - }, - // This setup file applies Storybook project annotations for Vitest - // More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations - setupFiles: [".storybook/vitest.setup.ts"], - }, - }, - ], - }, - }), -);