@vitest-agent/mcp 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/README.md +1 -2
  2. package/index.d.ts +3 -2
  3. package/index.js +1 -1
  4. package/package.json +1 -1
  5. package/server.js +2 -4
  6. package/tools/run-tests.js +17 -3
  7. package/patterns/_meta.json +0 -67
  8. package/patterns/authoring-a-custom-vitest-agent-reporter.md +0 -82
  9. package/patterns/known-issues-and-caveats.md +0 -52
  10. package/patterns/operating-vitest-agent-as-an-agent.md +0 -62
  11. package/patterns/running-tests-via-mcp.md +0 -103
  12. package/patterns/silencing-leaking-output-in-tests.md +0 -91
  13. package/patterns/testing-effect-schema-definitions.md +0 -71
  14. package/patterns/testing-effect-services-with-mock-layers.md +0 -63
  15. package/resources/index.js +0 -166
  16. package/resources/indexes.js +0 -77
  17. package/resources/manifest-schema.js +0 -46
  18. package/resources/paths.js +0 -20
  19. package/resources/patterns.js +0 -22
  20. package/resources/upstream-docs.js +0 -22
  21. package/vendor/vitest-docs/ATTRIBUTION.md +0 -5
  22. package/vendor/vitest-docs/api/advanced/artifacts.md +0 -189
  23. package/vendor/vitest-docs/api/advanced/metadata.md +0 -68
  24. package/vendor/vitest-docs/api/advanced/plugin.md +0 -168
  25. package/vendor/vitest-docs/api/advanced/reporters.md +0 -342
  26. package/vendor/vitest-docs/api/advanced/runner.md +0 -334
  27. package/vendor/vitest-docs/api/advanced/test-case.md +0 -302
  28. package/vendor/vitest-docs/api/advanced/test-collection.md +0 -89
  29. package/vendor/vitest-docs/api/advanced/test-module.md +0 -140
  30. package/vendor/vitest-docs/api/advanced/test-project.md +0 -321
  31. package/vendor/vitest-docs/api/advanced/test-specification.md +0 -96
  32. package/vendor/vitest-docs/api/advanced/test-suite.md +0 -230
  33. package/vendor/vitest-docs/api/advanced/vitest.md +0 -684
  34. package/vendor/vitest-docs/api/assert-type.md +0 -22
  35. package/vendor/vitest-docs/api/assert.md +0 -1960
  36. package/vendor/vitest-docs/api/browser/assertions.md +0 -1277
  37. package/vendor/vitest-docs/api/browser/commands.md +0 -154
  38. package/vendor/vitest-docs/api/browser/context.md +0 -338
  39. package/vendor/vitest-docs/api/browser/interactivity.md +0 -681
  40. package/vendor/vitest-docs/api/browser/locators.md +0 -1171
  41. package/vendor/vitest-docs/api/browser/react.md +0 -346
  42. package/vendor/vitest-docs/api/browser/svelte.md +0 -292
  43. package/vendor/vitest-docs/api/browser/vue.md +0 -222
  44. package/vendor/vitest-docs/api/describe.md +0 -374
  45. package/vendor/vitest-docs/api/expect-typeof.md +0 -571
  46. package/vendor/vitest-docs/api/expect.md +0 -2304
  47. package/vendor/vitest-docs/api/hooks.md +0 -463
  48. package/vendor/vitest-docs/api/mock.md +0 -701
  49. package/vendor/vitest-docs/api/test.md +0 -926
  50. package/vendor/vitest-docs/api/vi.md +0 -1372
  51. package/vendor/vitest-docs/config/alias.md +0 -13
  52. package/vendor/vitest-docs/config/allowonly.md +0 -32
  53. package/vendor/vitest-docs/config/api.md +0 -27
  54. package/vendor/vitest-docs/config/attachmentsdir.md +0 -6
  55. package/vendor/vitest-docs/config/bail.md +0 -9
  56. package/vendor/vitest-docs/config/benchmark.md +0 -65
  57. package/vendor/vitest-docs/config/browser/api.md +0 -23
  58. package/vendor/vitest-docs/config/browser/commands.md +0 -6
  59. package/vendor/vitest-docs/config/browser/connecttimeout.md +0 -10
  60. package/vendor/vitest-docs/config/browser/detailspanelposition.md +0 -38
  61. package/vendor/vitest-docs/config/browser/enabled.md +0 -40
  62. package/vendor/vitest-docs/config/browser/expect.md +0 -250
  63. package/vendor/vitest-docs/config/browser/headless.md +0 -7
  64. package/vendor/vitest-docs/config/browser/instances.md +0 -47
  65. package/vendor/vitest-docs/config/browser/isolate.md +0 -11
  66. package/vendor/vitest-docs/config/browser/locators.md +0 -24
  67. package/vendor/vitest-docs/config/browser/orchestratorscripts.md +0 -39
  68. package/vendor/vitest-docs/config/browser/playwright.md +0 -214
  69. package/vendor/vitest-docs/config/browser/preview.md +0 -32
  70. package/vendor/vitest-docs/config/browser/provider.md +0 -79
  71. package/vendor/vitest-docs/config/browser/screenshotdirectory.md +0 -6
  72. package/vendor/vitest-docs/config/browser/screenshotfailures.md +0 -6
  73. package/vendor/vitest-docs/config/browser/testerhtmlpath.md +0 -5
  74. package/vendor/vitest-docs/config/browser/trace.md +0 -43
  75. package/vendor/vitest-docs/config/browser/trackunhandlederrors.md +0 -10
  76. package/vendor/vitest-docs/config/browser/ui.md +0 -7
  77. package/vendor/vitest-docs/config/browser/viewport.md +0 -6
  78. package/vendor/vitest-docs/config/browser/webdriverio.md +0 -64
  79. package/vendor/vitest-docs/config/cache.md +0 -26
  80. package/vendor/vitest-docs/config/chaiconfig.md +0 -29
  81. package/vendor/vitest-docs/config/clearmocks.md +0 -22
  82. package/vendor/vitest-docs/config/coverage.md +0 -455
  83. package/vendor/vitest-docs/config/css.md +0 -47
  84. package/vendor/vitest-docs/config/dangerouslyignoreunhandlederrors.md +0 -23
  85. package/vendor/vitest-docs/config/deps.md +0 -127
  86. package/vendor/vitest-docs/config/detectasyncleaks.md +0 -39
  87. package/vendor/vitest-docs/config/diff.md +0 -96
  88. package/vendor/vitest-docs/config/dir.md +0 -7
  89. package/vendor/vitest-docs/config/disableconsoleintercept.md +0 -15
  90. package/vendor/vitest-docs/config/env.md +0 -5
  91. package/vendor/vitest-docs/config/environment.md +0 -96
  92. package/vendor/vitest-docs/config/environmentoptions.md +0 -30
  93. package/vendor/vitest-docs/config/exclude.md +0 -49
  94. package/vendor/vitest-docs/config/execargv.md +0 -10
  95. package/vendor/vitest-docs/config/expandsnapshotdiff.md +0 -7
  96. package/vendor/vitest-docs/config/expect.md +0 -38
  97. package/vendor/vitest-docs/config/experimental.md +0 -510
  98. package/vendor/vitest-docs/config/faketimers.md +0 -51
  99. package/vendor/vitest-docs/config/fileparallelism.md +0 -11
  100. package/vendor/vitest-docs/config/forcereruntriggers.md +0 -19
  101. package/vendor/vitest-docs/config/globals.md +0 -42
  102. package/vendor/vitest-docs/config/globalsetup.md +0 -72
  103. package/vendor/vitest-docs/config/hideskippedtests.md +0 -7
  104. package/vendor/vitest-docs/config/hooktimeout.md +0 -7
  105. package/vendor/vitest-docs/config/include-source.md +0 -115
  106. package/vendor/vitest-docs/config/include.md +0 -71
  107. package/vendor/vitest-docs/config/includetasklocation.md +0 -17
  108. package/vendor/vitest-docs/config/index.md +0 -85
  109. package/vendor/vitest-docs/config/isolate.md +0 -13
  110. package/vendor/vitest-docs/config/logheapusage.md +0 -7
  111. package/vendor/vitest-docs/config/maxconcurrency.md +0 -9
  112. package/vendor/vitest-docs/config/maxworkers.md +0 -49
  113. package/vendor/vitest-docs/config/mockreset.md +0 -22
  114. package/vendor/vitest-docs/config/mode.md +0 -7
  115. package/vendor/vitest-docs/config/name.md +0 -111
  116. package/vendor/vitest-docs/config/onconsolelog.md +0 -25
  117. package/vendor/vitest-docs/config/onstacktrace.md +0 -32
  118. package/vendor/vitest-docs/config/onunhandlederror.md +0 -35
  119. package/vendor/vitest-docs/config/open.md +0 -7
  120. package/vendor/vitest-docs/config/outputfile.md +0 -7
  121. package/vendor/vitest-docs/config/passwithnotests.md +0 -7
  122. package/vendor/vitest-docs/config/pool.md +0 -45
  123. package/vendor/vitest-docs/config/printconsoletrace.md +0 -6
  124. package/vendor/vitest-docs/config/projects.md +0 -6
  125. package/vendor/vitest-docs/config/provide.md +0 -45
  126. package/vendor/vitest-docs/config/reporters.md +0 -69
  127. package/vendor/vitest-docs/config/resolvesnapshotpath.md +0 -36
  128. package/vendor/vitest-docs/config/restoremocks.md +0 -22
  129. package/vendor/vitest-docs/config/retry.md +0 -140
  130. package/vendor/vitest-docs/config/root.md +0 -6
  131. package/vendor/vitest-docs/config/runner.md +0 -6
  132. package/vendor/vitest-docs/config/sequence.md +0 -158
  133. package/vendor/vitest-docs/config/server.md +0 -68
  134. package/vendor/vitest-docs/config/setupfiles.md +0 -40
  135. package/vendor/vitest-docs/config/silent.md +0 -9
  136. package/vendor/vitest-docs/config/slowtestthreshold.md +0 -7
  137. package/vendor/vitest-docs/config/snapshotenvironment.md +0 -27
  138. package/vendor/vitest-docs/config/snapshotformat.md +0 -28
  139. package/vendor/vitest-docs/config/snapshotserializers.md +0 -6
  140. package/vendor/vitest-docs/config/stricttags.md +0 -30
  141. package/vendor/vitest-docs/config/tags.md +0 -141
  142. package/vendor/vitest-docs/config/teardowntimeout.md +0 -7
  143. package/vendor/vitest-docs/config/testnamepattern.md +0 -21
  144. package/vendor/vitest-docs/config/testtimeout.md +0 -7
  145. package/vendor/vitest-docs/config/typecheck.md +0 -77
  146. package/vendor/vitest-docs/config/ui.md +0 -15
  147. package/vendor/vitest-docs/config/unstubenvs.md +0 -20
  148. package/vendor/vitest-docs/config/unstubglobals.md +0 -20
  149. package/vendor/vitest-docs/config/update.md +0 -16
  150. package/vendor/vitest-docs/config/vmmemorylimit.md +0 -30
  151. package/vendor/vitest-docs/config/watch.md +0 -11
  152. package/vendor/vitest-docs/config/watchtriggerpatterns.md +0 -29
  153. package/vendor/vitest-docs/guide/advanced/index.md +0 -147
  154. package/vendor/vitest-docs/guide/advanced/pool.md +0 -148
  155. package/vendor/vitest-docs/guide/advanced/reporters.md +0 -93
  156. package/vendor/vitest-docs/guide/advanced/tests.md +0 -125
  157. package/vendor/vitest-docs/guide/browser/aria-snapshots.md +0 -470
  158. package/vendor/vitest-docs/guide/browser/component-testing.md +0 -571
  159. package/vendor/vitest-docs/guide/browser/index.md +0 -630
  160. package/vendor/vitest-docs/guide/browser/multiple-setups.md +0 -121
  161. package/vendor/vitest-docs/guide/browser/trace-view.md +0 -126
  162. package/vendor/vitest-docs/guide/browser/visual-regression-testing.md +0 -734
  163. package/vendor/vitest-docs/guide/cli-generated.md +0 -972
  164. package/vendor/vitest-docs/guide/cli.md +0 -234
  165. package/vendor/vitest-docs/guide/common-errors.md +0 -163
  166. package/vendor/vitest-docs/guide/coverage.md +0 -515
  167. package/vendor/vitest-docs/guide/debugging.md +0 -127
  168. package/vendor/vitest-docs/guide/environment.md +0 -101
  169. package/vendor/vitest-docs/guide/extending-matchers.md +0 -160
  170. package/vendor/vitest-docs/guide/features.md +0 -310
  171. package/vendor/vitest-docs/guide/filtering.md +0 -175
  172. package/vendor/vitest-docs/guide/ide.md +0 -43
  173. package/vendor/vitest-docs/guide/improving-performance.md +0 -245
  174. package/vendor/vitest-docs/guide/in-source.md +0 -159
  175. package/vendor/vitest-docs/guide/index.md +0 -128
  176. package/vendor/vitest-docs/guide/learn/async.md +0 -147
  177. package/vendor/vitest-docs/guide/learn/debugging-tests.md +0 -210
  178. package/vendor/vitest-docs/guide/learn/matchers.md +0 -277
  179. package/vendor/vitest-docs/guide/learn/mock-functions.md +0 -277
  180. package/vendor/vitest-docs/guide/learn/setup-teardown.md +0 -240
  181. package/vendor/vitest-docs/guide/learn/snapshots.md +0 -166
  182. package/vendor/vitest-docs/guide/learn/testing-in-practice.md +0 -430
  183. package/vendor/vitest-docs/guide/learn/writing-tests-with-ai.md +0 -127
  184. package/vendor/vitest-docs/guide/learn/writing-tests.md +0 -231
  185. package/vendor/vitest-docs/guide/lifecycle.md +0 -379
  186. package/vendor/vitest-docs/guide/migration.md +0 -863
  187. package/vendor/vitest-docs/guide/mocking/classes.md +0 -158
  188. package/vendor/vitest-docs/guide/mocking/dates.md +0 -52
  189. package/vendor/vitest-docs/guide/mocking/file-system.md +0 -74
  190. package/vendor/vitest-docs/guide/mocking/functions.md +0 -61
  191. package/vendor/vitest-docs/guide/mocking/globals.md +0 -20
  192. package/vendor/vitest-docs/guide/mocking/modules.md +0 -414
  193. package/vendor/vitest-docs/guide/mocking/requests.md +0 -114
  194. package/vendor/vitest-docs/guide/mocking/timers.md +0 -48
  195. package/vendor/vitest-docs/guide/mocking.md +0 -239
  196. package/vendor/vitest-docs/guide/open-telemetry.md +0 -156
  197. package/vendor/vitest-docs/guide/parallelism.md +0 -82
  198. package/vendor/vitest-docs/guide/profiling-test-performance.md +0 -243
  199. package/vendor/vitest-docs/guide/projects.md +0 -291
  200. package/vendor/vitest-docs/guide/recipes.md +0 -59
  201. package/vendor/vitest-docs/guide/reporters.md +0 -723
  202. package/vendor/vitest-docs/guide/snapshot.md +0 -620
  203. package/vendor/vitest-docs/guide/test-annotations.md +0 -103
  204. package/vendor/vitest-docs/guide/test-context.md +0 -902
  205. package/vendor/vitest-docs/guide/test-tags.md +0 -314
  206. package/vendor/vitest-docs/guide/testing-types.md +0 -149
  207. package/vendor/vitest-docs/guide/ui.md +0 -160
  208. package/vendor/vitest-docs/guide/using-plugins.md +0 -5
  209. package/vendor/vitest-docs/manifest.json +0 -1691
