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
@@ -62,33 +62,27 @@ const types = () =>
62
62
  },
63
63
  // - command: scroll # Scroll up or down. Make sure the correct portion of the page is focused before scrolling.
64
64
  // direction: down # Available directions are: up, down, left, right
65
- // method: keyboard # Optional. Available methods are: keyboard (default), mouse. Use mouse only if the prompt explicitly asks for it.
66
- // amount: 300 # Optional. The amount of pixels to scroll. Defaults to 300 for keyboard and 200 for mouse.
65
+ // amount: 300 # Optional. The amount of pixels to scroll. Defaults to 300.
67
66
  ScrollCommand: {
68
67
  command: '"scroll"',
69
68
  direction: '"up" | "down" | "left" | "right"',
70
- "method?": '"keyboard" | "mouse"',
71
69
  "amount?": "number",
72
70
  },
73
71
  // - command: scroll-until-text # Scroll until text is found
74
72
  // text: Sign Up # The text to find on screen. The longer and more unique the better.
75
73
  // direction: down # Available directions are: up, down, left, right
76
- // method: keyboard # Optional. Available methods are: keyboard (default), mouse. Use mouse only if the prompt explicitly asks for it.
77
74
  ScrollUntilTextCommand: {
78
75
  command: '"scroll-until-text"',
79
76
  text: "string",
80
77
  direction: '"up" | "down" | "left" | "right"',
81
- "method?": '"keyboard" | "mouse"',
82
78
  },
83
79
  // - command: scroll-until-image # Scroll until icon or image is found
84
80
  // description: Submit at the bottom of the form
85
81
  // direction: down # Available directions are: up, down, left, rights
86
- // method: keyboard # Optional. Available methods are: keyboard (default), mouse. Use mouse only if the prompt explicitly asks for it.
87
82
  ScrollUntilImageCommand: {
88
83
  command: '"scroll-until-image"',
89
84
  description: "string",
90
85
  direction: '"up" | "down" | "left" | "right"',
91
- "method?": '"keyboard" | "mouse"',
92
86
  },
93
87
  // - command: wait-for-text # Wait until text is seen on screen. Not recommended unless explicitly requested by user.
94
88
  // text: Copyright 2024 # The text to find on screen.
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Debug script to inspect the full locate API response
5
+ * Run this with: TD_API_KEY=your_key node debug-locate-response.js
6
+ */
7
+
8
+ const TestDriverSDK = require("./sdk.js");
9
+
10
+ async function debugLocateResponse() {
11
+ const client = new TestDriverSDK(process.env.TD_API_KEY);
12
+
13
+ try {
14
+ console.log("Connecting to sandbox (Linux)...");
15
+ await client.connect({ headless: true });
16
+
17
+ console.log("Opening a test page...");
18
+ await client.focusApplication("Google Chrome");
19
+ await client.type("https://example.com");
20
+ await client.pressKeys(["enter"]);
21
+
22
+ // Wait for page to load
23
+ await new Promise((resolve) => setTimeout(resolve, 3000));
24
+
25
+ console.log("\nFinding an element to inspect the response...");
26
+ const element = await client.find("the heading that says Example Domain");
27
+
28
+ console.log("\n=".repeat(60));
29
+ console.log("FULL LOCATE API RESPONSE:");
30
+ console.log("=".repeat(60));
31
+
32
+ const response = element.getResponse();
33
+ console.log(JSON.stringify(response, null, 2));
34
+
35
+ console.log("\n=".repeat(60));
36
+ console.log("RESPONSE KEYS:");
37
+ console.log("=".repeat(60));
38
+
39
+ if (response) {
40
+ Object.keys(response).forEach((key) => {
41
+ const value = response[key];
42
+ const type = Array.isArray(value) ? "array" : typeof value;
43
+ const preview =
44
+ typeof value === "string" && value.length > 100
45
+ ? `${value.substring(0, 100)}... (${value.length} chars)`
46
+ : typeof value === "object"
47
+ ? JSON.stringify(value)
48
+ : value;
49
+
50
+ console.log(` ${key} (${type}): ${preview}`);
51
+ });
52
+ }
53
+
54
+ console.log("\n=".repeat(60));
55
+ console.log("ELEMENT PROPERTIES:");
56
+ console.log("=".repeat(60));
57
+ console.log(" found:", element.found());
58
+ console.log(" x:", element.x);
59
+ console.log(" y:", element.y);
60
+ console.log(" centerX:", element.centerX);
61
+ console.log(" centerY:", element.centerY);
62
+ console.log(" width:", element.width);
63
+ console.log(" height:", element.height);
64
+ console.log(" confidence:", element.confidence);
65
+ console.log(" text:", element.text);
66
+ console.log(" label:", element.label);
67
+ console.log(
68
+ " screenshot:",
69
+ element.screenshot ? `${element.screenshot.length} chars` : null,
70
+ );
71
+ console.log(" boundingBox:", element.boundingBox);
72
+
73
+ await client.disconnect();
74
+ } catch (error) {
75
+ console.error("Error:", error.message);
76
+ console.error(error.stack);
77
+ await client.disconnect();
78
+ process.exit(1);
79
+ }
80
+ }
81
+
82
+ debugLocateResponse();
@@ -34,10 +34,14 @@
34
34
  top: 0;
