testdriverai 6.2.1 → 7.0.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 (264) 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/MIGRATION.md +389 -0
  5. package/PLUGIN_MIGRATION.md +222 -0
  6. package/PROMPT_CACHE.md +200 -0
  7. package/SDK_LOGGING.md +222 -0
  8. package/SDK_MIGRATION.md +474 -0
  9. package/SDK_README.md +1122 -0
  10. package/{testdriver → _testdriver}/acceptance/drag-and-drop.yaml +2 -2
  11. package/{testdriver → _testdriver}/acceptance/snippets/login.yaml +1 -1
  12. package/_testdriver/examples/desktop/lifecycle/prerun.yaml +0 -0
  13. package/{testdriver → _testdriver}/examples/web/lifecycle/prerun.yaml +6 -1
  14. package/{testdriver → _testdriver}/lifecycle/postrun.yaml +3 -2
  15. package/_testdriver/lifecycle/prerun.yaml +15 -0
  16. package/{testdriver → _testdriver}/lifecycle/provision.yaml +7 -2
  17. package/agent/index.js +258 -68
  18. package/agent/interface.js +15 -0
  19. package/agent/lib/cache.js +142 -0
  20. package/agent/lib/commander.js +1 -39
  21. package/agent/lib/commands.js +143 -188
  22. package/agent/lib/redraw.js +6 -3
  23. package/agent/lib/sandbox.js +19 -5
  24. package/agent/lib/sdk.js +1 -0
  25. package/agent/lib/system.js +0 -3
  26. package/agent/lib/validation.js +1 -7
  27. package/debug-locate-response.js +82 -0
  28. package/debug-screenshot-1763401388589.png +0 -0
  29. package/debugger/index.html +16 -5
  30. package/docs/ARCHITECTURE.md +424 -0
  31. package/docs/AWESOME_LOGS_QUICK_REF.md +100 -0
  32. package/docs/QUICK_START_TEST_RECORDING.md +215 -0
  33. package/docs/SDK_AWESOME_LOGS.md +468 -0
  34. package/docs/TEST_RECORDING.md +388 -0
  35. package/docs/docs.json +232 -152
  36. package/docs/sdk-browser-rendering.md +167 -0
  37. package/docs/v6/getting-started/self-hosting.mdx +407 -0
  38. package/docs/{guide → v6/guide}/dashcam.mdx +1 -1
  39. package/docs/{guide → v6/guide}/environment-variables.mdx +4 -5
  40. package/docs/{guide → v6/guide}/lifecycle.mdx +1 -1
  41. package/docs/v6/overview/comparison.mdx +101 -0
  42. package/docs/v7/README.md +135 -0
  43. package/docs/v7/api/ai.mdx +205 -0
  44. package/docs/v7/api/assert.mdx +285 -0
  45. package/docs/v7/api/assertions.mdx +403 -0
  46. package/docs/v7/api/click.mdx +287 -0
  47. package/docs/v7/api/client.mdx +322 -0
  48. package/docs/v7/api/elements.mdx +479 -0
  49. package/docs/v7/api/exec.mdx +346 -0
  50. package/docs/v7/api/find.mdx +316 -0
  51. package/docs/v7/api/focusApplication.mdx +294 -0
  52. package/docs/v7/api/hover.mdx +279 -0
  53. package/docs/v7/api/pressKeys.mdx +349 -0
  54. package/docs/v7/api/sandbox.mdx +404 -0
  55. package/docs/v7/api/scroll.mdx +300 -0
  56. package/docs/v7/api/type.mdx +314 -0
  57. package/docs/v7/commands/assert.mdx +45 -0
  58. package/docs/v7/commands/exec.mdx +282 -0
  59. package/docs/v7/commands/focus-application.mdx +44 -0
  60. package/docs/v7/commands/hover-image.mdx +69 -0
  61. package/docs/v7/commands/hover-text.mdx +47 -0
  62. package/docs/v7/commands/if.mdx +53 -0
  63. package/docs/v7/commands/match-image.mdx +67 -0
  64. package/docs/v7/commands/press-keys.mdx +87 -0
  65. package/docs/v7/commands/remember.mdx +49 -0
  66. package/docs/v7/commands/run.mdx +44 -0
  67. package/docs/v7/commands/scroll-until-image.mdx +66 -0
  68. package/docs/v7/commands/scroll-until-text.mdx +60 -0
  69. package/docs/v7/commands/scroll.mdx +69 -0
  70. package/docs/v7/commands/type.mdx +45 -0
  71. package/docs/v7/commands/wait-for-image.mdx +54 -0
  72. package/docs/v7/commands/wait-for-text.mdx +48 -0
  73. package/docs/v7/commands/wait.mdx +45 -0
  74. package/docs/v7/getting-started/quickstart.mdx +199 -0
  75. package/docs/v7/guides/migration.mdx +562 -0
  76. package/docs/{getting-started → v7/guides}/self-hosting.mdx +11 -12
  77. package/docs/v7/playwright.mdx +342 -0
  78. package/eslint.config.js +19 -1
  79. package/examples/run-tests-with-recording.sh +70 -0
  80. package/examples/screenshot-example.js +63 -0
  81. package/examples/sdk-awesome-logs-demo.js +177 -0
  82. package/examples/sdk-cache-thresholds.js +96 -0
  83. package/examples/sdk-element-properties.js +155 -0
  84. package/examples/sdk-simple-example.js +65 -0
  85. package/examples/test-recording-example.test.js +166 -0
  86. package/interfaces/cli/lib/base.js +10 -4
  87. package/interfaces/logger.js +2 -1
  88. package/interfaces/shared-test-state.mjs +69 -0
  89. package/interfaces/vitest-plugin.mjs +744 -0
  90. package/mcp-server/AI_GUIDELINES.md +57 -0
  91. package/package.json +18 -5
  92. package/schema.json +8 -29
  93. package/scripts/view-test-results.mjs +96 -0
  94. package/sdk-log-formatter.js +714 -0
  95. package/sdk.d.ts +735 -0
  96. package/sdk.js +1906 -0
  97. package/{.github/workflows/self-hosted.yml → self-hosted.yml} +13 -4
  98. package/setup/aws/cloudformation.yaml +9 -2
  99. package/test/mcp-example-test.yaml +27 -0
  100. package/test-find-api.js +73 -0
  101. package/test-prompt-cache.js +96 -0
  102. package/test-sandbox-render.js +28 -0
  103. package/test-sdk-methods.js +15 -0
  104. package/test-sdk-refactor.js +53 -0
  105. package/test-stack-trace.mjs +57 -0
  106. package/testdriver/acceptance-sdk/QUICK_REFERENCE.md +61 -0
  107. package/testdriver/acceptance-sdk/README.md +128 -0
  108. package/testdriver/acceptance-sdk/TEST_REPORTING.md +245 -0
  109. package/testdriver/acceptance-sdk/assert.test.mjs +44 -0
  110. package/testdriver/acceptance-sdk/drag-and-drop.test.mjs +70 -0
  111. package/testdriver/acceptance-sdk/element-not-found.test.mjs +38 -0
  112. package/testdriver/acceptance-sdk/exec-js.test.mjs +55 -0
  113. package/testdriver/acceptance-sdk/exec-output.test.mjs +71 -0
  114. package/testdriver/acceptance-sdk/exec-pwsh.test.mjs +69 -0
  115. package/testdriver/acceptance-sdk/focus-window.test.mjs +48 -0
  116. package/testdriver/acceptance-sdk/formatted-logging.test.mjs +41 -0
  117. package/testdriver/acceptance-sdk/hover-image.test.mjs +43 -0
  118. package/testdriver/acceptance-sdk/hover-text-with-description.test.mjs +50 -0
  119. package/testdriver/acceptance-sdk/hover-text.test.mjs +41 -0
  120. package/testdriver/acceptance-sdk/match-image.test.mjs +48 -0
  121. package/testdriver/acceptance-sdk/press-keys.test.mjs +64 -0
  122. package/testdriver/acceptance-sdk/prompt.test.mjs +45 -0
  123. package/testdriver/acceptance-sdk/scroll-keyboard.test.mjs +52 -0
  124. package/testdriver/acceptance-sdk/scroll-until-image.test.mjs +51 -0
  125. package/testdriver/acceptance-sdk/scroll-until-text.test.mjs +42 -0
  126. package/testdriver/acceptance-sdk/scroll.test.mjs +50 -0
  127. package/testdriver/acceptance-sdk/setup/globalTeardown.mjs +11 -0
  128. package/testdriver/acceptance-sdk/setup/lifecycleHelpers.mjs +239 -0
  129. package/testdriver/acceptance-sdk/setup/testHelpers.mjs +648 -0
  130. package/testdriver/acceptance-sdk/setup/vitestSetup.mjs +40 -0
  131. package/testdriver/acceptance-sdk/type-checking-demo.js +49 -0
  132. package/testdriver/acceptance-sdk/type.test.mjs +84 -0
  133. package/verify-element-api.js +89 -0
  134. package/verify-types.js +0 -0
  135. package/vitest.config.example.js +19 -0
  136. package/vitest.config.mjs +65 -0
  137. package/vitest.config.mjs.bak +44 -0
  138. package/.github/workflows/acceptance-v6.yml +0 -169
  139. package/docs/overview/comparison.mdx +0 -82
  140. package/testdriver/lifecycle/prerun.yaml +0 -17
  141. /package/{testdriver/examples/desktop/lifecycle/prerun.yaml → .env.example} +0 -0
  142. /package/{testdriver → _testdriver}/acceptance/assert.yaml +0 -0
  143. /package/{testdriver → _testdriver}/acceptance/dashcam.yaml +0 -0
  144. /package/{testdriver → _testdriver}/acceptance/embed.yaml +0 -0
  145. /package/{testdriver → _testdriver}/acceptance/exec-js.yaml +0 -0
  146. /package/{testdriver → _testdriver}/acceptance/exec-output.yaml +0 -0
  147. /package/{testdriver → _testdriver}/acceptance/exec-shell.yaml +0 -0
  148. /package/{testdriver → _testdriver}/acceptance/focus-window.yaml +0 -0
  149. /package/{testdriver → _testdriver}/acceptance/hover-image.yaml +0 -0
  150. /package/{testdriver → _testdriver}/acceptance/hover-text-with-description.yaml +0 -0
  151. /package/{testdriver → _testdriver}/acceptance/hover-text.yaml +0 -0
  152. /package/{testdriver → _testdriver}/acceptance/if-else.yaml +0 -0
  153. /package/{testdriver → _testdriver}/acceptance/match-image.yaml +0 -0
  154. /package/{testdriver → _testdriver}/acceptance/press-keys.yaml +0 -0
  155. /package/{testdriver → _testdriver}/acceptance/prompt.yaml +0 -0
  156. /package/{testdriver → _testdriver}/acceptance/remember.yaml +0 -0
  157. /package/{testdriver → _testdriver}/acceptance/screenshots/cart.png +0 -0
  158. /package/{testdriver → _testdriver}/acceptance/scroll-keyboard.yaml +0 -0
  159. /package/{testdriver → _testdriver}/acceptance/scroll-until-image.yaml +0 -0
  160. /package/{testdriver → _testdriver}/acceptance/scroll-until-text.yaml +0 -0
  161. /package/{testdriver → _testdriver}/acceptance/scroll.yaml +0 -0
  162. /package/{testdriver → _testdriver}/acceptance/snippets/match-cart.yaml +0 -0
  163. /package/{testdriver → _testdriver}/acceptance/type.yaml +0 -0
  164. /package/{testdriver → _testdriver}/behavior/failure.yaml +0 -0
  165. /package/{testdriver → _testdriver}/behavior/hover-text.yaml +0 -0
  166. /package/{testdriver → _testdriver}/behavior/lifecycle/postrun.yaml +0 -0
  167. /package/{testdriver → _testdriver}/behavior/lifecycle/prerun.yaml +0 -0
  168. /package/{testdriver → _testdriver}/behavior/lifecycle/provision.yaml +0 -0
  169. /package/{testdriver → _testdriver}/behavior/secrets.yaml +0 -0
  170. /package/{testdriver → _testdriver}/edge-cases/dashcam-chrome.yaml +0 -0
  171. /package/{testdriver → _testdriver}/edge-cases/exec-pwsh-multiline.yaml +0 -0
  172. /package/{testdriver → _testdriver}/edge-cases/js-exception.yaml +0 -0
  173. /package/{testdriver → _testdriver}/edge-cases/js-promise.yaml +0 -0
  174. /package/{testdriver → _testdriver}/edge-cases/lifecycle/postrun.yaml +0 -0
  175. /package/{testdriver → _testdriver}/edge-cases/prompt-in-middle.yaml +0 -0
  176. /package/{testdriver → _testdriver}/edge-cases/prompt-nested.yaml +0 -0
  177. /package/{testdriver → _testdriver}/edge-cases/success-test.yaml +0 -0
  178. /package/{testdriver → _testdriver}/examples/android/example.yaml +0 -0
  179. /package/{testdriver → _testdriver}/examples/android/lifecycle/postrun.yaml +0 -0
  180. /package/{testdriver → _testdriver}/examples/android/lifecycle/provision.yaml +0 -0
  181. /package/{testdriver → _testdriver}/examples/android/readme.md +0 -0
  182. /package/{testdriver → _testdriver}/examples/chrome-extension/lifecycle/provision.yaml +0 -0
  183. /package/{testdriver → _testdriver}/examples/desktop/lifecycle/provision.yaml +0 -0
  184. /package/{testdriver → _testdriver}/examples/vscode-extension/lifecycle/provision.yaml +0 -0
  185. /package/{testdriver → _testdriver}/examples/web/lifecycle/postrun.yaml +0 -0
  186. /package/docs/{account → v6/account}/dashboard.mdx +0 -0
  187. /package/docs/{account → v6/account}/enterprise.mdx +0 -0
  188. /package/docs/{account → v6/account}/pricing.mdx +0 -0
  189. /package/docs/{account → v6/account}/projects.mdx +0 -0
  190. /package/docs/{account → v6/account}/team.mdx +0 -0
  191. /package/docs/{action → v6/action}/ami.mdx +0 -0
  192. /package/docs/{action → v6/action}/performance.mdx +0 -0
  193. /package/docs/{action → v6/action}/secrets.mdx +0 -0
  194. /package/docs/{apps → v6/apps}/chrome-extensions.mdx +0 -0
  195. /package/docs/{apps → v6/apps}/desktop-apps.mdx +0 -0
  196. /package/docs/{apps → v6/apps}/mobile-apps.mdx +0 -0
  197. /package/docs/{apps → v6/apps}/static-websites.mdx +0 -0
  198. /package/docs/{apps → v6/apps}/tauri-apps.mdx +0 -0
  199. /package/docs/{bugs → v6/bugs}/jira.mdx +0 -0
  200. /package/docs/{cli → v6/cli}/overview.mdx +0 -0
  201. /package/docs/{commands → v6/commands}/assert.mdx +0 -0
  202. /package/docs/{commands → v6/commands}/exec.mdx +0 -0
  203. /package/docs/{commands → v6/commands}/focus-application.mdx +0 -0
  204. /package/docs/{commands → v6/commands}/hover-image.mdx +0 -0
  205. /package/docs/{commands → v6/commands}/hover-text.mdx +0 -0
  206. /package/docs/{commands → v6/commands}/if.mdx +0 -0
  207. /package/docs/{commands → v6/commands}/match-image.mdx +0 -0
  208. /package/docs/{commands → v6/commands}/press-keys.mdx +0 -0
  209. /package/docs/{commands → v6/commands}/remember.mdx +0 -0
  210. /package/docs/{commands → v6/commands}/run.mdx +0 -0
  211. /package/docs/{commands → v6/commands}/scroll-until-image.mdx +0 -0
  212. /package/docs/{commands → v6/commands}/scroll-until-text.mdx +0 -0
  213. /package/docs/{commands → v6/commands}/scroll.mdx +0 -0
  214. /package/docs/{commands → v6/commands}/type.mdx +0 -0
  215. /package/docs/{commands → v6/commands}/wait-for-image.mdx +0 -0
  216. /package/docs/{commands → v6/commands}/wait-for-text.mdx +0 -0
  217. /package/docs/{commands → v6/commands}/wait.mdx +0 -0
  218. /package/docs/{exporting → v6/exporting}/junit.mdx +0 -0
  219. /package/docs/{exporting → v6/exporting}/playwright.mdx +0 -0
  220. /package/docs/{features → v6/features}/auto-healing.mdx +0 -0
  221. /package/docs/{features → v6/features}/generation.mdx +0 -0
  222. /package/docs/{features → v6/features}/parallel-testing.mdx +0 -0
  223. /package/docs/{features → v6/features}/reusable-snippets.mdx +0 -0
  224. /package/docs/{features → v6/features}/selectorless.mdx +0 -0
  225. /package/docs/{features → v6/features}/visual-assertions.mdx +0 -0
  226. /package/docs/{getting-started → v6/getting-started}/ci.mdx +0 -0
  227. /package/docs/{getting-started → v6/getting-started}/cli.mdx +0 -0
  228. /package/docs/{getting-started → v6/getting-started}/editing.mdx +0 -0
  229. /package/docs/{getting-started → v6/getting-started}/playwright.mdx +0 -0
  230. /package/docs/{getting-started → v6/getting-started}/running.mdx +0 -0
  231. /package/docs/{getting-started → v6/getting-started}/vscode.mdx +0 -0
  232. /package/docs/{guide → v6/guide}/assertions.mdx +0 -0
  233. /package/docs/{guide → v6/guide}/authentication.mdx +0 -0
  234. /package/docs/{guide → v6/guide}/code.mdx +0 -0
  235. /package/docs/{guide → v6/guide}/locating.mdx +0 -0
  236. /package/docs/{guide → v6/guide}/protips.mdx +0 -0
  237. /package/docs/{guide → v6/guide}/variables.mdx +0 -0
  238. /package/docs/{guide → v6/guide}/waiting.mdx +0 -0
  239. /package/docs/{importing → v6/importing}/csv.mdx +0 -0
  240. /package/docs/{importing → v6/importing}/gherkin.mdx +0 -0
  241. /package/docs/{importing → v6/importing}/jira.mdx +0 -0
  242. /package/docs/{importing → v6/importing}/testrail.mdx +0 -0
  243. /package/docs/{integrations → v6/integrations}/electron.mdx +0 -0
  244. /package/docs/{integrations → v6/integrations}/netlify.mdx +0 -0
  245. /package/docs/{integrations → v6/integrations}/vercel.mdx +0 -0
  246. /package/docs/{interactive → v6/interactive}/explore.mdx +0 -0
  247. /package/docs/{interactive → v6/interactive}/run.mdx +0 -0
  248. /package/docs/{interactive → v6/interactive}/save.mdx +0 -0
  249. /package/docs/{overview → v6/overview}/faq.mdx +0 -0
  250. /package/docs/{overview → v6/overview}/performance.mdx +0 -0
  251. /package/docs/{overview → v6/overview}/quickstart.mdx +0 -0
  252. /package/docs/{overview → v6/overview}/what-is-testdriver.mdx +0 -0
  253. /package/docs/{scenarios → v6/scenarios}/ai-chatbot.mdx +0 -0
  254. /package/docs/{scenarios → v6/scenarios}/cookie-banner.mdx +0 -0
  255. /package/docs/{scenarios → v6/scenarios}/file-upload.mdx +0 -0
  256. /package/docs/{scenarios → v6/scenarios}/form-filling.mdx +0 -0
  257. /package/docs/{scenarios → v6/scenarios}/log-in.mdx +0 -0
  258. /package/docs/{scenarios → v6/scenarios}/pdf-generation.mdx +0 -0
  259. /package/docs/{scenarios → v6/scenarios}/spell-check.mdx +0 -0
  260. /package/docs/{security → v6/security}/action.mdx +0 -0
  261. /package/docs/{security → v6/security}/agent.mdx +0 -0
  262. /package/docs/{security → v6/security}/platform.mdx +0 -0
  263. /package/docs/{tutorials → v6/tutorials}/advanced-test.mdx +0 -0
  264. /package/docs/{tutorials → v6/tutorials}/basic-test.mdx +0 -0
