@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,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.