@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,430 +0,0 @@
1
- # Testing in Practice
2
-
3
- The previous pages covered the Vitest API: assertions, mocking, snapshots, and test lifecycle hooks. This page focuses on applying those tools to real code. It covers how to decide what to test, how to structure tests effectively, and how to organize test files as a project grows.
4
-
5
- ## What to Test
6
-
7
- When you sit down to write tests for a function or module, start by thinking about its **contract**: what does it promise to do for the code that calls it? The contract is defined by its inputs (arguments, configuration) and its outputs (return values, side effects, errors). These are the things your tests should verify.
8
-
9
- Consider a `formatPrice` function:
10
-
11
- ```js [formatPrice.js]
12
- export function formatPrice(amount, currency) {
13
- return new Intl.NumberFormat('en-US', {
14
- style: 'currency',
15
- currency,
16
- }).format(amount)
17
- }
18
- ```
19
-
20
- The contract here is: given an amount and a currency code, return a formatted price string. Good tests for this function would cover:
21
-
22
- ```js [formatPrice.test.js]
23
- import { expect, test } from 'vitest'
24
- import { formatPrice } from './formatPrice.js'
25
-
26
- test('formats USD prices', () => {
27
- expect(formatPrice(10, 'USD')).toBe('$10.00')
28
- })
29
-
30
- test('formats EUR prices', () => {
31
- expect(formatPrice(10, 'EUR')).toBe('€10.00')
32
- })
33
-
34
- test('handles zero', () => {
35
- expect(formatPrice(0, 'USD')).toBe('$0.00')
36
- })
37
-
38
- test('handles negative amounts', () => {
39
- expect(formatPrice(-5.5, 'USD')).toBe('-$5.50')
40
- })
41
-
42
- test('rounds to two decimal places', () => {
43
- expect(formatPrice(10.999, 'USD')).toBe('$11.00')
44
- })
45
- ```
46
-
47
- Notice what these tests *don't* do. They don't check which internal `Intl.NumberFormat` options were passed, or whether an intermediate variable was set. They only check the output.
48
-
49
- ::: tip
50
- A good rule of thumb: if someone refactors the internals but the output stays the same, should the test break? If it would, you're probably testing implementation details rather than behavior.
51
- :::
52
-
53
- ## Structuring a Test
54
-
55
- Most tests follow a natural three-part structure, sometimes called "Arrange, Act, Assert":
56
-
57
- 1. **Set up** the data your test needs
58
- 2. **Call** the function or perform the action you're testing
59
- 3. **Check** that the result matches your expectations
60
-
61
- ```js
62
- test('removes an item from the list', () => {
63
- // Set up
64
- const list = new ShoppingList()
65
- list.add('milk')
66
- list.add('bread')
67
-
68
- // Act
69
- list.remove('milk')
70
-
71
- // Check
72
- expect(list.getItems()).toEqual(['bread'])
73
- })
74
- ```
75
-
76
- You don't need comments labeling each section. The structure becomes natural once you've written a few tests. The important thing is keeping each test focused on one behavior.
77
-
78
- ### One Behavior Per Test
79
-
80
- If you find yourself writing "and" in a test name ("formats price and handles errors and logs the result"), that's a sign you should split it into separate tests.
81
-
82
- ### Descriptive Names
83
-
84
- Write test names that describe the behavior, not the implementation. "returns formatted price for USD" is better than "calls Intl.NumberFormat with correct options". When a test fails, the name should tell you what broke without having to read the test body.
85
-
86
- ## Testing Edge Cases
87
-
88
- After covering the main behavior, think about the boundaries. What happens at the edges? What inputs are unusual but valid? What should happen when things go wrong?
89
-
90
- Here's an example with a `parseAge` function that takes user input and returns a number:
91
-
92
- ```js [parseAge.js]
93
- export function parseAge(input) {
94
- const age = Number(input)
95
- if (Number.isNaN(age) || age < 0 || age > 150) {
96
- throw new Error(`Invalid age: ${input}`)
97
- }
98
- return Math.floor(age)
99
- }
100
- ```
101
-
102
- The happy path is straightforward, but the edge cases are where bugs hide:
103
-
104
- ```js [parseAge.test.js]
105
- import { expect, test } from 'vitest'
106
- import { parseAge } from './parseAge.js'
107
-
108
- test('parses a valid age', () => {
109
- expect(parseAge('25')).toBe(25)
110
- })
111
-
112
- test('rounds down decimal ages', () => {
113
- expect(parseAge('25.9')).toBe(25)
114
- })
115
-
116
- test('handles zero', () => {
117
- expect(parseAge('0')).toBe(0)
118
- })
119
-
120
- test('handles the upper boundary', () => {
121
- expect(parseAge('150')).toBe(150)
122
- })
123
-
124
- test('throws for negative numbers', () => {
125
- expect(() => parseAge('-1')).toThrow('Invalid age: -1')
126
- })
127
-
128
- test('throws for numbers above 150', () => {
129
- expect(() => parseAge('151')).toThrow('Invalid age: 151')
130
- })
131
-
132
- test('throws for non-numeric strings', () => {
133
- expect(() => parseAge('abc')).toThrow('Invalid age: abc')
134
- })
135
-
136
- test('throws for empty string', () => {
137
- expect(() => parseAge('')).toThrow('Invalid age: ')
138
- })
139
- ```
140
-
141
- You don't need to test every possible input. Focus on the boundaries (0, 150, 151, -1), the error paths, and the types of inputs your function might realistically receive.
142
-
143
- ::: tip
144
- If you're unsure whether an edge case matters, ask yourself: could a real user or a real caller trigger this? If yes, test it.
145
- :::
146
-
147
- ### Property-Based Testing
148
-
149
- For functions with a wide range of valid inputs, manually choosing edge cases can only go so far. **Property-based testing** is a technique where you describe the *properties* that should hold for any input, and the testing framework generates hundreds of random inputs to try to find one that breaks.
150
-
151
- For example, you might say "for any valid age string, `parseAge` should return a non-negative integer" and let the tool find the counterexample. [fast-check](https://fast-check.dev/) is a popular property-based testing library that integrates well with Vitest. It's an advanced technique, but worth knowing about as your testing needs grow.
152
-
153
- ## When to Mock
154
-
155
- Mocking is a powerful tool, but it's easy to overuse.
156
-
157
- ### Slow Dependencies
158
-
159
- Network requests, file system operations, and database calls can make your tests take seconds instead of milliseconds. Replace them with mocks to keep the feedback loop fast.
160
-
161
- For HTTP requests specifically, consider using [Mock Service Worker](https://mswjs.io/) instead of mocking fetch directly. See the [Mocking Requests](/guide/mocking/requests) guide for setup instructions.
162
-
163
- ### Non-Deterministic Values
164
-
165
- If your code depends on the current date, a random number, or a UUID generator, mock those to make your tests predictable. Vitest provides [`vi.useFakeTimers()`](/api/vi#vi-usefaketimers) and [`vi.setSystemTime()`](/api/vi#vi-setsystemtime) for controlling time in tests.
166
-
167
- ### What Not to Mock
168
-
169
- Don't mock the thing you're testing. If you're testing a `UserService`, don't mock the `UserService`. Mock its *dependencies* (the database, the email sender) and let the service itself run for real.
170
-
171
- Also, prefer real implementations when they're fast and reliable. If a dependency is a simple in-memory data structure or a pure function, there's no reason to mock it. The closer your tests are to real usage, the more confidence they give you.
172
-
173
- ::: tip
174
- Only reach for mocks when the real thing is slow, flaky, or has side effects you can't control in a test.
175
- :::
176
-
177
- ## Fixing Bugs with Tests
178
-
179
- When you find a bug, it's tempting to jump straight into the code and fix it. A better approach is to write a failing test first that reproduces the bug, then fix the code and watch the test turn green.
180
-
181
- This has several benefits. The test proves the bug is real and not just a misunderstanding. It documents exactly what was broken. And it prevents the same bug from coming back later, because the test will catch it if someone accidentally reintroduces the same problem.
182
-
183
- Here's what this looks like in practice. Suppose users report that `parseAge` crashes when given a string with leading spaces like `" 25"`. First, write a test that reproduces the problem:
184
-
185
- ```js
186
- test('handles leading spaces', () => {
187
- expect(parseAge(' 25')).toBe(25)
188
- })
189
- ```
190
-
191
- Run it and confirm it fails. Now you know exactly what's broken and have a clear target. Fix the implementation:
192
-
193
- ```js
194
- export function parseAge(input) {
195
- const age = Number(input.trim())
196
- // ...
197
- }
198
- ```
199
-
200
- Run the test again. It passes. The bug is fixed, and you have a regression test that will catch it if someone removes the `.trim()` call later.
201
-
202
- ::: tip
203
- If you use AI agents to fix bugs, configure them to follow the same principle: reproduce the issue with a failing test first, then fix the code. This prevents the agent from "fixing" a bug by changing the test instead of the code, and gives you confidence that the fix actually works.
204
- :::
205
-
206
- ## Organizing Test Files
207
-
208
- There's no single right way to organize tests, but some patterns scale better than others.
209
-
210
- ### File Layout
211
-
212
- The simplest starting point is one test file per source file. For every `utils.js`, there's a `utils.test.js` right next to it. This makes it easy to find the tests for any given piece of code, and most editors will show them side by side in the file tree:
213
-
214
- ```
215
- src/
216
- utils.js
217
- utils.test.js
218
- formatPrice.js
219
- formatPrice.test.js
220
- ```
221
-
222
- Some teams prefer a separate `__tests__` or `test` directory instead. Either approach works. The important thing is consistency across the project. Vitest's [`include`](/config/include) pattern matches both layouts by default.
223
-
224
- ### Grouping with `describe`
225
-
226
- When a module exports multiple functions, use `describe` blocks to group the tests for each one. This keeps the test output organized and makes it clear which function a failing test belongs to:
227
-
228
- ```js
229
- describe('formatPrice', () => {
230
- test('formats USD prices', () => { /* ... */ })
231
- test('handles zero', () => { /* ... */ })
232
- })
233
-
234
- describe('parseAmount', () => {
235
- test('parses valid amounts', () => { /* ... */ })
236
- test('throws for invalid input', () => { /* ... */ })
237
- })
238
- ```
239
-
240
- Avoid nesting `describe` blocks more than one or two levels deep. Deeply nested test trees are hard to read and usually mean the source module is doing too many things at once.
241
-
242
- ### Splitting Large Files
243
-
244
- As a project grows, some test files will inevitably get long. If a test file grows beyond a few hundred lines, consider splitting it by theme or feature area. For example, `userService.test.js` might become `userService.creation.test.js` and `userService.auth.test.js`. This also makes it faster to run a subset of tests during development.
245
-
246
- ### Naming Tests
247
-
248
- Test names matter more than you might expect. When a test fails in CI, the name is often the first thing someone reads. Names like "works correctly" or "handles edge case" don't tell you what broke.
249
-
250
- Prefer names that describe the specific behavior: "returns 0 for an empty cart", "throws if the email format is invalid", "preserves existing items when adding a new one". The test output should read like a specification of what the module does.
251
-
252
- ## A Worked Example
253
-
254
- Let's put it all together. Here's a small `TodoList` module:
255
-
256
- ```js [todoList.js]
257
- let nextId = 1
258
-
259
- export function createTodoList() {
260
- const items = []
261
-
262
- return {
263
- add(text) {
264
- if (!text.trim()) {
265
- throw new Error('Todo text cannot be empty')
266
- }
267
- const todo = { id: nextId++, text, completed: false }
268
- items.push(todo)
269
- return todo
270
- },
271
-
272
- remove(id) {
273
- const index = items.findIndex(item => item.id === id)
274
- if (index === -1) {
275
- throw new Error(`Todo with id ${id} not found`)
276
- }
277
- items.splice(index, 1)
278
- },
279
-
280
- toggle(id) {
281
- const todo = items.find(item => item.id === id)
282
- if (!todo) {
283
- throw new Error(`Todo with id ${id} not found`)
284
- }
285
- todo.completed = !todo.completed
286
- },
287
-
288
- getAll() {
289
- return items
290
- },
291
-
292
- getCompleted() {
293
- return items.filter(item => item.completed)
294
- },
295
- }
296
- }
297
- ```
298
-
299
- Looking at this code, we can identify the behaviors to test:
300
-
301
- - Adding items (the main purpose)
302
- - Adding empty items (should fail)
303
- - Removing items by ID
304
- - Removing items that don't exist (should fail)
305
- - Toggling completion status
306
- - Getting all items vs. completed items
307
-
308
- Here's how the test file might look:
309
-
310
- ```js [todoList.test.js]
311
- import { describe, expect, test } from 'vitest'
312
- import { createTodoList } from './todoList.js'
313
-
314
- describe('add', () => {
315
- test('adds a new todo', () => {
316
- const list = createTodoList()
317
- const todo = list.add('Buy groceries')
318
-
319
- expect(todo.text).toBe('Buy groceries')
320
- expect(todo.completed).toBe(false)
321
- expect(list.getAll()).toHaveLength(1)
322
- })
323
-
324
- test('assigns unique IDs to each todo', () => {
325
- const list = createTodoList()
326
- const first = list.add('First')
327
- const second = list.add('Second')
328
-
329
- expect(first.id).not.toBe(second.id)
330
- })
331
-
332
- test('throws when text is empty', () => {
333
- const list = createTodoList()
334
- expect(() => list.add('')).toThrow('Todo text cannot be empty')
335
- })
336
-
337
- test('throws when text is only whitespace', () => {
338
- const list = createTodoList()
339
- expect(() => list.add(' ')).toThrow('Todo text cannot be empty')
340
- })
341
- })
342
-
343
- describe('remove', () => {
344
- test('removes a todo by ID', () => {
345
- const list = createTodoList()
346
- const todo = list.add('Buy groceries')
347
-
348
- list.remove(todo.id)
349
-
350
- expect(list.getAll()).toHaveLength(0)
351
- })
352
-
353
- test('keeps other items when removing one', () => {
354
- const list = createTodoList()
355
- const first = list.add('First')
356
- list.add('Second')
357
-
358
- list.remove(first.id)
359
-
360
- expect(list.getAll()).toHaveLength(1)
361
- expect(list.getAll()[0].text).toBe('Second')
362
- })
363
-
364
- test('throws when ID does not exist', () => {
365
- const list = createTodoList()
366
- expect(() => list.remove(999)).toThrow('Todo with id 999 not found')
367
- })
368
- })
369
-
370
- describe('toggle', () => {
371
- test('marks a todo as completed', () => {
372
- const list = createTodoList()
373
- const todo = list.add('Buy groceries')
374
-
375
- list.toggle(todo.id)
376
-
377
- expect(list.getAll()[0].completed).toBe(true)
378
- })
379
-
380
- test('toggles back to incomplete', () => {
381
- const list = createTodoList()
382
- const todo = list.add('Buy groceries')
383
-
384
- list.toggle(todo.id)
385
- list.toggle(todo.id)
386
-
387
- expect(list.getAll()[0].completed).toBe(false)
388
- })
389
-
390
- test('throws when ID does not exist', () => {
391
- const list = createTodoList()
392
- expect(() => list.toggle(999)).toThrow('Todo with id 999 not found')
393
- })
394
- })
395
-
396
- describe('getCompleted', () => {
397
- test('returns only completed todos', () => {
398
- const list = createTodoList()
399
- const buy = list.add('Buy groceries')
400
- list.add('Clean house')
401
- list.toggle(buy.id)
402
-
403
- const completed = list.getCompleted()
404
-
405
- expect(completed).toHaveLength(1)
406
- expect(completed[0].text).toBe('Buy groceries')
407
- })
408
-
409
- test('returns empty array when nothing is completed', () => {
410
- const list = createTodoList()
411
- list.add('Buy groceries')
412
-
413
- expect(list.getCompleted()).toHaveLength(0)
414
- })
415
- })
416
- ```
417
-
418
- Each `describe` block focuses on one method. Each test verifies one specific behavior. The test names read like a specification of what the module does. And if any of these tests fail, the name and the assertion will tell you exactly what broke.
419
-
420
- ::: tip
421
- Notice that we create a fresh `createTodoList()` in every test. This keeps tests independent, which means they can run in any order without affecting each other. If you find yourself repeating the same setup in every test, that's a good candidate for [`beforeEach`](/api/hooks#beforeeach) or a [`test.extend`](/guide/test-context#extend-test-context) fixture.
422
- :::
423
-
424
- ::: details What about `nextId`?
425
- The `nextId` counter at the top of the module is shared across all calls to `createTodoList()`, including across tests. This means IDs aren't predictable: one test might get IDs 1 and 2, while another gets 3 and 4 depending on execution order. This works fine here because the tests only check *relative* uniqueness (`first.id !== second.id`), not specific ID values. If a test asserted `expect(todo.id).toBe(1)`, it would break depending on which tests ran before it. When you have shared module-level state like this, make sure your tests don't depend on its specific value.
426
- :::
427
-
428
- ---
429
-
430
- If you're building a web application and want to test components in a real browser environment, check out [Component Testing](/guide/browser/component-testing) for testing React, Vue, Svelte, and other UI frameworks.
@@ -1,127 +0,0 @@
1
- # Writing Tests with AI
2
-
3
- AI coding assistants can help you write tests faster, but the quality of the output depends heavily on what you put in. A vague prompt produces vague tests. A specific prompt with the right context produces tests that are actually worth keeping.
4
-
5
- This page covers how to get good test code from AI tools, and what to watch for when reviewing the results.
6
-
7
- ## Providing Context
8
-
9
- The single most important thing you can do is give the AI enough context to understand what it's testing.
10
-
11
- Start with the source file itself. The AI needs to see the actual implementation, not just a description of what the function does. Include the full file, or at least the function you want tested along with its imports and types.
12
-
13
- Share existing test files from the same project. This helps the AI match your conventions: whether you use `test` or `it`, how you structure `describe` blocks, whether you prefer `test.extend` fixtures or `beforeEach`, and how you name your tests. AI tools are good at pattern matching, but they need patterns to match against.
14
-
15
- Include your Vitest config, especially if you've enabled [`globals`](/config/globals), set a custom [`environment`](/config/environment), or configured [`setupFiles`](/config/setupfiles). Without this context, the AI might generate unnecessary imports, use the wrong test environment, or miss setup that your tests depend on.
16
-
17
- If the code under test has dependencies that need mocking, share those files too (or at least their type signatures). The AI can't write a useful mock for a database client it's never seen.
18
-
19
- ::: tip
20
- If your project has an `AGENTS.md` or similar file with coding conventions, include that as well. Many AI tools pick up on these automatically and will follow the rules defined there.
21
- :::
22
-
23
- ## Writing Good Prompts
24
-
25
- Specific prompts produce better tests than generic ones. Compare these two:
26
-
27
- **Vague:** "Write tests for `userService.js`"
28
-
29
- This will produce tests, but they'll likely be shallow: one happy-path test per function, minimal edge case coverage, and generic test names.
30
-
31
- **Better:** "Write tests for the `createUser` function in `userService.js`. Cover validation errors (missing name, invalid email format, duplicate email), the successful creation path, and verify that the password is hashed before being stored."
32
-
33
- This tells the AI exactly which function to focus on, which scenarios matter, and what behavior to verify. The output will be more thorough and more relevant.
34
-
35
- ### Tips for Better Prompts
36
-
37
- - Ask for edge cases explicitly. "Include tests for empty inputs, boundary values, and error handling" produces more comprehensive coverage than leaving it to the AI's judgment. Without this nudge, most tools will generate a handful of happy-path tests and stop there.
38
- - Mention specific Vitest features if you want them used. "Use `toMatchInlineSnapshot` for the error messages" or "use `test.each` for the different currency formats" guides the AI toward the right tools instead of letting it fall back to repetitive copy-paste tests.
39
- - If you're testing async code, say so. "The function returns a Promise" or "this calls an external API" helps the AI use `async`/`await` and appropriate matchers like `.resolves` and `.rejects`.
40
- - Tell the AI what *not* to do. "Test against the real implementation, don't mock any modules" or "don't use snapshot tests" prevents common defaults you don't want. AI tools tend to over-mock, and an explicit constraint prevents that.
41
- - Describe the test structure you want. "Group tests by method using `describe` blocks" or "use `test.extend` fixtures for the database connection instead of `beforeEach`" saves you from restructuring the output afterwards.
42
- - Reference existing tests when asking for additions. "Follow the same style as the tests in `auth.test.js`" is more effective than describing the style from scratch. The AI will pick up on naming conventions, assertion patterns, and import styles from the example.
43
- - If the first result isn't right, iterate. "These tests are too focused on implementation details. Rewrite them to only assert on the return values and thrown errors" is a valid follow-up. Refining through conversation often produces better results than trying to write the perfect prompt upfront.
44
-
45
- ## Reviewing AI-Generated Tests
46
-
47
- AI-generated tests can look convincing at first glance but still have problems. Here's what to check before committing them.
48
-
49
- ### Do the tests actually assert something meaningful?
50
-
51
- Watch for tests that call a function but only check that it doesn't throw, or tests that assert on the mock itself rather than the behavior. A test like this gives false confidence:
52
-
53
- ```js
54
- test('creates a user', () => {
55
- const user = createUser('Alice', 'alice@example.com')
56
- expect(user).toBeDefined() // this passes for almost anything
57
- })
58
- ```
59
-
60
- A better assertion checks the actual properties:
61
-
62
- ```js
63
- test('creates a user with the correct fields', () => {
64
- const user = createUser('Alice', 'alice@example.com')
65
- expect(user).toMatchObject({
66
- name: 'Alice',
67
- email: 'alice@example.com',
68
- })
69
- expect(user.id).toBeTypeOf('string')
70
- })
71
- ```
72
-
73
- ### Are they testing behavior or implementation?
74
-
75
- AI tends to over-mock. If you see a test that mocks every dependency and then asserts that specific internal methods were called in a specific order, that's testing implementation details. These tests break every time you refactor, even if the behavior stays the same.
76
-
77
- Ask yourself: if someone changed the internals but the function still returned the correct result, would this test break? If yes, it's probably too coupled to the implementation. See [Testing in Practice](/guide/learn/testing-in-practice#what-to-test) for more on this distinction.
78
-
79
- ### Do the tests actually run?
80
-
81
- Always run the tests before committing. AI-generated tests can have import errors, reference functions that don't exist, or use APIs incorrectly. A test that looks correct in a chat window might fail immediately when you actually execute it:
82
-
83
- ```bash
84
- vitest run src/userService.test.js
85
- ```
86
-
87
- ### Are there real edge cases?
88
-
89
- AI tools tend to generate happy-path tests and skip the hard cases. After reviewing the generated tests, ask yourself: what happens with empty input? What about `null` or `undefined`? What if the network request fails? What if the list is empty?
90
-
91
- If these scenarios aren't covered, ask the AI to add them, or write them yourself.
92
-
93
- ## Iterating on the Output
94
-
95
- Treat AI-generated tests as a first draft, not a finished product. A good workflow looks like:
96
-
97
- 1. **Generate** the initial tests with a specific prompt and good context
98
- 2. **Run** them immediately to catch errors
99
- 3. **Review** each test for the issues described above
100
- 4. **Ask for revisions** if entire sections need improvement ("these tests mock too much, rewrite them to test the actual integration with the database module")
101
- 5. **Edit manually** for small fixes rather than re-prompting for every detail
102
-
103
- Over time, as the AI sees more of your codebase and test patterns, its output will improve. The earlier tests in your project set the pattern for everything that follows, so it's worth getting those right.
104
-
105
- ## Common Pitfalls
106
-
107
- ### Wrong APIs
108
-
109
- The most frequent issue with AI-generated Vitest tests is using the wrong API surface. AI models are trained on a lot of Jest code, so they sometimes generate `jest.fn()` instead of `vi.fn()`, or `jest.mock` instead of `vi.mock`. These will fail immediately.
110
-
111
- A related problem is imports: if your config has `globals: true`, the AI might still add `import { test, expect } from 'vitest'` (harmless but unnecessary), or the reverse, generating tests without imports when globals aren't enabled. If you keep seeing Jest APIs, point the AI to the [Vitest API reference](/api/vi) or include it in the context.
112
-
113
- ### Mock Cleanup
114
-
115
- AI-generated tests often set up spies with `vi.spyOn` or replace modules with `vi.mock` but never restore them. If your config doesn't have [`restoreMocks: true`](/config/restoremocks), these mocks leak between tests and cause confusing failures. The easiest fix is enabling that config option globally.
116
-
117
- On a related note, AI tools tend to mock modules using string paths (`vi.mock('./module.js')`) when the `import()` form (`vi.mock(import('./module.js'))`) is preferable for type safety and automatic refactoring. See [Mock Functions](/guide/learn/mock-functions#mocking-modules) for why this matters.
118
-
119
- ### Verbose Test Names
120
-
121
- AI tends to produce names like "should correctly return the formatted price string when given a valid positive number and a supported currency code." These are hard to scan when you have dozens of tests. Shorter names that describe the behavior work better: "formats USD prices", "throws for negative amounts", "returns empty array when no items match."
122
-
123
- ### Watch Mode
124
-
125
- Vitest runs in watch mode by default, waiting for file changes and re-running tests interactively. Vitest tries to detect CI and non-interactive or agent environments and disable watch mode automatically, but this detection can be fragile.
126
-
127
- When telling an AI agent to run tests, always use `vitest run` or `vitest --no-watch` to ensure the process exits after the tests finish.