testdriverai 6.2.2 → 7.1.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 (300) hide show
  1. package/.github/workflows/acceptance-linux.yml +75 -0
  2. package/.github/workflows/acceptance-sdk-tests.yml +133 -0
  3. package/.vscode/settings.json +5 -1
  4. package/AGENTS.md +550 -0
  5. package/CODEOWNERS +0 -1
  6. package/README.md +126 -0
  7. package/{testdriver → _testdriver}/acceptance/drag-and-drop.yaml +2 -2
  8. package/{testdriver → _testdriver}/acceptance/snippets/login.yaml +1 -1
  9. package/_testdriver/examples/desktop/lifecycle/prerun.yaml +0 -0
  10. package/{testdriver → _testdriver}/examples/web/lifecycle/prerun.yaml +6 -1
  11. package/{testdriver → _testdriver}/lifecycle/postrun.yaml +3 -2
  12. package/_testdriver/lifecycle/prerun.yaml +15 -0
  13. package/{testdriver → _testdriver}/lifecycle/provision.yaml +7 -2
  14. package/agent/index.js +300 -85
  15. package/agent/interface.js +15 -0
  16. package/agent/lib/cache.js +142 -0
  17. package/agent/lib/commander.js +1 -39
  18. package/agent/lib/commands.js +910 -296
  19. package/agent/lib/redraw.js +129 -41
  20. package/agent/lib/sandbox.js +29 -6
  21. package/agent/lib/sdk.js +22 -0
  22. package/agent/lib/system.js +0 -3
  23. package/agent/lib/validation.js +1 -7
  24. package/debug-locate-response.js +82 -0
  25. package/debugger/index.html +15 -4
  26. package/docs/ARCHITECTURE.md +424 -0
  27. package/docs/AWESOME_LOGS_QUICK_REF.md +100 -0
  28. package/docs/MIGRATION.md +425 -0
  29. package/docs/PRESETS.md +210 -0
  30. package/docs/QUICK_START_TEST_RECORDING.md +215 -0
  31. package/docs/SDK_AWESOME_LOGS.md +468 -0
  32. package/docs/TEST_RECORDING.md +388 -0
  33. package/docs/docs.json +286 -152
  34. package/docs/guide/best-practices-polling.mdx +154 -0
  35. package/docs/sdk-browser-rendering.md +167 -0
  36. package/docs/v6/getting-started/self-hosting.mdx +407 -0
  37. package/docs/{guide → v6/guide}/dashcam.mdx +1 -1
  38. package/docs/{guide → v6/guide}/environment-variables.mdx +4 -5
  39. package/docs/{guide → v6/guide}/lifecycle.mdx +1 -1
  40. package/docs/v6/overview/comparison.mdx +101 -0
  41. package/docs/v7/README.md +135 -0
  42. package/docs/v7/api/ai.mdx +205 -0
  43. package/docs/v7/api/assert.mdx +285 -0
  44. package/docs/v7/api/assertions.mdx +403 -0
  45. package/docs/v7/api/click.mdx +287 -0
  46. package/docs/v7/api/client.mdx +322 -0
  47. package/docs/v7/api/dashcam.mdx +497 -0
  48. package/docs/v7/api/doubleClick.mdx +102 -0
  49. package/docs/v7/api/elements.mdx +479 -0
  50. package/docs/v7/api/exec.mdx +346 -0
  51. package/docs/v7/api/find.mdx +316 -0
  52. package/docs/v7/api/focusApplication.mdx +294 -0
  53. package/docs/v7/api/hover.mdx +279 -0
  54. package/docs/v7/api/mouseDown.mdx +161 -0
  55. package/docs/v7/api/mouseUp.mdx +164 -0
  56. package/docs/v7/api/pressKeys.mdx +349 -0
  57. package/docs/v7/api/rightClick.mdx +123 -0
  58. package/docs/v7/api/sandbox.mdx +404 -0
  59. package/docs/v7/api/scroll.mdx +300 -0
  60. package/docs/v7/api/type.mdx +314 -0
  61. package/docs/v7/commands/assert.mdx +45 -0
  62. package/docs/v7/commands/exec.mdx +282 -0
  63. package/docs/v7/commands/focus-application.mdx +44 -0
  64. package/docs/v7/commands/hover-image.mdx +69 -0
  65. package/docs/v7/commands/hover-text.mdx +47 -0
  66. package/docs/v7/commands/if.mdx +53 -0
  67. package/docs/v7/commands/match-image.mdx +67 -0
  68. package/docs/v7/commands/press-keys.mdx +87 -0
  69. package/docs/v7/commands/remember.mdx +49 -0
  70. package/docs/v7/commands/run.mdx +44 -0
  71. package/docs/v7/commands/scroll-until-image.mdx +66 -0
  72. package/docs/v7/commands/scroll-until-text.mdx +60 -0
  73. package/docs/v7/commands/scroll.mdx +69 -0
  74. package/docs/v7/commands/type.mdx +45 -0
  75. package/docs/v7/commands/wait-for-image.mdx +54 -0
  76. package/docs/v7/commands/wait-for-text.mdx +48 -0
  77. package/docs/v7/commands/wait.mdx +45 -0
  78. package/docs/v7/getting-started/configuration.mdx +380 -0
  79. package/docs/v7/getting-started/quickstart.mdx +332 -0
  80. package/docs/v7/guides/best-practices.mdx +486 -0
  81. package/docs/v7/guides/caching-ai.mdx +215 -0
  82. package/docs/v7/guides/caching-selectors.mdx +292 -0
  83. package/docs/v7/guides/caching.mdx +366 -0
  84. package/docs/v7/guides/ci-cd/azure.mdx +587 -0
  85. package/docs/v7/guides/ci-cd/circleci.mdx +523 -0
  86. package/docs/v7/guides/ci-cd/github-actions.mdx +457 -0
  87. package/docs/v7/guides/ci-cd/gitlab.mdx +498 -0
  88. package/docs/v7/guides/ci-cd/jenkins.mdx +664 -0
  89. package/docs/v7/guides/ci-cd/travis.mdx +438 -0
  90. package/docs/v7/guides/debugging.mdx +349 -0
  91. package/docs/v7/guides/faq.mdx +393 -0
  92. package/docs/v7/guides/migration.mdx +562 -0
  93. package/docs/v7/guides/performance.mdx +517 -0
  94. package/docs/{getting-started → v7/guides}/self-hosting.mdx +11 -12
  95. package/docs/v7/guides/troubleshooting.mdx +526 -0
  96. package/docs/v7/guides/vitest-plugin.mdx +477 -0
  97. package/docs/v7/guides/vitest.mdx +535 -0
  98. package/docs/v7/platforms/linux.mdx +308 -0
  99. package/docs/v7/platforms/macos.mdx +433 -0
  100. package/docs/v7/platforms/windows.mdx +430 -0
  101. package/docs/v7/playwright.mdx +342 -0
  102. package/docs/v7/presets/chrome-extension.mdx +223 -0
  103. package/docs/v7/presets/chrome.mdx +287 -0
  104. package/docs/v7/presets/electron.mdx +435 -0
  105. package/docs/v7/presets/vscode.mdx +398 -0
  106. package/docs/v7/presets/webapp.mdx +396 -0
  107. package/docs/v7/progressive-apis/CORE.md +459 -0
  108. package/docs/v7/progressive-apis/HOOKS.md +360 -0
  109. package/docs/v7/progressive-apis/PROGRESSIVE_DISCLOSURE.md +230 -0
  110. package/docs/v7/progressive-apis/PROVISION.md +266 -0
  111. package/eslint.config.js +19 -1
  112. package/interfaces/cli/lib/base.js +10 -4
  113. package/interfaces/logger.js +2 -1
  114. package/interfaces/shared-test-state.mjs +69 -0
  115. package/interfaces/vitest-plugin.mjs +830 -0
  116. package/package.json +29 -5
  117. package/schema.json +8 -29
  118. package/scripts/view-test-results.mjs +96 -0
  119. package/sdk-log-formatter.js +714 -0
  120. package/sdk.d.ts +1028 -0
  121. package/sdk.js +2567 -0
  122. package/{.github/workflows/self-hosted.yml → self-hosted.yml} +13 -4
  123. package/setup/aws/cloudformation.yaml +9 -2
  124. package/src/core/Dashcam.js +469 -0
  125. package/src/core/index.d.ts +150 -0
  126. package/src/core/index.js +12 -0
  127. package/src/presets/index.mjs +331 -0
  128. package/src/vitest/extended.mjs +108 -0
  129. package/src/vitest/hooks.d.ts +119 -0
  130. package/src/vitest/hooks.mjs +298 -0
  131. package/src/vitest/index.mjs +64 -0
  132. package/src/vitest/lifecycle.mjs +277 -0
  133. package/src/vitest/utils.mjs +150 -0
  134. package/test/dashcam.test.js +137 -0
  135. package/test/mcp-example-test.yaml +27 -0
  136. package/testdriver/acceptance-sdk/QUICK_REFERENCE.md +61 -0
  137. package/testdriver/acceptance-sdk/README.md +128 -0
  138. package/testdriver/acceptance-sdk/TEST_REPORTING.md +245 -0
  139. package/testdriver/acceptance-sdk/assert.test.mjs +26 -0
  140. package/testdriver/acceptance-sdk/auto-cache-key-demo.test.mjs +56 -0
  141. package/testdriver/acceptance-sdk/chrome-extension.test.mjs +89 -0
  142. package/testdriver/acceptance-sdk/drag-and-drop.test.mjs +58 -0
  143. package/testdriver/acceptance-sdk/element-not-found.test.mjs +25 -0
  144. package/testdriver/acceptance-sdk/exec-js.test.mjs +43 -0
  145. package/testdriver/acceptance-sdk/exec-output.test.mjs +59 -0
  146. package/testdriver/acceptance-sdk/exec-pwsh.test.mjs +57 -0
  147. package/testdriver/acceptance-sdk/focus-window.test.mjs +36 -0
  148. package/testdriver/acceptance-sdk/formatted-logging.test.mjs +26 -0
  149. package/testdriver/acceptance-sdk/hooks-example.test.mjs +38 -0
  150. package/testdriver/acceptance-sdk/hover-image.test.mjs +34 -0
  151. package/testdriver/acceptance-sdk/hover-text-with-description.test.mjs +38 -0
  152. package/testdriver/acceptance-sdk/hover-text.test.mjs +27 -0
  153. package/testdriver/acceptance-sdk/match-image.test.mjs +36 -0
  154. package/testdriver/acceptance-sdk/presets-example.test.mjs +87 -0
  155. package/testdriver/acceptance-sdk/press-keys.test.mjs +50 -0
  156. package/testdriver/acceptance-sdk/prompt.test.mjs +33 -0
  157. package/testdriver/acceptance-sdk/scroll-keyboard.test.mjs +38 -0
  158. package/testdriver/acceptance-sdk/scroll-until-image.test.mjs +39 -0
  159. package/testdriver/acceptance-sdk/scroll-until-text.test.mjs +28 -0
  160. package/testdriver/acceptance-sdk/scroll.test.mjs +41 -0
  161. package/testdriver/acceptance-sdk/setup/globalTeardown.mjs +11 -0
  162. package/testdriver/acceptance-sdk/setup/testHelpers.mjs +420 -0
  163. package/testdriver/acceptance-sdk/setup/vitestSetup.mjs +40 -0
  164. package/testdriver/acceptance-sdk/sully-ai.test.mjs +234 -0
  165. package/testdriver/acceptance-sdk/test-console-logs.test.mjs +42 -0
  166. package/testdriver/acceptance-sdk/type-checking-demo.js +49 -0
  167. package/testdriver/acceptance-sdk/type.test.mjs +45 -0
  168. package/verify-element-api.js +89 -0
  169. package/verify-types.js +0 -0
  170. package/vitest.config.example.js +19 -0
  171. package/vitest.config.mjs +66 -0
  172. package/vitest.config.mjs.bak +44 -0
  173. package/.github/workflows/acceptance-v6.yml +0 -169
  174. package/.vscode/mcp.json +0 -9
  175. package/docs/overview/comparison.mdx +0 -82
  176. package/testdriver/lifecycle/prerun.yaml +0 -17
  177. /package/{testdriver/examples/desktop/lifecycle/prerun.yaml → .env.example} +0 -0
  178. /package/{testdriver → _testdriver}/acceptance/assert.yaml +0 -0
  179. /package/{testdriver → _testdriver}/acceptance/dashcam.yaml +0 -0
  180. /package/{testdriver → _testdriver}/acceptance/embed.yaml +0 -0
  181. /package/{testdriver → _testdriver}/acceptance/exec-js.yaml +0 -0
  182. /package/{testdriver → _testdriver}/acceptance/exec-output.yaml +0 -0
  183. /package/{testdriver → _testdriver}/acceptance/exec-shell.yaml +0 -0
  184. /package/{testdriver → _testdriver}/acceptance/focus-window.yaml +0 -0
  185. /package/{testdriver → _testdriver}/acceptance/hover-image.yaml +0 -0
  186. /package/{testdriver → _testdriver}/acceptance/hover-text-with-description.yaml +0 -0
  187. /package/{testdriver → _testdriver}/acceptance/hover-text.yaml +0 -0
  188. /package/{testdriver → _testdriver}/acceptance/if-else.yaml +0 -0
  189. /package/{testdriver → _testdriver}/acceptance/match-image.yaml +0 -0
  190. /package/{testdriver → _testdriver}/acceptance/press-keys.yaml +0 -0
  191. /package/{testdriver → _testdriver}/acceptance/prompt.yaml +0 -0
  192. /package/{testdriver → _testdriver}/acceptance/remember.yaml +0 -0
  193. /package/{testdriver → _testdriver}/acceptance/screenshots/cart.png +0 -0
  194. /package/{testdriver → _testdriver}/acceptance/scroll-keyboard.yaml +0 -0
  195. /package/{testdriver → _testdriver}/acceptance/scroll-until-image.yaml +0 -0
  196. /package/{testdriver → _testdriver}/acceptance/scroll-until-text.yaml +0 -0
  197. /package/{testdriver → _testdriver}/acceptance/scroll.yaml +0 -0
  198. /package/{testdriver → _testdriver}/acceptance/snippets/match-cart.yaml +0 -0
  199. /package/{testdriver → _testdriver}/acceptance/type.yaml +0 -0
  200. /package/{testdriver → _testdriver}/behavior/failure.yaml +0 -0
  201. /package/{testdriver → _testdriver}/behavior/hover-text.yaml +0 -0
  202. /package/{testdriver → _testdriver}/behavior/lifecycle/postrun.yaml +0 -0
  203. /package/{testdriver → _testdriver}/behavior/lifecycle/prerun.yaml +0 -0
  204. /package/{testdriver → _testdriver}/behavior/lifecycle/provision.yaml +0 -0
  205. /package/{testdriver → _testdriver}/behavior/secrets.yaml +0 -0
  206. /package/{testdriver → _testdriver}/edge-cases/dashcam-chrome.yaml +0 -0
  207. /package/{testdriver → _testdriver}/edge-cases/exec-pwsh-multiline.yaml +0 -0
  208. /package/{testdriver → _testdriver}/edge-cases/js-exception.yaml +0 -0
  209. /package/{testdriver → _testdriver}/edge-cases/js-promise.yaml +0 -0
  210. /package/{testdriver → _testdriver}/edge-cases/lifecycle/postrun.yaml +0 -0
  211. /package/{testdriver → _testdriver}/edge-cases/prompt-in-middle.yaml +0 -0
  212. /package/{testdriver → _testdriver}/edge-cases/prompt-nested.yaml +0 -0
  213. /package/{testdriver → _testdriver}/edge-cases/success-test.yaml +0 -0
  214. /package/{testdriver → _testdriver}/examples/android/example.yaml +0 -0
  215. /package/{testdriver → _testdriver}/examples/android/lifecycle/postrun.yaml +0 -0
  216. /package/{testdriver → _testdriver}/examples/android/lifecycle/provision.yaml +0 -0
  217. /package/{testdriver → _testdriver}/examples/android/readme.md +0 -0
  218. /package/{testdriver → _testdriver}/examples/chrome-extension/lifecycle/provision.yaml +0 -0
  219. /package/{testdriver → _testdriver}/examples/desktop/lifecycle/provision.yaml +0 -0
  220. /package/{testdriver → _testdriver}/examples/vscode-extension/lifecycle/provision.yaml +0 -0
  221. /package/{testdriver → _testdriver}/examples/web/lifecycle/postrun.yaml +0 -0
  222. /package/docs/{account → v6/account}/dashboard.mdx +0 -0
  223. /package/docs/{account → v6/account}/enterprise.mdx +0 -0
  224. /package/docs/{account → v6/account}/pricing.mdx +0 -0
  225. /package/docs/{account → v6/account}/projects.mdx +0 -0
  226. /package/docs/{account → v6/account}/team.mdx +0 -0
  227. /package/docs/{action → v6/action}/ami.mdx +0 -0
  228. /package/docs/{action → v6/action}/performance.mdx +0 -0
  229. /package/docs/{action → v6/action}/secrets.mdx +0 -0
  230. /package/docs/{apps → v6/apps}/chrome-extensions.mdx +0 -0
  231. /package/docs/{apps → v6/apps}/desktop-apps.mdx +0 -0
  232. /package/docs/{apps → v6/apps}/mobile-apps.mdx +0 -0
  233. /package/docs/{apps → v6/apps}/static-websites.mdx +0 -0
  234. /package/docs/{apps → v6/apps}/tauri-apps.mdx +0 -0
  235. /package/docs/{bugs → v6/bugs}/jira.mdx +0 -0
  236. /package/docs/{cli → v6/cli}/overview.mdx +0 -0
  237. /package/docs/{commands → v6/commands}/assert.mdx +0 -0
  238. /package/docs/{commands → v6/commands}/exec.mdx +0 -0
  239. /package/docs/{commands → v6/commands}/focus-application.mdx +0 -0
  240. /package/docs/{commands → v6/commands}/hover-image.mdx +0 -0
  241. /package/docs/{commands → v6/commands}/hover-text.mdx +0 -0
  242. /package/docs/{commands → v6/commands}/if.mdx +0 -0
  243. /package/docs/{commands → v6/commands}/match-image.mdx +0 -0
  244. /package/docs/{commands → v6/commands}/press-keys.mdx +0 -0
  245. /package/docs/{commands → v6/commands}/remember.mdx +0 -0
  246. /package/docs/{commands → v6/commands}/run.mdx +0 -0
  247. /package/docs/{commands → v6/commands}/scroll-until-image.mdx +0 -0
  248. /package/docs/{commands → v6/commands}/scroll-until-text.mdx +0 -0
  249. /package/docs/{commands → v6/commands}/scroll.mdx +0 -0
  250. /package/docs/{commands → v6/commands}/type.mdx +0 -0
  251. /package/docs/{commands → v6/commands}/wait-for-image.mdx +0 -0
  252. /package/docs/{commands → v6/commands}/wait-for-text.mdx +0 -0
  253. /package/docs/{commands → v6/commands}/wait.mdx +0 -0
  254. /package/docs/{exporting → v6/exporting}/junit.mdx +0 -0
  255. /package/docs/{exporting → v6/exporting}/playwright.mdx +0 -0
  256. /package/docs/{features → v6/features}/auto-healing.mdx +0 -0
  257. /package/docs/{features → v6/features}/generation.mdx +0 -0
  258. /package/docs/{features → v6/features}/parallel-testing.mdx +0 -0
  259. /package/docs/{features → v6/features}/reusable-snippets.mdx +0 -0
  260. /package/docs/{features → v6/features}/selectorless.mdx +0 -0
  261. /package/docs/{features → v6/features}/visual-assertions.mdx +0 -0
  262. /package/docs/{getting-started → v6/getting-started}/ci.mdx +0 -0
  263. /package/docs/{getting-started → v6/getting-started}/cli.mdx +0 -0
  264. /package/docs/{getting-started → v6/getting-started}/editing.mdx +0 -0
  265. /package/docs/{getting-started → v6/getting-started}/playwright.mdx +0 -0
  266. /package/docs/{getting-started → v6/getting-started}/running.mdx +0 -0
  267. /package/docs/{getting-started → v6/getting-started}/vscode.mdx +0 -0
  268. /package/docs/{guide → v6/guide}/assertions.mdx +0 -0
  269. /package/docs/{guide → v6/guide}/authentication.mdx +0 -0
  270. /package/docs/{guide → v6/guide}/code.mdx +0 -0
  271. /package/docs/{guide → v6/guide}/locating.mdx +0 -0
  272. /package/docs/{guide → v6/guide}/protips.mdx +0 -0
  273. /package/docs/{guide → v6/guide}/variables.mdx +0 -0
  274. /package/docs/{guide → v6/guide}/waiting.mdx +0 -0
  275. /package/docs/{importing → v6/importing}/csv.mdx +0 -0
  276. /package/docs/{importing → v6/importing}/gherkin.mdx +0 -0
  277. /package/docs/{importing → v6/importing}/jira.mdx +0 -0
  278. /package/docs/{importing → v6/importing}/testrail.mdx +0 -0
  279. /package/docs/{integrations → v6/integrations}/electron.mdx +0 -0
  280. /package/docs/{integrations → v6/integrations}/netlify.mdx +0 -0
  281. /package/docs/{integrations → v6/integrations}/vercel.mdx +0 -0
  282. /package/docs/{interactive → v6/interactive}/explore.mdx +0 -0
  283. /package/docs/{interactive → v6/interactive}/run.mdx +0 -0
  284. /package/docs/{interactive → v6/interactive}/save.mdx +0 -0
  285. /package/docs/{overview → v6/overview}/faq.mdx +0 -0
  286. /package/docs/{overview → v6/overview}/performance.mdx +0 -0
  287. /package/docs/{overview → v6/overview}/quickstart.mdx +0 -0
  288. /package/docs/{overview → v6/overview}/what-is-testdriver.mdx +0 -0
  289. /package/docs/{scenarios → v6/scenarios}/ai-chatbot.mdx +0 -0
  290. /package/docs/{scenarios → v6/scenarios}/cookie-banner.mdx +0 -0
  291. /package/docs/{scenarios → v6/scenarios}/file-upload.mdx +0 -0
  292. /package/docs/{scenarios → v6/scenarios}/form-filling.mdx +0 -0
  293. /package/docs/{scenarios → v6/scenarios}/log-in.mdx +0 -0
  294. /package/docs/{scenarios → v6/scenarios}/pdf-generation.mdx +0 -0
  295. /package/docs/{scenarios → v6/scenarios}/spell-check.mdx +0 -0
  296. /package/docs/{security → v6/security}/action.mdx +0 -0
  297. /package/docs/{security → v6/security}/agent.mdx +0 -0
  298. /package/docs/{security → v6/security}/platform.mdx +0 -0
  299. /package/docs/{tutorials → v6/tutorials}/advanced-test.mdx +0 -0
  300. /package/docs/{tutorials → v6/tutorials}/basic-test.mdx +0 -0
