diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 27b9accd..b1943c58 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -14,10 +14,10 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- - name: Use Node.js 22.13.1
+ - name: Use Node.js 22.18.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.13.1'
+ node-version: '22.18.0'
- name: Install pnpm
run: |
@@ -42,7 +42,7 @@ jobs:
strategy:
matrix:
- node-version: ['22.13.1', 24]
+ node-version: ['22.18.0', 24]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
diff --git a/.github/workflows/release-ember-client.yml b/.github/workflows/release-ember-client.yml
index 5a980411..e78743e7 100644
--- a/.github/workflows/release-ember-client.yml
+++ b/.github/workflows/release-ember-client.yml
@@ -39,7 +39,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.14.0'
+ node-version: '22.18.0'
registry-url: 'https://registry.npmjs.org'
- name: Upgrade npm for Trusted Publishers
@@ -124,7 +124,7 @@ jobs:
- name: Set Node.js back to release version
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.14.0'
+ node-version: '22.18.0'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
diff --git a/.github/workflows/release-ruby-client.yml b/.github/workflows/release-ruby-client.yml
index 55e6632c..13957bb2 100644
--- a/.github/workflows/release-ruby-client.yml
+++ b/.github/workflows/release-ruby-client.yml
@@ -34,7 +34,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.13.1'
+ node-version: '22.18.0'
- name: Set up Ruby
uses: ruby/setup-ruby@97ecb7b512899eb71ab1bf2310a624c6f1589ac6 # v1
diff --git a/.github/workflows/release-static-site-client.yml b/.github/workflows/release-static-site-client.yml
index d4febdf5..d26426a4 100644
--- a/.github/workflows/release-static-site-client.yml
+++ b/.github/workflows/release-static-site-client.yml
@@ -34,7 +34,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.14.0'
+ node-version: '22.18.0'
registry-url: 'https://registry.npmjs.org'
- name: Upgrade npm for Trusted Publishers
@@ -115,7 +115,7 @@ jobs:
- name: Set Node.js back to release version
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.14.0'
+ node-version: '22.18.0'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
diff --git a/.github/workflows/release-storybook-client.yml b/.github/workflows/release-storybook-client.yml
index 9cf55f7f..9f5b7885 100644
--- a/.github/workflows/release-storybook-client.yml
+++ b/.github/workflows/release-storybook-client.yml
@@ -34,7 +34,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.14.0'
+ node-version: '22.18.0'
registry-url: 'https://registry.npmjs.org'
- name: Upgrade npm for Trusted Publishers
@@ -115,7 +115,7 @@ jobs:
- name: Set Node.js back to release version
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.14.0'
+ node-version: '22.18.0'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
diff --git a/.github/workflows/release-swift-client.yml b/.github/workflows/release-swift-client.yml
index 44c32d26..6389de07 100644
--- a/.github/workflows/release-swift-client.yml
+++ b/.github/workflows/release-swift-client.yml
@@ -33,7 +33,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.14.0'
+ node-version: '22.18.0'
registry-url: 'https://registry.npmjs.org'
- name: Upgrade npm for Trusted Publishers
@@ -150,7 +150,7 @@ jobs:
- name: Restore Node.js for publishing
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.14.0'
+ node-version: '22.18.0'
registry-url: 'https://registry.npmjs.org'
- name: Restore npm for publishing
diff --git a/.github/workflows/release-vitest-client.yml b/.github/workflows/release-vitest-client.yml
index 78f890a4..923ff113 100644
--- a/.github/workflows/release-vitest-client.yml
+++ b/.github/workflows/release-vitest-client.yml
@@ -34,7 +34,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.14.0'
+ node-version: '22.18.0'
registry-url: 'https://registry.npmjs.org'
- name: Upgrade npm for Trusted Publishers
@@ -115,7 +115,7 @@ jobs:
- name: Set Node.js back to release version
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.14.0'
+ node-version: '22.18.0'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index c7a96128..f5e75e83 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -31,7 +31,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.14.0'
+ node-version: '22.18.0'
registry-url: 'https://registry.npmjs.org'
- name: Upgrade npm for Trusted Publishers
@@ -159,7 +159,7 @@ jobs:
- name: Restore Node.js for publishing
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.14.0'
+ node-version: '22.18.0'
registry-url: 'https://registry.npmjs.org'
- name: Restore npm and pnpm for publishing
diff --git a/.github/workflows/reporter.yml b/.github/workflows/reporter.yml
index ea0ae830..08a9c013 100644
--- a/.github/workflows/reporter.yml
+++ b/.github/workflows/reporter.yml
@@ -15,10 +15,10 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- - name: Use Node.js 22.13.1
+ - name: Use Node.js 22.18.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.13.1'
+ node-version: '22.18.0'
- name: Install pnpm
run: |
diff --git a/.github/workflows/sdk-e2e.yml b/.github/workflows/sdk-e2e.yml
index 037f9694..ec920a62 100644
--- a/.github/workflows/sdk-e2e.yml
+++ b/.github/workflows/sdk-e2e.yml
@@ -16,10 +16,10 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- - name: Use Node.js 22.13.1
+ - name: Use Node.js 22.18.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.13.1'
+ node-version: '22.18.0'
- name: Install pnpm
run: |
@@ -78,10 +78,10 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- - name: Use Node.js 22.13.1
+ - name: Use Node.js 22.18.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.13.1'
+ node-version: '22.18.0'
- name: Install pnpm
run: |
@@ -141,10 +141,10 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- - name: Use Node.js 22.13.1
+ - name: Use Node.js 22.18.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.13.1'
+ node-version: '22.18.0'
- name: Install pnpm
run: |
@@ -221,10 +221,10 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- - name: Use Node.js 22.13.1
+ - name: Use Node.js 22.18.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.13.1'
+ node-version: '22.18.0'
- name: Install pnpm
run: |
@@ -295,10 +295,10 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- - name: Use Node.js 22.13.1
+ - name: Use Node.js 22.18.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.13.1'
+ node-version: '22.18.0'
- name: Install pnpm
run: |
@@ -366,10 +366,10 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- - name: Use Node.js 22.13.1
+ - name: Use Node.js 22.18.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.13.1'
+ node-version: '22.18.0'
- name: Install pnpm
run: |
@@ -424,10 +424,10 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- - name: Use Node.js 22.13.1
+ - name: Use Node.js 22.18.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.13.1'
+ node-version: '22.18.0'
- name: Install pnpm
run: |
diff --git a/.github/workflows/sdk-unit.yml b/.github/workflows/sdk-unit.yml
index 5f15859f..2d68d3af 100644
--- a/.github/workflows/sdk-unit.yml
+++ b/.github/workflows/sdk-unit.yml
@@ -62,10 +62,10 @@ jobs:
with:
ruby-version: ${{ matrix.ruby-version }}
- - name: Use Node.js 22.13.1
+ - name: Use Node.js 22.18.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.13.1'
+ node-version: '22.18.0'
- name: Install pnpm
run: |
@@ -103,7 +103,7 @@ jobs:
strategy:
matrix:
- node-version: ['22.13.1', 24]
+ node-version: ['22.18.0', 24]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
@@ -153,7 +153,7 @@ jobs:
strategy:
matrix:
- node-version: ['22.13.1', 24]
+ node-version: ['22.18.0', 24]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
@@ -195,7 +195,7 @@ jobs:
# Vitest SDK - runs on multiple Node versions
vitest:
- name: Vitest SDK
+ name: Vitest SDK (Node ${{ matrix.node-version }}, Vitest ${{ matrix.vitest-version }})
runs-on: ubuntu-latest
timeout-minutes: 8
needs: changes
@@ -203,7 +203,8 @@ jobs:
strategy:
matrix:
- node-version: ['22.13.1', 24]
+ node-version: ['22.18.0', 24]
+ vitest-version: [4, 5]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
@@ -229,6 +230,11 @@ jobs:
working-directory: ./clients/vitest
run: pnpm install --frozen-lockfile
+ - name: Install Vitest 4 for compatibility tests
+ if: matrix.vitest-version == 4
+ working-directory: ./clients/vitest
+ run: pnpm add -D vitest@4.1.11 @vitest/browser@4.1.11 @vitest/browser-playwright@4.1.11
+
- name: Get installed Playwright version
working-directory: ./clients/vitest
id: playwright-version
@@ -250,6 +256,12 @@ jobs:
working-directory: ./clients/vitest
run: pnpm run lint
+ - name: Run Vitest client browser tests
+ working-directory: ./clients/vitest
+ run: pnpm run test:browser
+ env:
+ CI: true
+
- name: Run Vitest client unit tests
working-directory: ./clients/vitest
run: pnpm run test:unit
@@ -290,10 +302,10 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- - name: Use Node.js 22.13.1
+ - name: Use Node.js 22.18.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.13.1'
+ node-version: '22.18.0'
- name: Install pnpm
run: |
diff --git a/.github/workflows/tui.yml b/.github/workflows/tui.yml
index 19985417..d53b4902 100644
--- a/.github/workflows/tui.yml
+++ b/.github/workflows/tui.yml
@@ -15,10 +15,10 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- - name: Use Node.js 22.13.1
+ - name: Use Node.js 22.18.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
- node-version: '22.13.1'
+ node-version: '22.18.0'
- name: Setup tui-driver
uses: vizzly-testing/tui-driver@f21ea93489f2160eccf4d58844e456a9b38a0491 # main
diff --git a/README.md b/README.md
index 66242053..9a1b98c1 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@ build or diff data for scripts, automation, and coding agents.
## Quick Start
-You need Node.js 22+.
+You need Node.js 22.18 or newer within Node 22, or Node.js 24+.
```bash
pnpm install -g @vizzly-testing/cli
@@ -43,6 +43,19 @@ existing Vizzly config.
Use `vizzly init --agent-skill` to install or refresh only the local skill, or
`vizzly init --skip-agent-skill` when you want config without the agent prompt.
+### TypeScript Configuration
+
+Vizzly loads `vizzly.config.ts` with Node's native type stripping. Type
+annotations, interfaces, and `satisfies` work without installing TypeScript.
+Use `import type` for type-only imports and include file extensions when
+importing local helpers, such as `./helpers.ts`.
+
+Enums, namespaces containing runtime code, and constructor parameter properties
+aren't supported. Replace them with ordinary JavaScript values and assignments.
+Node doesn't apply `tsconfig.json` path aliases when loading your config.
+These restrictions apply to the config and its imports; they don't change how
+your application or tests compile.
+
### Start Local TDD
Start the TDD server, run your tests, and open the dashboard at the URL the
diff --git a/clients/ember/package.json b/clients/ember/package.json
index f2b02e21..ffd46188 100644
--- a/clients/ember/package.json
+++ b/clients/ember/package.json
@@ -61,7 +61,7 @@
"check:fix": "biome check --write src tests bin"
},
"engines": {
- "node": ">=22.0.0"
+ "node": "^22.18.0 || >=24.0.0"
},
"publishConfig": {
"access": "public",
diff --git a/clients/static-site/CHANGELOG.md b/clients/static-site/CHANGELOG.md
index fab908d2..7adec232 100644
--- a/clients/static-site/CHANGELOG.md
+++ b/clients/static-site/CHANGELOG.md
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [Unreleased]
+
+### Changed
+
+- Require Node.js 22.18 or newer within Node 22, or Node.js 24+.
+- Remove the unused Cosmiconfig dependency. Configuration still comes from
+ the CLI and the existing interactions file loader.
+
## [0.3.0] - 2026-06-01
## What's Changed
diff --git a/clients/static-site/README.md b/clients/static-site/README.md
index e54ef0ec..7093bd6b 100644
--- a/clients/static-site/README.md
+++ b/clients/static-site/README.md
@@ -2,6 +2,10 @@
Seamlessly integrate your static sites (Gatsby, Astro, Jekyll, Next.js static export, etc.) into Vizzly's visual development workflow. Iterate locally with `vizzly tdd`, automatically create team builds from CI/CD, and collaborate on visual changes with position-based comments and review rules.
+## Requirements
+
+Use Node.js 22.18 or newer within Node 22, or Node.js 24+.
+
## Installation
```bash
diff --git a/clients/static-site/package.json b/clients/static-site/package.json
index 5f819a36..566ee2f0 100644
--- a/clients/static-site/package.json
+++ b/clients/static-site/package.json
@@ -57,7 +57,7 @@
"check:fix": "biome check --write src"
},
"engines": {
- "node": ">=22.0.0"
+ "node": "^22.18.0 || >=24.0.0"
},
"publishConfig": {
"access": "public",
@@ -67,7 +67,6 @@
"@vizzly-testing/cli": ">=0.24.0"
},
"dependencies": {
- "cosmiconfig": "^9.0.0",
"fast-xml-parser": "^5.8.0",
"playwright-core": "^1.50.0",
"serve-handler": "^6.1.5",
diff --git a/clients/storybook/package.json b/clients/storybook/package.json
index 064cbdfb..6efa9e75 100644
--- a/clients/storybook/package.json
+++ b/clients/storybook/package.json
@@ -53,7 +53,7 @@
"check:fix": "biome check --write src tests"
},
"engines": {
- "node": ">=22.0.0"
+ "node": "^22.18.0 || >=24.0.0"
},
"publishConfig": {
"access": "public",
diff --git a/clients/swift/PREVIEWS.md b/clients/swift/PREVIEWS.md
index bd27159b..78f68f0f 100644
--- a/clients/swift/PREVIEWS.md
+++ b/clients/swift/PREVIEWS.md
@@ -8,7 +8,7 @@ Preview capture is optional. It does not change the `Vizzly` or
## Requirements
- Xcode 26.6
-- Node.js 22+
+- Node.js 22.18 or newer within Node 22, or Node.js 24+
- An arm64 Mac
- An iOS 17+ Simulator
- A scene-based iOS app
diff --git a/clients/swift/package.json b/clients/swift/package.json
index c168e7a3..a522dd6a 100644
--- a/clients/swift/package.json
+++ b/clients/swift/package.json
@@ -45,7 +45,7 @@
"prepublishOnly": "pnpm run check"
},
"engines": {
- "node": ">=22.0.0"
+ "node": "^22.18.0 || >=24.0.0"
},
"peerDependencies": {
"@vizzly-testing/cli": ">=0.36.0"
diff --git a/clients/vitest/CHANGELOG.md b/clients/vitest/CHANGELOG.md
index d1c8096a..1bd04103 100644
--- a/clients/vitest/CHANGELOG.md
+++ b/clients/vitest/CHANGELOG.md
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [Unreleased]
+
+### Changed
+
+- Require Node.js 22.18 or newer within Node 22, or Node.js 24+.
+
+### Fixed
+
+- Pass browser settings through Vitest environment variables so screenshot
+ uploads, build IDs, and fail-on-diff settings work with Vitest 5.
+- Honor fail-on-diff during local runs that also carry a build ID.
+
## [0.2.0] - 2026-06-01
## What's Changed
diff --git a/clients/vitest/README.md b/clients/vitest/README.md
index e57e3e4d..869c11ed 100644
--- a/clients/vitest/README.md
+++ b/clients/vitest/README.md
@@ -22,6 +22,10 @@ standard `toMatchScreenshot` API - no code changes required!
- 🚀 **CI/CD Ready** - Parallel execution and baseline management
- 🔬 **Better Diffing** - Powered by honeydiff (Rust-based, faster than pixelmatch)
+## Requirements
+
+Use Node.js 22.18 or newer within Node 22, or Node.js 24+.
+
## Installation
```bash
diff --git a/clients/vitest/package.json b/clients/vitest/package.json
index 96117047..76050f9c 100644
--- a/clients/vitest/package.json
+++ b/clients/vitest/package.json
@@ -40,6 +40,7 @@
"scripts": {
"test": "pnpm run test:unit",
"test:unit": "vitest run --config vitest.config.js",
+ "test:browser": "node --test --test-reporter=spec tests/browser-integration.test.js",
"test:e2e": "vitest run --config vitest.e2e.config.js",
"test:e2e:tdd": "../../bin/vizzly.js tdd run 'pnpm run test:e2e' --no-open",
"test:e2e:cloud": "../../bin/vizzly.js run 'pnpm run test:e2e'",
@@ -52,7 +53,7 @@
"prepublishOnly": "pnpm run lint && pnpm run test:unit"
},
"engines": {
- "node": ">=22.0.0"
+ "node": "^22.18.0 || >=24.0.0"
},
"publishConfig": {
"access": "public",
@@ -64,10 +65,10 @@
},
"devDependencies": {
"@biomejs/biome": "^2.5.10",
- "@vitest/browser": "^4.1.11",
- "@vitest/browser-playwright": "^4.1.11",
+ "@vitest/browser": "^5.0.0",
+ "@vitest/browser-playwright": "^5.0.0",
"playwright": "^1.49.1",
"serve-handler": "^6.1.6",
- "vitest": "^4.1.11"
+ "vitest": "^5.0.0"
}
}
diff --git a/clients/vitest/src/index.js b/clients/vitest/src/index.js
index 3dd77ff7..5e68c7d2 100644
--- a/clients/vitest/src/index.js
+++ b/clients/vitest/src/index.js
@@ -91,19 +91,18 @@ export function vizzlyPlugin() {
return {
test: {
- setupFiles: [resolve(import.meta.dirname || __dirname, 'setup.js')],
+ setupFiles: [resolve(import.meta.dirname, 'setup.js')],
+ env: {
+ VIZZLY_SERVER_URL: serverUrl,
+ VIZZLY_BUILD_ID: buildId,
+ VIZZLY_FAIL_ON_DIFF: failOnDiff,
+ },
browser: {
// Disable Vitest's native screenshot testing
// Our custom matcher completely replaces it
screenshotFailures: false,
},
},
- // Pass Vizzly environment variables to browser context via define
- define: {
- __VIZZLY_SERVER_URL__: JSON.stringify(serverUrl),
- __VIZZLY_BUILD_ID__: JSON.stringify(buildId),
- __VIZZLY_FAIL_ON_DIFF__: JSON.stringify(failOnDiff),
- },
};
},
};
diff --git a/clients/vitest/src/setup.js b/clients/vitest/src/setup.js
index bf658a16..ef59e8d2 100644
--- a/clients/vitest/src/setup.js
+++ b/clients/vitest/src/setup.js
@@ -70,10 +70,7 @@ export function shouldFailOnDiff(override = null) {
return override === true;
}
- let value =
- typeof __VIZZLY_FAIL_ON_DIFF__ !== 'undefined'
- ? __VIZZLY_FAIL_ON_DIFF__
- : '';
+ let value = import.meta.env.VIZZLY_FAIL_ON_DIFF || '';
return value === true || value === 'true' || value === '1';
}
@@ -84,10 +81,8 @@ async function toMatchScreenshot(element, name, options = {}) {
name = args.name;
options = args.options;
- let serverUrl =
- typeof __VIZZLY_SERVER_URL__ !== 'undefined' ? __VIZZLY_SERVER_URL__ : '';
- let buildId =
- typeof __VIZZLY_BUILD_ID__ !== 'undefined' ? __VIZZLY_BUILD_ID__ : '';
+ let serverUrl = import.meta.env.VIZZLY_SERVER_URL || '';
+ let buildId = import.meta.env.VIZZLY_BUILD_ID || '';
// If no server URL, Vizzly is not available
if (!serverUrl) {
@@ -155,8 +150,8 @@ async function toMatchScreenshot(element, name, options = {}) {
let result = await response.json();
- // In cloud mode, always pass
- if (buildId) {
+ // Local runs also have build IDs; the server response identifies TDD mode.
+ if (buildId && result.tddMode !== true) {
return {
pass: true,
message: () => '',
diff --git a/clients/vitest/tests/browser-integration.test.js b/clients/vitest/tests/browser-integration.test.js
new file mode 100644
index 00000000..d277c1d8
--- /dev/null
+++ b/clients/vitest/tests/browser-integration.test.js
@@ -0,0 +1,150 @@
+import assert from 'node:assert/strict';
+import { execFile } from 'node:child_process';
+import {
+ cp,
+ mkdtemp,
+ readdir,
+ readFile,
+ rm,
+ symlink,
+ writeFile,
+} from 'node:fs/promises';
+import { createServer } from 'node:http';
+import { tmpdir } from 'node:os';
+import { join, resolve } from 'node:path';
+import { test } from 'node:test';
+import { promisify } from 'node:util';
+import { getDimensionsSync } from '@vizzly-testing/honeydiff';
+import { createApiClient } from '../../../src/api/client.js';
+import { CONFIG_DEFAULTS } from '../../../src/config/core.js';
+import { createApiHandler } from '../../../src/server/handlers/api-handler.js';
+import { createTddHandler } from '../../../src/server/handlers/tdd-handler.js';
+import { createHttpServer } from '../../../src/server/http-server.js';
+
+let run = promisify(execFile);
+let packageDir = resolve(import.meta.dirname, '..');
+let vitestCli = join(packageDir, 'node_modules/vitest/vitest.mjs');
+
+for (let scenario of ['disabled', 'tdd', 'tdd-run', 'cloud']) {
+ test(`browser matcher works in ${scenario} mode`, async t => {
+ let workingDir = await mkdtemp(join(tmpdir(), 'vizzly-vitest-browser-'));
+ t.after(() => rm(workingDir, { recursive: true, force: true }));
+ await writeFile(join(workingDir, 'package.json'), '{"type":"module"}');
+ await cp(join(packageDir, 'src'), join(workingDir, 'src'), {
+ recursive: true,
+ });
+ await cp(
+ join(packageDir, 'tests/browser'),
+ join(workingDir, 'tests/browser'),
+ {
+ recursive: true,
+ }
+ );
+ await symlink(
+ join(packageDir, 'node_modules'),
+ join(workingDir, 'node_modules')
+ );
+
+ let uploads = [];
+ let handler;
+ let server;
+ let serverUrl = '';
+ let buildId = '';
+ if (scenario === 'cloud') {
+ buildId = 'browser-build';
+ } else if (scenario === 'tdd-run') {
+ buildId = 'local-build';
+ }
+
+ if (scenario === 'cloud') {
+ // Only the external cloud API is replaced; captures use the real local server.
+ let cloud = createServer(async (req, res) => {
+ let chunks = [];
+ for await (let chunk of req) chunks.push(chunk);
+ uploads.push({
+ path: req.url,
+ body: JSON.parse(Buffer.concat(chunks)),
+ });
+ res.setHeader('Content-Type', 'application/json');
+ res.end(JSON.stringify({ upload_required: true }));
+ });
+ await new Promise(resolve => cloud.listen(0, '127.0.0.1', resolve));
+ t.after(() => new Promise(resolve => cloud.close(resolve)));
+ let client = createApiClient({
+ baseUrl: `http://127.0.0.1:${cloud.address().port}`,
+ token: 'vzt_browser_test',
+ });
+ handler = createApiHandler(client);
+ } else if (scenario.startsWith('tdd')) {
+ handler = createTddHandler(CONFIG_DEFAULTS, workingDir);
+ await handler.initialize();
+ }
+
+ if (handler) {
+ server = createHttpServer(0, handler, { workingDir });
+ await server.start();
+ t.after(() => server.stop());
+ serverUrl = `http://127.0.0.1:${server.getServer().address().port}`;
+ }
+
+ let env = {
+ ...process.env,
+ VIZZLY_HOME: join(workingDir, 'home'),
+ VIZZLY_SERVER_URL: serverUrl,
+ VIZZLY_BUILD_ID: buildId,
+ VIZZLY_FAIL_ON_DIFF: 'true',
+ TEST_SCENARIO: scenario,
+ };
+ delete env.VIZZLY_TOKEN;
+ try {
+ await run(
+ process.execPath,
+ [vitestCli, 'run', '--config', 'tests/browser/fixture.config.js'],
+ {
+ cwd: workingDir,
+ env,
+ }
+ );
+ } catch (error) {
+ throw new Error(`${error.stdout}\n${error.stderr}`, { cause: error });
+ }
+
+ if (scenario === 'disabled') {
+ let files = await readdir(join(workingDir, 'tests/browser'));
+ assert.ok(!files.includes('__screenshots__'));
+ } else if (scenario.startsWith('tdd')) {
+ let report = JSON.parse(
+ await readFile(join(workingDir, '.vizzly/report-data.json'), 'utf8')
+ );
+ assert.equal(report.comparisons.length, 3);
+ let diff = report.comparisons.find(item => item.name === 'changing-page');
+ assert.equal(diff.status, 'failed');
+ assert.ok(diff.diffPercentage > 0);
+ } else {
+ let stats = await handler.flush();
+ assert.equal(stats.uploaded, 2);
+ assert.equal(stats.failed, 0);
+ assert.ok(
+ uploads.every(
+ upload => upload.path === '/api/sdk/builds/browser-build/screenshots'
+ )
+ );
+ let captures = uploads.filter(upload => upload.body.image_data);
+ assert.equal(captures.length, 2);
+ let page = captures.find(upload => upload.body.name === 'page').body;
+ assert.equal(page.properties.theme, 'light');
+ assert.equal(page.threshold, 5);
+ assert.equal(page.minClusterSize, 10);
+ assert.equal(page.captureMode, 'full_page');
+ let button = captures.find(upload => upload.body.name === 'button').body;
+ assert.equal(button.captureMode, 'element');
+ assert.deepEqual(
+ getDimensionsSync(Buffer.from(button.image_data, 'base64')),
+ {
+ width: 200,
+ height: 100,
+ }
+ );
+ }
+ });
+}
diff --git a/clients/vitest/tests/browser/fixture.config.js b/clients/vitest/tests/browser/fixture.config.js
new file mode 100644
index 00000000..3bed8036
--- /dev/null
+++ b/clients/vitest/tests/browser/fixture.config.js
@@ -0,0 +1,19 @@
+import { resolve } from 'node:path';
+import { playwright } from '@vitest/browser-playwright';
+import { defineConfig } from 'vitest/config';
+import { vizzlyPlugin } from '../../src/index.js';
+
+export default defineConfig({
+ root: resolve(import.meta.dirname, '../..'),
+ plugins: [vizzlyPlugin()],
+ test: {
+ include: ['tests/browser/matcher.test.js'],
+ env: { TEST_SCENARIO: process.env.TEST_SCENARIO },
+ browser: {
+ enabled: true,
+ headless: true,
+ viewport: { width: 400, height: 300 },
+ instances: [{ browser: 'chromium', provider: playwright() }],
+ },
+ },
+});
diff --git a/clients/vitest/tests/browser/matcher.test.js b/clients/vitest/tests/browser/matcher.test.js
new file mode 100644
index 00000000..4f82f849
--- /dev/null
+++ b/clients/vitest/tests/browser/matcher.test.js
@@ -0,0 +1,48 @@
+import { expect, test } from 'vitest';
+import { page } from 'vitest/browser';
+
+let scenario = import.meta.env.TEST_SCENARIO;
+let properties = { url: 'https://example.test/visual-test' };
+
+if (scenario === 'disabled') {
+ test('passes without capturing when no Vizzly server is available', async () => {
+ await expect(null).toMatchScreenshot('disabled');
+ });
+} else {
+ test('captures the page with metadata and comparison options', async () => {
+ document.body.innerHTML = '
Hello Vizzly
';
+ await expect(page).toMatchScreenshot('page', {
+ properties: { ...properties, theme: 'light' },
+ fullPage: true,
+ threshold: 5,
+ minClusterSize: 10,
+ });
+ });
+
+ test('captures an element', async () => {
+ document.body.innerHTML =
+ '';
+ await expect(page.getByRole('button', { name: 'Save' })).toMatchScreenshot(
+ 'button',
+ { properties, fullPage: true }
+ );
+ });
+
+ if (scenario.startsWith('tdd')) {
+ test('fails on a diff by default and respects the screenshot override', async () => {
+ document.body.innerHTML =
+ '';
+ await expect(page).toMatchScreenshot('changing-page', { properties });
+
+ document.body.firstElementChild.style.background = 'white';
+ await expect(
+ expect(page).toMatchScreenshot('changing-page', { properties })
+ ).rejects.toThrow('Visual difference detected: changing-page');
+
+ await expect(page).toMatchScreenshot('changing-page', {
+ properties,
+ failOnDiff: false,
+ });
+ });
+ }
+}
diff --git a/clients/vitest/tests/e2e/example.test.js b/clients/vitest/tests/e2e/example.test.js
index 35921d7f..06a02bf9 100644
--- a/clients/vitest/tests/e2e/example.test.js
+++ b/clients/vitest/tests/e2e/example.test.js
@@ -13,9 +13,8 @@
import { beforeAll, describe, expect, test } from 'vitest';
import { page } from 'vitest/browser';
-// Base URL for test-site assets (defined in vitest.e2e.config.js)
-// eslint-disable-next-line no-undef
-let baseUrl = __TEST_SITE_URL__;
+// Base URL for test-site assets (configured in vitest.e2e.config.js)
+let baseUrl = import.meta.env.TEST_SITE_URL;
// Load test-site CSS before all tests
beforeAll(async () => {
diff --git a/clients/vitest/tests/vitest-plugin.spec.js b/clients/vitest/tests/vitest-plugin.spec.js
index 7ea3a7fa..5dc4da85 100644
--- a/clients/vitest/tests/vitest-plugin.spec.js
+++ b/clients/vitest/tests/vitest-plugin.spec.js
@@ -118,10 +118,10 @@ describe('Vitest Plugin Integration', () => {
let plugin = vizzlyPlugin();
config = plugin.config(config, { mode: 'test' });
- expect(config.define).toBeDefined();
- expect(config.define.__VIZZLY_SERVER_URL__).toBeDefined();
- expect(config.define.__VIZZLY_BUILD_ID__).toBeDefined();
- expect(config.define.__VIZZLY_FAIL_ON_DIFF__).toBeDefined();
+ expect(config.test.env).toBeDefined();
+ expect(config.test.env.VIZZLY_SERVER_URL).toBeDefined();
+ expect(config.test.env.VIZZLY_BUILD_ID).toBeDefined();
+ expect(config.test.env.VIZZLY_FAIL_ON_DIFF).toBeDefined();
});
it('should pass failOnDiff from discovered server config', async () => {
@@ -144,10 +144,10 @@ describe('Vitest Plugin Integration', () => {
let plugin = vizzlyPlugin();
let config = plugin.config({ test: {} }, { mode: 'test' });
- expect(JSON.parse(config.define.__VIZZLY_SERVER_URL__)).toBe(
+ expect(config.test.env.VIZZLY_SERVER_URL).toBe(
'http://localhost:47392'
);
- expect(JSON.parse(config.define.__VIZZLY_FAIL_ON_DIFF__)).toBe('true');
+ expect(config.test.env.VIZZLY_FAIL_ON_DIFF).toBe('true');
} finally {
process.chdir(originalCwd);
rmSync(tempDir, { recursive: true, force: true });
diff --git a/clients/vitest/vitest.e2e.config.js b/clients/vitest/vitest.e2e.config.js
index fabc7240..e2131305 100644
--- a/clients/vitest/vitest.e2e.config.js
+++ b/clients/vitest/vitest.e2e.config.js
@@ -1,8 +1,8 @@
import { existsSync } from 'node:fs';
import { createServer } from 'node:http';
import { resolve } from 'node:path';
-import handler from 'serve-handler';
import { playwright } from '@vitest/browser-playwright';
+import handler from 'serve-handler';
import { defineConfig } from 'vitest/config';
import { vizzlyPlugin } from './src/index.js';
@@ -23,7 +23,7 @@ let server = createServer((req, res) => {
});
// Listen on port 0 to get a random available port
-await new Promise((resolve) => {
+await new Promise(resolve => {
server.listen(0, () => resolve());
});
@@ -47,8 +47,8 @@ export default defineConfig({
headless: true,
},
include: ['tests/e2e/**/*.test.js'],
- },
- define: {
- __TEST_SITE_URL__: JSON.stringify(`http://localhost:${testSitePort}`),
+ env: {
+ TEST_SITE_URL: `http://localhost:${testSitePort}`,
+ },
},
});
diff --git a/package.json b/package.json
index 3771d411..1be448d0 100644
--- a/package.json
+++ b/package.json
@@ -87,7 +87,7 @@
"fix": "pnpm run format && pnpm run lint:fix"
},
"engines": {
- "node": ">=22.0.0"
+ "node": "^22.18.0 || >=24.0.0"
},
"publishConfig": {
"access": "public",
@@ -98,7 +98,7 @@
"@vizzly-testing/honeydiff": "^0.17.0",
"ansis": "^4.2.0",
"commander": "^15.0.0",
- "cosmiconfig": "^9.0.0",
+ "cosmiconfig": "^10.0.1",
"dotenv": "^17.2.1",
"form-data": "^4.0.0",
"glob": "^13.0.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6367333b..247f02b0 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -28,8 +28,8 @@ importers:
specifier: ^15.0.0
version: 15.0.0
cosmiconfig:
- specifier: ^9.0.0
- version: 9.0.2(typescript@7.0.2)
+ specifier: ^10.0.1
+ version: 10.0.1
dotenv:
specifier: ^17.2.1
version: 17.4.2
@@ -270,9 +270,6 @@ importers:
'@vizzly-testing/cli':
specifier: '>=0.24.0'
version: 0.30.0(typescript@7.0.2)
- cosmiconfig:
- specifier: ^9.0.0
- version: 9.0.2(typescript@7.0.2)
fast-xml-parser:
specifier: ^5.8.0
version: 5.11.2
@@ -373,11 +370,11 @@ importers:
specifier: ^2.5.10
version: 2.5.15
'@vitest/browser':
- specifier: ^4.1.11
- version: 4.1.11(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vitest@4.1.11)
+ specifier: ^5.0.0
+ version: 5.0.0(vite@8.3.3(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vitest@5.0.0)
'@vitest/browser-playwright':
- specifier: ^4.1.11
- version: 4.1.11(playwright@1.63.0)(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vitest@4.1.11)
+ specifier: ^5.0.0
+ version: 5.0.0(playwright@1.63.0)(vite@8.3.3(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vitest@5.0.0)
playwright:
specifier: ^1.49.1
version: 1.63.0
@@ -385,8 +382,8 @@ importers:
specifier: ^6.1.6
version: 6.1.7
vitest:
- specifier: ^4.1.11
- version: 4.1.11(@types/node@26.6.4)(@vitest/browser-playwright@4.1.11)(jsdom@26.1.0(canvas@3.2.3))(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))
+ specifier: ^5.0.0
+ version: 5.0.0(@types/node@26.6.4)(@vitest/browser-playwright@5.0.0)(@vitest/ui@5.0.0)(jsdom@26.1.0(canvas@3.2.3))(vite@8.3.3(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))
examples/custom-plugin:
dependencies:
@@ -1593,8 +1590,8 @@ packages:
cpu: [x64]
os: [win32]
- '@blazediff/core@1.9.1':
- resolution: {integrity: sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA==}
+ '@blazediff/core@1.10.0':
+ resolution: {integrity: sha512-AOQff0zgR7cGsZL+4E7hVkmujoPUpm0J9xzWGWZj5wCjd3gmxESXAPfKyuzs93VdpQNFhHlBhfOjrcZ+XTERtQ==}
'@cacheable/memory@2.2.0':
resolution: {integrity: sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==}
@@ -2686,9 +2683,6 @@ packages:
'@socket.io/component-emitter@3.1.2':
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
- '@standard-schema/spec@1.1.0':
- resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
-
'@storybook/builder-vite@10.6.1':
resolution: {integrity: sha512-kUMRRRS4MpJdxOLhrlQX3cpMYi2vVB3tIIRXyqWmAjVM6xT7OZ1SCQEMFPP+S3ToRqaYWZQb8aBqrJucbbYufA==}
peerDependencies:
@@ -3081,25 +3075,22 @@ packages:
oxc-transform-react:
optional: true
- '@vitest/browser-playwright@4.1.11':
- resolution: {integrity: sha512-riLBxPqwnJ0lWs2DN2WeUfYeKLoAjbP2Xx8cLQdSddzMi20sksIa6K2mPz79DyMZKKVKH2ksOC2yJvtNcZg8cg==}
+ '@vitest/browser-playwright@5.0.0':
+ resolution: {integrity: sha512-N+gED9y4/8pypaHjz/x0ah3CjoBr+N0hWWT+Gq4VXtMzyB+rUIdHni0ulzpD1j4H77iWy5Jg8PRMlVn6kjxo6g==}
peerDependencies:
playwright: '*'
- vitest: 4.1.11
+ vitest: 5.0.0
- '@vitest/browser@4.1.11':
- resolution: {integrity: sha512-bwMovvAeuTFOK5kIFevw4VEf+1gVEICv4SYK4k3knJOxl6b1zEWud8mYKD73e1B0odAn174h1MofURy2TPWf3w==}
+ '@vitest/browser@5.0.0':
+ resolution: {integrity: sha512-JC9FG5xIRxPHXJPcdCaluIJcEoeM0IwGQ3xneuJk09LXKHRNs40BqWDWymQikbb20yOpYvzpKzmYgPRuSzKmvg==}
peerDependencies:
- vitest: 4.1.11
+ vitest: 5.0.0
'@vitest/expect@3.2.4':
resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==}
- '@vitest/expect@4.1.11':
- resolution: {integrity: sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==}
-
- '@vitest/mocker@4.1.11':
- resolution: {integrity: sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==}
+ '@vitest/mocker@5.0.0':
+ resolution: {integrity: sha512-66PGTMIiVJP3t4a5yxU9qPtf7MdTBs8jmToMvy+HVflB3Yy13WJZTtPePdvU+wjRV02SKK5doLbSA6o9pwOmiA==}
peerDependencies:
msw: ^2.4.9
vite: ^6.0.0 || ^7.0.0 || ^8.0.0
@@ -3112,26 +3103,25 @@ packages:
'@vitest/pretty-format@3.2.4':
resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==}
- '@vitest/pretty-format@4.1.11':
- resolution: {integrity: sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==}
-
- '@vitest/runner@4.1.11':
- resolution: {integrity: sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==}
-
- '@vitest/snapshot@4.1.11':
- resolution: {integrity: sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==}
+ '@vitest/pretty-format@5.0.0':
+ resolution: {integrity: sha512-PVRNuB3wpReb4SQEs4zTKM4KWFhQ5pw3spE8naoDJNB5T5aWRzGKHwXcLUllr0WeOTXpB6bSr3CJLo5+7XQSSQ==}
'@vitest/spy@3.2.4':
resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==}
- '@vitest/spy@4.1.11':
- resolution: {integrity: sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==}
+ '@vitest/spy@5.0.0':
+ resolution: {integrity: sha512-uy+luWBAPw9XfthoHi5AkfHUnuPYEESjl0p/r+meoBnU8bxg5GDQ3Ey8MjcJ6sqahkL4PFyrvfMJJBw7LbU06g==}
+
+ '@vitest/ui@5.0.0':
+ resolution: {integrity: sha512-h2FIFwggCY2GxUd2UdQoYNVQkOIqEQLPhNREcl3FUiRsdzQep7NWwYbSmhGEA9nFLPDq5pXzRMcBZQU8Py83sg==}
+ peerDependencies:
+ vitest: 5.0.0
'@vitest/utils@3.2.4':
resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==}
- '@vitest/utils@4.1.11':
- resolution: {integrity: sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==}
+ '@vitest/utils@5.0.0':
+ resolution: {integrity: sha512-dO++xL3vDfvhTAVimfkuQUA3k+JClIF1i1vAkPqpcGAthRmeWnXmHB7YPViPvgCwviX8u7Y5W1u2N//AaQr3fw==}
'@vizzly-testing/bear-den@0.1.4':
resolution: {integrity: sha512-sPRHB5U1HzxQqbRm5kjd1GER0SE1BiRZTGKPXQUHCtvladwNeY86NmLqhB9qTfXIJDXUYdRYetbHugeJVtsF4Q==}
@@ -3184,7 +3174,7 @@ packages:
'@vizzly-testing/ember@file:clients/ember':
resolution: {directory: clients/ember, type: directory}
- engines: {node: '>=22.0.0'}
+ engines: {node: ^22.18.0 || >=24.0.0}
hasBin: true
peerDependencies:
'@vizzly-testing/cli': '>=0.12.0'
@@ -3869,8 +3859,8 @@ packages:
resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
engines: {node: '>=18'}
- chai@6.2.2:
- resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==}
+ chai@6.3.0:
+ resolution: {integrity: sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==}
engines: {node: '>=18'}
chalk@2.4.2:
@@ -4243,6 +4233,10 @@ packages:
resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==}
engines: {node: '>= 0.10'}
+ cosmiconfig@10.0.1:
+ resolution: {integrity: sha512-/zvGoYn0y27QTBmK+0B+oPdEPC4fKGUmJsMTQbDjqph00TrkqfVFW/M+C6ya54sYCgHC6QCwK/mI6djt8cEGHQ==}
+ engines: {node: ^22.18 || >= 24}
+
cosmiconfig@9.0.2:
resolution: {integrity: sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==}
engines: {node: '>=14'}
@@ -4863,6 +4857,9 @@ packages:
picomatch:
optional: true
+ fflate@0.8.3:
+ resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==}
+
figures@2.0.0:
resolution: {integrity: sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==}
engines: {node: '>=4'}
@@ -6298,10 +6295,6 @@ packages:
resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
engines: {node: '>= 0.4'}
- obug@2.1.3:
- resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==}
- engines: {node: '>=12.20.0'}
-
obug@2.2.1:
resolution: {integrity: sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==}
engines: {node: '>=12.20.0'}
@@ -6501,10 +6494,6 @@ packages:
resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==}
engines: {node: '>=8.6'}
- picomatch@4.0.5:
- resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==}
- engines: {node: '>=12'}
-
picomatch@4.0.7:
resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==}
engines: {node: '>=12'}
@@ -7198,8 +7187,8 @@ packages:
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
engines: {node: '>= 0.8'}
- std-env@4.1.0:
- resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==}
+ std-env@4.3.0:
+ resolution: {integrity: sha512-OtU/EgQ1kIm5KwqQpBC6ZEMXrZRui11w8zgfTWp8cdO9B8OaPsbA8bTHO2P+HNo1VlUTGMVBwPhydu6poeXiag==}
stop-iteration-iterator@1.1.0:
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
@@ -7490,11 +7479,12 @@ packages:
tiny-lr@2.0.0:
resolution: {integrity: sha512-f6nh0VMRvhGx4KCeK1lQ/jaL0Zdb5WdR+Jk8q9OSUQnaSDxAEGH1fgqLZ+cMl5EW3F2MGnCsalBO1IsnnogW1Q==}
- tinybench@2.9.0:
- resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
+ tinybench@6.1.4:
+ resolution: {integrity: sha512-9APumHG7r4yOk4X4WlkmE71aZcv1gvin1czO3OQ1U9iJcFA5Ja/ygyb0vPOVHTthFozUYs8CLoLUlM8grb2lTQ==}
+ engines: {node: '>=20.0.0'}
- tinyexec@1.2.4:
- resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==}
+ tinyexec@1.3.0:
+ resolution: {integrity: sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==}
engines: {node: '>=18'}
tinyglobby@0.2.16:
@@ -7509,8 +7499,8 @@ packages:
resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
engines: {node: '>=14.0.0'}
- tinyrainbow@3.1.0:
- resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==}
+ tinyrainbow@3.2.0:
+ resolution: {integrity: sha512-LgO3D9yZJjApUiuUfl9iFAwrtaX4+lok3wJIqttGoKCHlWUqHqbQpnxCf82L8FjgKsh4iGo78hqJwgL8F6To2A==}
engines: {node: '>=14.0.0'}
tinyspy@4.0.6:
@@ -7794,8 +7784,8 @@ packages:
yaml:
optional: true
- vite@8.3.2:
- resolution: {integrity: sha512-SQr1x6W5vVSbROg7vsyXIaxK9b0G7zsT68acdWWRmnBUsgDieLCRG+Rep9WdZgcposvv/GSnr4GUUBqB3vXq6w==}
+ vite@8.3.3:
+ resolution: {integrity: sha512-cTAldKPImjg6c+gk48U19POPn3GCBzZwpdsN8ZMEEcbpes+6/wvfqUd0C2y3qYY4wsj8PwgFwrZ/1jBPVttMSg==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
peerDependencies:
@@ -7837,23 +7827,23 @@ packages:
yaml:
optional: true
- vitest@4.1.11:
- resolution: {integrity: sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==}
- engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0}
+ vitest@5.0.0:
+ resolution: {integrity: sha512-gpsMNoRhMjMktVxPtstOH4/PJuPyovVaMDr4oDilXaGH1EcqM2OE96SoHT2VIQ6fTGtTjqmHDrEu2X9RQiXf8Q==}
+ engines: {node: ^22.12.0 || ^24.0.0 || >=26.0.0}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
'@opentelemetry/api': ^1.9.0
- '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0
- '@vitest/browser-playwright': 4.1.11
- '@vitest/browser-preview': 4.1.11
- '@vitest/browser-webdriverio': 4.1.11
- '@vitest/coverage-istanbul': 4.1.11
- '@vitest/coverage-v8': 4.1.11
- '@vitest/ui': 4.1.11
+ '@types/node': ^22.0.0 || >=24.0.0
+ '@vitest/browser-playwright': 5.0.0
+ '@vitest/browser-preview': 5.0.0
+ '@vitest/browser-webdriverio': ^5.0.0-beta.5 || >=5.0.0
+ '@vitest/coverage-istanbul': 5.0.0
+ '@vitest/coverage-v8': 5.0.0
+ '@vitest/ui': 5.0.0
happy-dom: '*'
jsdom: '*'
- vite: ^6.0.0 || ^7.0.0 || ^8.0.0
+ vite: ^6.4.0 || ^7.0.0 || ^8.0.0
peerDependenciesMeta:
'@edge-runtime/vm':
optional: true
@@ -10158,7 +10148,7 @@ snapshots:
'@biomejs/cli-win32-x64@2.5.15':
optional: true
- '@blazediff/core@1.9.1': {}
+ '@blazediff/core@1.10.0': {}
'@cacheable/memory@2.2.0':
dependencies:
@@ -11322,8 +11312,6 @@ snapshots:
'@socket.io/component-emitter@3.1.2': {}
- '@standard-schema/spec@1.1.0': {}
-
'@storybook/builder-vite@10.6.1(storybook@10.6.1(prettier@3.9.9)(react@19.3.0))(vite@8.3.1(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))':
dependencies:
storybook: 10.6.1(prettier@3.9.9)(react@19.3.0)
@@ -11648,30 +11636,31 @@ snapshots:
optionalDependencies:
babel-plugin-react-compiler: 1.0.0
- '@vitest/browser-playwright@4.1.11(playwright@1.63.0)(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vitest@4.1.11)':
+ '@vitest/browser-playwright@5.0.0(playwright@1.63.0)(vite@8.3.3(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vitest@5.0.0)':
dependencies:
- '@vitest/browser': 4.1.11(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vitest@4.1.11)
- '@vitest/mocker': 4.1.11(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))
+ '@vitest/browser': 5.0.0(vite@8.3.3(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vitest@5.0.0)
+ '@vitest/mocker': 5.0.0(vite@8.3.3(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))
playwright: 1.63.0
- tinyrainbow: 3.1.0
- vitest: 4.1.11(@types/node@26.6.4)(@vitest/browser-playwright@4.1.11)(jsdom@26.1.0(canvas@3.2.3))(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))
+ tinyrainbow: 3.2.0
+ vitest: 5.0.0(@types/node@26.6.4)(@vitest/browser-playwright@5.0.0)(@vitest/ui@5.0.0)(jsdom@26.1.0(canvas@3.2.3))(vite@8.3.3(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))
transitivePeerDependencies:
- bufferutil
- msw
- utf-8-validate
- vite
- '@vitest/browser@4.1.11(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vitest@4.1.11)':
+ '@vitest/browser@5.0.0(vite@8.3.3(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vitest@5.0.0)':
dependencies:
- '@blazediff/core': 1.9.1
- '@vitest/mocker': 4.1.11(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))
- '@vitest/utils': 4.1.11
- magic-string: 0.30.21
+ '@blazediff/core': 1.10.0
+ '@vitest/mocker': 5.0.0(vite@8.3.3(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))
+ '@vitest/ui': 5.0.0(vitest@5.0.0)
+ '@vitest/utils': 5.0.0
+ magic-string: 1.4.3
pngjs: 7.0.0
sirv: 3.0.2
- tinyrainbow: 3.1.0
- vitest: 4.1.11(@types/node@26.6.4)(@vitest/browser-playwright@4.1.11)(jsdom@26.1.0(canvas@3.2.3))(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))
- ws: 8.21.3
+ tinyrainbow: 3.2.0
+ vitest: 5.0.0(@types/node@26.6.4)(@vitest/browser-playwright@5.0.0)(@vitest/ui@5.0.0)(jsdom@26.1.0(canvas@3.2.3))(vite@8.3.3(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))
+ ws: 8.22.0
transitivePeerDependencies:
- bufferutil
- msw
@@ -11686,48 +11675,38 @@ snapshots:
chai: 5.3.3
tinyrainbow: 2.0.0
- '@vitest/expect@4.1.11':
- dependencies:
- '@standard-schema/spec': 1.1.0
- '@types/chai': 5.2.3
- '@vitest/spy': 4.1.11
- '@vitest/utils': 4.1.11
- chai: 6.2.2
- tinyrainbow: 3.1.0
-
- '@vitest/mocker@4.1.11(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))':
+ '@vitest/mocker@5.0.0(vite@8.3.3(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))':
dependencies:
- '@vitest/spy': 4.1.11
+ '@jridgewell/trace-mapping': 0.3.31
+ '@vitest/spy': 5.0.0
estree-walker: 3.0.3
- magic-string: 0.30.21
+ magic-string: 1.4.3
optionalDependencies:
- vite: 8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)
+ vite: 8.3.3(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)
'@vitest/pretty-format@3.2.4':
dependencies:
tinyrainbow: 2.0.0
- '@vitest/pretty-format@4.1.11':
- dependencies:
- tinyrainbow: 3.1.0
-
- '@vitest/runner@4.1.11':
+ '@vitest/pretty-format@5.0.0':
dependencies:
- '@vitest/utils': 4.1.11
- pathe: 2.0.3
-
- '@vitest/snapshot@4.1.11':
- dependencies:
- '@vitest/pretty-format': 4.1.11
- '@vitest/utils': 4.1.11
- magic-string: 0.30.21
- pathe: 2.0.3
+ tinyrainbow: 3.2.0
'@vitest/spy@3.2.4':
dependencies:
tinyspy: 4.0.6
- '@vitest/spy@4.1.11': {}
+ '@vitest/spy@5.0.0': {}
+
+ '@vitest/ui@5.0.0(vitest@5.0.0)':
+ dependencies:
+ '@vitest/utils': 5.0.0
+ fflate: 0.8.3
+ flatted: 3.4.4
+ pathe: 2.0.3
+ sirv: 3.0.2
+ tinyrainbow: 3.2.0
+ vitest: 5.0.0(@types/node@26.6.4)(@vitest/browser-playwright@5.0.0)(@vitest/ui@5.0.0)(jsdom@26.1.0(canvas@3.2.3))(vite@8.3.3(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))
'@vitest/utils@3.2.4':
dependencies:
@@ -11735,11 +11714,11 @@ snapshots:
loupe: 3.2.1
tinyrainbow: 2.0.0
- '@vitest/utils@4.1.11':
+ '@vitest/utils@5.0.0':
dependencies:
- '@vitest/pretty-format': 4.1.11
+ '@vitest/pretty-format': 5.0.0
convert-source-map: 2.0.0
- tinyrainbow: 3.1.0
+ tinyrainbow: 3.2.0
'@vizzly-testing/bear-den@0.1.4(@heroicons/react@2.2.0(react@19.3.0))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(tailwindcss@4.3.3)':
dependencies:
@@ -12801,7 +12780,7 @@ snapshots:
loupe: 3.2.1
pathval: 2.0.1
- chai@6.2.2: {}
+ chai@6.3.0: {}
chalk@2.4.2:
dependencies:
@@ -13009,6 +12988,11 @@ snapshots:
object-assign: 4.1.1
vary: 1.1.2
+ cosmiconfig@10.0.1:
+ dependencies:
+ env-paths: 2.2.1
+ js-yaml: 5.4.3
+
cosmiconfig@9.0.2(typescript@7.0.2):
dependencies:
env-paths: 2.2.1
@@ -14006,6 +13990,8 @@ snapshots:
optionalDependencies:
picomatch: 4.0.7
+ fflate@0.8.3: {}
+
figures@2.0.0:
dependencies:
escape-string-regexp: 1.0.5
@@ -15469,8 +15455,6 @@ snapshots:
has-symbols: 1.1.0
object-keys: 1.1.1
- obug@2.1.3: {}
-
obug@2.2.1: {}
odiff-bin@3.2.1: {}
@@ -15679,8 +15663,6 @@ snapshots:
picomatch@2.3.2: {}
- picomatch@4.0.5: {}
-
picomatch@4.0.7: {}
pkce-challenge@5.0.1: {}
@@ -16487,7 +16469,7 @@ snapshots:
statuses@2.0.2: {}
- std-env@4.1.0: {}
+ std-env@4.3.0: {}
stop-iteration-iterator@1.1.0:
dependencies:
@@ -16909,9 +16891,9 @@ snapshots:
transitivePeerDependencies:
- supports-color
- tinybench@2.9.0: {}
+ tinybench@6.1.4: {}
- tinyexec@1.2.4: {}
+ tinyexec@1.3.0: {}
tinyglobby@0.2.16:
dependencies:
@@ -16925,7 +16907,7 @@ snapshots:
tinyrainbow@2.0.0: {}
- tinyrainbow@3.1.0: {}
+ tinyrainbow@3.2.0: {}
tinyspy@4.0.6: {}
@@ -17211,7 +17193,7 @@ snapshots:
terser: 5.51.2
yaml: 2.9.1
- vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1):
+ vite@8.3.3(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1):
dependencies:
lightningcss: 1.33.0
picomatch: 4.0.7
@@ -17226,31 +17208,26 @@ snapshots:
terser: 5.51.2
yaml: 2.9.1
- vitest@4.1.11(@types/node@26.6.4)(@vitest/browser-playwright@4.1.11)(jsdom@26.1.0(canvas@3.2.3))(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)):
+ vitest@5.0.0(@types/node@26.6.4)(@vitest/browser-playwright@5.0.0)(@vitest/ui@5.0.0)(jsdom@26.1.0(canvas@3.2.3))(vite@8.3.3(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)):
dependencies:
- '@vitest/expect': 4.1.11
- '@vitest/mocker': 4.1.11(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))
- '@vitest/pretty-format': 4.1.11
- '@vitest/runner': 4.1.11
- '@vitest/snapshot': 4.1.11
- '@vitest/spy': 4.1.11
- '@vitest/utils': 4.1.11
+ '@types/chai': 5.2.3
+ '@vitest/mocker': 5.0.0(vite@8.3.3(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))
+ chai: 6.3.0
es-module-lexer: 2.3.2
expect-type: 1.4.0
- magic-string: 0.30.21
- obug: 2.1.3
- pathe: 2.0.3
- picomatch: 4.0.5
- std-env: 4.1.0
- tinybench: 2.9.0
- tinyexec: 1.2.4
+ magic-string: 1.4.3
+ obug: 2.2.1
+ picomatch: 4.0.7
+ std-env: 4.3.0
+ tinybench: 6.1.4
+ tinyexec: 1.3.0
tinyglobby: 0.2.17
- tinyrainbow: 3.1.0
- vite: 8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)
+ vite: 8.3.3(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 26.6.4
- '@vitest/browser-playwright': 4.1.11(playwright@1.63.0)(vite@8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vitest@4.1.11)
+ '@vitest/browser-playwright': 5.0.0(playwright@1.63.0)(vite@8.3.3(@types/node@26.6.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vitest@5.0.0)
+ '@vitest/ui': 5.0.0(vitest@5.0.0)
jsdom: 26.1.0(canvas@3.2.3)
transitivePeerDependencies:
- msw
diff --git a/tests/utils/config-loader.test.js b/tests/utils/config-loader.test.js
index c7de38fd..8ee87ccd 100644
--- a/tests/utils/config-loader.test.js
+++ b/tests/utils/config-loader.test.js
@@ -1,5 +1,11 @@
import assert from 'node:assert';
-import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
+import {
+ existsSync,
+ mkdirSync,
+ mkdtempSync,
+ rmSync,
+ writeFileSync,
+} from 'node:fs';
import { join } from 'node:path';
import { afterEach, beforeEach, describe, it } from 'node:test';
import {
@@ -116,6 +122,37 @@ describe('utils/config-loader', () => {
assert.strictEqual(config.comparison.threshold, 1.5);
});
+ it('loads native TypeScript config with type-only helper imports', async () => {
+ let dir = mkdtempSync(join(testDir, 'typescript-'));
+ writeFileSync(
+ join(dir, 'types.ts'),
+ 'export interface Config { comparison: { threshold: number } }'
+ );
+ writeFileSync(
+ join(dir, 'vizzly.config.ts'),
+ `import type { Config } from './types.ts';
+let threshold: number = 1.5;
+export default { comparison: { threshold } } satisfies Config;`
+ );
+
+ let config = await loadConfig(join(dir, 'vizzly.config.ts'));
+
+ assert.strictEqual(config.comparison.threshold, 1.5);
+ });
+
+ it('rejects TypeScript enums instead of silently using default config', async () => {
+ let dir = mkdtempSync(join(testDir, 'typescript-enum-'));
+ writeFileSync(
+ join(dir, 'vizzly.config.ts'),
+ `enum Threshold { Normal = 7 }
+export default { comparison: { threshold: Threshold.Normal } };`
+ );
+
+ await assert.rejects(loadConfig(join(dir, 'vizzly.config.ts')), {
+ code: 'ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX',
+ });
+ });
+
it('applies CLI overrides', async () => {
let config = await loadConfig(null, {
token: 'cli-token',