@@ -0,0 +1,75 @@
1
+ name: v6 Linux
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ push:
6
+ branches:
7
+ - main
8
+ paths-ignore:
9
+ - "docs/**"
10
+ pull_request:
11
+ branches:
12
+ - main
13
+
14
+ schedule:
15
+ - cron: "0 0 * * *"
16
+
17
+ jobs:
18
+ # Job to gather all test files
19
+ test-setup:
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - uses: actions/checkout@v3
23
+ - uses: actions/setup-node@v3
24
+ with:
25
+ node-version: 22
26
+ cache: npm
27
+ - run: npm ci
28
+
29
+ gather:
30
+ name: Gather Test Files
31
+ runs-on: ubuntu-latest
32
+ outputs:
33
+ test_files: ${{ steps.test_list.outputs.files }}
34
+ steps:
35
+ - name: Check out repository
36
+ uses: actions/checkout@v2
37
+
38
+ - name: Find all test files
39
+ id: test_list
40
+ run: |
41
+ FILES=$(ls ./testdriver/acceptance/*.yaml)
42
+ FILENAMES=$(basename -a $FILES)
43
+ FILES_JSON=$(echo "$FILENAMES" | jq -R -s -c 'split("\n")[:-1]')
44
+ echo "files=$FILES_JSON" >> $GITHUB_OUTPUT
45
+ test:
46
+ needs:
47
+ - gather
48
+ runs-on: ubuntu-latest
49
+ strategy:
50
+ matrix:
51
+ test: ${{ fromJson(needs.gather.outputs.test_files) }}
52
+ max-parallel: 8
53
+ fail-fast: false
54
+ steps:
55
+ - name: Checkout repository
56
+ uses: actions/checkout@v4
57
+ with:
58
+ fetch-depth: 0
59
+
60
+ - name: Set up Node.js
61
+ uses: actions/setup-node@v4
62
+ with:
63
+ node-version: "20"
64
+ cache: "npm"
65
+
66
+ - name: Install dependencies
67
+ run: NODE_ENV=production npm ci
68
+ - name: Run test in headless mode
69
+ run: node bin/testdriverai.js run testdriver/acceptance/${{ matrix.test }} --junit=out.xml
70
+ env:
71
+ FORCE_COLOR: 3
72
+ TD_API_KEY: 49c2996c-0687-40bf-9f2c-5d2e55b2a2c6
73
+ TD_WEBSITE: https://testdriver-sandbox.vercel.app
74
+ TD_THIS_FILE: ${{ matrix.test }}
75
+ TD_API_ROOT: "https://replayable-dev-ian-mac-m1-16.ngrok.io"
@@ -0,0 +1,133 @@
1
+ name: Acceptance SDK Tests
2
+
3
+ on:
4
+ pull_request:
5
+ branches:
6
+ - main
7
+ push:
8
+ branches: [main]
9
+ paths-ignore:
10
+ - "docs/**"
11
+ # So that we can manually trigger tests when there's flake
12
+ workflow_dispatch:
13
+
14
+ jobs:
15
+ test-workflow:
16
+ name: Run SDK Tests - ${{ matrix.platform }}
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 30
19
+ strategy:
20
+ fail-fast: false
21
+ matrix:
22
+ platform: [linux, windows]
23
+ steps:
24
+ - name: Checkout repository
25
+ uses: actions/checkout@v4
26
+ with:
27
+ fetch-depth: 0
28
+
29
+ - name: Set up Node.js
30
+ uses: actions/setup-node@v4
31
+ with:
32
+ node-version: "20"
33
+ cache: "npm"
34
+
35
+ - name: Install dependencies
36
+ run: npm ci
37
+
38
+ - name: Run ESLint
39
+ run: npx eslint . --max-warnings 0
40
+
41
+ - name: Run Prettier
42
+ run: npx prettier --check .
43
+
44
+ - name: Run SDK tests with Vitest - ${{ matrix.platform }}
45
+ run: npx vitest run testdriver/acceptance-sdk/*.test.mjs
46
+ env:
47
+ FORCE_COLOR: 3
48
+ TD_API_KEY: ${{ secrets.TESTDRIVER_API_KEY }}
49
+ TEST_PLATFORM: ${{ matrix.platform }}
50
+ VERBOSE: true
51
+ LOGGING: true
52
+ continue-on-error: true
53
+
54
+ - name: Generate GitHub Summary
55
+ if: always()
56
+ run: |
57
+ echo "# 🧪 TestDriver SDK Test Results" >> $GITHUB_STEP_SUMMARY
58
+ echo "" >> $GITHUB_STEP_SUMMARY
59
+
60
+ if [ -f test-results/results.json ]; then
61
+ node -e "
62
+ const fs = require('fs');
63
+ const results = JSON.parse(fs.readFileSync('test-results/results.json', 'utf8'));
64
+
65
+ const total = results.numTotalTests || 0;
66
+ const passed = results.numPassedTests || 0;
67
+ const failed = results.numFailedTests || 0;
68
+ const skipped = results.numPendingTests || 0;
69
+ const duration = ((results.testResults?.[0]?.endTime - results.testResults?.[0]?.startTime) / 1000 || 0).toFixed(2);
70
+
71
+ console.log('## 📊 Overview\n');
72
+ console.log('| Metric | Count |');
73
+ console.log('|--------|-------|');
74
+ console.log('| ✅ Passed | ' + passed + ' |');
75
+ console.log('| ❌ Failed | ' + failed + ' |');
76
+ console.log('| ⏭️ Skipped | ' + skipped + ' |');
77
+ console.log('| 📝 Total | ' + total + ' |');
78
+ console.log('| ⏱️ Duration | ' + duration + 's |');
79
+ console.log('');
80
+
81
+ if (failed > 0) {
82
+ console.log('## ❌ Failed Tests\n');
83
+ results.testResults?.forEach(file => {
84
+ file.assertionResults?.filter(test => test.status === 'failed').forEach(test => {
85
+ console.log('### ' + test.fullName);
86
+ console.log('**File:** \`' + file.name + '\`');
87
+ console.log('');
88
+ if (test.failureMessages?.length > 0) {
89
+ console.log('**Error:**');
90
+ console.log('\`\`\`');
91
+ console.log(test.failureMessages.join('\n').substring(0, 1000));
92
+ console.log('\`\`\`');
93
+ console.log('');
94
+ }
95
+ });
96
+ });
97
+ }
98
+
99
+ if (passed > 0) {
100
+ console.log('## ✅ Passed Tests\n');
101
+ results.testResults?.forEach(file => {
102
+ const passedTests = file.assertionResults?.filter(test => test.status === 'passed') || [];
103
+ if (passedTests.length > 0) {
104
+ console.log('### ' + file.name.split('/').pop());
105
+ passedTests.forEach(test => {
106
+ console.log('- ✅ ' + test.title);
107
+ });
108
+ console.log('');
109
+ }
110
+ });
111
+ }
112
+ " >> $GITHUB_STEP_SUMMARY
113
+ else
114
+ echo "⚠️ No test results found" >> $GITHUB_STEP_SUMMARY
115
+ fi
116
+
117
+ - name: Test Summary (JUnit)
118
+ uses: test-summary/action@v2
119
+ with:
120
+ paths: "test-results/junit.xml"
121
+ if: always()
122
+
123
+ - name: Upload test results
124
+ if: always()
125
+ uses: actions/upload-artifact@v4
126
+ with:
127
+ name: test-results-${{ matrix.platform }}
128
+ path: |
129
+ test-results/junit.xml
130
+ test-results/results.json
131
+ test-results/index.html
132
+ retention-days: 7
133
+ if-no-files-found: ignore
@@ -6,5 +6,9 @@
6
6
  "editor.defaultFormatter": "esbenp.prettier-vscode",
7
7
  "yaml.schemas": {
8
8
  "https://raw.githubusercontent.com/testdriverai/testdriverai/main/schema.json": "file:///Users/kid/Desktop/td/internal/testdriverai/testdriver.yaml"
9
- }
9
+ },
10
+ "vitest.enable": true,
11
+ "vitest.commandLine": "npx vitest --watch",
12
+ "vitest.include": ["**/testdriver/acceptance-sdk/*.test.mjs"],
13
+ "vitest.exclude": []
10
14
  }
package/MIGRATION.md ADDED
@@ -0,0 +1,389 @@
1
+ # Migrating from CLI to SDK
2
+
3
+ This guide helps you migrate from using TestDriver as a CLI tool to using it as an SDK in your JavaScript/Node.js applications.
4
+
5
+ ## Key Differences
6
+
7
+ ### CLI Approach (Old)
8
+
9
+ ```bash
10
+ # YAML-based test files
11
+ testdriverai run testdriver/my-test.yaml
12
+ ```
13
+
14
+ ```yaml
15
+ # testdriver/my-test.yaml
16
+ version: 6.1.10
17
+ steps:
18
+ - prompt: "Login to the application"
19
+ commands:
20
+ - command: hover-text
21
+ text: "Email"
22
+ - command: type
23
+ string: "user@example.com"
24
+ - command: hover-text
25
+ text: "Submit"
26
+ - command: wait-for-text
27
+ text: "Dashboard"
28
+ ```
29
+
30
+ ### SDK Approach (New)
31
+
32
+ ```javascript
33
+ // JavaScript-based tests
34
+ const TestDriver = require("testdriverai");
35
+
36
+ async function testLogin() {
37
+ const client = new TestDriver(process.env.TD_API_KEY);
38
+ await client.auth();
39
+ await client.connect();
40
+
41
+ await client.hoverText("Email");
42
+ await client.type("user@example.com");
43
+ await client.hoverText("Submit");
44
+ await client.waitForText("Dashboard");
45
+
46
+ await client.disconnect();
47
+ }
48
+ ```
49
+
50
+ ## Command Mapping
51
+
52
+ Here's how CLI commands map to SDK methods:
53
+
54
+ | YAML Command | SDK Method | Example |
55
+ | -------------------- | -------------------- | ----------------------------------------- |
56
+ | `hover-text` | `hoverText()` | `await client.hoverText('Submit')` |
57
+ | `hover-image` | `hoverImage()` | `await client.hoverImage('red button')` |
58
+ | `match-image` | `matchImage()` | `await client.matchImage('./button.png')` |
59
+ | `type` | `type()` | `await client.type('hello')` |
60
+ | `press-keys` | `pressKeys()` | `await client.pressKeys(['enter'])` |
61
+ | `click` | `click()` | `await client.click(100, 200)` |
62
+ | `scroll` | `scroll()` | `await client.scroll('down', 500)` |
63
+ | `wait` | `wait()` | `await client.wait(3000)` |
64
+ | `wait-for-text` | `waitForText()` | `await client.waitForText('Success')` |
65
+ | `wait-for-image` | `waitForImage()` | `await client.waitForImage('logo')` |
66
+ | `scroll-until-text` | `scrollUntilText()` | `await client.scrollUntilText('Footer')` |
67
+ | `scroll-until-image` | `scrollUntilImage()` | `await client.scrollUntilImage('banner')` |
68
+ | `focus-application` | `focusApplication()` | `await client.focusApplication('Chrome')` |
69
+ | `remember` | `remember()` | `await client.remember('user name')` |
70
+ | `assert` | `assert()` | `await client.assert('form is visible')` |
71
+ | `exec` | `exec()` | `await client.exec('js', code, 5000)` |
72
+
73
+ ## Converting YAML to SDK
74
+
75
+ ### Example 1: Simple Form Interaction
76
+
77
+ **YAML (CLI):**
78
+
79
+ ```yaml
80
+ version: 6.1.10
81
+ steps:
82
+ - prompt: "Fill out contact form"
83
+ commands:
84
+ - command: hover-text
85
+ text: "Name"
86
+ - command: type
87
+ string: "John Doe"
88
+ - command: hover-text
89
+ text: "Email"
90
+ - command: type
91
+ string: "john@example.com"
92
+ - command: hover-text
93
+ text: "Submit"
94
+ - command: wait-for-text
95
+ text: "Thank you"
96
+ timeout: 5000
97
+ ```
98
+
99
+ **SDK (JavaScript):**
100
+
101
+ ```javascript
102
+ const TestDriver = require("testdriverai");
103
+
104
+ async function fillContactForm() {
105
+ const client = new TestDriver(process.env.TD_API_KEY);
106
+
107
+ await client.auth();
108
+ await client.connect();
109
+
110
+ await client.hoverText("Name");
111
+ await client.type("John Doe");
112
+ await client.hoverText("Email");
113
+ await client.type("john@example.com");
114
+ await client.hoverText("Submit");
115
+ await client.waitForText("Thank you", 5000);
116
+
117
+ await client.disconnect();
118
+ }
119
+
120
+ fillContactForm();
121
+ ```
122
+
123
+ ### Example 2: Complex Navigation Flow
124
+
125
+ **YAML (CLI):**
126
+
127
+ ```yaml
128
+ version: 6.1.10
129
+ steps:
130
+ - prompt: "Navigate to settings"
131
+ commands:
132
+ - command: focus-application
133
+ name: "Google Chrome"
134
+ - command: wait
135
+ timeout: 2000
136
+ - command: hover-text
137
+ text: "Menu"
138
+ - command: wait
139
+ timeout: 1000
140
+ - command: hover-text
141
+ text: "Settings"
142
+ - command: scroll
143
+ direction: "down"
144
+ amount: 500
145
+ - command: assert
146
+ expect: "The settings page is displayed"
147
+ ```
148
+
149
+ **SDK (JavaScript):**
150
+
151
+ ```javascript
152
+ const TestDriver = require("testdriverai");
153
+
154
+ async function navigateToSettings() {
155
+ const client = new TestDriver(process.env.TD_API_KEY);
156
+
157
+ await client.auth();
158
+ await client.connect();
159
+
160
+ await client.focusApplication("Google Chrome");
161
+ await client.wait(2000);
162
+ await client.hoverText("Menu");
163
+ await client.wait(1000);
164
+ await client.hoverText("Settings");
165
+ await client.scroll("down", 500);
166
+ await client.assert("The settings page is displayed");
167
+
168
+ await client.disconnect();
169
+ }
170
+
171
+ navigateToSettings();
172
+ ```
173
+
174
+ ### Example 3: Using Variables and Loops
175
+
176
+ **YAML (CLI):**
177
+
178
+ ```yaml
179
+ version: 6.1.10
180
+ steps:
181
+ - prompt: "Process multiple items"
182
+ commands:
183
+ - command: exec
184
+ language: "js"
185
+ code: |
186
+ const items = ['Item 1', 'Item 2', 'Item 3'];
187
+ result = items;
188
+ ```
189
+
190
+ **SDK (JavaScript):**
191
+
192
+ ```javascript
193
+ const TestDriver = require("testdriverai");
194
+
195
+ async function processMultipleItems() {
196
+ const client = new TestDriver(process.env.TD_API_KEY);
197
+
198
+ await client.auth();
199
+ await client.connect();
200
+
201
+ const items = ["Item 1", "Item 2", "Item 3"];
202
+
203
+ for (const item of items) {
204
+ await client.hoverText(item);
205
+ await client.wait(1000);
206
+ }
207
+
208
+ await client.disconnect();
209
+ }
210
+
211
+ processMultipleItems();
212
+ ```
213
+
214
+ ## Benefits of Using SDK
215
+
216
+ ### 1. **Native JavaScript Control Flow**
217
+
218
+ ```javascript
219
+ // Use if/else statements
220
+ if (await checkCondition()) {
221
+ await client.hoverText("Option A");
222
+ } else {
223
+ await client.hoverText("Option B");
224
+ }
225
+
226
+ // Use loops
227
+ for (let i = 0; i < 5; i++) {
228
+ await client.scroll("down", 100);
229
+ }
230
+
231
+ // Use try/catch for error handling
232
+ try {
233
+ await client.waitForText("Success", 5000);
234
+ } catch (error) {
235
+ console.error("Timeout waiting for success message");
236
+ }
237
+ ```
238
+
239
+ ### 2. **Integration with Testing Frameworks**
240
+
241
+ ```javascript
242
+ // Jest
243
+ describe("Login Flow", () => {
244
+ let client;
245
+
246
+ beforeAll(async () => {
247
+ client = new TestDriver(process.env.TD_API_KEY);
248
+ await client.auth();
249
+ await client.connect();
250
+ });
251
+
252
+ afterAll(async () => {
253
+ await client.disconnect();
254
+ });
255
+
256
+ test("should login successfully", async () => {
257
+ await client.hoverText("Email");
258
+ await client.type("test@example.com");
259
+ await client.hoverText("Submit");
260
+ await client.waitForText("Dashboard");
261
+ });
262
+ });
263
+ ```
264
+
265
+ ### 3. **Dynamic Test Data**
266
+
267
+ ```javascript
268
+ const users = [
269
+ { email: "user1@test.com", password: "pass1" },
270
+ { email: "user2@test.com", password: "pass2" },
271
+ ];
272
+
273
+ for (const user of users) {
274
+ await client.hoverText("Email");
275
+ await client.type(user.email);
276
+ await client.hoverText("Password");
277
+ await client.type(user.password);
278
+ await client.hoverText("Login");
279
+ await client.waitForText("Dashboard");
280
+ // Logout for next iteration
281
+ await client.hoverText("Logout");
282
+ }
283
+ ```
284
+
285
+ ### 4. **Reusable Functions**
286
+
287
+ ```javascript
288
+ async function login(client, email, password) {
289
+ await client.hoverText("Email");
290
+ await client.type(email);
291
+ await client.hoverText("Password");
292
+ await client.type(password);
293
+ await client.hoverText("Login");
294
+ await client.waitForText("Dashboard");
295
+ }
296
+
297
+ async function logout(client) {
298
+ await client.hoverText("Menu");
299
+ await client.hoverText("Logout");
300
+ }
301
+
302
+ // Use anywhere
303
+ await login(client, "user@test.com", "password123");
304
+ await logout(client);
305
+ ```
306
+
307
+ ## When to Use CLI vs SDK
308
+
309
+ ### Use CLI When:
310
+
311
+ - ✅ You need exploratory testing with AI-generated tests
312
+ - ✅ You want to quickly prototype tests without writing code
313
+ - ✅ You prefer declarative YAML configuration
314
+ - ✅ You're using the interactive edit mode
315
+
316
+ ### Use SDK When:
317
+
318
+ - ✅ You need programmatic control over test execution
319
+ - ✅ You want to integrate with existing test frameworks (Jest, Mocha, etc.)
320
+ - ✅ You need complex control flow (loops, conditionals, error handling)
321
+ - ✅ You want to use dynamic test data
322
+ - ✅ You're building automated CI/CD pipelines
323
+ - ✅ You need to reuse test logic across multiple tests
324
+
325
+ ## Running Both CLI and SDK
326
+
327
+ You can use both approaches in the same project:
328
+
329
+ ```json
330
+ {
331
+ "scripts": {
332
+ "test:cli": "testdriverai run testdriver/regression.yaml",
333
+ "test:sdk": "node tests/login.test.js",
334
+ "test:all": "npm run test:cli && npm run test:sdk"
335
+ }
336
+ }
337
+ ```
338
+
339
+ ## Best Practices
340
+
341
+ 1. **Use environment variables for credentials:**
342
+
343
+ ```javascript
344
+ const client = new TestDriver(process.env.TD_API_KEY);
345
+ ```
346
+
347
+ 2. **Always disconnect after tests:**
348
+
349
+ ```javascript
350
+ try {
351
+ // Your tests
352
+ } finally {
353
+ await client.disconnect();
354
+ }
355
+ ```
356
+
357
+ 3. **Create helper functions for common actions:**
358
+
359
+ ```javascript
360
+ const helpers = {
361
+ login: async (client, email, password) => {
362
+ /* ... */
363
+ },
364
+ navigateTo: async (client, page) => {
365
+ /* ... */
366
+ },
367
+ fillForm: async (client, data) => {
368
+ /* ... */
369
+ },
370
+ };
371
+ ```
372
+
373
+ 4. **Use async/await consistently:**
374
+
375
+ ```javascript
376
+ // ✅ Good
377
+ await client.hoverText("Submit");
378
+ await client.wait(1000);
379
+
380
+ // ❌ Bad
381
+ client.hoverText("Submit");
382
+ client.wait(1000);
383
+ ```
384
+
385
+ ## Next Steps
386
+
387
+ - Read the [SDK Documentation](./SDK_README.md) for complete API reference
388
+ - Check out [examples](./examples/sdk-example.js) for more use cases
389
+ - Join our [Discord](https://discord.com/invite/cWDFW8DzPm) for support