@@ -0,0 +1,396 @@
1
+ ---
2
+ title: "Web App Preset"
3
+ sidebarTitle: "Web App"
4
+ description: "Generic preset for testing web applications"
5
+ icon: "globe"
6
+ ---
7
+
8
+ ## Overview
9
+
10
+ The `webApp()` preset provides a generic interface for testing web applications. It currently uses Chrome under the hood but provides a more semantic API for web app testing.
11
+
12
+ ## Quick Start
13
+
14
+ ```javascript
15
+ import { test } from 'vitest';
16
+ import { webApp } from 'testdriverai/presets';
17
+
18
+ test('web app test', async (context) => {
19
+ const { testdriver } = await webApp(context, {
20
+ url: 'https://myapp.com',
21
+ browser: 'chrome'
22
+ });
23
+
24
+ await testdriver.find('Login button').click();
25
+ });
26
+ ```
27
+
28
+ ## Signature
29
+
30
+ ```typescript
31
+ webApp(context, options): Promise<WebAppResult>
32
+ ```
33
+
34
+ ### Parameters
35
+
36
+ <ParamField path="context" type="object" required>
37
+ Vitest test context - automatically passed to your test function
38
+ </ParamField>
39
+
40
+ <ParamField path="options" type="object">
41
+ Configuration options for web app testing
42
+
43
+ <Expandable title="properties">
44
+ <ParamField path="url" type="string" default="http://testdriver-sandbox.vercel.app/">
45
+ URL to navigate to when browser launches
46
+ </ParamField>
47
+
48
+ <ParamField path="browser" type="'chrome'" default="chrome">
49
+ Browser to use (currently only Chrome is supported)
50
+ </ParamField>
51
+
52
+ <ParamField path="maximized" type="boolean" default={true}>
53
+ Start browser in maximized window mode
54
+ </ParamField>
55
+
56
+ <ParamField path="guest" type="boolean" default={true}>
57
+ Use browser guest/incognito mode (no profile data)
58
+ </ParamField>
59
+
60
+ <ParamField path="dashcam" type="boolean" default={true}>
61
+ Enable Dashcam test recording
62
+ </ParamField>
63
+
64
+ <ParamField path="os" type="'linux' | 'mac' | 'windows'" default="linux">
65
+ Target operating system for the test
66
+ </ParamField>
67
+ </Expandable>
68
+ </ParamField>
69
+
70
+ ### Returns
71
+
72
+ <ResponseField name="testdriver" type="TestDriver" required>
73
+ TestDriver instance ready to use
74
+ </ResponseField>
75
+
76
+ <ResponseField name="dashcam" type="Dashcam">
77
+ Dashcam instance for test recording (if enabled)
78
+ </ResponseField>
79
+
80
+ ## Examples
81
+
82
+ ### Basic Web App Testing
83
+
84
+ ```javascript
85
+ import { test } from 'vitest';
86
+ import { webApp } from 'testdriverai/presets';
87
+
88
+ test('user login flow', async (context) => {
89
+ const { testdriver } = await webApp(context, {
90
+ url: 'https://myapp.com/login'
91
+ });
92
+
93
+ await testdriver.find('email input').type('user@example.com');
94
+ await testdriver.find('password input').type('password123');
95
+ await testdriver.find('Login button').click();
96
+
97
+ await testdriver.assert('Dashboard is visible');
98
+ });
99
+ ```
100
+
101
+ ### E-commerce Testing
102
+
103
+ ```javascript
104
+ import { test } from 'vitest';
105
+ import { webApp } from 'testdriverai/presets';
106
+
107
+ test('product purchase', async (context) => {
108
+ const { testdriver, dashcam } = await webApp(context, {
109
+ url: 'https://shop.example.com'
110
+ });
111
+
112
+ // Search for product
113
+ await testdriver.find('search input').type('laptop');
114
+ await testdriver.find('search button').click();
115
+
116
+ // Select product
117
+ await testdriver.find('first product result').click();
118
+
119
+ // Add to cart
120
+ await testdriver.find('Add to Cart').click();
121
+
122
+ // Proceed to checkout
123
+ await testdriver.find('Cart icon').click();
124
+ await testdriver.find('Checkout').click();
125
+
126
+ await testdriver.assert('Checkout page loaded');
127
+ });
128
+ ```
129
+
130
+ ### SPA Navigation
131
+
132
+ ```javascript
133
+ import { test } from 'vitest';
134
+ import { webApp } from 'testdriverai/presets';
135
+
136
+ test('single page app routing', async (context) => {
137
+ const { testdriver } = await webApp(context, {
138
+ url: 'https://spa.example.com'
139
+ });
140
+
141
+ // Navigate through SPA routes
142
+ await testdriver.find('About link').click();
143
+ await testdriver.assert('About page content is visible');
144
+
145
+ await testdriver.find('Products link').click();
146
+ await testdriver.assert('Products page content is visible');
147
+
148
+ await testdriver.find('Contact link').click();
149
+ await testdriver.assert('Contact form is visible');
150
+ });
151
+ ```
152
+
153
+ ### Form Validation
154
+
155
+ ```javascript
156
+ import { test } from 'vitest';
157
+ import { webApp } from 'testdriverai/presets';
158
+
159
+ test('form validation errors', async (context) => {
160
+ const { testdriver } = await webApp(context, {
161
+ url: 'https://myapp.com/register'
162
+ });
163
+
164
+ // Submit empty form
165
+ await testdriver.find('Submit button').click();
166
+
167
+ // Verify validation errors
168
+ await testdriver.assert('Email is required error is shown');
169
+ await testdriver.assert('Password is required error is shown');
170
+
171
+ // Fill valid data
172
+ await testdriver.find('email input').type('test@example.com');
173
+ await testdriver.find('password input').type('SecurePass123!');
174
+
175
+ // Submit again
176
+ await testdriver.find('Submit button').click();
177
+
178
+ await testdriver.assert('Registration successful');
179
+ });
180
+ ```
181
+
182
+ ### API Integration Testing
183
+
184
+ ```javascript
185
+ import { test } from 'vitest';
186
+ import { webApp } from 'testdriverai/presets';
187
+
188
+ test('data fetching and display', async (context) => {
189
+ const { testdriver } = await webApp(context, {
190
+ url: 'https://api-demo.example.com'
191
+ });
192
+
193
+ // Trigger data fetch
194
+ await testdriver.find('Load Data button').click();
195
+
196
+ // Wait for loading state
197
+ await testdriver.assert('Loading spinner is visible');
198
+
199
+ // Wait for data to load
200
+ await testdriver.assert('Data table is populated');
201
+
202
+ // Verify specific data
203
+ await testdriver.assert('First row contains expected data');
204
+ });
205
+ ```
206
+
207
+ ### Responsive Design Testing
208
+
209
+ ```javascript
210
+ import { test } from 'vitest';
211
+ import { webApp } from 'testdriverai/presets';
212
+
213
+ test('mobile menu', async (context) => {
214
+ const { testdriver } = await webApp(context, {
215
+ url: 'https://responsive.example.com',
216
+ maximized: false // Start in default window size
217
+ });
218
+
219
+ // Resize to mobile
220
+ await testdriver.exec('sh', 'xdotool getactivewindow windowsize 375 667', 5000);
221
+
222
+ // Open mobile menu
223
+ await testdriver.find('hamburger menu icon').click();
224
+
225
+ // Navigate in mobile menu
226
+ await testdriver.find('Products in mobile menu').click();
227
+
228
+ await testdriver.assert('Products page is displayed');
229
+ });
230
+ ```
231
+
232
+ ## Browser Support
233
+
234
+ Currently, `webApp()` only supports Chrome:
235
+
236
+ ```javascript
237
+ // ✅ Supported
238
+ const { testdriver } = await webApp(context, {
239
+ browser: 'chrome'
240
+ });
241
+
242
+ // ❌ Not yet supported
243
+ const { testdriver } = await webApp(context, {
244
+ browser: 'firefox' // Throws error
245
+ });
246
+ ```
247
+
248
+ Future releases will add support for Firefox, Edge, and Safari.
249
+
250
+ ## What It Does
251
+
252
+ When you call `webApp()`, it automatically:
253
+
254
+ 1. **Validates Browser** - Checks that requested browser is supported
255
+ 2. **Delegates to Browser Preset** - Currently uses the Chrome preset
256
+ 3. **Returns Standard Interface** - Provides consistent API regardless of browser
257
+
258
+ All the heavy lifting is done by the underlying browser preset (currently `chrome()`).
259
+
260
+ ## When to Use
261
+
262
+ Use `webApp()` when:
263
+
264
+ - You want browser-agnostic code (for future multi-browser support)
265
+ - You're testing a generic web application
266
+ - You prefer semantic naming over specific browser names
267
+
268
+ Use `chrome()` directly when:
269
+
270
+ - You need Chrome-specific features
271
+ - You want explicit browser control
272
+ - You're testing Chrome extensions or Chrome-specific behavior
273
+
274
+ ## Using with provision()
275
+
276
+ The `webApp()` preset can also be called via the unified `provision()` function:
277
+
278
+ ```javascript
279
+ import { provision } from 'testdriverai/presets';
280
+
281
+ test('using provision', async (context) => {
282
+ const { testdriver } = await provision('webapp', {
283
+ url: 'https://example.com',
284
+ browser: 'chrome'
285
+ }, context);
286
+
287
+ // Same functionality as webApp() directly
288
+ });
289
+ ```
290
+
291
+ ## Migration Path
292
+
293
+ If you're currently using `chrome()` for web app testing, you can easily switch to `webApp()`:
294
+
295
+ ```javascript
296
+ // Before
297
+ import { chrome } from 'testdriverai/presets';
298
+ const { testdriver } = await chrome(context, { url });
299
+
300
+ // After
301
+ import { webApp } from 'testdriverai/presets';
302
+ const { testdriver } = await webApp(context, { url, browser: 'chrome' });
303
+ ```
304
+
305
+ The behavior is identical, but `webApp()` provides a more generic interface for future browser additions.
306
+
307
+ ## Common Patterns
308
+
309
+ ### Authentication Flow
310
+
311
+ ```javascript
312
+ test('login and navigate', async (context) => {
313
+ const { testdriver } = await webApp(context, {
314
+ url: 'https://myapp.com'
315
+ });
316
+
317
+ // Login
318
+ await testdriver.find('email').type('user@example.com');
319
+ await testdriver.find('password').type('password');
320
+ await testdriver.find('Login').click();
321
+
322
+ // Wait for redirect
323
+ await testdriver.assert('Dashboard is loaded');
324
+
325
+ // Navigate authenticated area
326
+ await testdriver.find('Settings').click();
327
+ await testdriver.assert('Settings page is loaded');
328
+ });
329
+ ```
330
+
331
+ ### File Upload
332
+
333
+ ```javascript
334
+ test('upload file', async (context) => {
335
+ const { testdriver } = await webApp(context, {
336
+ url: 'https://upload.example.com'
337
+ });
338
+
339
+ // Click upload button
340
+ await testdriver.find('Upload file button').click();
341
+
342
+ // Type file path in file dialog
343
+ await testdriver.type('/tmp/test-file.pdf');
344
+ await testdriver.pressKeys(['enter']);
345
+
346
+ // Verify upload
347
+ await testdriver.assert('File uploaded successfully');
348
+ });
349
+ ```
350
+
351
+ ### Search and Filter
352
+
353
+ ```javascript
354
+ test('search with filters', async (context) => {
355
+ const { testdriver } = await webApp(context, {
356
+ url: 'https://catalog.example.com'
357
+ });
358
+
359
+ // Enter search query
360
+ await testdriver.find('search input').type('laptop');
361
+
362
+ // Apply filters
363
+ await testdriver.find('Price filter').click();
364
+ await testdriver.find('$500 - $1000').click();
365
+
366
+ await testdriver.find('Brand filter').click();
367
+ await testdriver.find('Dell').click();
368
+
369
+ // Submit search
370
+ await testdriver.find('Search button').click();
371
+
372
+ await testdriver.assert('Filtered results are displayed');
373
+ });
374
+ ```
375
+
376
+ ## Error Handling
377
+
378
+ ```javascript
379
+ test('handles unsupported browser', async (context) => {
380
+ try {
381
+ const { testdriver } = await webApp(context, {
382
+ browser: 'firefox' // Not yet supported
383
+ });
384
+ } catch (error) {
385
+ expect(error.message).toContain('not yet implemented');
386
+ }
387
+ });
388
+ ```
389
+
390
+ ## See Also
391
+
392
+ - [Provision API](/v7/progressive-apis/PROVISION) - Overview of all presets
393
+ - [Chrome Preset](/v7/presets/chrome) - Direct Chrome testing
394
+ - [VS Code Preset](/v7/presets/vscode) - Testing VS Code extensions
395
+ - [Electron Preset](/v7/presets/electron) - Testing Electron apps
396
+ - [Vitest Integration](/v7/guides/vitest) - Complete Vitest setup guide