testdriverai 7.1.0 → 7.1.2

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 (325) hide show
  1. package/.env.example +2 -0
  2. package/.github/workflows/linux-tests.yml +28 -0
  3. package/agent/index.js +18 -45
  4. package/agent/interface.js +13 -2
  5. package/agent/lib/commands.js +1 -1
  6. package/agent/lib/redraw.js +1 -1
  7. package/agent/lib/sandbox.js +30 -2
  8. package/agent/lib/valid-version.js +2 -2
  9. package/debugger/index.html +1 -1
  10. package/docs/docs.json +140 -131
  11. package/docs/v6/getting-started/self-hosting.mdx +3 -2
  12. package/docs/v7/_drafts/agents.mdx +852 -0
  13. package/docs/v7/_drafts/auto-cache-key.mdx +167 -0
  14. package/docs/v7/{guides → _drafts}/caching-selectors.mdx +125 -17
  15. package/docs/v7/_drafts/dashcam-title-feature.mdx +89 -0
  16. package/docs/v7/_drafts/error-handling.mdx +501 -0
  17. package/docs/v7/_drafts/implementation-plan.mdx +994 -0
  18. package/docs/v7/_drafts/init-command.mdx +95 -0
  19. package/docs/v7/_drafts/optimal-sdk-design.mdx +1348 -0
  20. package/docs/v7/_drafts/plugin-migration.mdx +222 -0
  21. package/docs/v7/_drafts/prompt-cache.mdx +200 -0
  22. package/docs/{QUICK_START_TEST_RECORDING.md → v7/_drafts/quick-start-test-recording.mdx} +3 -3
  23. package/docs/v7/_drafts/sdk-logging.mdx +222 -0
  24. package/docs/v7/_drafts/sdk-migration.mdx +474 -0
  25. package/docs/v7/_drafts/sdk-v7-complete.mdx +345 -0
  26. package/docs/v7/{guides → _drafts}/self-hosting.mdx +1 -1
  27. package/docs/v7/{guides → _drafts}/troubleshooting.mdx +2 -2
  28. package/docs/v7/{guides → _drafts}/vitest-plugin.mdx +4 -4
  29. package/docs/v7/api/{ai.mdx → act.mdx} +24 -24
  30. package/docs/v7/api/client.mdx +1 -1
  31. package/docs/v7/api/dashcam.mdx +2 -2
  32. package/docs/v7/api/elements.mdx +143 -41
  33. package/docs/v7/api/find.mdx +258 -0
  34. package/docs/v7/api/type.mdx +51 -7
  35. package/docs/v7/features/ai-native.mdx +427 -0
  36. package/docs/v7/features/easy-to-write.mdx +351 -0
  37. package/docs/v7/features/enterprise.mdx +540 -0
  38. package/docs/v7/features/fast.mdx +424 -0
  39. package/docs/v7/features/observable.mdx +623 -0
  40. package/docs/v7/features/powerful.mdx +531 -0
  41. package/docs/v7/features/scalable.mdx +417 -0
  42. package/docs/v7/features/stable.mdx +514 -0
  43. package/docs/v7/getting-started/configuration.mdx +1 -1
  44. package/docs/v7/getting-started/generating-tests.mdx +525 -0
  45. package/docs/v7/getting-started/installation.mdx +486 -0
  46. package/docs/v7/getting-started/quickstart.mdx +51 -5
  47. package/docs/v7/getting-started/running-and-debugging.mdx +511 -0
  48. package/docs/v7/getting-started/setting-up-in-ci.mdx +612 -0
  49. package/docs/v7/getting-started/writing-tests.mdx +535 -0
  50. package/docs/v7/overview/what-is-testdriver.mdx +398 -0
  51. package/docs/v7/playwright.mdx +3 -3
  52. package/docs/v7/presets/chrome.mdx +16 -0
  53. package/docs/v7/presets/electron.mdx +18 -0
  54. package/docs/v7/presets/vscode.mdx +19 -0
  55. package/examples/run-tests-with-recording.sh +70 -0
  56. package/examples/screenshot-example.js +63 -0
  57. package/examples/sdk-awesome-logs-demo.js +177 -0
  58. package/examples/sdk-cache-thresholds.js +96 -0
  59. package/examples/sdk-element-properties.js +155 -0
  60. package/examples/sdk-simple-example.js +65 -0
  61. package/examples/test-recording-example.test.js +166 -0
  62. package/interfaces/cli/commands/init.js +358 -0
  63. package/interfaces/vitest-plugin.mjs +214 -10
  64. package/{src → lib}/core/Dashcam.js +41 -4
  65. package/{src → lib}/vitest/hooks.mjs +118 -100
  66. package/lib/vitest/setup.mjs +44 -0
  67. package/package.json +9 -10
  68. package/sdk.d.ts +15 -2
  69. package/sdk.js +72 -17
  70. package/{self-hosted.yml → setup/aws/self-hosted.yml} +1 -1
  71. package/{testdriver/acceptance-sdk → test/manual}/test-console-logs.test.mjs +1 -1
  72. package/test/manual/test-find-api.js +73 -0
  73. package/test/manual/test-init.sh +54 -0
  74. package/test/manual/test-prompt-cache.js +96 -0
  75. package/test/manual/test-provision-auth.mjs +22 -0
  76. package/test/manual/test-sandbox-render.js +28 -0
  77. package/test/manual/test-sdk-methods.js +15 -0
  78. package/test/manual/test-sdk-refactor.js +53 -0
  79. package/test/manual/test-stack-trace.mjs +57 -0
  80. package/test/testdriver/assert.test.mjs +41 -0
  81. package/{testdriver/acceptance-sdk → test/testdriver}/auto-cache-key-demo.test.mjs +1 -1
  82. package/{testdriver/acceptance-sdk → test/testdriver}/drag-and-drop.test.mjs +1 -1
  83. package/{testdriver/acceptance-sdk → test/testdriver}/element-not-found.test.mjs +1 -1
  84. package/{testdriver/acceptance-sdk → test/testdriver}/exec-js.test.mjs +1 -1
  85. package/{testdriver/acceptance-sdk → test/testdriver}/exec-output.test.mjs +3 -3
  86. package/{testdriver/acceptance-sdk → test/testdriver}/exec-pwsh.test.mjs +3 -3
  87. package/{testdriver/acceptance-sdk → test/testdriver}/focus-window.test.mjs +1 -1
  88. package/{testdriver/acceptance-sdk → test/testdriver}/formatted-logging.test.mjs +1 -1
  89. package/{testdriver/acceptance-sdk → test/testdriver}/hover-image.test.mjs +1 -1
  90. package/{testdriver/acceptance-sdk → test/testdriver}/hover-text-with-description.test.mjs +1 -1
  91. package/{testdriver/acceptance-sdk → test/testdriver}/hover-text.test.mjs +1 -1
  92. package/{testdriver/acceptance-sdk → test/testdriver}/match-image.test.mjs +1 -1
  93. package/{testdriver/acceptance-sdk → test/testdriver}/press-keys.test.mjs +1 -1
  94. package/{testdriver/acceptance-sdk → test/testdriver}/prompt.test.mjs +2 -2
  95. package/{testdriver/acceptance-sdk → test/testdriver}/scroll-keyboard.test.mjs +1 -1
  96. package/{testdriver/acceptance-sdk → test/testdriver}/scroll-until-image.test.mjs +1 -1
  97. package/{testdriver/acceptance-sdk → test/testdriver}/scroll-until-text.test.mjs +1 -1
  98. package/{testdriver/acceptance-sdk → test/testdriver}/scroll.test.mjs +1 -1
  99. package/{src/vitest/lifecycle.mjs → test/testdriver/setup/lifecycleHelpers.mjs} +84 -99
  100. package/test/testdriver/setup/testHelpers.mjs +653 -0
  101. package/{testdriver/acceptance-sdk → test/testdriver}/type.test.mjs +1 -1
  102. package/vitest.config.mjs +8 -59
  103. package/.github/dependabot.yml +0 -11
  104. package/.github/workflows/acceptance-linux.yml +0 -75
  105. package/.github/workflows/acceptance-sdk-tests.yml +0 -133
  106. package/.github/workflows/acceptance-tests.yml +0 -130
  107. package/.github/workflows/lint.yml +0 -27
  108. package/.github/workflows/publish-canary.yml +0 -40
  109. package/.github/workflows/publish-latest.yml +0 -61
  110. package/.github/workflows/test-install.yml +0 -29
  111. package/.vscode/extensions.json +0 -3
  112. package/.vscode/launch.json +0 -22
  113. package/.vscode/settings.json +0 -14
  114. package/AGENTS.md +0 -550
  115. package/CODEOWNERS +0 -2
  116. package/_testdriver/acceptance/assert.yaml +0 -7
  117. package/_testdriver/acceptance/dashcam.yaml +0 -9
  118. package/_testdriver/acceptance/drag-and-drop.yaml +0 -49
  119. package/_testdriver/acceptance/embed.yaml +0 -9
  120. package/_testdriver/acceptance/exec-js.yaml +0 -29
  121. package/_testdriver/acceptance/exec-output.yaml +0 -43
  122. package/_testdriver/acceptance/exec-shell.yaml +0 -40
  123. package/_testdriver/acceptance/focus-window.yaml +0 -16
  124. package/_testdriver/acceptance/hover-image.yaml +0 -18
  125. package/_testdriver/acceptance/hover-text-with-description.yaml +0 -29
  126. package/_testdriver/acceptance/hover-text.yaml +0 -14
  127. package/_testdriver/acceptance/if-else.yaml +0 -31
  128. package/_testdriver/acceptance/match-image.yaml +0 -15
  129. package/_testdriver/acceptance/press-keys.yaml +0 -35
  130. package/_testdriver/acceptance/prompt.yaml +0 -11
  131. package/_testdriver/acceptance/remember.yaml +0 -27
  132. package/_testdriver/acceptance/screenshots/cart.png +0 -0
  133. package/_testdriver/acceptance/scroll-keyboard.yaml +0 -34
  134. package/_testdriver/acceptance/scroll-until-image.yaml +0 -26
  135. package/_testdriver/acceptance/scroll-until-text.yaml +0 -20
  136. package/_testdriver/acceptance/scroll.yaml +0 -33
  137. package/_testdriver/acceptance/snippets/login.yaml +0 -29
  138. package/_testdriver/acceptance/snippets/match-cart.yaml +0 -8
  139. package/_testdriver/acceptance/type.yaml +0 -29
  140. package/_testdriver/behavior/failure.yaml +0 -7
  141. package/_testdriver/behavior/hover-text.yaml +0 -13
  142. package/_testdriver/behavior/lifecycle/postrun.yaml +0 -10
  143. package/_testdriver/behavior/lifecycle/prerun.yaml +0 -8
  144. package/_testdriver/behavior/lifecycle/provision.yaml +0 -8
  145. package/_testdriver/behavior/secrets.yaml +0 -7
  146. package/_testdriver/edge-cases/dashcam-chrome.yaml +0 -8
  147. package/_testdriver/edge-cases/exec-pwsh-multiline.yaml +0 -10
  148. package/_testdriver/edge-cases/js-exception.yaml +0 -8
  149. package/_testdriver/edge-cases/js-promise.yaml +0 -19
  150. package/_testdriver/edge-cases/lifecycle/postrun.yaml +0 -10
  151. package/_testdriver/edge-cases/prompt-in-middle.yaml +0 -23
  152. package/_testdriver/edge-cases/prompt-nested.yaml +0 -7
  153. package/_testdriver/edge-cases/success-test.yaml +0 -9
  154. package/_testdriver/examples/android/example.yaml +0 -12
  155. package/_testdriver/examples/android/lifecycle/postrun.yaml +0 -11
  156. package/_testdriver/examples/android/lifecycle/provision.yaml +0 -47
  157. package/_testdriver/examples/android/readme.md +0 -7
  158. package/_testdriver/examples/chrome-extension/lifecycle/provision.yaml +0 -74
  159. package/_testdriver/examples/desktop/lifecycle/prerun.yaml +0 -0
  160. package/_testdriver/examples/desktop/lifecycle/provision.yaml +0 -64
  161. package/_testdriver/examples/vscode-extension/lifecycle/provision.yaml +0 -73
  162. package/_testdriver/examples/web/lifecycle/postrun.yaml +0 -7
  163. package/_testdriver/examples/web/lifecycle/prerun.yaml +0 -22
  164. package/_testdriver/lifecycle/postrun.yaml +0 -8
  165. package/_testdriver/lifecycle/prerun.yaml +0 -15
  166. package/_testdriver/lifecycle/provision.yaml +0 -25
  167. package/docs/v7/guides/ci-cd/azure.mdx +0 -587
  168. package/docs/v7/guides/ci-cd/circleci.mdx +0 -523
  169. package/docs/v7/guides/ci-cd/github-actions.mdx +0 -457
  170. package/docs/v7/guides/ci-cd/gitlab.mdx +0 -498
  171. package/docs/v7/guides/ci-cd/jenkins.mdx +0 -664
  172. package/docs/v7/guides/ci-cd/travis.mdx +0 -438
  173. package/scripts/view-test-results.mjs +0 -96
  174. package/src/vitest/extended.mjs +0 -108
  175. package/src/vitest/index.mjs +0 -64
  176. package/src/vitest/utils.mjs +0 -150
  177. package/styles/.vale-config/2-MDX.ini +0 -5
  178. package/styles/Microsoft/AMPM.yml +0 -9
  179. package/styles/Microsoft/Accessibility.yml +0 -30
  180. package/styles/Microsoft/Acronyms.yml +0 -64
  181. package/styles/Microsoft/Adverbs.yml +0 -272
  182. package/styles/Microsoft/Auto.yml +0 -11
  183. package/styles/Microsoft/Avoid.yml +0 -14
  184. package/styles/Microsoft/Contractions.yml +0 -50
  185. package/styles/Microsoft/Dashes.yml +0 -13
  186. package/styles/Microsoft/DateFormat.yml +0 -8
  187. package/styles/Microsoft/DateNumbers.yml +0 -40
  188. package/styles/Microsoft/DateOrder.yml +0 -8
  189. package/styles/Microsoft/Ellipses.yml +0 -9
  190. package/styles/Microsoft/FirstPerson.yml +0 -16
  191. package/styles/Microsoft/Foreign.yml +0 -13
  192. package/styles/Microsoft/Gender.yml +0 -8
  193. package/styles/Microsoft/GenderBias.yml +0 -42
  194. package/styles/Microsoft/GeneralURL.yml +0 -11
  195. package/styles/Microsoft/HeadingAcronyms.yml +0 -7
  196. package/styles/Microsoft/HeadingColons.yml +0 -8
  197. package/styles/Microsoft/HeadingPunctuation.yml +0 -13
  198. package/styles/Microsoft/Headings.yml +0 -28
  199. package/styles/Microsoft/Hyphens.yml +0 -14
  200. package/styles/Microsoft/Negative.yml +0 -13
  201. package/styles/Microsoft/Ordinal.yml +0 -13
  202. package/styles/Microsoft/OxfordComma.yml +0 -8
  203. package/styles/Microsoft/Passive.yml +0 -183
  204. package/styles/Microsoft/Percentages.yml +0 -7
  205. package/styles/Microsoft/Plurals.yml +0 -7
  206. package/styles/Microsoft/Quotes.yml +0 -7
  207. package/styles/Microsoft/RangeTime.yml +0 -13
  208. package/styles/Microsoft/Semicolon.yml +0 -8
  209. package/styles/Microsoft/SentenceLength.yml +0 -6
  210. package/styles/Microsoft/Spacing.yml +0 -8
  211. package/styles/Microsoft/Suspended.yml +0 -7
  212. package/styles/Microsoft/Terms.yml +0 -42
  213. package/styles/Microsoft/URLFormat.yml +0 -9
  214. package/styles/Microsoft/Units.yml +0 -16
  215. package/styles/Microsoft/Vocab.yml +0 -25
  216. package/styles/Microsoft/We.yml +0 -11
  217. package/styles/Microsoft/Wordiness.yml +0 -127
  218. package/styles/Microsoft/meta.json +0 -4
  219. package/styles/alex/Ablist.yml +0 -274
  220. package/styles/alex/Condescending.yml +0 -16
  221. package/styles/alex/Gendered.yml +0 -110
  222. package/styles/alex/LGBTQ.yml +0 -55
  223. package/styles/alex/OCD.yml +0 -10
  224. package/styles/alex/Press.yml +0 -12
  225. package/styles/alex/ProfanityLikely.yml +0 -1289
  226. package/styles/alex/ProfanityMaybe.yml +0 -282
  227. package/styles/alex/ProfanityUnlikely.yml +0 -251
  228. package/styles/alex/README.md +0 -27
  229. package/styles/alex/Race.yml +0 -85
  230. package/styles/alex/Suicide.yml +0 -26
  231. package/styles/alex/meta.json +0 -4
  232. package/styles/config/vocabularies/Docs/accept.txt +0 -47
  233. package/styles/config/vocabularies/Docs/reject.txt +0 -4
  234. package/styles/proselint/Airlinese.yml +0 -8
  235. package/styles/proselint/AnimalLabels.yml +0 -48
  236. package/styles/proselint/Annotations.yml +0 -9
  237. package/styles/proselint/Apologizing.yml +0 -8
  238. package/styles/proselint/Archaisms.yml +0 -52
  239. package/styles/proselint/But.yml +0 -8
  240. package/styles/proselint/Cliches.yml +0 -782
  241. package/styles/proselint/CorporateSpeak.yml +0 -30
  242. package/styles/proselint/Currency.yml +0 -5
  243. package/styles/proselint/Cursing.yml +0 -15
  244. package/styles/proselint/DateCase.yml +0 -7
  245. package/styles/proselint/DateMidnight.yml +0 -7
  246. package/styles/proselint/DateRedundancy.yml +0 -10
  247. package/styles/proselint/DateSpacing.yml +0 -7
  248. package/styles/proselint/DenizenLabels.yml +0 -52
  249. package/styles/proselint/Diacritical.yml +0 -95
  250. package/styles/proselint/GenderBias.yml +0 -45
  251. package/styles/proselint/GroupTerms.yml +0 -39
  252. package/styles/proselint/Hedging.yml +0 -8
  253. package/styles/proselint/Hyperbole.yml +0 -6
  254. package/styles/proselint/Jargon.yml +0 -11
  255. package/styles/proselint/LGBTOffensive.yml +0 -13
  256. package/styles/proselint/LGBTTerms.yml +0 -15
  257. package/styles/proselint/Malapropisms.yml +0 -8
  258. package/styles/proselint/Needless.yml +0 -358
  259. package/styles/proselint/Nonwords.yml +0 -38
  260. package/styles/proselint/Oxymorons.yml +0 -22
  261. package/styles/proselint/P-Value.yml +0 -6
  262. package/styles/proselint/RASSyndrome.yml +0 -30
  263. package/styles/proselint/README.md +0 -12
  264. package/styles/proselint/Skunked.yml +0 -13
  265. package/styles/proselint/Spelling.yml +0 -17
  266. package/styles/proselint/Typography.yml +0 -11
  267. package/styles/proselint/Uncomparables.yml +0 -50
  268. package/styles/proselint/Very.yml +0 -6
  269. package/styles/proselint/meta.json +0 -15
  270. package/styles/write-good/Cliches.yml +0 -702
  271. package/styles/write-good/E-Prime.yml +0 -32
  272. package/styles/write-good/Illusions.yml +0 -11
  273. package/styles/write-good/Passive.yml +0 -183
  274. package/styles/write-good/README.md +0 -27
  275. package/styles/write-good/So.yml +0 -5
  276. package/styles/write-good/ThereIs.yml +0 -6
  277. package/styles/write-good/TooWordy.yml +0 -221
  278. package/styles/write-good/Weasel.yml +0 -29
  279. package/styles/write-good/meta.json +0 -4
  280. package/test/dashcam.test.js +0 -137
  281. package/test/mcp-example-test.yaml +0 -27
  282. package/test/test_parser.js +0 -47
  283. package/testdriver/acceptance-sdk/QUICK_REFERENCE.md +0 -61
  284. package/testdriver/acceptance-sdk/README.md +0 -128
  285. package/testdriver/acceptance-sdk/TEST_REPORTING.md +0 -245
  286. package/testdriver/acceptance-sdk/assert.test.mjs +0 -26
  287. package/testdriver/acceptance-sdk/hooks-example.test.mjs +0 -38
  288. package/testdriver/acceptance-sdk/presets-example.test.mjs +0 -87
  289. package/testdriver/acceptance-sdk/setup/testHelpers.mjs +0 -420
  290. package/testdriver/acceptance-sdk/sully-ai.test.mjs +0 -234
  291. package/testdriver/acceptance-sdk/type-checking-demo.js +0 -49
  292. package/vale.ini +0 -18
  293. package/vitest.config.example.js +0 -19
  294. package/vitest.config.mjs.bak +0 -44
  295. /package/docs/{ARCHITECTURE.md → v7/_drafts/architecture.mdx} +0 -0
  296. /package/docs/{AWESOME_LOGS_QUICK_REF.md → v7/_drafts/awesome-logs-quick-ref.mdx} +0 -0
  297. /package/docs/v7/{guides → _drafts}/best-practices.mdx +0 -0
  298. /package/docs/v7/{guides → _drafts}/caching-ai.mdx +0 -0
  299. /package/docs/v7/{guides → _drafts}/caching.mdx +0 -0
  300. /package/docs/{MIGRATION.md → v7/_drafts/cli-to-sdk-migration.mdx} +0 -0
  301. /package/{CONTRIBUTING.md → docs/v7/_drafts/contributing.mdx} +0 -0
  302. /package/docs/v7/{progressive-apis/CORE.md → _drafts/core.mdx} +0 -0
  303. /package/docs/v7/{guides → _drafts}/debugging.mdx +0 -0
  304. /package/docs/v7/{guides → _drafts}/faq.mdx +0 -0
  305. /package/docs/v7/{progressive-apis/HOOKS.md → _drafts/hooks.mdx} +0 -0
  306. /package/docs/v7/{guides → _drafts}/migration.mdx +0 -0
  307. /package/docs/v7/{guides → _drafts}/performance.mdx +0 -0
  308. /package/docs/{PRESETS.md → v7/_drafts/presets.mdx} +0 -0
  309. /package/docs/v7/{progressive-apis/PROGRESSIVE_DISCLOSURE.md → _drafts/progressive-disclosure.mdx} +0 -0
  310. /package/docs/v7/{progressive-apis/PROVISION.md → _drafts/provision.mdx} +0 -0
  311. /package/docs/{SDK_AWESOME_LOGS.md → v7/_drafts/sdk-awesome-logs.mdx} +0 -0
  312. /package/docs/{sdk-browser-rendering.md → v7/_drafts/sdk-browser-rendering.mdx} +0 -0
  313. /package/docs/{TEST_RECORDING.md → v7/_drafts/test-recording.mdx} +0 -0
  314. /package/docs/v7/{guides → _drafts}/vitest.mdx +0 -0
  315. /package/docs/v7/{README.md → overview/readme.mdx} +0 -0
  316. /package/{src → lib}/core/index.d.ts +0 -0
  317. /package/{src → lib}/core/index.js +0 -0
  318. /package/{src → lib}/presets/index.mjs +0 -0
  319. /package/{src → lib}/vitest/hooks.d.ts +0 -0
  320. /package/{debug-locate-response.js → test/manual/debug-locate-response.js} +0 -0
  321. /package/{verify-element-api.js → test/manual/verify-element-api.js} +0 -0
  322. /package/{verify-types.js → test/manual/verify-types.js} +0 -0
  323. /package/{testdriver/acceptance-sdk → test/testdriver}/chrome-extension.test.mjs +0 -0
  324. /package/{testdriver/acceptance-sdk → test/testdriver}/setup/globalTeardown.mjs +0 -0
  325. /package/{testdriver/acceptance-sdk → test/testdriver}/setup/vitestSetup.mjs +0 -0
