@vitest-agent/mcp 1.0.1 → 1.2.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 (229) hide show
  1. package/README.md +1 -2
  2. package/bin/vitest-agent-mcp.js +1 -17
  3. package/index.d.ts +324 -315
  4. package/index.js +2 -4
  5. package/middleware/idempotency.js +1 -1
  6. package/package.json +2 -2
  7. package/server.js +2 -4
  8. package/tools/acceptance-metrics.js +1 -1
  9. package/tools/cache-health.js +1 -1
  10. package/tools/commit-changes.js +1 -1
  11. package/tools/configure.js +1 -1
  12. package/tools/coverage.js +1 -1
  13. package/tools/errors.js +1 -1
  14. package/tools/failure-signature-get.js +1 -1
  15. package/tools/file-coverage.js +1 -1
  16. package/tools/history.js +1 -1
  17. package/tools/inventory.js +1 -1
  18. package/tools/overview.js +1 -1
  19. package/tools/run-tests.js +15 -3
  20. package/tools/settings-list.js +1 -1
  21. package/tools/status.js +1 -1
  22. package/tools/tdd-artifact.js +1 -1
  23. package/tools/tdd-task.js +1 -1
  24. package/tools/test.js +1 -1
  25. package/tools/trends.js +1 -1
  26. package/tools/turn-search.js +1 -1
  27. package/public/patterns/_meta.json +0 -67
  28. package/public/patterns/authoring-a-custom-vitest-agent-reporter.md +0 -82
  29. package/public/patterns/known-issues-and-caveats.md +0 -52
  30. package/public/patterns/operating-vitest-agent-as-an-agent.md +0 -53
  31. package/public/patterns/running-tests-via-mcp.md +0 -58
  32. package/public/patterns/silencing-leaking-output-in-tests.md +0 -91
  33. package/public/patterns/testing-effect-schema-definitions.md +0 -71
  34. package/public/patterns/testing-effect-services-with-mock-layers.md +0 -63
  35. package/public/vendor/vitest-docs/ATTRIBUTION.md +0 -5
  36. package/public/vendor/vitest-docs/api/advanced/artifacts.md +0 -189
  37. package/public/vendor/vitest-docs/api/advanced/metadata.md +0 -68
  38. package/public/vendor/vitest-docs/api/advanced/plugin.md +0 -168
  39. package/public/vendor/vitest-docs/api/advanced/reporters.md +0 -342
  40. package/public/vendor/vitest-docs/api/advanced/runner.md +0 -334
  41. package/public/vendor/vitest-docs/api/advanced/test-case.md +0 -302
  42. package/public/vendor/vitest-docs/api/advanced/test-collection.md +0 -89
  43. package/public/vendor/vitest-docs/api/advanced/test-module.md +0 -140
  44. package/public/vendor/vitest-docs/api/advanced/test-project.md +0 -321
  45. package/public/vendor/vitest-docs/api/advanced/test-specification.md +0 -96
  46. package/public/vendor/vitest-docs/api/advanced/test-suite.md +0 -230
  47. package/public/vendor/vitest-docs/api/advanced/vitest.md +0 -684
  48. package/public/vendor/vitest-docs/api/assert-type.md +0 -22
  49. package/public/vendor/vitest-docs/api/assert.md +0 -1960
  50. package/public/vendor/vitest-docs/api/browser/assertions.md +0 -1277
  51. package/public/vendor/vitest-docs/api/browser/commands.md +0 -154
  52. package/public/vendor/vitest-docs/api/browser/context.md +0 -338
  53. package/public/vendor/vitest-docs/api/browser/interactivity.md +0 -681
  54. package/public/vendor/vitest-docs/api/browser/locators.md +0 -1171
  55. package/public/vendor/vitest-docs/api/browser/react.md +0 -346
  56. package/public/vendor/vitest-docs/api/browser/svelte.md +0 -292
  57. package/public/vendor/vitest-docs/api/browser/vue.md +0 -222
  58. package/public/vendor/vitest-docs/api/describe.md +0 -374
  59. package/public/vendor/vitest-docs/api/expect-typeof.md +0 -571
  60. package/public/vendor/vitest-docs/api/expect.md +0 -2304
  61. package/public/vendor/vitest-docs/api/hooks.md +0 -463
  62. package/public/vendor/vitest-docs/api/mock.md +0 -701
  63. package/public/vendor/vitest-docs/api/test.md +0 -926
  64. package/public/vendor/vitest-docs/api/vi.md +0 -1372
  65. package/public/vendor/vitest-docs/config/alias.md +0 -13
  66. package/public/vendor/vitest-docs/config/allowonly.md +0 -32
  67. package/public/vendor/vitest-docs/config/api.md +0 -27
  68. package/public/vendor/vitest-docs/config/attachmentsdir.md +0 -6
  69. package/public/vendor/vitest-docs/config/bail.md +0 -9
  70. package/public/vendor/vitest-docs/config/benchmark.md +0 -65
  71. package/public/vendor/vitest-docs/config/browser/api.md +0 -23
  72. package/public/vendor/vitest-docs/config/browser/commands.md +0 -6
  73. package/public/vendor/vitest-docs/config/browser/connecttimeout.md +0 -10
  74. package/public/vendor/vitest-docs/config/browser/detailspanelposition.md +0 -38
  75. package/public/vendor/vitest-docs/config/browser/enabled.md +0 -40
  76. package/public/vendor/vitest-docs/config/browser/expect.md +0 -250
  77. package/public/vendor/vitest-docs/config/browser/headless.md +0 -7
  78. package/public/vendor/vitest-docs/config/browser/instances.md +0 -47
  79. package/public/vendor/vitest-docs/config/browser/isolate.md +0 -11
  80. package/public/vendor/vitest-docs/config/browser/locators.md +0 -24
  81. package/public/vendor/vitest-docs/config/browser/orchestratorscripts.md +0 -39
  82. package/public/vendor/vitest-docs/config/browser/playwright.md +0 -214
  83. package/public/vendor/vitest-docs/config/browser/preview.md +0 -32
  84. package/public/vendor/vitest-docs/config/browser/provider.md +0 -79
  85. package/public/vendor/vitest-docs/config/browser/screenshotdirectory.md +0 -6
  86. package/public/vendor/vitest-docs/config/browser/screenshotfailures.md +0 -6
  87. package/public/vendor/vitest-docs/config/browser/testerhtmlpath.md +0 -5
  88. package/public/vendor/vitest-docs/config/browser/trace.md +0 -43
  89. package/public/vendor/vitest-docs/config/browser/trackunhandlederrors.md +0 -10
  90. package/public/vendor/vitest-docs/config/browser/ui.md +0 -7
  91. package/public/vendor/vitest-docs/config/browser/viewport.md +0 -6
  92. package/public/vendor/vitest-docs/config/browser/webdriverio.md +0 -64
  93. package/public/vendor/vitest-docs/config/cache.md +0 -26
  94. package/public/vendor/vitest-docs/config/chaiconfig.md +0 -29
  95. package/public/vendor/vitest-docs/config/clearmocks.md +0 -22
  96. package/public/vendor/vitest-docs/config/coverage.md +0 -455
  97. package/public/vendor/vitest-docs/config/css.md +0 -47
  98. package/public/vendor/vitest-docs/config/dangerouslyignoreunhandlederrors.md +0 -23
  99. package/public/vendor/vitest-docs/config/deps.md +0 -127
  100. package/public/vendor/vitest-docs/config/detectasyncleaks.md +0 -39
  101. package/public/vendor/vitest-docs/config/diff.md +0 -96
  102. package/public/vendor/vitest-docs/config/dir.md +0 -7
  103. package/public/vendor/vitest-docs/config/disableconsoleintercept.md +0 -15
  104. package/public/vendor/vitest-docs/config/env.md +0 -5
  105. package/public/vendor/vitest-docs/config/environment.md +0 -96
  106. package/public/vendor/vitest-docs/config/environmentoptions.md +0 -30
  107. package/public/vendor/vitest-docs/config/exclude.md +0 -49
  108. package/public/vendor/vitest-docs/config/execargv.md +0 -10
  109. package/public/vendor/vitest-docs/config/expandsnapshotdiff.md +0 -7
  110. package/public/vendor/vitest-docs/config/expect.md +0 -38
  111. package/public/vendor/vitest-docs/config/experimental.md +0 -510
  112. package/public/vendor/vitest-docs/config/faketimers.md +0 -51
  113. package/public/vendor/vitest-docs/config/fileparallelism.md +0 -11
  114. package/public/vendor/vitest-docs/config/forcereruntriggers.md +0 -19
  115. package/public/vendor/vitest-docs/config/globals.md +0 -42
  116. package/public/vendor/vitest-docs/config/globalsetup.md +0 -72
  117. package/public/vendor/vitest-docs/config/hideskippedtests.md +0 -7
  118. package/public/vendor/vitest-docs/config/hooktimeout.md +0 -7
  119. package/public/vendor/vitest-docs/config/include-source.md +0 -115
  120. package/public/vendor/vitest-docs/config/include.md +0 -71
  121. package/public/vendor/vitest-docs/config/includetasklocation.md +0 -17
  122. package/public/vendor/vitest-docs/config/index.md +0 -85
  123. package/public/vendor/vitest-docs/config/isolate.md +0 -13
  124. package/public/vendor/vitest-docs/config/logheapusage.md +0 -7
  125. package/public/vendor/vitest-docs/config/maxconcurrency.md +0 -9
  126. package/public/vendor/vitest-docs/config/maxworkers.md +0 -49
  127. package/public/vendor/vitest-docs/config/mockreset.md +0 -22
  128. package/public/vendor/vitest-docs/config/mode.md +0 -7
  129. package/public/vendor/vitest-docs/config/name.md +0 -111
  130. package/public/vendor/vitest-docs/config/onconsolelog.md +0 -25
  131. package/public/vendor/vitest-docs/config/onstacktrace.md +0 -32
  132. package/public/vendor/vitest-docs/config/onunhandlederror.md +0 -35
  133. package/public/vendor/vitest-docs/config/open.md +0 -7
  134. package/public/vendor/vitest-docs/config/outputfile.md +0 -7
  135. package/public/vendor/vitest-docs/config/passwithnotests.md +0 -7
  136. package/public/vendor/vitest-docs/config/pool.md +0 -45
  137. package/public/vendor/vitest-docs/config/printconsoletrace.md +0 -6
  138. package/public/vendor/vitest-docs/config/projects.md +0 -6
  139. package/public/vendor/vitest-docs/config/provide.md +0 -45
  140. package/public/vendor/vitest-docs/config/reporters.md +0 -69
  141. package/public/vendor/vitest-docs/config/resolvesnapshotpath.md +0 -36
  142. package/public/vendor/vitest-docs/config/restoremocks.md +0 -22
  143. package/public/vendor/vitest-docs/config/retry.md +0 -140
  144. package/public/vendor/vitest-docs/config/root.md +0 -6
  145. package/public/vendor/vitest-docs/config/runner.md +0 -6
  146. package/public/vendor/vitest-docs/config/sequence.md +0 -158
  147. package/public/vendor/vitest-docs/config/server.md +0 -68
  148. package/public/vendor/vitest-docs/config/setupfiles.md +0 -40
  149. package/public/vendor/vitest-docs/config/silent.md +0 -9
  150. package/public/vendor/vitest-docs/config/slowtestthreshold.md +0 -7
  151. package/public/vendor/vitest-docs/config/snapshotenvironment.md +0 -27
  152. package/public/vendor/vitest-docs/config/snapshotformat.md +0 -28
  153. package/public/vendor/vitest-docs/config/snapshotserializers.md +0 -6
  154. package/public/vendor/vitest-docs/config/stricttags.md +0 -30
  155. package/public/vendor/vitest-docs/config/tags.md +0 -141
  156. package/public/vendor/vitest-docs/config/teardowntimeout.md +0 -7
  157. package/public/vendor/vitest-docs/config/testnamepattern.md +0 -21
  158. package/public/vendor/vitest-docs/config/testtimeout.md +0 -7
  159. package/public/vendor/vitest-docs/config/typecheck.md +0 -77
  160. package/public/vendor/vitest-docs/config/ui.md +0 -15
  161. package/public/vendor/vitest-docs/config/unstubenvs.md +0 -20
  162. package/public/vendor/vitest-docs/config/unstubglobals.md +0 -20
  163. package/public/vendor/vitest-docs/config/update.md +0 -16
  164. package/public/vendor/vitest-docs/config/vmmemorylimit.md +0 -30
  165. package/public/vendor/vitest-docs/config/watch.md +0 -11
  166. package/public/vendor/vitest-docs/config/watchtriggerpatterns.md +0 -29
  167. package/public/vendor/vitest-docs/guide/advanced/index.md +0 -147
  168. package/public/vendor/vitest-docs/guide/advanced/pool.md +0 -148
  169. package/public/vendor/vitest-docs/guide/advanced/reporters.md +0 -93
  170. package/public/vendor/vitest-docs/guide/advanced/tests.md +0 -125
  171. package/public/vendor/vitest-docs/guide/browser/aria-snapshots.md +0 -470
  172. package/public/vendor/vitest-docs/guide/browser/component-testing.md +0 -571
  173. package/public/vendor/vitest-docs/guide/browser/index.md +0 -630
  174. package/public/vendor/vitest-docs/guide/browser/multiple-setups.md +0 -121
  175. package/public/vendor/vitest-docs/guide/browser/trace-view.md +0 -126
  176. package/public/vendor/vitest-docs/guide/browser/visual-regression-testing.md +0 -734
  177. package/public/vendor/vitest-docs/guide/cli-generated.md +0 -972
  178. package/public/vendor/vitest-docs/guide/cli.md +0 -234
  179. package/public/vendor/vitest-docs/guide/common-errors.md +0 -163
  180. package/public/vendor/vitest-docs/guide/coverage.md +0 -515
  181. package/public/vendor/vitest-docs/guide/debugging.md +0 -127
  182. package/public/vendor/vitest-docs/guide/environment.md +0 -101
  183. package/public/vendor/vitest-docs/guide/extending-matchers.md +0 -160
  184. package/public/vendor/vitest-docs/guide/features.md +0 -310
  185. package/public/vendor/vitest-docs/guide/filtering.md +0 -175
  186. package/public/vendor/vitest-docs/guide/ide.md +0 -43
  187. package/public/vendor/vitest-docs/guide/improving-performance.md +0 -245
  188. package/public/vendor/vitest-docs/guide/in-source.md +0 -159
  189. package/public/vendor/vitest-docs/guide/index.md +0 -128
  190. package/public/vendor/vitest-docs/guide/learn/async.md +0 -147
  191. package/public/vendor/vitest-docs/guide/learn/debugging-tests.md +0 -210
  192. package/public/vendor/vitest-docs/guide/learn/matchers.md +0 -277
  193. package/public/vendor/vitest-docs/guide/learn/mock-functions.md +0 -277
  194. package/public/vendor/vitest-docs/guide/learn/setup-teardown.md +0 -240
  195. package/public/vendor/vitest-docs/guide/learn/snapshots.md +0 -166
  196. package/public/vendor/vitest-docs/guide/learn/testing-in-practice.md +0 -430
  197. package/public/vendor/vitest-docs/guide/learn/writing-tests-with-ai.md +0 -127
  198. package/public/vendor/vitest-docs/guide/learn/writing-tests.md +0 -231
  199. package/public/vendor/vitest-docs/guide/lifecycle.md +0 -379
  200. package/public/vendor/vitest-docs/guide/migration.md +0 -863
  201. package/public/vendor/vitest-docs/guide/mocking/classes.md +0 -158
  202. package/public/vendor/vitest-docs/guide/mocking/dates.md +0 -52
  203. package/public/vendor/vitest-docs/guide/mocking/file-system.md +0 -74
  204. package/public/vendor/vitest-docs/guide/mocking/functions.md +0 -61
  205. package/public/vendor/vitest-docs/guide/mocking/globals.md +0 -20
  206. package/public/vendor/vitest-docs/guide/mocking/modules.md +0 -414
  207. package/public/vendor/vitest-docs/guide/mocking/requests.md +0 -114
  208. package/public/vendor/vitest-docs/guide/mocking/timers.md +0 -48
  209. package/public/vendor/vitest-docs/guide/mocking.md +0 -239
  210. package/public/vendor/vitest-docs/guide/open-telemetry.md +0 -156
  211. package/public/vendor/vitest-docs/guide/parallelism.md +0 -82
  212. package/public/vendor/vitest-docs/guide/profiling-test-performance.md +0 -243
  213. package/public/vendor/vitest-docs/guide/projects.md +0 -291
  214. package/public/vendor/vitest-docs/guide/recipes.md +0 -59
  215. package/public/vendor/vitest-docs/guide/reporters.md +0 -723
  216. package/public/vendor/vitest-docs/guide/snapshot.md +0 -620
  217. package/public/vendor/vitest-docs/guide/test-annotations.md +0 -103
  218. package/public/vendor/vitest-docs/guide/test-context.md +0 -902
  219. package/public/vendor/vitest-docs/guide/test-tags.md +0 -314
  220. package/public/vendor/vitest-docs/guide/testing-types.md +0 -149
  221. package/public/vendor/vitest-docs/guide/ui.md +0 -160
  222. package/public/vendor/vitest-docs/guide/using-plugins.md +0 -5
  223. package/public/vendor/vitest-docs/manifest.json +0 -1691
  224. package/resources/index.js +0 -166
  225. package/resources/indexes.js +0 -77
  226. package/resources/manifest-schema.js +0 -46
  227. package/resources/paths.js +0 -20
  228. package/resources/patterns.js +0 -22
  229. package/resources/upstream-docs.js +0 -22
@@ -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.