35
35
  left: 0;
36
36
  transform-origin: top left;
37
+ overflow: hidden;
37
38
  }
38
39
 
40
+ html,
39
41
  body {
40
42
  overflow: hidden;
43
+ width: 100%;
44
+ height: 100%;
41
45
  }
42
46
 
43
47
  *::-webkit-scrollbar {
@@ -66,6 +70,7 @@
66
70
 
67
71
  .overlay {
68
72
  position: relative;
73
+ overflow: hidden;
69
74
  }
70
75
 
71
76
  .screenshot {
@@ -179,6 +184,7 @@
179
184
  width: 100%;
180
185
  height: 100%;
181
186
  z-index: 1;
187
+ overflow: hidden;
182
188
  }
183
189
 
184
190
  /* Loading screen styles */
@@ -330,7 +336,7 @@
330
336
  <div class="message">Click to interact with VM</div>
331
337
  </div>
332
338
  </div>
333
- <iframe id="vm-iframe" src=""></iframe>
339
+ <iframe id="vm-iframe" src="" credentialless></iframe>
334
340
  </div>
335
341
 
336
342
  <script>
@@ -354,6 +360,10 @@
354
360
 
355
361
  const iframe = document.querySelector("#vm-iframe");
356
362
 
363
+ // Detect if OS is Linux
364
+ const isLinux = parsedData.os === "linux";
365
+ const topBarOffset = isLinux ? 14 : 0;
366
+
357
367
  // set overlay width and height to match the given resolution
358
368
  const overlayWidth = parsedData.resolution[0];
359
369
  const overlayHeight = parsedData.resolution[1];
@@ -361,7 +371,8 @@
361
371
  iframe.style.display = "block";
362
372
  iframe.src = parsedData.url;
363
373
  iframe.style.width = overlayWidth + "px";
364
- iframe.style.height = overlayHeight + "px";
374
+ // Increase iframe height by 14px for Linux to account for top bar
375
+ iframe.style.height = overlayHeight + topBarOffset + "px";
365
376
 
366
377
  // Calculate scale factor to fit within window if needed
367
378
  const windowWidth = window.innerWidth;
@@ -513,7 +524,7 @@
513
524
  const boxElement = document.createElement("div");
514
525
  boxElement.className = "bounding-box";
515
526
  boxElement.style.left = toCss(box.x);
516
- boxElement.style.top = toCss(box.y);
527
+ boxElement.style.top = toCss(box.y + topBarOffset);
517
528
  boxElement.style.width = toCss(box.width);
518
529
  boxElement.style.height = toCss(box.height);
519
530
  effects.appendChild(boxElement);
@@ -541,14 +552,14 @@
541
552
  // Mouse event handlers
542
553
  addEventHandler(events.mouseMove, (event, { x, y } = {}) => {
543
554
  mouse.style.marginLeft = toCss(x);
544
- mouse.style.marginTop = toCss(y);
555
+ mouse.style.marginTop = toCss(y + topBarOffset);
545
556
  });
546
557
 
547
558
  addEventHandler(
548
559
  events.mouseClick,
549
560
  (event, { x, y, click = "single" } = {}) => {
550
561
  mouse.style.marginLeft = toCss(x);
551
- mouse.style.marginTop = toCss(y);
562
+ mouse.style.marginTop = toCss(y + topBarOffset);
552
563
  // Reset class so animation can restart
553
564
  mouse.setAttribute("class", "mouse");
554
565
  // Force reflow
@@ -0,0 +1,424 @@
1
+ # TestDriver Test Recording Architecture
2
+
3
+ ## Overview
4
+
5
+ This system provides comprehensive test execution tracking, linking test runs with dashcam screen recordings and CI/CD pipelines in the TestDriver dashboard.
6
+
7
+ ## Architecture Diagram
8
+
9
+ ```
10
+ ┌─────────────────────────────────────────────────────────────┐
11
+ │ Developer's Machine / CI │
12
+ ├─────────────────────────────────────────────────────────────┤
13
+ │ │
14
+ │ ┌──────────────┐ ┌──────────────┐ │
15
+ │ │ Vitest │────────▶│ TD Vitest │ │
16
+ │ │ Test Runner │ │ Plugin │ │
17
+ │ └──────────────┘ └──────┬───────┘ │
18
+ │ │ │
19
+ │ ┌──────────────┐ │ │
20
+ │ │ Dashcam │ │ │
21
+ │ │ Recording │ │ │
22
+ │ └──────┬───────┘ │ │
23
+ │ │ │ │
24
+ │ │ (records screen) │ (reports results) │
25
+ │ │ │ │
26
+ └─────────┼─────────────────────────┼───────────────────────────┘
27
+ │ │
28
+ │ │
29
+ ▼ ▼
30
+ ┌─────────────────────────────────────────────────────────────┐
31
+ │ TestDriver API Server │
32
+ ├─────────────────────────────────────────────────────────────┤
33
+ │ │
34
+ │ ┌──────────────┐ ┌──────────────┐ │
35
+ │ │ Replay API │ │ Test Run API │ │
36
+ │ │ (dashcam) │ │ (new) │ │
37
+ │ └──────┬───────┘ └──────┬───────┘ │
38
+ │ │ │ │
39
+ │ └────────┬───────────────┘ │
40
+ │ │ │
41
+ │ ▼ │
42
+ │ ┌────────────────┐ │
43
+ │ │ MongoDB │ │
44
+ │ │ │ │
45
+ │ │ • TdTestRun │ │
46
+ │ │ • TdTestCase │ │
47
+ │ │ • TdSandbox │ │
48
+ │ │ • Replay │ │
49
+ │ └────────────────┘ │
50
+ │ │
51
+ └───────────────────────────┬───────────────────────────────────┘
52
+
53
+
54
+
55
+ ┌─────────────────────────────────────────────────────────────┐
56
+ │ TestDriver Web Dashboard │
57
+ ├─────────────────────────────────────────────────────────────┤
58
+ │ │
59
+ │ ┌─────────────────────────────────────────┐ │
60
+ │ │ Test Runs View (NEW) │ │
61
+ │ │ │ │
62
+ │ │ • List all test runs │ │
63
+ │ │ • Filter by status, date, CI │ │
64
+ │ │ • Show pass/fail statistics │ │
65
+ │ │ • Link to CI/CD runs │ │
66
+ │ └─────────────────────────────────────────┘ │
67
+ │ │
68
+ │ ┌─────────────────────────────────────────┐ │
69
+ │ │ Test Run Detail View (NEW) │ │
70
+ │ │ │ │
71
+ │ │ • Test case list with status │ │
72
+ │ │ • Dashcam replay player (embedded) │ │
73
+ │ │ • Error messages and stack traces │ │
74
+ │ │ • Sandbox details │ │
75
+ │ │ • Git commit info │ │
76
+ │ └─────────────────────────────────────────┘ │
77
+ │ │
78
+ └───────────────────────────────────────────────────────────────┘
79
+ ```
80
+
81
+ ## Data Models
82
+
83
+ ### TdTestRun
84
+ Represents a complete test suite execution (e.g., `npx vitest run`).
85
+
86
+ **Key Fields:**
87
+ - `runId`: Unique identifier
88
+ - `suiteName`: Name of the test suite
89
+ - `status`: running | passed | failed | cancelled
90
+ - `totalTests`, `passedTests`, `failedTests`: Statistics
91
+ - `platform`: windows | mac | linux
92
+ - CI/CD metadata (provider, runId, url)
93
+ - Git metadata (repo, branch, commit)
94
+ - `dashcamSessionId`: Links to dashcam recordings
95
+
96
+ **Relationships:**
97
+ - `team`: Owner team
98
+ - `sandbox`: TdSandbox where tests ran
99
+ - `testCases`: Collection of TdTestCase
100
+ - `replays`: Associated Replay records
101
+
102
+ ### TdTestCase
103
+ Represents an individual test within a test run.
104
+
105
+ **Key Fields:**
106
+ - `testName`: Test name from `test('...')`
107
+ - `testFile`: Path to test file
108
+ - `suiteName`: Describe block name
109
+ - `status`: passed | failed | skipped | pending
110
+ - `duration`: Test duration in ms
111
+ - `errorMessage`, `errorStack`: Failure details
112
+ - `replayUrl`: Direct link to dashcam replay
113
+ - `replayStartTime`, `replayEndTime`: Timestamps within replay
114
+
115
+ **Relationships:**
116
+ - `testRun`: Parent TdTestRun
117
+ - `replay`: Associated Replay record
118
+
119
+ ### TdSandbox
120
+ Represents a spawned VM/sandbox instance.
121
+
122
+ **Key Fields:**
123
+ - `sandboxId`: Unique identifier
124
+ - `platform`: windows | mac | linux
125
+ - `status`: provisioning | ready | running | stopped | terminated
126
+ - `instanceId`, `instanceType`: AWS EC2 details
127
+ - `ipAddress`, `vncUrl`, `wsUrl`: Connection details
128
+ - `spawnTime`, `readyTime`, `terminateTime`: Lifecycle timestamps
129
+ - `dashcamAuth`: Whether dashcam was authenticated
130
+ - `dashcamProjectId`: Dashcam project for replays
131
+
132
+ **Relationships:**
133
+ - `team`: Owner team
134
+ - `user`: User who spawned it
135
+ - `testRuns`: Tests that ran on this sandbox
136
+ - `replays`: Dashcam recordings from this sandbox
137
+
138
+ **Note:** Sandbox creation/updates happen via WebSocket (not REST API) as part of the sandbox provisioning flow.
139
+
140
+ ### Replay (Extended)
141
+ Existing model extended with test run associations.
142
+
143
+ **New Fields:**
144
+ - `tdTestRun`: Associated test run
145
+ - `tdTestCase`: Associated test case
146
+ - `tdSandbox`: Sandbox where recorded
147
+
148
+ ## API Endpoints
149
+
150
+ ### POST /api/v1/testdriver/test-run-create
151
+ Create a new test run.
152
+
153
+ **Auth:** Required (Bearer token)
154
+
155
+ **Request:**
156
+ ```json
157
+ {
158
+ "runId": "vitest-1234567890-abc123",
159
+ "suiteName": "Integration Tests",
160
+ "platform": "windows",
161
+ "sandboxId": "sandbox-xyz",
162
+ "ciProvider": "GitHub Actions",
163
+ "ciRunId": "12345",
164
+ "repo": "myorg/myrepo",
165
+ "branch": "main",
166
+ "commit": "abc123def456"
167
+ }
168
+ ```
169
+
170
+ **Response:**
171
+ ```json
172
+ {
173
+ "data": {
174
+ "id": "...",
175
+ "runId": "vitest-1234567890-abc123",
176
+ "status": "running",
177
+ "startTime": 1700000000000
178
+ }
179
+ }
180
+ ```
181
+
182
+ ### POST /api/v1/testdriver/test-run-complete
183
+ Mark a test run as complete.
184
+
185
+ **Auth:** Required
186
+
187
+ **Request:**
188
+ ```json
189
+ {
190
+ "runId": "vitest-1234567890-abc123",
191
+ "status": "passed",
192
+ "totalTests": 25,
193
+ "passedTests": 24,
194
+ "failedTests": 1,
195
+ "skippedTests": 0
196
+ }
197
+ ```
198
+
199
+ ### POST /api/v1/testdriver/test-case-create
200
+ Record a test case result (create or update).
201
+
202
+ **Auth:** Required
203
+
204
+ **Request:**
205
+ ```json
206
+ {
207
+ "runId": "vitest-1234567890-abc123",
208
+ "testName": "should login successfully",
209
+ "testFile": "tests/auth/login.test.js",
210
+ "suiteName": "Authentication Tests",
211
+ "status": "passed",
212
+ "startTime": 1700000001000,
213
+ "endTime": 1700000002500,
214
+ "duration": 1500,
215
+ "replayUrl": "https://app.dashcam.io/replay/abc123"
216
+ }
217
+ ```
218
+
219
+ ## Components
220
+
221
+ ### Vitest Plugin (`interfaces/vitest-plugin.mjs`)
222
+ Automatically integrates with Vitest test runs.
223
+
224
+ **Features:**
225
+ - Auto-detects CI/CD environment (GitHub Actions, GitLab, etc.)
226
+ - Extracts Git metadata from environment or git commands
227
+ - Creates test run at start
228
+ - Records each test case result
229
+ - Associates with dashcam session if `DASHCAM_SESSION_ID` is set
230
+ - Completes test run with statistics
231
+ - Uses plugin architecture for better global state management
232
+
233
+ **Usage:**
234
+ ```javascript
235
+ // vitest.config.mjs
236
+ import testDriverPlugin from './interfaces/vitest-plugin.mjs';
237
+
238
+ export default {
239
+ plugins: [
240
+ testDriverPlugin({
241
+ apiKey: process.env.TD_API_KEY,
242
+ apiRoot: process.env.TD_API_ROOT || 'https://testdriver-api.onrender.com',
243
+ }),
244
+ ],
245
+ }
246
+ ```
247
+
248
+ ### SDK Methods (`sdk.js`)
249
+
250
+ #### `client.createTestRun(options)`
251
+ Create a test run programmatically.
252
+
253
+ #### `client.recordTestCase(options)`
254
+ Record a test case result.
255
+
256
+ #### `client.completeTestRun(options)`
257
+ Mark test run as complete.
258
+
259
+ ## Integration Flows
260
+
261
+ ### Flow 1: Automated with Vitest Reporter
262
+
263
+ ```
264
+ 1. Developer runs: npx vitest run
265
+ 2. Vitest starts, reporter initializes
266
+ 3. Reporter creates TdTestRun
267
+ 4. For each test:
268
+ - Vitest runs test
269
+ - Reporter records TdTestCase (passed/failed)
270
+ 5. All tests complete
271
+ 6. Reporter calls completeTestRun()
272
+ 7. Results visible in dashboard
273
+ ```
274
+
275
+ ### Flow 2: With Dashcam Recording
276
+
277
+ ```
278
+ 1. Start dashcam: dashcam start
279
+ 2. Set session ID: export DASHCAM_SESSION_ID=$(dashcam session-id)
280
+ 3. Run tests: npx vitest run
281
+ 4. Reporter creates test run with dashcamSessionId
282
+ 5. Tests execute, dashcam records
283
+ 6. Stop dashcam: dashcam stop
284
+ 7. Publish: dashcam publish -p PROJECT_ID
285
+ 8. Replay URL returned
286
+ 9. Dashboard shows test results + replay link
287
+ ```
288
+
289
+ ### Flow 3: CI/CD Pipeline (GitHub Actions)
290
+
291
+ ```yaml
292
+ jobs:
293
+ test:
294
+ runs-on: windows-latest
295
+ steps:
296
+ - uses: actions/checkout@v3
297
+ - run: npm install
298
+ - name: Start Dashcam
299
+ run: |
300
+ dashcam start
301
+ echo "DASHCAM_SESSION_ID=$(dashcam session-id)" >> $GITHUB_ENV
302
+ - name: Run Tests
303
+ env:
304
+ TD_API_KEY: ${{ secrets.TD_API_KEY }}
305
+ run: npx vitest run
306
+ - name: Publish Recording
307
+ if: always()
308
+ run: |
309
+ dashcam stop
310
+ dashcam publish -p ${{ secrets.DASHCAM_PROJECT_ID }}
311
+ ```
312
+
313
+ Reporter auto-detects:
314
+ - GitHub repo, branch, commit
315
+ - Workflow run ID and URL
316
+ - Job ID
317
+ - Actor (who triggered)
318
+
319
+ ## Dashcam Association Strategies
320
+
321
+ ### Strategy 1: Session ID (Implemented)
322
+ - Set `DASHCAM_SESSION_ID` environment variable
323
+ - Reporter includes in test run creation
324
+ - Dashboard queries replays by session ID
325
+ - Shows all replays from that session
326
+
327
+ ### Strategy 2: Explicit URL (Implemented)
328
+ - Dashcam publishes, returns URL
329
+ - Pass URL to `recordTestCase()`
330
+ - Direct 1:1 link between test and replay
331
+
332
+ ### Strategy 3: Timestamp Matching (Future)
333
+ - Parse dashcam logs for replay timestamps
334
+ - Match test start/end times with replay markers
335
+ - Automatically associate without manual linking
336
+ - Allows seeking to exact test within long replay
337
+
338
+ ### Strategy 4: Log Parsing (Future)
339
+ - Dashcam logs test names/files during recording
340
+ - Parse logs to extract test-to-timestamp mapping
341
+ - Generate replay URLs with timestamp seek parameters
342
+ - Example: `https://app.dashcam.io/replay/abc123?t=45000` (seek to 45s)
343
+
344
+ ## Dashboard Views (To Be Built)
345
+
346
+ ### Test Runs List
347
+ - Table of all test runs
348
+ - Columns: Suite Name, Status, Tests (passed/failed), Duration, Date, CI Link
349
+ - Filters: Status, Date range, CI provider, Platform
350
+ - Search: By suite name, repo, branch
351
+
352
+ ### Test Run Detail
353
+ - Header: Suite name, status, duration, platform
354
+ - Statistics card: Total/passed/failed/skipped
355
+ - Test cases table: Name, Status, Duration, Replay link
356
+ - Sidebar: Git info, CI info, Sandbox details
357
+ - Dashcam replay player (embedded iframe)
358
+ - Click test case → seek replay to that test's time range
359
+
360
+ ### Sandbox Management
361
+ - List of active/terminated sandboxes
362
+ - Lifecycle timeline visualization
363
+ - Cost tracking (duration × instance type)
364
+ - Associated test runs
365
+
366
+ ## Environment Variables
367
+
368
+ | Variable | Required | Description |
369
+ |----------|----------|-------------|
370
+ | `TD_API_KEY` | Yes | TestDriver API key for authentication |
371
+ | `DASHCAM_SESSION_ID` | No | Links test run to dashcam session |
372
+ | `TD_SANDBOX_ID` | No | Sandbox ID if running in TestDriver sandbox |
373
+ | `GITHUB_ACTIONS` | Auto | Detected for GitHub Actions integration |
374
+ | `GITLAB_CI` | Auto | Detected for GitLab CI integration |
375
+ | `CIRCLECI` | Auto | Detected for CircleCI integration |
376
+
377
+ ## Future Enhancements
378
+
379
+ 1. **Real-time Test Streaming**
380
+ - WebSocket connection from reporter
381
+ - Live test progress in dashboard
382
+ - See tests pass/fail as they run
383
+
384
+ 2. **Flaky Test Detection**
385
+ - Track test history across runs
386
+ - Identify tests that intermittently fail
387
+ - Suggest fixes based on error patterns
388
+
389
+ 3. **Performance Regression Detection**
390
+ - Compare test durations across runs
391
+ - Alert on significant slowdowns
392
+ - Visualize performance trends
393
+
394
+ 4. **Advanced Dashcam Integration**
395
+ - Automatic timestamp extraction from logs
396
+ - AI-powered test failure analysis from replays
397
+ - Highlight exact moment of failure in replay
398
+
399
+ 5. **Multi-Framework Support**
400
+ - Jest reporter
401
+ - Mocha reporter
402
+ - Playwright reporter
403
+ - Cypress plugin
404
+
405
+ 6. **Cost Analytics**
406
+ - Track sandbox costs per test run
407
+ - Optimize instance types
408
+ - Budget alerts
409
+
410
+ ## Security Considerations
411
+
412
+ - API keys stored securely (environment variables)
413
+ - Bearer token authentication for all API calls
414
+ - Team-based access control (tests only visible to team members)
415
+ - Replay access control (dashcam's existing permissions)
416
+ - No sensitive data in test metadata (sanitize error messages)
417
+
418
+ ## Performance Considerations
419
+
420
+ - Async test case recording (doesn't slow tests)
421
+ - Batch updates for large test suites
422
+ - Efficient database indexing (runId, testFile, status)
423
+ - Replay association is lazy (doesn't block test recording)
424
+ - Optional reporter (disable in local development)