package/AGENTS.md DELETED
@@ -1,550 +0,0 @@
1
- # TestDriver Agent Instructions
2
-
3
- This guide teaches AI agents how to write modular, iteratively-debuggable Vitest tests using the TestDriver SDK.
4
-
5
- ## Core Principles
6
-
7
- ### 1. One Action Per Step
8
-
9
- Each `it()` block performs exactly **ONE state-changing action** plus optional assertions.
10
-
11
- **State-changing actions:**
12
- - `click()` - clicking on elements
13
- - `type()` - typing text
14
- - `pressKeys()` - keyboard shortcuts
15
- - `scroll()` - scrolling the page
16
-
17
- **NOT state-changing (can combine with actions):**
18
- - `find()` - locating elements
19
- - `assert()` - verifying state
20
- - `exists()` - checking element presence
21
- - `screenshot()` - capturing screen
22
-
23
- ```javascript
24
- // ✅ CORRECT: One action per step
25
- it("step01: click the login button", async () => {
26
- const button = await testdriver.find("Login button");
27
- await button.click();
28
- // Optional: verify the action worked
29
- const form = await testdriver.find("Login form");
30
- expect(form.exists()).toBe(true);
31
- });
32
-
33
- it("step02: type username", async () => {
34
- await testdriver.type("testuser");
35
- await testdriver.assert("username field contains 'testuser'");
36
- });
37
-
38
- // ❌ WRONG: Multiple actions in one step
39
- it("login flow", async () => {
40
- await testdriver.find("Login").click();
41
- await testdriver.type("user"); // second action!
42
- await testdriver.type("password"); // third action!
43
- await testdriver.find("Submit").click(); // fourth action!
44
- });
45
- ```
46
-
47
- ### 2. Step Naming Convention
48
-
49
- Use zero-padded step numbers for proper sorting and easy `--testNamePattern` filtering:
50
-
51
- ```javascript
52
- it("step01: open application", async () => { ... });
53
- it("step02: click login button", async () => { ... });
54
- it("step03: enter username", async () => { ... });
55
- it("step04: enter password", async () => { ... });
56
- it("step05: submit form", async () => { ... });
57
- it("step06: verify dashboard loaded", async () => { ... });
58
- ```
59
-
60
- ### 3. All Steps in One File
61
-
62
- Write all steps for a test flow in the same file. This allows:
63
- - Running the entire flow: `vitest path/to/test.test.js`
64
- - Debugging a single step: `vitest --testNamePattern "step03"`
65
-
66
- ### 4. Optional Assertions
67
-
68
- Assertions verify the action worked. Use them when appropriate:
69
-
70
- ```javascript
71
- // After clicking - verify navigation or state change
72
- it("step01: click submit button", async () => {
73
- await testdriver.find("Submit button").click();
74
- await testdriver.assert("form was submitted successfully");
75
- });
76
-
77
- // After typing - verify text appeared (optional, typing is deterministic)
78
- it("step02: type search query", async () => {
79
- await testdriver.type("search term");
80
- // assertion optional for typing
81
- });
82
-
83
- // Use exists() for element presence
84
- it("step03: verify modal appeared", async () => {
85
- const modal = await testdriver.find("Confirmation modal");
86
- expect(modal.exists()).toBe(true);
87
- });
88
- ```
89
-
90
- ## Test Structure
91
-
92
- ### Basic Template
93
-
94
- ```javascript
95
- import { describe, it, expect } from "vitest";
96
- import { TestDriver } from "testdriverai/vitest";
97
-
98
- describe("Feature Name", () => {
99
- it("step01: provision and first action", async (context) => {
100
- const testdriver = TestDriver(context);
101
- await testdriver.provision.chrome({ url: 'https://example.com' });
102
-
103
- // First action + optional assertion
104
- });
105
-
106
- it("step02: second action", async (context) => {
107
- const testdriver = TestDriver(context);
108
-
109
- // action + optional assertion
110
- });
111
- });
112
- ```
113
-
114
- **Key Points:**
115
- - Each test gets its own `testdriver` via `TestDriver(context)`
116
- - Call `provision.chrome({ url })` in the first step to launch the browser
117
- - Subsequent steps don't need to provision - the sandbox persists
118
-
119
- ## Shared Helpers
120
-
121
- ### Reusing Common Flows
122
-
123
- Before writing steps for common flows (login, navigation, setup), check if a helper already exists.
124
-
125
- **Helper Location:** `testdriver/helpers/`
126
-
127
- ### Creating a Helper
128
-
129
- ```javascript
130
- // testdriver/helpers/login.js
131
- export async function login(testdriver, username = "testuser", password = "password") {
132
- const loginButton = await testdriver.find("Login button");
133
- await loginButton.click();
134
-
135
- await testdriver.type(username);
136
- await testdriver.pressKeys(["Tab"]);
137
- await testdriver.type(password);
138
-
139
- const submitButton = await testdriver.find("Submit button");
140
- await submitButton.click();
141
-
142
- await testdriver.assert("user is logged in");
143
- }
144
- ```
145
-
146
- ### Using a Helper
147
-
148
- ```javascript
149
- import { describe, it, expect } from "vitest";
150
- import { TestDriver } from "testdriverai/vitest";
151
- import { login } from "./helpers/login.js";
152
-
153
- describe("Dashboard Tests", () => {
154
- it("step01: provision and login", async (context) => {
155
- const testdriver = TestDriver(context);
156
- await testdriver.provision.chrome({ url: 'https://example.com' });
157
- await login(testdriver);
158
- });
159
-
160
- it("step02: navigate to settings", async (context) => {
161
- const testdriver = TestDriver(context);
162
- const settingsLink = await testdriver.find("Settings link in sidebar");
163
- await settingsLink.click();
164
- });
165
-
166
- // ... more steps
167
- });
168
- ```
169
-
170
- ### When to Create Helpers
171
-
172
- Create a helper when:
173
- - Flow is used in multiple tests (login, logout, navigation)
174
- - Flow has 3+ steps that are always done together
175
- - Flow requires specific credentials or configuration
176
-
177
- ## Iterative Development Workflow
178
-
179
- **CRITICAL: Write and run tests ONE STEP AT A TIME.** Do not write the entire test file upfront. Build it incrementally.
180
-
181
- ### The Loop
182
-
183
- ```
184
- ┌─────────────────────────────────────────────────────────┐
185
- │ 1. Write ONE step │
186
- │ 2. Run that step: vitest --testNamePattern "stepNN" │
187
- │ 3. Did it pass? │
188
- │ ├─ YES → Go to step 1, write next step │
189
- │ └─ NO → Fix the step, go to step 2 │
190
- │ 4. When all steps pass, run entire file │
191
- └─────────────────────────────────────────────────────────┘
192
- ```
193
-
194
- ### Detailed Workflow
195
-
196
- #### Phase 1: Setup the Test File
197
-
198
- Create the file with the describe block and NO steps yet:
199
-
200
- ```javascript
201
- import { describe, it, expect } from "vitest";
202
- import { TestDriver } from "testdriverai/vitest";
203
-
204
- describe("My Feature Test", () => {
205
- // Steps will be added one at a time below
206
- });
207
- ```
208
-
209
- #### Phase 2: Write Step 1
210
-
211
- Add the first step with provisioning:
212
-
213
- ```javascript
214
- it("step01: open app and click login", async (context) => {
215
- const testdriver = TestDriver(context);
216
- await testdriver.provision.chrome({ url: 'https://example.com/login' });
217
-
218
- const button = await testdriver.find("Login button in the header");
219
- await button.click();
220
- });
221
- ```
222
-
223
- #### Phase 3: Run Step 1
224
-
225
- ```bash
226
- vitest --testNamePattern "step01" path/to/test.test.js
227
- ```
228
-
229
- **If it passes:** Move to Phase 4.
230
-
231
- **If it fails:**
232
- - Check the error message
233
- - Take a screenshot to see actual screen state
234
- - Common fixes:
235
- - Improve the `find()` description (be more specific)
236
- - The element might not be visible yet (add scroll or wait)
237
- - Wrong element clicked (check coordinates)
238
- - Edit the step and re-run the same command
239
-
240
- #### Phase 4: Write Step 2
241
-
242
- Only after step 1 passes, add step 2:
243
-
244
- ```javascript
245
- it("step02: type username", async (context) => {
246
- const testdriver = TestDriver(context);
247
- await testdriver.type("testuser");
248
- });
249
- ```
250
-
251
- #### Phase 5: Run Step 2
252
-
253
- ```bash
254
- vitest --testNamePattern "step02" path/to/test.test.js
255
- ```
256
-
257
- The sandbox persists from step 1, so the app is already in the right state.
258
-
259
- **If it passes:** Continue to step 3.
260
-
261
- **If it fails:** Fix and re-run step 2 only.
262
-
263
- #### Phase 6: Repeat
264
-
265
- Continue this pattern:
266
- 1. Write step N
267
- 2. Run step N
268
- 3. Fix until passing
269
- 4. Write step N+1
270
-
271
- #### Phase 7: Run Full Test
272
-
273
- When all steps pass individually:
274
-
275
- ```bash
276
- vitest path/to/test.test.js
277
- ```
278
-
279
- This runs all steps in sequence to verify the complete flow.
280
-
281
- ### Why One Step at a Time?
282
-
283
- 1. **Faster debugging** - If step 5 fails, you only re-run step 5, not steps 1-4
284
- 2. **Sandbox reuse** - The sandbox persists, so previous steps don't need to re-run
285
- 3. **Immediate feedback** - You see if each action works before moving on
286
- 4. **Easier fixes** - Smaller changes are easier to debug
287
-
288
- ### Example: Building a Test Incrementally
289
-
290
- **Goal:** Test user login
291
-
292
- **Iteration 1:** Write and run step01
293
- ```javascript
294
- it("step01: provision and click login", async (context) => {
295
- const testdriver = TestDriver(context);
296
- await testdriver.provision.chrome({ url: 'https://example.com' });
297
-
298
- const button = await testdriver.find("Login button");
299
- await button.click();
300
- });
301
- ```
302
- ```bash
303
- vitest --testNamePattern "step01" login.test.js
304
- # ✅ Passed
305
- ```
306
-
307
- **Iteration 2:** Write and run step02
308
- ```javascript
309
- it("step02: type username", async (context) => {
310
- const testdriver = TestDriver(context);
311
- await testdriver.type("admin");
312
- });
313
- ```
314
- ```bash
315
- vitest --testNamePattern "step02" login.test.js
316
- # ❌ Failed - typing into wrong field
317
- ```
318
-
319
- **Iteration 2b:** Fix step02 - need to click the field first
320
- ```javascript
321
- it("step02: click username field", async (context) => {
322
- const testdriver = TestDriver(context);
323
- const field = await testdriver.find("Username input field");
324
- await field.click();
325
- });
326
- ```
327
- ```bash
328
- vitest --testNamePattern "step02" login.test.js
329
- # ✅ Passed
330
- ```
331
-
332
- **Iteration 3:** Write and run step03
333
- ```javascript
334
- it("step03: type username", async (context) => {
335
- const testdriver = TestDriver(context);
336
- await testdriver.type("admin");
337
- });
338
- ```
339
- ```bash
340
- vitest --testNamePattern "step03" login.test.js
341
- # ✅ Passed
342
- ```
343
-
344
- Continue until complete...
345
-
346
- ## Sandbox Persistence
347
-
348
- TestDriver automatically persists sandbox connections:
349
-
350
- - **Project-local:** `.testdriver-sandbox.json` in current directory
351
- - **Timeout:** 10 minutes of inactivity
352
- - **Auto-reconnect:** Automatically reuses recent sandbox on next run
353
-
354
- During development:
355
- - Don't call `disconnect()` in `afterAll`
356
- - Sandbox stays alive between test runs
357
- - If sandbox expires, a new one is created automatically
358
-
359
- ### One-Time Setup Steps
360
-
361
- Use `it.once()` for steps that should only run once per sandbox session (app launch, provisioning):
362
-
363
- ```javascript
364
- import { describe, it, beforeAll, expect } from "testdriverai/vitest";
365
- import TestDriver from "testdriverai";
366
-
367
- describe("My Test", () => {
368
- let testdriver;
369
-
370
- beforeAll(async () => {
371
- testdriver = new TestDriver(process.env.TD_API_KEY);
372
- await testdriver.connect();
373
-
374
- // Store globally so it.once() can check isReconnected
375
- globalThis.__testdriver = testdriver;
376
- });
377
-
378
- // Only runs once per sandbox session - skipped on reconnect
379
- it.once("launch the application", async () => {
380
- await testdriver.exec("sh", "google-chrome https://example.com", 5000);
381
- await testdriver.assert("application is loaded");
382
- });
383
-
384
- // Always runs
385
- it("click the login button", async () => {
386
- const button = await testdriver.find("Login button");
387
- await button.click();
388
- });
389
-
390
- // Always runs
391
- it("type username", async () => {
392
- await testdriver.type("testuser");
393
- });
394
- });
395
- ```
396
-
397
- **When to use `it.once()`:**
398
- - Launching the application
399
- - Navigating to initial URL
400
- - One-time provisioning steps
401
- - Any step that sets up state that persists in the sandbox
402
-
403
- **Regular `it()` steps:**
404
- - All subsequent actions
405
- - Steps you're actively developing/debugging
406
-
407
- This lets you run the full file and one-time steps are automatically skipped on reconnect:
408
- ```bash
409
- # First run: setup runs, then all steps
410
- vitest path/to/test.test.js
411
-
412
- # Second run (within 10 min): setup skipped, runs from first regular step
413
- vitest path/to/test.test.js
414
- ```
415
-
416
- **How it works:**
417
- - The SDK sets `testdriver.isReconnected = true` when it reconnects to an existing sandbox
418
- - `it.once()` checks `globalThis.__testdriver.isReconnected` to decide whether to skip
419
-
420
- ## SDK Quick Reference
421
-
422
- ### Finding Elements
423
-
424
- ```javascript
425
- // Find returns an Element with coordinates
426
- const element = await testdriver.find("description of element");
427
-
428
- // Chain directly
429
- await testdriver.find("Submit button").click();
430
-
431
- // Check if found
432
- if (element.exists()) { ... }
433
-
434
- // Get coordinates
435
- const { x, y, centerX, centerY } = element.getCoordinates();
436
- ```
437
-
438
- ### Actions
439
-
440
- ```javascript
441
- // Click (on found element)
442
- await element.click();
443
- await element.click("double-click");
444
- await element.click("right-click");
445
-
446
- // Type text (into focused field)
447
- await testdriver.type("text to type");
448
- await testdriver.type("text", 100); // with delay between keys
449
-
450
- // Keyboard shortcuts
451
- await testdriver.pressKeys(["ctrl", "c"]);
452
- await testdriver.pressKeys(["cmd", "shift", "p"]);
453
-
454
- // Scroll
455
- await testdriver.scroll("down", 300);
456
- await testdriver.scroll("up", 500, "keyboard");
457
- ```
458
-
459
- ### Verification
460
-
461
- ```javascript
462
- // AI-powered assertion (flexible, visual)
463
- const passed = await testdriver.assert("the form was submitted successfully");
464
- expect(passed).toBe(true);
465
-
466
- // Element existence
467
- const element = await testdriver.find("Success message");
468
- expect(element.exists()).toBe(true);
469
-
470
- // Screenshot for debugging
471
- const screenshot = await testdriver.screenshot();
472
- ```
473
-
474
- ### Remember (Extract Values)
475
-
476
- ```javascript
477
- // Extract dynamic values from screen
478
- const orderNumber = await testdriver.remember("the order confirmation number");
479
- console.log("Order:", orderNumber);
480
- ```
481
-
482
- ## Example: Complete Test File
483
-
484
- ```javascript
485
- import { describe, it, expect } from "vitest";
486
- import { TestDriver } from "testdriverai/vitest";
487
-
488
- describe("User Registration", () => {
489
- it("step01: provision and navigate to registration", async (context) => {
490
- const testdriver = TestDriver(context);
491
- await testdriver.provision.chrome({ url: 'https://example.com' });
492
-
493
- const signupLink = await testdriver.find("Sign Up link in navigation");
494
- await signupLink.click();
495
- await testdriver.assert("registration form is visible");
496
- });
497
-
498
- it("step02: enter email address", async (context) => {
499
- const testdriver = TestDriver(context);
500
- const emailField = await testdriver.find("Email input field");
501
- await emailField.click();
502
- await testdriver.type("test@example.com");
503
- });
504
-
505
- it("step03: enter password", async (context) => {
506
- const testdriver = TestDriver(context);
507
- const passwordField = await testdriver.find("Password input field");
508
- await passwordField.click();
509
- await testdriver.type("SecurePass123!");
510
- });
511
-
512
- it("step04: confirm password", async (context) => {
513
- const testdriver = TestDriver(context);
514
- const confirmField = await testdriver.find("Confirm password field");
515
- await confirmField.click();
516
- await testdriver.type("SecurePass123!");
517
- });
518
-
519
- it("step05: accept terms and conditions", async (context) => {
520
- const testdriver = TestDriver(context);
521
- const checkbox = await testdriver.find("Terms and conditions checkbox");
522
- await checkbox.click();
523
- });
524
-
525
- it("step06: submit registration", async (context) => {
526
- const testdriver = TestDriver(context);
527
- const submitButton = await testdriver.find("Create Account button");
528
- await submitButton.click();
529
- await testdriver.assert("account was created successfully");
530
- });
531
-
532
- it("step07: verify welcome message", async (context) => {
533
- const testdriver = TestDriver(context);
534
- const welcome = await testdriver.find("Welcome message");
535
- expect(welcome.exists()).toBe(true);
536
- });
537
- });
538
- ```
539
-
540
- ## Tips for AI Agents
541
-
542
- 1. **Write ONE step at a time** - Never write the full test upfront. Write step 1, run it, fix it, then write step 2.
543
- 2. **Run after each step** - Use `vitest --testNamePattern "stepNN"` to test each step immediately
544
- 3. **Search before writing** - Check `testdriver/helpers/` for existing flows
545
- 4. **Descriptive find()** - Include location, color, text: "blue Submit button below the form"
546
- 5. **One action at a time** - Easier to debug when things fail
547
- 6. **Assert after important actions** - Especially navigation and form submissions
548
- 7. **Use step numbers** - Makes `--testNamePattern` filtering easy
549
- 8. **Don't disconnect during dev** - Let sandbox persist for faster iteration
550
- 9. **Check screenshots** - When steps fail, look at actual screen state
package/CODEOWNERS DELETED
@@ -1,2 +0,0 @@
1
- # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners#example-of-a-codeowners-file
2
- @ianjennings
@@ -1,7 +0,0 @@
1
- version: 6.0.1
2
- session: 6877c33b74c5eac738259a74
3
- steps:
4
- - prompt: assert the testdriver login page shows
5
- commands:
6
- - command: assert
7
- expect: the TestDriver.ai Sandbox login page is displayed
@@ -1,9 +0,0 @@
1
- version: 6.0.0
2
- session: 685b38f0eb7de6d6447396cf
3
- steps:
4
- - prompt: fetch user data from API
5
- commands:
6
- - command: hover-text
7
- text: Sign In
8
- description: black button below the password field
9
- action: click
@@ -1,49 +0,0 @@
1
- # yaml-language-server: $schema=https://raw.githubusercontent.com/testdriverai/cli/refs/heads/main/schema.json
2
-
3
- version: 6.0.5
4
- session: 687aa621328371880ec75e89
5
- steps:
6
- - prompt: Show the desktop
7
- commands:
8
- - command: press-keys
9
- keys:
10
- - win
11
- - d
12
- - prompt: Open the context menu
13
- commands:
14
- - command: press-keys
15
- keys:
16
- - shift
17
- - f10
18
- - prompt: Hover over "New" in the context menu
19
- commands:
20
- - command: hover-text
21
- text: New
22
- description: new option in the open context menu on the desktop
23
- action: hover
24
- - prompt: Click "Text Document" in the context menu
25
- commands:
26
- - command: hover-text
27
- text: Text Document
28
- description: text document option in the new submenu of the desktop context menu
29
- action: click
30
- - prompt: Unfocus the "Text Document" text field
31
- commands:
32
- - command: press-keys
33
- keys:
34
- - esc
35
- - prompt: Drag the "New Text Document" icon to the "Recycle Bin"
36
- commands:
37
- - command: hover-text
38
- text: New Text Document
39
- description: new text document icon in the center of the desktop
40
- action: mouseDown
41
- - command: hover-text
42
- text: Recycle Bin
43
- description: recycle bin icon in the top left corner of the desktop
44
- action: mouseUp
45
-
46
- - prompt: '"New Text Document" icon is not on the Desktop'
47
- commands:
48
- - command: assert
49
- expect: the "New Text Document" icon is not visible on the Desktop
@@ -1,9 +0,0 @@
1
- version: 6.0.11
2
- session: 682f5fc22856e2eb40664261
3
- steps:
4
- - prompt: run login test
5
- commands:
6
- - command: run
7
- file: ./snippets/login.yaml
8
- - command: assert
9
- expect: home page appears
@@ -1,29 +0,0 @@
1
- version: 5.7.7
2
- session: 682f5fc22856e2eb40664269
3
- steps:
4
- - prompt: fetch user data from API
5
- commands:
6
- - command: exec
7
- output: user
8
- lang: js
9
- code: >
10
- const response = await
11
- fetch('https://jsonplaceholder.typicode.com/users');
12
-
13
- const user = await response.json();
14
-
15
- console.log('user', user[0]);
16
-
17
- result = user[0].email;
18
- - command: hover-text
19
- text: Username
20
- description: input field for username
21
- action: click
22
- - command: type
23
- text: ${OUTPUT.user}
24
- - prompt: assert that the username field shows a valid email address
25
- commands:
26
- - command: assert
27
- expect: >-
28
- the username field contains "Sincere@april.biz" which is a valid email
29
- address
@@ -1,43 +0,0 @@
1
- version: 6.0.1-canary.dd4927e.0
2
- session: 686f219f56143a3ffe789d1e
3
- steps:
4
- - prompt: set the date for our test
5
- commands:
6
- - command: exec
7
- lang: pwsh
8
- output: queryString
9
- code: |
10
- $date = (Get-Date).AddMonths(1)
11
- Write-Output $date.ToString("yyyy-MM-dd")
12
- - command: assert
13
- expect: ${OUTPUT.queryString} is a valid date
14
- - prompt: set the date for our assertion
15
- commands:
16
- - command: exec
17
- lang: pwsh
18
- output: expectedDate
19
- code: |
20
- $date = (Get-Date).AddMonths(1)
21
- Write-Output $date.ToString("ddd MMM d yyyy")
22
- # Go to a public calendar that accepts query strings to set the date
23
- - prompt: >-
24
- now press ctrl + l, then type
25
- https://teamup.com/ks48cf2135e7e080bc?view=d&date=${OUTPUT.queryString} and press enter
26
- commands:
27
- - command: focus-application
28
- name: Google Chrome
29
- - command: press-keys
30
- keys:
31
- - ctrl
32
- - l
33
- - command: type
34
- text: https://teamup.com/ks48cf2135e7e080bc?view=d&date=${OUTPUT.queryString}
35
- - command: press-keys
36
- keys:
37
- - enter
38
- - prompt: assert that the date ${OUTPUT.expectedDate} shows
39
- commands:
40
- - command: focus-application
41
- name: Google Chrome
42
- - command: assert
43
- expect: the text ${OUTPUT.expectedDate} is visible on screen