@@ -1,734 +0,0 @@
1
- # Visual Regression Testing
2
-
3
- Vitest can run visual regression tests out of the box. It captures screenshots
4
- of your UI components and pages, then compares them against reference images to
5
- detect unintended visual changes.
6
-
7
- Unlike functional tests that verify behavior, visual tests catch styling issues,
8
- layout shifts, and rendering problems that might otherwise go unnoticed without
9
- thorough manual testing.
10
-
11
- ## Why Visual Regression Testing?
12
-
13
- Visual bugs don’t throw errors, they just look wrong. That’s where visual
14
- testing comes in.
15
-
16
- - That button still submits the form... but why is it hot pink now?
17
- - The text fits perfectly... until someone views it on mobile
18
- - Everything works great... except those two containers are out of viewport
19
- - That careful CSS refactor works... but broke the layout on a page no one tests
20
-
21
- Visual regression testing acts as a safety net for your UI, automatically
22
- catching these visual changes before they reach production.
23
-
24
- ## Getting Started
25
-
26
- ::: warning Browser Rendering Differences
27
- Visual regression tests are **inherently unstable across different
28
- environments**. Screenshots will look different on different machines because
29
- of:
30
-
31
- - Font rendering (the big one. Windows, macOS, Linux, they all render text
32
- differently)
33
- - GPU drivers and hardware acceleration
34
- - Whether you're running headless or not
35
- - Browser settings and versions
36
- - ...and honestly, sometimes just the phase of the moon
37
-
38
- That's why Vitest includes the browser and platform in screenshot names (like
39
- `button-chromium-darwin.png`).
40
-
41
- For stable tests, use the same environment everywhere. We **strongly recommend**
42
- cloud services like
43
- [Azure App Testing](https://azure.microsoft.com/en-us/products/app-testing/)
44
- or [Docker containers](https://playwright.dev/docs/docker).
45
- :::
46
-
47
- Visual regression testing in Vitest can be done through the
48
- [`toMatchScreenshot` assertion](/api/browser/assertions.html#tomatchscreenshot):
49
-
50
- ```ts
51
- import { expect, test } from 'vitest'
52
- import { page } from 'vitest/browser'
53
-
54
- test('hero section looks correct', async () => {
55
- // ...the rest of the test
56
-
57
- // capture and compare screenshot
58
- await expect(page.getByTestId('hero')).toMatchScreenshot('hero-section')
59
- })
60
- ```
61
-
62
- ### Creating References
63
-
64
- When you run a visual test for the first time, Vitest creates a reference (also
65
- called baseline) screenshot and fails the test with the following error message:
66
-
67
- ```
68
- expect(element).toMatchScreenshot()
69
-
70
- No existing reference screenshot found; a new one was created. Review it before running tests again.
71
-
72
- Reference screenshot:
73
- tests/__screenshots__/hero.test.ts/hero-section-chromium-darwin.png
74
- ```
75
-
76
- This is normal. Check that the screenshot looks right, then run the test again.
77
- Vitest will now compare future runs against this baseline.
78
-
79
- ::: tip
80
- Reference screenshots live in `__screenshots__` folders next to your tests.
81
- **Don't forget to commit them!**
82
- :::
83
-
84
- ### Screenshot Organization
85
-
86
- By default, screenshots are organized as:
87
-
88
- ```
89
- .
90
- ├── __screenshots__
91
- │ └── test-file.test.ts
92
- │ ├── test-name-chromium-darwin.png
93
- │ ├── test-name-firefox-linux.png
94
- │ └── test-name-webkit-win32.png
95
- └── test-file.test.ts
96
- ```
97
-
98
- The naming convention includes:
99
- - **Test name**: either the first argument of the `toMatchScreenshot()` call,
100
- or automatically generated from the test's name.
101
- - **Browser name**: `chrome`, `chromium`, `firefox` or `webkit`.
102
- - **Platform**: `aix`, `darwin`, `freebsd`, `linux`, `openbsd`, `sunos`, or
103
- `win32`.
104
-
105
- This ensures screenshots from different environments don't overwrite each other.
106
-
107
- ### Updating References
108
-
109
- When you intentionally change your UI, you'll need to update the reference
110
- screenshots:
111
-
112
- ```bash
113
- $ vitest --update
114
- ```
115
-
116
- Review updated screenshots before committing to make sure changes are
117
- intentional.
118
-
119
- ## How Visual Tests Work
120
-
121
- Visual regression tests need stable screenshots to compare against. But pages aren't instantly stable as images load, animations finish, fonts render, and layouts settle.
122
-
123
- Vitest handles this automatically through "Stable Screenshot Detection":
124
-
125
- 1. Vitest takes a first screenshot (or uses the reference screenshot if available) as baseline
126
- 1. It takes another screenshot and compares it with the baseline
127
- - If the screenshots match, the page is stable and testing continues
128
- - If they differ, Vitest uses the newest screenshot as the baseline and repeats
129
- 1. This continues until stability is achieved or the timeout is reached
130
-
131
- This ensures that transient visual changes (like loading spinners or animations) don't cause false failures. If something never stops animating though, you'll hit the timeout, so consider [disabling animations during testing](#disable-animations).
132
-
133
- If a stable screenshot is captured after retries (one or more) and a reference screenshot exists, Vitest performs a final comparison with the reference using `createDiff: true`. This will generate a diff image if they don't match.
134
-
135
- During stability detection, Vitest calls comparators with `createDiff: false` since it only needs to know if screenshots match. This keeps the detection process fast.
136
-
137
- ## Configuring Visual Tests
138
-
139
- ### Global Configuration
140
-
141
- Configure visual regression testing defaults in your
142
- [Vitest config](/config/browser/expect#tomatchscreenshot):
143
-
144
- ```ts [vitest.config.ts]
145
- import { defineConfig } from 'vitest/config'
146
-
147
- export default defineConfig({
148
- test: {
149
- browser: {
150
- expect: {
151
- toMatchScreenshot: {
152
- comparatorName: 'pixelmatch',
153
- comparatorOptions: {
154
- // 0-1, how different can colors be?
155
- threshold: 0.2,
156
- // 1% of pixels can differ
157
- allowedMismatchedPixelRatio: 0.01,
158
- },
159
- },
160
- },
161
- },
162
- },
163
- })
164
- ```
165
-
166
- ### Per-Test Configuration
167
-
168
- Override global settings for specific tests:
169
-
170
- ```ts
171
- await expect(element).toMatchScreenshot('button-hover', {
172
- comparatorName: 'pixelmatch',
173
- comparatorOptions: {
174
- // more lax comparison for text-heavy elements
175
- allowedMismatchedPixelRatio: 0.1,
176
- },
177
- })
178
- ```
179
-
180
- ## Best Practices
181
-
182
- ### Test Specific Elements
183
-
184
- Unless you explicitly want to test the whole page, prefer capturing specific
185
- components to reduce false positives:
186
-
187
- ```ts
188
- // ❌ Captures entire page; prone to unrelated changes
189
- await expect(page).toMatchScreenshot()
190
-
191
- // ✅ Captures only the component under test
192
- await expect(page.getByTestId('product-card')).toMatchScreenshot()
193
- ```
194
-
195
- ### Handle Dynamic Content
196
-
197
- Dynamic content like timestamps, user data, or random values will cause tests
198
- to fail. You can either mock the sources of dynamic content or mask them when
199
- using the Playwright provider by using the
200
- [`mask` option](https://playwright.dev/docs/api/class-page#page-screenshot-option-mask)
201
- in `screenshotOptions`.
202
-
203
- ```ts
204
- await expect(page.getByTestId('profile')).toMatchScreenshot({
205
- screenshotOptions: {
206
- mask: [page.getByTestId('last-seen')],
207
- },
208
- })
209
- ```
210
-
211
- ### Disable Animations
212
-
213
- Animations can cause flaky tests. Disable them during testing by injecting
214
- a custom CSS snippet:
215
-
216
- ```css
217
- *, *::before, *::after {
218
- animation-duration: 0s !important;
219
- animation-delay: 0s !important;
220
- transition-duration: 0s !important;
221
- transition-delay: 0s !important;
222
- }
223
- ```
224
-
225
- ::: tip
226
- When using the Playwright provider, animations are automatically disabled
227
- when using the assertion: the `animations` option's value in `screenshotOptions`
228
- is set to `"disabled"` by default.
229
- :::
230
-
231
- ### Set Appropriate Thresholds
232
-
233
- Tuning thresholds is tricky. It depends on the content, test environment,
234
- what's acceptable for your app, and might also change based on the test.
235
-
236
- Vitest does not set a default for the mismatching pixels, that's up for the
237
- user to decide based on their needs. The recommendation is to use
238
- `allowedMismatchedPixelRatio`, so that the threshold is computed on the size
239
- of the screenshot and not a fixed number.
240
-
241
- When setting both `allowedMismatchedPixelRatio` and
242
- `allowedMismatchedPixels`, Vitest uses whichever limit is stricter.
243
-
244
- ### Set consistent viewport sizes
245
-
246
- As the browser instance might have a different default size, it's best to
247
- set a specific viewport size, either on the test or the instance
248
- configuration:
249
-
250
- ```ts
251
- await page.viewport(1280, 720)
252
- ```
253
-
254
- ```ts [vitest.config.ts]
255
- import { playwright } from '@vitest/browser-playwright'
256
- import { defineConfig } from 'vitest/config'
257
-
258
- export default defineConfig({
259
- test: {
260
- browser: {
261
- enabled: true,
262
- provider: playwright(),
263
- instances: [
264
- {
265
- browser: 'chromium',
266
- viewport: { width: 1280, height: 720 },
267
- },
268
- ],
269
- },
270
- },
271
- })
272
- ```
273
-
274
- ### Use Git LFS
275
-
276
- Store reference screenshots in
277
- [Git LFS](https://github.com/git-lfs/git-lfs?tab=readme-ov-file) if you plan to
278
- have a large test suite.
279
-
280
- ## Debugging Failed Tests
281
-
282
- When a visual test fails, Vitest provides three images to help debug:
283
-
284
- 1. **Reference screenshot**: the expected baseline image
285
- 1. **Actual screenshot**: what was captured during the test
286
- 1. **Diff image**: highlights the differences, but this might not get generated
287
-
288
- You'll see something like:
289
-
290
- ```
291
- expect(element).toMatchScreenshot()
292
-
293
- Screenshot does not match the stored reference.
294
- 245 pixels (ratio 0.03) differ.
295
-
296
- Reference screenshot:
297
- tests/__screenshots__/button.test.ts/button-chromium-darwin.png
298
-
299
- Actual screenshot:
300
- tests/.vitest-attachments/button.test.ts/button-chromium-darwin-actual.png
301
-
302
- Diff image:
303
- tests/.vitest-attachments/button.test.ts/button-chromium-darwin-diff.png
304
- ```
305
-
306
- ### Understanding the diff image
307
-
308
- - **Red pixels** are areas that differ between reference and actual
309
- - **Yellow pixels** are anti-aliasing differences (when anti-alias is not ignored)
310
- - **Transparent/original** are unchanged areas
311
-
312
- :::tip
313
- If the diff is mostly red, something's really wrong. If it's speckled with a
314
- few red pixels around text, you probably just need to bump your threshold.
315
- :::
316
-
317
- ## Common Issues and Solutions
318
-
319
- ### False Positives from Font Rendering
320
-
321
- Font availability and rendering varies significantly between systems. Some
322
- possible solutions might be to:
323
-
324
- - Use web fonts and wait for them to load:
325
-
326
- ```ts
327
- // wait for fonts to load
328
- await document.fonts.ready
329
-
330
- // continue with your tests
331
- ```
332
-
333
- - Increase comparison threshold for text-heavy areas:
334
-
335
- ```ts
336
- await expect(page.getByTestId('article-summary')).toMatchScreenshot({
337
- comparatorName: 'pixelmatch',
338
- comparatorOptions: {
339
- // 10% of the pixels are allowed to change
340
- allowedMismatchedPixelRatio: 0.1,
341
- },
342
- })
343
- ```
344
-
345
- - Use a cloud service or containerized environment for consistent font rendering.
346
-
347
- ### Flaky Tests or Different Screenshot Sizes
348
-
349
- If tests pass and fail randomly, or if screenshots have different dimensions
350
- between runs:
351
-
352
- - Wait for everything to load, including loading indicators
353
- - Set explicit viewport sizes: `await page.viewport(1920, 1080)`
354
- - Check for responsive behavior at viewport boundaries
355
- - Check for unintended animations or transitions
356
- - Increase test timeout for large screenshots
357
- - Use a cloud service or containerized environment
358
-
359
- ## Visual Regression Testing for Teams
360
-
361
- Remember when we mentioned visual tests need a stable environment? Well, here's
362
- the thing: your local machine isn't it.
363
-
364
- For teams, you've basically got three options:
365
-
366
- 1. **Self-hosted runners**, complex to set up, painful to maintain
367
- 1. **GitHub Actions**, free (for open source), works with any provider
368
- 1. **Cloud services**, like
369
- [Azure App Testing](https://azure.microsoft.com/en-us/products/app-testing/),
370
- built for this exact problem
371
-
372
- We'll focus on options 2 and 3 since they're the quickest to get running.
373
-
374
- To be upfront, the main trade-offs for each are:
375
-
376
- - **GitHub Actions**: visual tests only run in CI (developers can't run them
377
- locally)
378
- - **Microsoft's service**: works everywhere but costs money and only works
379
- with Playwright
380
-
381
- :::: tabs key:vrt-for-teams
382
- === GitHub Actions
383
-
384
- The trick here is keeping visual tests separate from your regular tests,
385
- otherwise, you'll waste hours checking failing logs of screenshot mismatches.
386
-
387
- ### Organizing Your Tests
388
-
389
- First, isolate your visual tests. Stick them in a `visual` folder (or whatever
390
- makes sense for your project):
391
-
392
- ```json [package.json]
393
- {
394
- "scripts": {
395
- "test:unit": "vitest --exclude tests/visual/*.test.ts",
396
- "test:visual": "vitest tests/visual/*.test.ts"
397
- }
398
- }
399
- ```
400
-
401
- Now developers can run `npm run test:unit` locally without visual tests getting
402
- in the way. Visual tests stay in CI where the environment is consistent.
403
-
404
- ::: tip Alternative
405
- Not a fan of glob patterns? You could also use separate
406
- [Test Projects](/guide/projects) instead and run them using:
407
-
408
- - `vitest --project unit`
409
- - `vitest --project visual`
410
- :::
411
-
412
- ### CI Setup
413
-
414
- Your CI needs browsers installed. How you do this depends on your provider:
415
-
416
- ::: tabs key:provider
417
- == Playwright
418
-
419
- [Playwright](https://npmx.dev/package/playwright) makes this easy. Just pin
420
- your version and add this before running tests:
421
-
422
- ```yaml [.github/workflows/ci.yml]
423
- # ...the rest of the workflow
424
- - name: Install Playwright Browsers
425
- run: npx --no playwright install --with-deps --only-shell
426
- ```
427
-
428
- == WebdriverIO
429
-
430
- [WebdriverIO](https://npmx.dev/package/webdriverio) expects you to bring
431
- your own browsers. The folks at
432
- [@browser-actions](https://github.com/browser-actions) have your back:
433
-
434
- ```yaml [.github/workflows/ci.yml]
435
- # ...the rest of the workflow
436
- - uses: browser-actions/setup-chrome@v1
437
- with:
438
- chrome-version: 120
439
- ```
440
-
441
- :::
442
-
443
- Then run your visual tests:
444
-
445
- ```yaml [.github/workflows/ci.yml]
446
- # ...the rest of the workflow
447
- # ...browser setup
448
- - name: Visual Regression Testing
449
- run: npm run test:visual
450
- ```
451
-
452
- ### The Update Workflow
453
-
454
- Here's where it gets interesting. You don't want to update screenshots on every
455
- PR automatically <small>*(chaos!)*</small>. Instead, create a
456
- manually-triggered workflow that developers can run when they intentionally
457
- change the UI.
458
-
459
- The workflow below:
460
- - Only runs on feature branches (never on main)
461
- - Credits the person who triggered it as co-author
462
- - Prevents concurrent runs on the same branch
463
- - Shows a nice summary:
464
- - **When screenshots changed**, it lists what changed
465
-
466
- <img alt="Action summary after updates" img-light src="/vrt-gha-summary-update-light.png">
467
- <img alt="Action summary after updates" img-dark src="/vrt-gha-summary-update-dark.png">
468
-
469
- - **When nothing changed**, well, it tells you that too
470
-
471
- <img alt="Action summary after no updates" img-light src="/vrt-gha-summary-no-update-light.png">
472
- <img alt="Action summary after no updates" img-dark src="/vrt-gha-summary-no-update-dark.png">
473
-
474
- ::: tip
475
- This is just one approach. Some teams prefer PR comments (`/update-screenshots`),
476
- others use labels. Adjust it to fit your workflow!
477
-
478
- The important part is having a controlled way to update baselines.
479
- :::
480
-
481
- ```yaml [.github/workflows/update-screenshots.yml]
482
- name: Update Visual Regression Screenshots
483
-
484
- on:
485
- workflow_dispatch: # manual trigger only
486
-
487
- env:
488
- AUTHOR_NAME: 'github-actions[bot]'
489
- AUTHOR_EMAIL: '41898282+github-actions[bot]@users.noreply.github.com'
490
- COMMIT_MESSAGE: |
491
- test: update visual regression screenshots
492
-
493
- Co-authored-by: ${{ github.actor }} <${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com>
494
-
495
- jobs:
496
- update-screenshots:
497
- runs-on: ubuntu-24.04
498
-
499
- # safety first: don't run on main
500
- if: github.ref_name != github.event.repository.default_branch
501
-
502
- # one at a time per branch
503
- concurrency:
504
- group: visual-regression-screenshots@${{ github.ref_name }}
505
- cancel-in-progress: true
506
-
507
- permissions:
508
- contents: write # needs to push changes
509
-
510
- steps:
511
- - name: Checkout selected branch
512
- uses: actions/checkout@v4
513
- with:
514
- ref: ${{ github.ref_name }}
515
- # use PAT if triggering other workflows
516
- # token: ${{ secrets.GITHUB_TOKEN }}
517
-
518
- - name: Configure Git
519
- run: |
520
- git config --global user.name "${{ env.AUTHOR_NAME }}"
521
- git config --global user.email "${{ env.AUTHOR_EMAIL }}"
522
-
523
- # your setup steps here (node, pnpm, whatever)
524
- - name: Setup Node.js
525
- uses: actions/setup-node@v4
526
- with:
527
- node-version: 24
528
-
529
- - name: Install dependencies
530
- run: npm ci
531
-
532
- - name: Install Playwright Browsers
533
- run: npx --no playwright install --with-deps --only-shell
534
-
535
- # the magic happens below 🪄
536
- - name: Update Visual Regression Screenshots
537
- run: npm run test:visual --update
538
-
539
- # check what changed
540
- - name: Check for changes
541
- id: check_changes
542
- run: |
543
- CHANGED_FILES=$(git status --porcelain | awk '{print $2}')
544
- if [ "${CHANGED_FILES:+x}" ]; then
545
- echo "changes=true" >> $GITHUB_OUTPUT
546
- echo "Changes detected"
547
-
548
- # save the list for the summary
549
- echo "changed_files<<EOF" >> $GITHUB_OUTPUT
550
- echo "$CHANGED_FILES" >> $GITHUB_OUTPUT
551
- echo "EOF" >> $GITHUB_OUTPUT
552
- echo "changed_count=$(echo "$CHANGED_FILES" | wc -l)" >> $GITHUB_OUTPUT
553
- else
554
- echo "changes=false" >> $GITHUB_OUTPUT
555
- echo "No changes detected"
556
- fi
557
-
558
- # commit if there are changes
559
- - name: Commit changes
560
- if: steps.check_changes.outputs.changes == 'true'
561
- run: |
562
- git add -A
563
- git commit -m "${{ env.COMMIT_MESSAGE }}"
564
-
565
- - name: Push changes
566
- if: steps.check_changes.outputs.changes == 'true'
567
- run: git push origin ${{ github.ref_name }}
568
-
569
- # pretty summary for humans
570
- - name: Summary
571
- run: |
572
- if [[ "${{ steps.check_changes.outputs.changes }}" == "true" ]]; then
573
- echo "### 📸 Visual Regression Screenshots Updated" >> $GITHUB_STEP_SUMMARY
574
- echo "" >> $GITHUB_STEP_SUMMARY
575
- echo "Successfully updated **${{ steps.check_changes.outputs.changed_count }}** screenshot(s) on \`${{ github.ref_name }}\`" >> $GITHUB_STEP_SUMMARY
576
- echo "" >> $GITHUB_STEP_SUMMARY
577
- echo "#### Changed Files:" >> $GITHUB_STEP_SUMMARY
578
- echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
579
- echo "${{ steps.check_changes.outputs.changed_files }}" >> $GITHUB_STEP_SUMMARY
580
- echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
581
- echo "" >> $GITHUB_STEP_SUMMARY
582
- echo "✅ The updated screenshots have been committed and pushed. Your visual regression baseline is now up to date!" >> $GITHUB_STEP_SUMMARY
583
- else
584
- echo "### ℹ️ No Screenshot Updates Required" >> $GITHUB_STEP_SUMMARY
585
- echo "" >> $GITHUB_STEP_SUMMARY
586
- echo "The visual regression test command ran successfully but no screenshots needed updating." >> $GITHUB_STEP_SUMMARY
587
- echo "" >> $GITHUB_STEP_SUMMARY
588
- echo "All screenshots are already up to date! 🎉" >> $GITHUB_STEP_SUMMARY
589
- fi
590
- ```
591
-
592
- === Azure App Testing
593
-
594
- Your tests stay local, only the browsers run in the cloud. It's Playwright's
595
- remote browser feature, but Microsoft handles all the infrastructure.
596
-
597
- ### Organizing Your Tests
598
-
599
- Keep visual tests separate to control costs. Only tests that actually take
600
- screenshots should use the service.
601
-
602
- The cleanest approach is using [Test Projects](/guide/projects):
603
-
604
- ```ts [vitest.config.ts]
605
- import { env } from 'node:process'
606
- import { defineConfig } from 'vitest/config'
607
- import { playwright } from '@vitest/browser-playwright'
608
-
609
- export default defineConfig({
610
- // ...global Vite config
611
- tests: {
612
- // ...global Vitest config
613
- projects: [
614
- {
615
- extends: true,
616
- test: {
617
- name: 'unit',
618
- include: ['tests/**/*.test.ts'],
619
- // regular config, can use local browsers
620
- },
621
- },
622
- {
623
- extends: true,
624
- test: {
625
- name: 'visual',
626
- // or you could use a different suffix, e.g.,: `tests/**/*.visual.ts?(x)`
627
- include: ['visual-regression-tests/**/*.test.ts?(x)'],
628
- browser: {
629
- enabled: true,
630
- provider: playwright({
631
- connectOptions: {
632
- wsEndpoint: `${env.PLAYWRIGHT_SERVICE_URL}?${new URLSearchParams({
633
- 'api-version': '2025-09-01',
634
- 'os': 'linux', // always use Linux for consistency
635
- // helps identifying runs in the service's dashboard
636
- 'runName': `Vitest ${env.CI ? 'CI' : 'local'} run @${new Date().toISOString()}`,
637
- })}`,
638
- exposeNetwork: '<loopback>',
639
- headers: {
640
- Authorization: `Bearer ${env.PLAYWRIGHT_SERVICE_ACCESS_TOKEN}`,
641
- },
642
- timeout: 30_000,
643
- }
644
- }),
645
- headless: true,
646
- instances: [
647
- {
648
- browser: 'chromium',
649
- viewport: { width: 2560, height: 1440 },
650
- },
651
- ],
652
- },
653
- },
654
- },
655
- ],
656
- },
657
- })
658
- ```
659
-
660
- Follow the [official guide to create a Playwright Workspace](https://learn.microsoft.com/en-us/azure/app-testing/playwright-workspaces/quickstart-run-end-to-end-tests?tabs=playwrightcli&pivots=playwright-test-runner#create-a-workspace).
661
-
662
- Once your workspace is created, configure Vitest to use it:
663
-
664
- 1. **Set the endpoint URL**: following the [official guide](https://learn.microsoft.com/en-us/azure/app-testing/playwright-workspaces/quickstart-run-end-to-end-tests?tabs=playwrightcli&pivots=playwright-test-runner#configure-the-browser-endpoint), retrieve the URL and set it as the `PLAYWRIGHT_SERVICE_URL` environment variable.
665
- 1. **Enable token authentication**: [enable access tokens](https://learn.microsoft.com/en-us/azure/app-testing/playwright-workspaces/how-to-manage-authentication?pivots=playwright-test-runner#enable-authentication-using-access-tokens) for your workspace, then [generate a token](https://learn.microsoft.com/en-us/azure/app-testing/playwright-workspaces/how-to-manage-access-tokens#generate-a-workspace-access-token) and set it as the `PLAYWRIGHT_SERVICE_ACCESS_TOKEN` environment variable.
666
-
667
- ::: danger Keep that Token Secret!
668
- Never commit `PLAYWRIGHT_SERVICE_ACCESS_TOKEN` to your repository. Anyone with
669
- the token can rack up your bill. Use environment variables locally and secrets
670
- in CI.
671
- :::
672
-
673
- Then split your `test` script like this:
674
-
675
- ```json [package.json]
676
- {
677
- "scripts": {
678
- "test:visual": "vitest --project visual",
679
- "test:unit": "vitest --project unit"
680
- }
681
- }
682
- ```
683
-
684
- ### Running Tests
685
-
686
- ```bash
687
- # Local development
688
- npm run test:unit # free, runs locally
689
- npm run test:visual # uses cloud browsers
690
-
691
- # Update screenshots
692
- npm run test:visual -- --update
693
- ```
694
-
695
- The best part of this approach is that it just works:
696
-
697
- - **Consistent screenshots**, everyone uses the same cloud browsers
698
- - **Works locally**, developers can run and update visual tests on their machines
699
- - **Pay for what you use**, only visual tests consume service minutes
700
- - **No Docker or workflow setups needed**, nothing to manage or maintain
701
-
702
- ### CI Setup
703
-
704
- In your CI, add the secrets:
705
-
706
- ```yaml
707
- env:
708
- PLAYWRIGHT_SERVICE_URL: ${{ vars.PLAYWRIGHT_SERVICE_URL }}
709
- PLAYWRIGHT_SERVICE_ACCESS_TOKEN: ${{ secrets.PLAYWRIGHT_SERVICE_ACCESS_TOKEN }}
710
- ```
711
-
712
- Then run your tests like normal. The service handles the rest.
713
-
714
- ::::
715
-
716
- ### So Which One?
717
-
718
- Both approaches work. The real question is what pain points matter most to your
719
- team.
720
-
721
- If you're already deep in the GitHub ecosystem, GitHub Actions is hard to beat.
722
- Free for open source, works with any browser provider, and you control
723
- everything.
724
-
725
- The downside? That "works on my machine" conversation when someone generates
726
- screenshots locally and they don't match CI expectations anymore.
727
-
728
- A cloud service makes sense if developers need to run visual tests locally.
729
-
730
- Some teams have designers checking their work or developers who prefer catching
731
- issues before pushing. It allows skipping the push-wait-check-fix-push cycle.
732
-
733
- Still on the fence? Start with GitHub Actions. You can always add a cloud
734
- service later if local testing becomes a pain point.