@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,1171 +0,0 @@
1
- # Locators
2
-
3
- A locator is a representation of an element or a number of elements. Every locator is defined by a string called a selector. Vitest abstracts this selector by providing convenient methods that generate them behind the scenes.
4
-
5
- The locator API uses a fork of [Playwright's locators](https://playwright.dev/docs/api/class-locator) called [Ivya](https://npmx.dev/ivya). However, Vitest provides this API to every [provider](/config/browser/provider), not just playwright.
6
-
7
- ::: tip
8
- This page covers API usage. To better understand locators and their usage, read [Playwright's "Locators" documentation](https://playwright.dev/docs/locators).
9
- :::
10
-
11
- ::: tip Difference from `testing-library`
12
- Vitest's `page.getBy*` methods return a locator object, not a DOM element. This makes locator queries composable and allows Vitest to retry interactions and assertions when needed.
13
-
14
- Compared to testing-library queries:
15
-
16
- - Use locator chaining (`.getBy*`, `.filter`, `.nth`) instead of `within(...)`.
17
- - Keep locators around and interact with them later (`await locator.click()`), instead of resolving elements up front.
18
- - Single-element escape hatches like `.element()` and `.query()` are strict and throw if multiple elements match.
19
-
20
- ```ts
21
- import { expect } from 'vitest'
22
- import { page } from 'vitest/browser'
23
-
24
- const deleteButton = page
25
- .getByRole('row')
26
- .filter({ hasText: 'Vitest' })
27
- .getByRole('button', { name: /delete/i })
28
-
29
- await deleteButton.click()
30
- await expect.element(deleteButton).toBeEnabled()
31
- ```
32
- :::
33
-
34
- ## getByRole
35
-
36
- ```ts
37
- function getByRole(
38
- role: ARIARole | string,
39
- options?: LocatorByRoleOptions,
40
- ): Locator
41
- ```
42
-
43
- Creates a way to locate an element by its [ARIA role](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles), [ARIA attributes](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes) and [accessible name](https://developer.mozilla.org/en-US/docs/Glossary/Accessible_name).
44
-
45
- ::: tip
46
- If you only query for a single element with `getByText('The name')` it's oftentimes better to use `getByRole(expectedRole, { name: 'The name' })`. The accessible name query does not replace other queries such as `*ByAltText` or `*ByTitle`. While the accessible name can be equal to these attributes, it does not replace the functionality of these attributes.
47
- :::
48
-
49
- Consider the following DOM structure.
50
-
51
- ```html
52
- <h3>Sign up</h3>
53
- <label>
54
- Login
55
- <input type="text" />
56
- </label>
57
- <label>
58
- Password
59
- <input type="password" />
60
- </label>
61
- <br/>
62
- <button>Submit</button>
63
- ```
64
-
65
- You can locate each element by its implicit role:
66
-
67
- ```ts
68
- await expect.element(
69
- page.getByRole('heading', { name: 'Sign up' })
70
- ).toBeVisible()
71
-
72
- await page.getByRole('textbox', { name: 'Login' }).fill('admin')
73
- await page.getByRole('textbox', { name: 'Password' }).fill('admin')
74
-
75
- await page.getByRole('button', { name: /submit/i }).click()
76
- ```
77
-
78
- ::: warning
79
- Roles are matched by string equality, without inheriting from the ARIA role hierarchy. As a result, querying a superclass role like `checkbox` will not include elements with a subclass role like `switch`.
80
-
81
- By default, many semantic elements in HTML have a role; for example, `<input type="radio">` has the "radio" role. Non-semantic elements in HTML do not have a role; `<div>` and `<span>` without added semantics return `null`. The `role` attribute can provide semantics.
82
-
83
- Providing roles via `role` or `aria-*` attributes to built-in elements that already have an implicit role is **highly discouraged** by ARIA guidelines.
84
- :::
85
-
86
- **Options**
87
-
88
- - `exact: boolean`
89
-
90
- Whether the `name` is matched exactly: case-sensitive and whole-string. Disabled by default. This option is ignored if `name` is a regular expression. Note that exact match still trims whitespace.
91
-
92
- ```tsx
93
- <button>Hello World</button>
94
-
95
- page.getByRole('button', { name: 'hello world' }) // ✅
96
- page.getByRole('button', { name: 'hello world', exact: true }) // ❌
97
- page.getByRole('button', { name: 'Hello World', exact: true }) // ✅
98
- ```
99
-
100
- - `checked: boolean`
101
-
102
- Should checked elements (set by `aria-checked` or `<input type="checkbox"/>`) be included or not. By default, the filter is not applied.
103
-
104
- See [`aria-checked`](https://www.w3.org/TR/wai-aria-1.2/#aria-checked) for more information
105
-
106
- ```tsx
107
- <>
108
- <button role="checkbox" aria-checked="true" />
109
- <input type="checkbox" checked />
110
- </>
111
-
112
- page.getByRole('checkbox', { checked: true }) // ✅
113
- page.getByRole('checkbox', { checked: false }) // ❌
114
- ```
115
-
116
- - `disabled: boolean`
117
-
118
- Should disabled elements be included or not. By default, the filter is not applied. Note that unlike other attributes, `disable` state is inherited.
119
-
120
- See [`aria-disabled`](https://www.w3.org/TR/wai-aria-1.2/#aria-disabled) for more information
121
-
122
- ```tsx
123
- <input type="text" disabled />
124
-
125
- page.getByRole('textbox', { disabled: true }) // ✅
126
- page.getByRole('textbox', { disabled: false }) // ❌
127
- ```
128
-
129
- - `expanded: boolean`
130
-
131
- Should expanded elements be included or not. By default, the filter is not applied.
132
-
133
- See [`aria-expanded`](https://www.w3.org/TR/wai-aria-1.2/#aria-expanded) for more information
134
-
135
- ```tsx
136
- <a aria-expanded="true" href="example.com">Link</a>
137
-
138
- page.getByRole('link', { expanded: true }) // ✅
139
- page.getByRole('link', { expanded: false }) // ❌
140
- ```
141
-
142
- - `includeHidden: boolean`
143
-
144
- Should elements that are [normally excluded](https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion) from the accessibility tree be queried. By default, only non-hidden elements are matched by role selector.
145
-
146
- Note that roles `none` and `presentation` are always included.
147
-
148
- ```tsx
149
- <button style="display: none" />
150
-
151
- page.getByRole('button') // ❌
152
- page.getByRole('button', { includeHidden: false }) // ❌
153
- page.getByRole('button', { includeHidden: true }) // ✅
154
- ```
155
-
156
- - `level: number`
157
-
158
- A number attribute that is usually present for `heading`, `listitem`, `row`, `treeitem` roles with default values for `<h1>-<h6>` elements. By default, the filter is not applied.
159
-
160
- See [`aria-level`](https://www.w3.org/TR/wai-aria-1.2/#aria-level) for more information
161
-
162
- ```tsx
163
- <>
164
- <h1>Heading Level One</h1>
165
- <div role="heading" aria-level="1">Second Heading Level One</div>
166
- </>
167
-
168
- page.getByRole('heading', { level: 1 }) // ✅
169
- page.getByRole('heading', { level: 2 }) // ❌
170
- ```
171
-
172
- - `name: string | RegExp`
173
-
174
- [An accessible name](https://developer.mozilla.org/en-US/docs/Glossary/Accessible_name). By default, matching is case-insensitive and searches for a substring. Use `exact` option to control this behavior.
175
-
176
- ```tsx
177
- <button>Click Me!</button>
178
-
179
- page.getByRole('button', { name: 'Click Me!' }) // ✅
180
- page.getByRole('button', { name: 'click me!' }) // ✅
181
- page.getByRole('button', { name: 'Click Me?' }) // ❌
182
- ```
183
-
184
- - `pressed: boolean`
185
-
186
- Should pressed elements be included or not. By default, the filter is not applied.
187
-
188
- See [`aria-pressed`](https://www.w3.org/TR/wai-aria-1.2/#aria-pressed) for more information
189
-
190
- ```tsx
191
- <button aria-pressed="true">👍</button>
192
-
193
- page.getByRole('button', { pressed: true }) // ✅
194
- page.getByRole('button', { pressed: false }) // ❌
195
- ```
196
-
197
- - `selected: boolean`
198
-
199
- Should selected elements be included or not. By default, the filter is not applied.
200
-
201
- See [`aria-selected`](https://www.w3.org/TR/wai-aria-1.2/#aria-selected) for more information
202
-
203
- ```tsx
204
- <button role="tab" aria-selected="true">Vue</button>
205
-
206
- page.getByRole('button', { selected: true }) // ✅
207
- page.getByRole('button', { selected: false }) // ❌
208
- ```
209
-
210
- **See also**
211
-
212
- - [List of ARIA roles at MDN](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles)
213
- - [List of ARIA roles at w3.org](https://www.w3.org/TR/wai-aria-1.2/#role_definitions)
214
- - [testing-library's `ByRole`](https://testing-library.com/docs/queries/byrole/)
215
-
216
- ## getByAltText
217
-
218
- ```ts
219
- function getByAltText(
220
- text: string | RegExp,
221
- options?: LocatorOptions,
222
- ): Locator
223
- ```
224
-
225
- Creates a locator capable of finding an element with an `alt` attribute that matches the text. Unlike testing-library's implementation, Vitest will match any element that has a matching `alt` attribute.
226
-
227
- ```tsx
228
- <img alt="Incredibles 2 Poster" src="/incredibles-2.png" />
229
-
230
- page.getByAltText(/incredibles.*? poster/i) // ✅
231
- page.getByAltText('non existing alt text') // ❌
232
- ```
233
-
234
- **Options**
235
-
236
- - `exact: boolean`
237
-
238
- Whether the `text` is matched exactly: case-sensitive and whole-string. Disabled by default. This option is ignored if `text` is a regular expression. Note that exact match still trims whitespace.
239
-
240
- **See also**
241
-
242
- - [testing-library's `ByAltText`](https://testing-library.com/docs/queries/byalttext/)
243
-
244
- ## getByLabelText
245
-
246
- ```ts
247
- function getByLabelText(
248
- text: string | RegExp,
249
- options?: LocatorOptions,
250
- ): Locator
251
- ```
252
-
253
- Creates a locator capable of finding an element that has an associated label.
254
-
255
- The `page.getByLabelText('Username')` locator will find every input in the example below:
256
-
257
- ```html
258
- // for/htmlFor relationship between label and form element id
259
- <label for="username-input">Username</label>
260
- <input id="username-input" />
261
-
262
- // The aria-labelledby attribute with form elements
263
- <label id="username-label">Username</label>
264
- <input aria-labelledby="username-label" />
265
-
266
- // Wrapper labels
267
- <label>Username <input /></label>
268
-
269
- // Wrapper labels where the label text is in another child element
270
- <label>
271
- <span>Username</span>
272
- <input />
273
- </label>
274
-
275
- // aria-label attributes
276
- // Take care because this is not a label that users can see on the page,
277
- // so the purpose of your input must be obvious to visual users.
278
- <input aria-label="Username" />
279
- ```
280
-
281
- **Options**
282
-
283
- - `exact: boolean`
284
-
285
- Whether the `text` is matched exactly: case-sensitive and whole-string. Disabled by default. This option is ignored if `text` is a regular expression. Note that exact match still trims whitespace.
286
-
287
- **See also**
288
-
289
- - [testing-library's `ByLabelText`](https://testing-library.com/docs/queries/bylabeltext/)
290
-
291
- ## getByPlaceholder
292
-
293
- ```ts
294
- function getByPlaceholder(
295
- text: string | RegExp,
296
- options?: LocatorOptions,
297
- ): Locator
298
- ```
299
-
300
- Creates a locator capable of finding an element that has the specified `placeholder` attribute. Vitest will match any element that has a matching `placeholder` attribute, not just `input`.
301
-
302
- ```tsx
303
- <input placeholder="Username" />
304
-
305
- page.getByPlaceholder('Username') // ✅
306
- page.getByPlaceholder('not found') // ❌
307
- ```
308
-
309
- ::: warning
310
- It is generally better to rely on a label using [`getByLabelText`](#getbylabeltext) than a placeholder.
311
- :::
312
-
313
- **Options**
314
-
315
- - `exact: boolean`
316
-
317
- Whether the `text` is matched exactly: case-sensitive and whole-string. Disabled by default. This option is ignored if `text` is a regular expression. Note that exact match still trims whitespace.
318
-
319
- **See also**
320
-
321
- - [testing-library's `ByPlaceholderText`](https://testing-library.com/docs/queries/byplaceholdertext/)
322
-
323
- ## getByText
324
-
325
- ```ts
326
- function getByText(
327
- text: string | RegExp,
328
- options?: LocatorOptions,
329
- ): Locator
330
- ```
331
-
332
- Creates a locator capable of finding an element that contains the specified text. The text will be matched against TextNode's [`nodeValue`](https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeValue) or input's value if the type is `button` or `reset`. Matching by text always normalizes whitespace, even with exact match. For example, it turns multiple spaces into one, turns line breaks into spaces and ignores leading and trailing whitespace.
333
-
334
- ```tsx
335
- <a href="/about">About ℹ️</a>
336
-
337
- page.getByText(/about/i) // ✅
338
- page.getByText('about', { exact: true }) // ❌
339
- ```
340
-
341
- ::: tip
342
- This locator is useful for locating non-interactive elements. If you need to locate an interactive element, like a button or an input, prefer [`getByRole`](#getbyrole).
343
- :::
344
-
345
- **Options**
346
-
347
- - `exact: boolean`
348
-
349
- Whether the `text` is matched exactly: case-sensitive and whole-string. Disabled by default. This option is ignored if `text` is a regular expression. Note that exact match still trims whitespace.
350
-
351
- **See also**
352
-
353
- - [testing-library's `ByText`](https://testing-library.com/docs/queries/bytext/)
354
-
355
- ## getByTitle
356
-
357
- ```ts
358
- function getByTitle(
359
- text: string | RegExp,
360
- options?: LocatorOptions,
361
- ): Locator
362
- ```
363
-
364
- Creates a locator capable of finding an element that has the specified `title` attribute. Unlike testing-library's `getByTitle`, Vitest cannot find `title` elements within an SVG.
365
-
366
- ```tsx
367
- <span title="Delete" id="2"></span>
368
-
369
- page.getByTitle('Delete') // ✅
370
- page.getByTitle('Create') // ❌
371
- ```
372
-
373
- **Options**
374
-
375
- - `exact: boolean`
376
-
377
- Whether the `text` is matched exactly: case-sensitive and whole-string. Disabled by default. This option is ignored if `text` is a regular expression. Note that exact match still trims whitespace.
378
-
379
- **See also**
380
-
381
- - [testing-library's `ByTitle`](https://testing-library.com/docs/queries/bytitle/)
382
-
383
- ## getByTestId
384
-
385
- ```ts
386
- function getByTestId(text: string | RegExp): Locator
387
- ```
388
-
389
- Creates a locator capable of finding an element that matches the specified test id attribute. You can configure the attribute name with [`browser.locators.testIdAttribute`](/config/browser/locators#testidattribute).
390
-
391
- ```tsx
392
- <div data-testid="custom-element" />
393
-
394
- page.getByTestId('custom-element') // ✅
395
- page.getByTestId('non-existing-element') // ❌
396
- ```
397
-
398
- ::: warning
399
- It is recommended to use this only after the other locators don't work for your use case. Using `data-testid` attributes does not resemble how your software is used and should be avoided if possible.
400
- :::
401
-
402
- **Options**
403
-
404
- - `exact: boolean`
405
-
406
- Whether the `text` is matched exactly: case-sensitive and whole-string. Disabled by default. This option is ignored if `text` is a regular expression. Note that exact match still trims whitespace.
407
-
408
- **See also**
409
-
410
- - [testing-library's `ByTestId`](https://testing-library.com/docs/queries/bytestid/)
411
-
412
- ## nth
413
-
414
- ```ts
415
- function nth(index: number): Locator
416
- ```
417
-
418
- This method returns a new locator that matches only a specific index within a multi-element query result. It's zero based, `nth(0)` selects the first element. Unlike `elements()[n]`, the `nth` locator will be retried until the element is present.
419
-
420
- ```html
421
- <div aria-label="one"><input/><input/><input/></div>
422
- <div aria-label="two"><input/></div>
423
- ```
424
-
425
- ```tsx
426
- page.getByRole('textbox').nth(0) // ✅
427
- page.getByRole('textbox').nth(4) // ❌
428
- ```
429
-
430
- ::: tip
431
- Before resorting to `nth`, you may find it useful to use chained locators to narrow down your search.
432
- Sometimes there is no better way to distinguish than by element position; although this can lead to flake, it's better than nothing.
433
- :::
434
-
435
- ```tsx
436
- page.getByLabel('two').getByRole('input') // ✅ better alternative to page.getByRole('textbox').nth(3)
437
- page.getByLabel('one').getByRole('input') // ❌ too ambiguous
438
- page.getByLabel('one').getByRole('input').nth(1) // ✅ pragmatic compromise
439
- ```
440
-
441
- ## first
442
-
443
- ```ts
444
- function first(): Locator
445
- ```
446
-
447
- This method returns a new locator that matches only the first index of a multi-element query result.
448
- It is sugar for `nth(0)`.
449
-
450
- ```html
451
- <input/> <input/> <input/>
452
- ```
453
-
454
- ```tsx
455
- page.getByRole('textbox').first() // ✅
456
- ```
457
-
458
- ## last
459
-
460
- ```ts
461
- function last(): Locator
462
- ```
463
-
464
- This method returns a new locator that matches only the last index of a multi-element query result.
465
- It is sugar for `nth(-1)`.
466
-
467
- ```html
468
- <input/> <input/> <input/>
469
- ```
470
-
471
- ```tsx
472
- page.getByRole('textbox').last() // ✅
473
- ```
474
-
475
- ## and
476
-
477
- ```ts
478
- function and(locator: Locator): Locator
479
- ```
480
-
481
- This method creates a new locator that matches both the parent and provided locator. The following example finds a button with a specific title:
482
-
483
- ```ts
484
- page.getByRole('button').and(page.getByTitle('Subscribe'))
485
- ```
486
-
487
- ## or
488
-
489
- ```ts
490
- function or(locator: Locator): Locator
491
- ```
492
-
493
- This method creates a new locator that matches either one or both locators.
494
-
495
- ::: warning
496
- Note that if locator matches more than a single element, calling another method might throw an error if it expects a single element:
497
-
498
- ```tsx
499
- <>
500
- <button>Click me</button>
501
- <a href="https://vitest.dev">Error happened!</a>
502
- </>
503
-
504
- page.getByRole('button')
505
- .or(page.getByRole('link'))
506
- .click() // ❌ matches multiple elements
507
- ```
508
- :::
509
-
510
- ## filter
511
-
512
- ```ts
513
- function filter(options: LocatorOptions): Locator
514
- ```
515
-
516
- This methods narrows down the locator according to the options, such as filtering by text. It can be chained to apply multiple filters.
517
-
518
- ### has
519
-
520
- - **Type:** `Locator`
521
-
522
- This options narrows down the selector to match elements that contain other elements matching provided locator. For example, with this HTML:
523
-
524
- ```html{1,3}
525
- <article>
526
- <div>Vitest</div>
527
- </article>
528
- <article>
529
- <div>Rolldown</div>
530
- </article>
531
- ```
532
-
533
- We can narrow down the locator to only find the `article` with `Vitest` text inside:
534
-
535
- ```ts
536
- page.getByRole('article').filter({ has: page.getByText('Vitest') }) // ✅
537
- ```
538
-
539
- ::: warning
540
- Provided locator (`page.getByText('Vitest')` in the example) must be relative to the parent locator (`page.getByRole('article')` in the example). It will be queried starting with the parent locator, not the document root.
541
-
542
- Meaning, you cannot pass down a locator that queries the element outside of the parent locator:
543
-
544
- ```ts
545
- page.getByText('Vitest').filter({ has: page.getByRole('article') }) // ❌
546
- ```
547
-
548
- This example will fail because the `article` element is outside the element with `Vitest` text.
549
- :::
550
-
551
- ::: tip
552
- This method can be chained to narrow down the element even further:
553
-
554
- ```ts
555
- page.getByRole('article')
556
- .filter({ has: page.getByRole('button', { name: 'delete row' }) })
557
- .filter({ has: page.getByText('Vitest') })
558
- ```
559
- :::
560
-
561
- ### hasNot
562
-
563
- - **Type:** `Locator`
564
-
565
- This option narrows down the selector to match elements that do not contain other elements matching provided locator. For example, with this HTML:
566
-
567
- ```html{1,3}
568
- <article>
569
- <div>Vitest</div>
570
- </article>
571
- <article>
572
- <div>Rolldown</div>
573
- </article>
574
- ```
575
-
576
- We can narrow down the locator to only find the `article` that doesn't have `Rolldown` inside.
577
-
578
- ```ts
579
- page.getByRole('article')
580
- .filter({ hasNot: page.getByText('Rolldown') }) // ✅
581
- page.getByRole('article')
582
- .filter({ hasNot: page.getByText('Vitest') }) // ❌
583
- ```
584
-
585
- ::: warning
586
- Note that provided locator is queried against the parent, not the document root, just like [`has`](#has) option.
587
- :::
588
-
589
- ### hasText
590
-
591
- - **Type:** `string | RegExp`
592
-
593
- This options narrows down the selector to only match elements that contain provided text somewhere inside. When the `string` is passed, matching is case-insensitive and searches for a substring.
594
-
595
- ```html{1,3}
596
- <article>
597
- <div>Vitest</div>
598
- </article>
599
- <article>
600
- <div>Rolldown</div>
601
- </article>
602
- ```
603
-
604
- Both locators will find the same element because the search is case-insensitive:
605
-
606
- ```ts
607
- page.getByRole('article').filter({ hasText: 'Vitest' }) // ✅
608
- page.getByRole('article').filter({ hasText: 'Vite' }) // ✅
609
- ```
610
-
611
- ### hasNotText
612
-
613
- - **Type:** `string | RegExp`
614
-
615
- This options narrows down the selector to only match elements that do not contain provided text somewhere inside. When the `string` is passed, matching is case-insensitive and searches for a substring.
616
-
617
- ## Methods
618
-
619
- All methods are asynchronous and must be awaited. Since Vitest 3, tests will fail if a method is not awaited.
620
-
621
- ### click
622
-
623
- ```ts
624
- function click(options?: UserEventClickOptions): Promise<void>
625
- ```
626
-
627
- Click on an element. You can use the options to set the cursor position.
628
-
629
- ```ts
630
- import { page } from 'vitest/browser'
631
-
632
- await page.getByRole('img', { name: 'Rose' }).click()
633
- ```
634
-
635
- - [See more at `userEvent.click`](/api/browser/interactivity#userevent-click)
636
-
637
- ### dblClick
638
-
639
- ```ts
640
- function dblClick(options?: UserEventDoubleClickOptions): Promise<void>
641
- ```
642
-
643
- Triggers a double click event on an element. You can use the options to set the cursor position.
644
-
645
- ```ts
646
- import { page } from 'vitest/browser'
647
-
648
- await page.getByRole('img', { name: 'Rose' }).dblClick()
649
- ```
650
-
651
- - [See more at `userEvent.dblClick`](/api/browser/interactivity#userevent-dblclick)
652
-
653
- ### tripleClick
654
-
655
- ```ts
656
- function tripleClick(options?: UserEventTripleClickOptions): Promise<void>
657
- ```
658
-
659
- Triggers a triple click event on an element. Since there is no `tripleclick` in browser api, this method will fire three click events in a row.
660
-
661
- ```ts
662
- import { page } from 'vitest/browser'
663
-
664
- await page.getByRole('img', { name: 'Rose' }).tripleClick()
665
- ```
666
-
667
- - [See more at `userEvent.tripleClick`](/api/browser/interactivity#userevent-tripleclick)
668
-
669
- ### wheel <Version>4.1.0</Version> {#wheel}
670
-
671
- ```ts
672
- function wheel(options: UserEventWheelOptions): Promise<void>
673
- ```
674
-
675
- Triggers a [`wheel` event](https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event) on an element. You can use the options to choose a general scroll `direction` or a precise `delta` value.
676
-
677
- ```ts
678
- import { page } from 'vitest/browser'
679
-
680
- // Scroll right
681
- await page.getByRole('tablist').wheel({ direction: 'right' })
682
- ```
683
-
684
- - [See more at `userEvent.wheel`](/api/browser/interactivity#userevent-wheel)
685
-
686
- ### clear
687
-
688
- ```ts
689
- function clear(options?: UserEventClearOptions): Promise<void>
690
- ```
691
-
692
- Clears the input element content.
693
-
694
- ```ts
695
- import { page } from 'vitest/browser'
696
-
697
- await page.getByRole('textbox', { name: 'Full Name' }).clear()
698
- ```
699
-
700
- - [See more at `userEvent.clear`](/api/browser/interactivity#userevent-clear)
701
-
702
- ### hover
703
-
704
- ```ts
705
- function hover(options?: UserEventHoverOptions): Promise<void>
706
- ```
707
-
708
- Moves the cursor position to the selected element.
709
-
710
- ```ts
711
- import { page } from 'vitest/browser'
712
-
713
- await page.getByRole('img', { name: 'Rose' }).hover()
714
- ```
715
-
716
- - [See more at `userEvent.hover`](/api/browser/interactivity#userevent-hover)
717
-
718
- ### unhover
719
-
720
- ```ts
721
- function unhover(options?: UserEventHoverOptions): Promise<void>
722
- ```
723
-
724
- This works the same as [`locator.hover`](#hover), but moves the cursor to the `document.body` element instead.
725
-
726
- ```ts
727
- import { page } from 'vitest/browser'
728
-
729
- await page.getByRole('img', { name: 'Rose' }).unhover()
730
- ```
731
-
732
- - [See more at `userEvent.unhover`](/api/browser/interactivity#userevent-unhover)
733
-
734
- ### fill
735
-
736
- ```ts
737
- function fill(text: string, options?: UserEventFillOptions): Promise<void>
738
- ```
739
-
740
- Sets the value of the current `input`, `textarea` or `contenteditable` element.
741
-
742
- ```ts
743
- import { page } from 'vitest/browser'
744
-
745
- await page.getByRole('input', { name: 'Full Name' }).fill('Mr. Bean')
746
- ```
747
-
748
- - [See more at `userEvent.fill`](/api/browser/interactivity#userevent-fill)
749
-
750
- ### dropTo
751
-
752
- ```ts
753
- function dropTo(
754
- target: Locator,
755
- options?: UserEventDragAndDropOptions,
756
- ): Promise<void>
757
- ```
758
-
759
- Drags the current element to the target location.
760
-
761
- ```ts
762
- import { page } from 'vitest/browser'
763
-
764
- const paris = page.getByText('Paris')
765
- const france = page.getByText('France')
766
-
767
- await paris.dropTo(france)
768
- ```
769
-
770
- - [See more at `userEvent.dragAndDrop`](/api/browser/interactivity#userevent-draganddrop)
771
-
772
- ### selectOptions
773
-
774
- ```ts
775
- function selectOptions(
776
- values:
777
- | HTMLElement
778
- | HTMLElement[]
779
- | Locator
780
- | Locator[]
781
- | string
782
- | string[],
783
- options?: UserEventSelectOptions,
784
- ): Promise<void>
785
- ```
786
-
787
- Choose one or more values from a `<select>` element.
788
-
789
- ```ts
790
- import { page } from 'vitest/browser'
791
-
792
- const languages = page.getByRole('select', { name: 'Languages' })
793
-
794
- await languages.selectOptions('EN')
795
- await languages.selectOptions(['ES', 'FR'])
796
- await languages.selectOptions([
797
- languages.getByRole('option', { name: 'Spanish' }),
798
- languages.getByRole('option', { name: 'French' }),
799
- ])
800
- ```
801
-
802
- - [See more at `userEvent.selectOptions`](/api/browser/interactivity#userevent-selectoptions)
803
-
804
- ### screenshot
805
-
806
- ```ts
807
- function screenshot(options: LocatorScreenshotOptions & { save: false }): Promise<string>
808
- function screenshot(options: LocatorScreenshotOptions & { base64: true }): Promise<{
809
- path: string
810
- base64: string
811
- }>
812
- function screenshot(options?: LocatorScreenshotOptions & { base64?: false }): Promise<string>
813
- ```
814
-
815
- Creates a screenshot of the element matching the locator's selector.
816
-
817
- You can specify the save location for the screenshot using the `path` option, which is relative to the current test file. If the `path` option is not set, Vitest will default to using [`browser.screenshotDirectory`](/config/browser/screenshotdirectory) (`__screenshot__` by default), along with the names of the file and the test to determine the screenshot's filepath.
818
-
819
- If you also need the content of the screenshot, you can specify `base64: true` to return it alongside the filepath where the screenshot is saved.
820
-
821
- ```ts
822
- import { page } from 'vitest/browser'
823
-
824
- const button = page.getByRole('button', { name: 'Click Me!' })
825
-
826
- const path = await button.screenshot()
827
-
828
- const { path, base64 } = await button.screenshot({
829
- path: './button-click-me.png',
830
- base64: true, // also return base64 string
831
- })
832
- // path - fullpath to the screenshot
833
- // bas64 - base64 encoded string of the screenshot
834
- ```
835
-
836
- ::: warning WARNING <Version>3.2.0</Version>
837
- Note that `screenshot` will always return a base64 string if `save` is set to `false`.
838
- The `path` is also ignored in that case.
839
- :::
840
-
841
- ### mark
842
-
843
- ```ts
844
- function mark(name: string, options?: { stack?: string }): Promise<void>
845
- ```
846
-
847
- Adds a named marker to the trace timeline and uses the current locator as marker context.
848
-
849
- Pass `options.stack` to override the callsite location in trace metadata. This is useful for wrapper libraries that need to preserve the end-user source location.
850
-
851
- ```ts
852
- import { page } from 'vitest/browser'
853
-
854
- const submitButton = page.getByRole('button', { name: 'Submit' })
855
-
856
- await submitButton.mark('before submit')
857
- await submitButton.click()
858
- await submitButton.mark('after submit')
859
- ```
860
-
861
- ::: tip
862
- This method is useful only when [`browser.trace`](/config/browser/trace) is enabled.
863
- :::
864
-
865
- ### query
866
-
867
- ```ts
868
- function query(): Element | null
869
- ```
870
-
871
- This method returns a single element matching the locator's selector or `null` if no element is found.
872
-
873
- If multiple elements match the selector, this method will throw an error. Use [`.elements()`](#elements) when you need all matching DOM Elements or [`.all()`](#all) if you need an array of locators matching the selector.
874
-
875
- ::: danger
876
- This is an escape hatch for external APIs that do not support locators. Prefer using locator methods instead.
877
- :::
878
-
879
- Consider the following DOM structure:
880
-
881
- ```html
882
- <div>Hello <span>World</span></div>
883
- <div>Hello</div>
884
- ```
885
-
886
- These locators will not throw an error:
887
-
888
- ```ts
889
- page.getByText('Hello World').query() // ✅ HTMLDivElement
890
- page.getByText('Hello Germany').query() // ✅ null
891
- page.getByText('World').query() // ✅ HTMLSpanElement
892
- page.getByText('Hello', { exact: true }).query() // ✅ HTMLSpanElement
893
- ```
894
-
895
- These locators will throw an error:
896
-
897
- ```ts
898
- // returns multiple elements
899
- page.getByText('Hello').query() // ❌
900
- page.getByText(/^Hello/).query() // ❌
901
- ```
902
-
903
- ### element
904
-
905
- ```ts
906
- function element(): Element
907
- ```
908
-
909
- This method returns a single element matching the locator's selector.
910
-
911
- If _no element_ matches the selector, an error is thrown. Consider using [`.query()`](#query) when you just need to check if the element exists.
912
-
913
- If _multiple elements_ match the selector, an error is thrown. Use [`.elements()`](#elements) when you need all matching DOM Elements or [`.all()`](#all) if you need an array of locators matching the selector.
914
-
915
- ::: danger
916
- This is an escape hatch for external APIs that do not support locators. Prefer using locator methods instead.
917
-
918
- It is called automatically when locator is used with `expect.element` every time the assertion is [retried](/api/browser/assertions):
919
-
920
- ```ts
921
- await expect.element(page.getByRole('button')).toBeDisabled()
922
- ```
923
- :::
924
-
925
- Consider the following DOM structure:
926
-
927
- ```html
928
- <div>Hello <span>World</span></div>
929
- <div>Hello Germany</div>
930
- <div>Hello</div>
931
- ```
932
-
933
- These locators will not throw an error:
934
-
935
- ```ts
936
- page.getByText('Hello World').element() // ✅
937
- page.getByText('Hello Germany').element() // ✅
938
- page.getByText('World').element() // ✅
939
- page.getByText('Hello', { exact: true }).element() // ✅
940
- ```
941
-
942
- These locators will throw an error:
943
-
944
- ```ts
945
- // returns multiple elements
946
- page.getByText('Hello').element() // ❌
947
- page.getByText(/^Hello/).element() // ❌
948
-
949
- // returns no elements
950
- page.getByText('Hello USA').element() // ❌
951
- ```
952
-
953
- ### elements
954
-
955
- ```ts
956
- function elements(): Element[]
957
- ```
958
-
959
- This method returns an array of elements matching the locator's selector.
960
-
961
- This function never throws an error. If there are no elements matching the selector, this method will return an empty array.
962
-
963
- Consider the following DOM structure:
964
-
965
- ```html
966
- <div>Hello <span>World</span></div>
967
- <div>Hello</div>
968
- ```
969
-
970
- These locators will always succeed:
971
-
972
- ```ts
973
- page.getByText('Hello World').elements() // ✅ [HTMLElement]
974
- page.getByText('World').elements() // ✅ [HTMLElement]
975
- page.getByText('Hello', { exact: true }).elements() // ✅ [HTMLElement]
976
- page.getByText('Hello').elements() // ✅ [HTMLElement, HTMLElement]
977
- page.getByText('Hello USA').elements() // ✅ []
978
- ```
979
-
980
- ### findElement <Version>4.1.0</Version> {#findelement}
981
-
982
- ```ts
983
- function findElement(
984
- options?: SelectorOptions
985
- ): Promise<HTMLElement | SVGElement>
986
- ```
987
-
988
- ::: danger WARNING
989
- This is an escape hatch for cases where you need the raw DOM element — for example, to pass it to a third-party library like FormKit that doesn't accept Vitest locators. If you are interacting with the element yourself, use other [builtin methods](#methods) instead.
990
- :::
991
-
992
- This method returns an element matching the locator. Unlike [`.element()`](#element), this method will wait and retry until a matching element appears in the DOM, using increasing intervals (0, 20, 50, 100, 100, 500ms).
993
-
994
- If _no element_ is found before the timeout, an error is thrown. By default, the timeout matches the test timeout.
995
-
996
- If _multiple elements_ match the selector and `strict` is `true` (the default), an error is thrown immediately without retrying. Set `strict` to `false` to return the first matching element instead.
997
-
998
- It accepts options:
999
-
1000
- - `timeout: number` - How long to wait in milliseconds until at least one element is found. By default, this shares timeout with the test.
1001
- - `strict: boolean` - When `true` (default), throws an error if multiple elements match the locator. When `false`, returns the first matching element.
1002
-
1003
- Consider the following DOM structure:
1004
-
1005
- ```html
1006
- <div>Hello <span>World</span></div>
1007
- <div>Hello Germany</div>
1008
- <div>Hello</div>
1009
- ```
1010
-
1011
- These locators will resolve successfully:
1012
-
1013
- ```ts
1014
- await page.getByText('Hello World').findElement() // ✅ HTMLDivElement
1015
- await page.getByText('World').findElement() // ✅ HTMLSpanElement
1016
- await page.getByText('Hello Germany').findElement() // ✅ HTMLDivElement
1017
- ```
1018
-
1019
- These locators will throw an error:
1020
-
1021
- ```ts
1022
- // multiple elements match, strict mode rejects
1023
- await page.getByText('Hello').findElement() // ❌
1024
- await page.getByText(/^Hello/).findElement() // ❌
1025
-
1026
- // no matching element before timeout
1027
- await page.getByText('Hello USA').findElement() // ❌
1028
- ```
1029
-
1030
- Using `strict: false` to allow multiple matches:
1031
-
1032
- ```ts
1033
- // returns the first matching element instead of throwing
1034
- await page.getByText('Hello').findElement({ strict: false }) // ✅ HTMLDivElement
1035
- ```
1036
-
1037
- ### all
1038
-
1039
- ```ts
1040
- function all(): Locator[]
1041
- ```
1042
-
1043
- This method returns an array of new locators that match the selector.
1044
-
1045
- Internally, this method calls `.elements` and wraps every element using [`page.elementLocator`](/api/browser/context#page).
1046
-
1047
- - [See `locator.elements()`](#elements)
1048
-
1049
- ## Properties
1050
-
1051
- ### selector
1052
-
1053
- The `selector` is a string that will be used to locate the element by the browser provider. Playwright will use a `playwright` locator syntax while `preview` and `webdriverio` will use CSS.
1054
-
1055
- ::: danger
1056
- You should not use this string in your test code. The `selector` string should only be used when working with the Commands API:
1057
-
1058
- ```ts [commands.ts]
1059
- import type { BrowserCommand } from 'vitest/node'
1060
-
1061
- const test: BrowserCommand<string> = function test(context, selector) {
1062
- // playwright
1063
- await context.iframe.locator(selector).click()
1064
- // webdriverio
1065
- await context.browser.$(selector).click()
1066
- }
1067
- ```
1068
-
1069
- ```ts [example.test.ts]
1070
- import { test } from 'vitest'
1071
- import { commands, page } from 'vitest/browser'
1072
-
1073
- test('works correctly', async () => {
1074
- await commands.test(page.getByText('Hello').selector) // ✅
1075
- // vitest will automatically unwrap it to a string
1076
- await commands.test(page.getByText('Hello')) // ✅
1077
- })
1078
- ```
1079
- :::
1080
-
1081
- ### length
1082
-
1083
- This getter returns a number of elements that this locator is matching. It is equivalent to calling `locator.elements().length`.
1084
-
1085
- Consider the following DOM structure:
1086
-
1087
- ```html
1088
- <button>Click Me!</button>
1089
- <button>Don't click me!</button>
1090
- ```
1091
-
1092
- This property will always succeed:
1093
-
1094
- ```ts
1095
- page.getByRole('button').length // ✅ 2
1096
- page.getByRole('button', { title: 'Click Me!' }).length // ✅ 1
1097
- page.getByRole('alert').length // ✅ 0
1098
- ```
1099
-
1100
- ## Custom Locators <Version>3.2.0</Version> <Badge type="danger">advanced</Badge> {#custom-locators}
1101
-
1102
- You can extend built-in locators API by defining an object of locator factories. These methods will exist as methods on the `page` object and any created locator.
1103
-
1104
- These locators can be useful if built-in locators are not enough. For example, when you use a custom framework for your UI.
1105
-
1106
- The locator factory needs to return a selector string or a locator itself.
1107
-
1108
- ::: tip
1109
- The selector syntax is identical to Playwright locators. Please, read [their guide](https://playwright.dev/docs/other-locators) to better understand how to work with them.
1110
- :::
1111
-
1112
- ```ts
1113
- import { locators } from 'vitest/browser'
1114
-
1115
- locators.extend({
1116
- getByArticleTitle(title) {
1117
- return `[data-title="${title}"]`
1118
- },
1119
- getByArticleCommentsCount(count) {
1120
- return `.comments :text("${count} comments")`
1121
- },
1122
- async previewComments() {
1123
- // you have access to the current locator via "this"
1124
- // beware that if the method was called on `page`, `this` will be `page`,
1125
- // not the locator!
1126
- if (this !== page) {
1127
- await this.click()
1128
- }
1129
- // ...
1130
- }
1131
- })
1132
-
1133
- // if you are using typescript, you can extend LocatorSelectors interface
1134
- // to have the autocompletion in locators.extend, page.* and locator.* methods
1135
- declare module 'vitest/browser' {
1136
- interface LocatorSelectors {
1137
- // if the custom method returns a string, it will be converted into a locator
1138
- // if it returns anything else, then it will be returned as usual
1139
- getByArticleTitle(title: string): Locator
1140
- getByArticleCommentsCount(count: number): Locator
1141
-
1142
- // Vitest will return a promise and won't try to convert it into a locator
1143
- previewComments(this: Locator): Promise<void>
1144
- }
1145
- }
1146
- ```
1147
-
1148
- If the method is called on the global `page` object, then selector will be applied to the whole page. In the example below, `getByArticleTitle` will find all elements with an attribute `data-title` with the value of `title`. However, if the method is called on the locator, then it will be scoped to that locator.
1149
-
1150
- ```html
1151
- <article data-title="Hello, World!">
1152
- Hello, World!
1153
- <button id="comments">2 comments</button>
1154
- </article>
1155
-
1156
- <article data-title="Hello, Vitest!">
1157
- Hello, Vitest!
1158
- <button id="comments">0 comments</button>
1159
- </article>
1160
- ```
1161
-
1162
- ```ts
1163
- const articles = page.getByRole('article')
1164
- const worldArticle = page.getByArticleTitle('Hello, World!') // ✅
1165
- const commentsElement = worldArticle.getByArticleCommentsCount(2) // ✅
1166
- const wrongCommentsElement = worldArticle.getByArticleCommentsCount(0) // ❌
1167
- const wrongElement = page.getByArticleTitle('No Article!') // ❌
1168
-
1169
- await commentsElement.previewComments() // ✅
1170
- await wrongCommentsElement.previewComments() // ❌
1171
- ```