testdriverai 6.2.2 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/.github/workflows/acceptance-linux.yml +75 -0
  2. package/.github/workflows/acceptance-sdk-tests.yml +133 -0
  3. package/.vscode/settings.json +5 -1
  4. package/AGENTS.md +550 -0
  5. package/CODEOWNERS +0 -1
  6. package/README.md +126 -0
  7. package/{testdriver → _testdriver}/acceptance/drag-and-drop.yaml +2 -2
  8. package/{testdriver → _testdriver}/acceptance/snippets/login.yaml +1 -1
  9. package/_testdriver/examples/desktop/lifecycle/prerun.yaml +0 -0
  10. package/{testdriver → _testdriver}/examples/web/lifecycle/prerun.yaml +6 -1
  11. package/{testdriver → _testdriver}/lifecycle/postrun.yaml +3 -2
  12. package/_testdriver/lifecycle/prerun.yaml +15 -0
  13. package/{testdriver → _testdriver}/lifecycle/provision.yaml +7 -2
  14. package/agent/index.js +300 -85
  15. package/agent/interface.js +15 -0
  16. package/agent/lib/cache.js +142 -0
  17. package/agent/lib/commander.js +1 -39
  18. package/agent/lib/commands.js +910 -296
  19. package/agent/lib/redraw.js +129 -41
  20. package/agent/lib/sandbox.js +29 -6
  21. package/agent/lib/sdk.js +22 -0
  22. package/agent/lib/system.js +0 -3
  23. package/agent/lib/validation.js +1 -7
  24. package/debug-locate-response.js +82 -0
  25. package/debugger/index.html +15 -4
  26. package/docs/ARCHITECTURE.md +424 -0
  27. package/docs/AWESOME_LOGS_QUICK_REF.md +100 -0
  28. package/docs/MIGRATION.md +425 -0
  29. package/docs/PRESETS.md +210 -0
  30. package/docs/QUICK_START_TEST_RECORDING.md +215 -0
  31. package/docs/SDK_AWESOME_LOGS.md +468 -0
  32. package/docs/TEST_RECORDING.md +388 -0
  33. package/docs/docs.json +286 -152
  34. package/docs/guide/best-practices-polling.mdx +154 -0
  35. package/docs/sdk-browser-rendering.md +167 -0
  36. package/docs/v6/getting-started/self-hosting.mdx +407 -0
  37. package/docs/{guide → v6/guide}/dashcam.mdx +1 -1
  38. package/docs/{guide → v6/guide}/environment-variables.mdx +4 -5
  39. package/docs/{guide → v6/guide}/lifecycle.mdx +1 -1
  40. package/docs/v6/overview/comparison.mdx +101 -0
  41. package/docs/v7/README.md +135 -0
  42. package/docs/v7/api/ai.mdx +205 -0
  43. package/docs/v7/api/assert.mdx +285 -0
  44. package/docs/v7/api/assertions.mdx +403 -0
  45. package/docs/v7/api/click.mdx +287 -0
  46. package/docs/v7/api/client.mdx +322 -0
  47. package/docs/v7/api/dashcam.mdx +497 -0
  48. package/docs/v7/api/doubleClick.mdx +102 -0
  49. package/docs/v7/api/elements.mdx +479 -0
  50. package/docs/v7/api/exec.mdx +346 -0
  51. package/docs/v7/api/find.mdx +316 -0
  52. package/docs/v7/api/focusApplication.mdx +294 -0
  53. package/docs/v7/api/hover.mdx +279 -0
  54. package/docs/v7/api/mouseDown.mdx +161 -0
  55. package/docs/v7/api/mouseUp.mdx +164 -0
  56. package/docs/v7/api/pressKeys.mdx +349 -0
  57. package/docs/v7/api/rightClick.mdx +123 -0
  58. package/docs/v7/api/sandbox.mdx +404 -0
  59. package/docs/v7/api/scroll.mdx +300 -0
  60. package/docs/v7/api/type.mdx +314 -0
  61. package/docs/v7/commands/assert.mdx +45 -0
  62. package/docs/v7/commands/exec.mdx +282 -0
  63. package/docs/v7/commands/focus-application.mdx +44 -0
  64. package/docs/v7/commands/hover-image.mdx +69 -0
  65. package/docs/v7/commands/hover-text.mdx +47 -0
  66. package/docs/v7/commands/if.mdx +53 -0
  67. package/docs/v7/commands/match-image.mdx +67 -0
  68. package/docs/v7/commands/press-keys.mdx +87 -0
  69. package/docs/v7/commands/remember.mdx +49 -0
  70. package/docs/v7/commands/run.mdx +44 -0
  71. package/docs/v7/commands/scroll-until-image.mdx +66 -0
  72. package/docs/v7/commands/scroll-until-text.mdx +60 -0
  73. package/docs/v7/commands/scroll.mdx +69 -0
  74. package/docs/v7/commands/type.mdx +45 -0
  75. package/docs/v7/commands/wait-for-image.mdx +54 -0
  76. package/docs/v7/commands/wait-for-text.mdx +48 -0
  77. package/docs/v7/commands/wait.mdx +45 -0
  78. package/docs/v7/getting-started/configuration.mdx +380 -0
  79. package/docs/v7/getting-started/quickstart.mdx +332 -0
  80. package/docs/v7/guides/best-practices.mdx +486 -0
  81. package/docs/v7/guides/caching-ai.mdx +215 -0
  82. package/docs/v7/guides/caching-selectors.mdx +292 -0
  83. package/docs/v7/guides/caching.mdx +366 -0
  84. package/docs/v7/guides/ci-cd/azure.mdx +587 -0
  85. package/docs/v7/guides/ci-cd/circleci.mdx +523 -0
  86. package/docs/v7/guides/ci-cd/github-actions.mdx +457 -0
  87. package/docs/v7/guides/ci-cd/gitlab.mdx +498 -0
  88. package/docs/v7/guides/ci-cd/jenkins.mdx +664 -0
  89. package/docs/v7/guides/ci-cd/travis.mdx +438 -0
  90. package/docs/v7/guides/debugging.mdx +349 -0
  91. package/docs/v7/guides/faq.mdx +393 -0
  92. package/docs/v7/guides/migration.mdx +562 -0
  93. package/docs/v7/guides/performance.mdx +517 -0
  94. package/docs/{getting-started → v7/guides}/self-hosting.mdx +11 -12
  95. package/docs/v7/guides/troubleshooting.mdx +526 -0
  96. package/docs/v7/guides/vitest-plugin.mdx +477 -0
  97. package/docs/v7/guides/vitest.mdx +535 -0
  98. package/docs/v7/platforms/linux.mdx +308 -0
  99. package/docs/v7/platforms/macos.mdx +433 -0
  100. package/docs/v7/platforms/windows.mdx +430 -0
  101. package/docs/v7/playwright.mdx +342 -0
  102. package/docs/v7/presets/chrome-extension.mdx +223 -0
  103. package/docs/v7/presets/chrome.mdx +287 -0
  104. package/docs/v7/presets/electron.mdx +435 -0
  105. package/docs/v7/presets/vscode.mdx +398 -0
  106. package/docs/v7/presets/webapp.mdx +396 -0
  107. package/docs/v7/progressive-apis/CORE.md +459 -0
  108. package/docs/v7/progressive-apis/HOOKS.md +360 -0
  109. package/docs/v7/progressive-apis/PROGRESSIVE_DISCLOSURE.md +230 -0
  110. package/docs/v7/progressive-apis/PROVISION.md +266 -0
  111. package/eslint.config.js +19 -1
  112. package/interfaces/cli/lib/base.js +10 -4
  113. package/interfaces/logger.js +2 -1
  114. package/interfaces/shared-test-state.mjs +69 -0
  115. package/interfaces/vitest-plugin.mjs +830 -0
  116. package/package.json +29 -5
  117. package/schema.json +8 -29
  118. package/scripts/view-test-results.mjs +96 -0
  119. package/sdk-log-formatter.js +714 -0
  120. package/sdk.d.ts +1028 -0
  121. package/sdk.js +2567 -0
  122. package/{.github/workflows/self-hosted.yml → self-hosted.yml} +13 -4
  123. package/setup/aws/cloudformation.yaml +9 -2
  124. package/src/core/Dashcam.js +469 -0
  125. package/src/core/index.d.ts +150 -0
  126. package/src/core/index.js +12 -0
  127. package/src/presets/index.mjs +331 -0
  128. package/src/vitest/extended.mjs +108 -0
  129. package/src/vitest/hooks.d.ts +119 -0
  130. package/src/vitest/hooks.mjs +298 -0
  131. package/src/vitest/index.mjs +64 -0
  132. package/src/vitest/lifecycle.mjs +277 -0
  133. package/src/vitest/utils.mjs +150 -0
  134. package/test/dashcam.test.js +137 -0
  135. package/test/mcp-example-test.yaml +27 -0
  136. package/testdriver/acceptance-sdk/QUICK_REFERENCE.md +61 -0
  137. package/testdriver/acceptance-sdk/README.md +128 -0
  138. package/testdriver/acceptance-sdk/TEST_REPORTING.md +245 -0
  139. package/testdriver/acceptance-sdk/assert.test.mjs +26 -0
  140. package/testdriver/acceptance-sdk/auto-cache-key-demo.test.mjs +56 -0
  141. package/testdriver/acceptance-sdk/chrome-extension.test.mjs +89 -0
  142. package/testdriver/acceptance-sdk/drag-and-drop.test.mjs +58 -0
  143. package/testdriver/acceptance-sdk/element-not-found.test.mjs +25 -0
  144. package/testdriver/acceptance-sdk/exec-js.test.mjs +43 -0
  145. package/testdriver/acceptance-sdk/exec-output.test.mjs +59 -0
  146. package/testdriver/acceptance-sdk/exec-pwsh.test.mjs +57 -0
  147. package/testdriver/acceptance-sdk/focus-window.test.mjs +36 -0
  148. package/testdriver/acceptance-sdk/formatted-logging.test.mjs +26 -0
  149. package/testdriver/acceptance-sdk/hooks-example.test.mjs +38 -0
  150. package/testdriver/acceptance-sdk/hover-image.test.mjs +34 -0
  151. package/testdriver/acceptance-sdk/hover-text-with-description.test.mjs +38 -0
  152. package/testdriver/acceptance-sdk/hover-text.test.mjs +27 -0
  153. package/testdriver/acceptance-sdk/match-image.test.mjs +36 -0
  154. package/testdriver/acceptance-sdk/presets-example.test.mjs +87 -0
  155. package/testdriver/acceptance-sdk/press-keys.test.mjs +50 -0
  156. package/testdriver/acceptance-sdk/prompt.test.mjs +33 -0
  157. package/testdriver/acceptance-sdk/scroll-keyboard.test.mjs +38 -0
  158. package/testdriver/acceptance-sdk/scroll-until-image.test.mjs +39 -0
  159. package/testdriver/acceptance-sdk/scroll-until-text.test.mjs +28 -0
  160. package/testdriver/acceptance-sdk/scroll.test.mjs +41 -0
  161. package/testdriver/acceptance-sdk/setup/globalTeardown.mjs +11 -0
  162. package/testdriver/acceptance-sdk/setup/testHelpers.mjs +420 -0
  163. package/testdriver/acceptance-sdk/setup/vitestSetup.mjs +40 -0
  164. package/testdriver/acceptance-sdk/sully-ai.test.mjs +234 -0
  165. package/testdriver/acceptance-sdk/test-console-logs.test.mjs +42 -0
  166. package/testdriver/acceptance-sdk/type-checking-demo.js +49 -0
  167. package/testdriver/acceptance-sdk/type.test.mjs +45 -0
  168. package/verify-element-api.js +89 -0
  169. package/verify-types.js +0 -0
  170. package/vitest.config.example.js +19 -0
  171. package/vitest.config.mjs +66 -0
  172. package/vitest.config.mjs.bak +44 -0
  173. package/.github/workflows/acceptance-v6.yml +0 -169
  174. package/.vscode/mcp.json +0 -9
  175. package/docs/overview/comparison.mdx +0 -82
  176. package/testdriver/lifecycle/prerun.yaml +0 -17
  177. /package/{testdriver/examples/desktop/lifecycle/prerun.yaml → .env.example} +0 -0
  178. /package/{testdriver → _testdriver}/acceptance/assert.yaml +0 -0
  179. /package/{testdriver → _testdriver}/acceptance/dashcam.yaml +0 -0
  180. /package/{testdriver → _testdriver}/acceptance/embed.yaml +0 -0
  181. /package/{testdriver → _testdriver}/acceptance/exec-js.yaml +0 -0
  182. /package/{testdriver → _testdriver}/acceptance/exec-output.yaml +0 -0
  183. /package/{testdriver → _testdriver}/acceptance/exec-shell.yaml +0 -0
  184. /package/{testdriver → _testdriver}/acceptance/focus-window.yaml +0 -0
  185. /package/{testdriver → _testdriver}/acceptance/hover-image.yaml +0 -0
  186. /package/{testdriver → _testdriver}/acceptance/hover-text-with-description.yaml +0 -0
  187. /package/{testdriver → _testdriver}/acceptance/hover-text.yaml +0 -0
  188. /package/{testdriver → _testdriver}/acceptance/if-else.yaml +0 -0
  189. /package/{testdriver → _testdriver}/acceptance/match-image.yaml +0 -0
  190. /package/{testdriver → _testdriver}/acceptance/press-keys.yaml +0 -0
  191. /package/{testdriver → _testdriver}/acceptance/prompt.yaml +0 -0
  192. /package/{testdriver → _testdriver}/acceptance/remember.yaml +0 -0
  193. /package/{testdriver → _testdriver}/acceptance/screenshots/cart.png +0 -0
  194. /package/{testdriver → _testdriver}/acceptance/scroll-keyboard.yaml +0 -0
  195. /package/{testdriver → _testdriver}/acceptance/scroll-until-image.yaml +0 -0
  196. /package/{testdriver → _testdriver}/acceptance/scroll-until-text.yaml +0 -0
  197. /package/{testdriver → _testdriver}/acceptance/scroll.yaml +0 -0
  198. /package/{testdriver → _testdriver}/acceptance/snippets/match-cart.yaml +0 -0
  199. /package/{testdriver → _testdriver}/acceptance/type.yaml +0 -0
  200. /package/{testdriver → _testdriver}/behavior/failure.yaml +0 -0
  201. /package/{testdriver → _testdriver}/behavior/hover-text.yaml +0 -0
  202. /package/{testdriver → _testdriver}/behavior/lifecycle/postrun.yaml +0 -0
  203. /package/{testdriver → _testdriver}/behavior/lifecycle/prerun.yaml +0 -0
  204. /package/{testdriver → _testdriver}/behavior/lifecycle/provision.yaml +0 -0
  205. /package/{testdriver → _testdriver}/behavior/secrets.yaml +0 -0
  206. /package/{testdriver → _testdriver}/edge-cases/dashcam-chrome.yaml +0 -0
  207. /package/{testdriver → _testdriver}/edge-cases/exec-pwsh-multiline.yaml +0 -0
  208. /package/{testdriver → _testdriver}/edge-cases/js-exception.yaml +0 -0
  209. /package/{testdriver → _testdriver}/edge-cases/js-promise.yaml +0 -0
  210. /package/{testdriver → _testdriver}/edge-cases/lifecycle/postrun.yaml +0 -0
  211. /package/{testdriver → _testdriver}/edge-cases/prompt-in-middle.yaml +0 -0
  212. /package/{testdriver → _testdriver}/edge-cases/prompt-nested.yaml +0 -0
  213. /package/{testdriver → _testdriver}/edge-cases/success-test.yaml +0 -0
  214. /package/{testdriver → _testdriver}/examples/android/example.yaml +0 -0
  215. /package/{testdriver → _testdriver}/examples/android/lifecycle/postrun.yaml +0 -0
  216. /package/{testdriver → _testdriver}/examples/android/lifecycle/provision.yaml +0 -0
  217. /package/{testdriver → _testdriver}/examples/android/readme.md +0 -0
  218. /package/{testdriver → _testdriver}/examples/chrome-extension/lifecycle/provision.yaml +0 -0
  219. /package/{testdriver → _testdriver}/examples/desktop/lifecycle/provision.yaml +0 -0
  220. /package/{testdriver → _testdriver}/examples/vscode-extension/lifecycle/provision.yaml +0 -0
  221. /package/{testdriver → _testdriver}/examples/web/lifecycle/postrun.yaml +0 -0
  222. /package/docs/{account → v6/account}/dashboard.mdx +0 -0
  223. /package/docs/{account → v6/account}/enterprise.mdx +0 -0
  224. /package/docs/{account → v6/account}/pricing.mdx +0 -0
  225. /package/docs/{account → v6/account}/projects.mdx +0 -0
  226. /package/docs/{account → v6/account}/team.mdx +0 -0
  227. /package/docs/{action → v6/action}/ami.mdx +0 -0
  228. /package/docs/{action → v6/action}/performance.mdx +0 -0
  229. /package/docs/{action → v6/action}/secrets.mdx +0 -0
  230. /package/docs/{apps → v6/apps}/chrome-extensions.mdx +0 -0
  231. /package/docs/{apps → v6/apps}/desktop-apps.mdx +0 -0
  232. /package/docs/{apps → v6/apps}/mobile-apps.mdx +0 -0
  233. /package/docs/{apps → v6/apps}/static-websites.mdx +0 -0
  234. /package/docs/{apps → v6/apps}/tauri-apps.mdx +0 -0
  235. /package/docs/{bugs → v6/bugs}/jira.mdx +0 -0
  236. /package/docs/{cli → v6/cli}/overview.mdx +0 -0
  237. /package/docs/{commands → v6/commands}/assert.mdx +0 -0
  238. /package/docs/{commands → v6/commands}/exec.mdx +0 -0
  239. /package/docs/{commands → v6/commands}/focus-application.mdx +0 -0
  240. /package/docs/{commands → v6/commands}/hover-image.mdx +0 -0
  241. /package/docs/{commands → v6/commands}/hover-text.mdx +0 -0
  242. /package/docs/{commands → v6/commands}/if.mdx +0 -0
  243. /package/docs/{commands → v6/commands}/match-image.mdx +0 -0
  244. /package/docs/{commands → v6/commands}/press-keys.mdx +0 -0
  245. /package/docs/{commands → v6/commands}/remember.mdx +0 -0
  246. /package/docs/{commands → v6/commands}/run.mdx +0 -0
  247. /package/docs/{commands → v6/commands}/scroll-until-image.mdx +0 -0
  248. /package/docs/{commands → v6/commands}/scroll-until-text.mdx +0 -0
  249. /package/docs/{commands → v6/commands}/scroll.mdx +0 -0
  250. /package/docs/{commands → v6/commands}/type.mdx +0 -0
  251. /package/docs/{commands → v6/commands}/wait-for-image.mdx +0 -0
  252. /package/docs/{commands → v6/commands}/wait-for-text.mdx +0 -0
  253. /package/docs/{commands → v6/commands}/wait.mdx +0 -0
  254. /package/docs/{exporting → v6/exporting}/junit.mdx +0 -0
  255. /package/docs/{exporting → v6/exporting}/playwright.mdx +0 -0
  256. /package/docs/{features → v6/features}/auto-healing.mdx +0 -0
  257. /package/docs/{features → v6/features}/generation.mdx +0 -0
  258. /package/docs/{features → v6/features}/parallel-testing.mdx +0 -0
  259. /package/docs/{features → v6/features}/reusable-snippets.mdx +0 -0
  260. /package/docs/{features → v6/features}/selectorless.mdx +0 -0
  261. /package/docs/{features → v6/features}/visual-assertions.mdx +0 -0
  262. /package/docs/{getting-started → v6/getting-started}/ci.mdx +0 -0
  263. /package/docs/{getting-started → v6/getting-started}/cli.mdx +0 -0
  264. /package/docs/{getting-started → v6/getting-started}/editing.mdx +0 -0
  265. /package/docs/{getting-started → v6/getting-started}/playwright.mdx +0 -0
  266. /package/docs/{getting-started → v6/getting-started}/running.mdx +0 -0
  267. /package/docs/{getting-started → v6/getting-started}/vscode.mdx +0 -0
  268. /package/docs/{guide → v6/guide}/assertions.mdx +0 -0
  269. /package/docs/{guide → v6/guide}/authentication.mdx +0 -0
  270. /package/docs/{guide → v6/guide}/code.mdx +0 -0
  271. /package/docs/{guide → v6/guide}/locating.mdx +0 -0
  272. /package/docs/{guide → v6/guide}/protips.mdx +0 -0
  273. /package/docs/{guide → v6/guide}/variables.mdx +0 -0
  274. /package/docs/{guide → v6/guide}/waiting.mdx +0 -0
  275. /package/docs/{importing → v6/importing}/csv.mdx +0 -0
  276. /package/docs/{importing → v6/importing}/gherkin.mdx +0 -0
  277. /package/docs/{importing → v6/importing}/jira.mdx +0 -0
  278. /package/docs/{importing → v6/importing}/testrail.mdx +0 -0
  279. /package/docs/{integrations → v6/integrations}/electron.mdx +0 -0
  280. /package/docs/{integrations → v6/integrations}/netlify.mdx +0 -0
  281. /package/docs/{integrations → v6/integrations}/vercel.mdx +0 -0
  282. /package/docs/{interactive → v6/interactive}/explore.mdx +0 -0
  283. /package/docs/{interactive → v6/interactive}/run.mdx +0 -0
  284. /package/docs/{interactive → v6/interactive}/save.mdx +0 -0
  285. /package/docs/{overview → v6/overview}/faq.mdx +0 -0
  286. /package/docs/{overview → v6/overview}/performance.mdx +0 -0
  287. /package/docs/{overview → v6/overview}/quickstart.mdx +0 -0
  288. /package/docs/{overview → v6/overview}/what-is-testdriver.mdx +0 -0
  289. /package/docs/{scenarios → v6/scenarios}/ai-chatbot.mdx +0 -0
  290. /package/docs/{scenarios → v6/scenarios}/cookie-banner.mdx +0 -0
  291. /package/docs/{scenarios → v6/scenarios}/file-upload.mdx +0 -0
  292. /package/docs/{scenarios → v6/scenarios}/form-filling.mdx +0 -0
  293. /package/docs/{scenarios → v6/scenarios}/log-in.mdx +0 -0
  294. /package/docs/{scenarios → v6/scenarios}/pdf-generation.mdx +0 -0
  295. /package/docs/{scenarios → v6/scenarios}/spell-check.mdx +0 -0
  296. /package/docs/{security → v6/security}/action.mdx +0 -0
  297. /package/docs/{security → v6/security}/agent.mdx +0 -0
  298. /package/docs/{security → v6/security}/platform.mdx +0 -0
  299. /package/docs/{tutorials → v6/tutorials}/advanced-test.mdx +0 -0
  300. /package/docs/{tutorials → v6/tutorials}/basic-test.mdx +0 -0
@@ -0,0 +1,342 @@
1
+ ---
2
+ title: "Get Started with TestDriver & Playwright"
3
+ sidebarTitle: "Playwright"
4
+ tag: "NEW"
5
+ description: "In this guide, you'll setup your TestDriver account, create a new Playwright project, and leverage TestDriver's AI to convert tests to natural language."
6
+ icon: "masks-theater"
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ `@testdriver.ai/playwright` is a backwards-compatible wrapper around `@playwright/test` that uses TestDriver's Vision AI to:
12
+
13
+ - Make [natural language assertions](#assertions-with-expect-tomatchprompt)
14
+ - [Replace brittle selectors](#locating-elements-with-testdriver-locate) with natural language
15
+ - [Perform actions](#performing-actions-with-testdriver-act) with a prompt
16
+ - Test with an [automated agent](#agentic-tests-with-test-agent)
17
+
18
+ We'll be incrementally converting Playwright's example test from the sample code:
19
+
20
+ ```typescript tests/example.spec.ts icon=square-js
21
+ // Before
22
+ test("get started link", async ({ page }) => {
23
+ await page.goto("https://playwright.dev/");
24
+ await page.getByRole("link", { name: "Get started" }).click();
25
+ await expect(
26
+ page.getByRole("heading", { name: "Installation" }),
27
+ ).toBeVisible();
28
+ });
29
+ ```
30
+
31
+ To using natural language with TestDriver:
32
+
33
+ ```typescript tests/example.spec.ts icon=square-js
34
+ // After
35
+ import { test } from "@testdriver.ai/playwright";
36
+
37
+ test.describe("get started link", () => {
38
+ test.beforeEach(async ({ page }) => page.goto("https://playwright.dev/"));
39
+ test.agent(`
40
+ - Click the 'Get started' link
41
+ - Verify the 'Installation' heading is visible
42
+ `);
43
+ });
44
+ ```
45
+
46
+ ## Prerequisites
47
+
48
+ <Steps>
49
+ <Step title="Create a TestDriver Account">
50
+ You will need a [Free TestDriver Account](https://app.testdriver.ai/team) to get an API key.
51
+
52
+ <Card title="Sign Up for TestDriver" icon="user-plus" horizontal href="https://app.testdriver.ai/team">
53
+
54
+ </Card>
55
+
56
+ </Step>
57
+ <Step title="Set up your environment">
58
+ Copy your API key from [the TestDriver dashboard](https://app.testdriver.ai/team), and set it as an environment variable.
59
+
60
+ <Tabs>
61
+ <Tab title="macOS / Linux">
62
+ ```bash Export an environment variable on macOS or Linux systems
63
+ export TD_API_KEY="your_api_key_here"
64
+ ```
65
+ </Tab>
66
+ <Tab title="Windows">
67
+ ```powershell Export an environment variable in PowerShell
68
+ setx TD_API_KEY "your_api_key_here"
69
+ ```
70
+ </Tab>
71
+ </Tabs>
72
+
73
+ </Step>
74
+ </Steps>
75
+
76
+ ## Setup Playwright
77
+
78
+ <Steps>
79
+ <Step title="Initialize Playwright">
80
+ <Info>
81
+ This is a condensed version of [Playwright's Installation Instructions](https://playwright.dev/docs/intro).
82
+
83
+ **If you're new to Playwright, you should follow their guide first.**
84
+ </Info>
85
+ In a new folder or an existing, run:
86
+
87
+ <Tabs>
88
+ <Tab title="npm">
89
+ ```bash
90
+ npm init playwright@latest
91
+ ```
92
+ </Tab>
93
+ <Tab title="yarn">
94
+ ```bash
95
+ yarn create playwright
96
+ ```
97
+ </Tab>
98
+ <Tab title="pnpm">
99
+ ```bash
100
+ pnpm create playwright
101
+ ```
102
+ </Tab>
103
+ </Tabs>
104
+ Select the following options when prompted:
105
+
106
+ ```console
107
+ ✔ Do you want to use TypeScript or JavaScript?
108
+ > TypeScript
109
+ ✔ Where to put your end-to-end tests?
110
+ > tests
111
+ ✔ Add a GitHub Actions workflow? (y/N)
112
+ > N
113
+ ✔ Install Playwright browsers (can be done manually via 'npx playwright install')? (Y/n)
114
+ > Y
115
+ ```
116
+
117
+ Then, confirm Playwright works by running:
118
+
119
+ <Tabs>
120
+ <Tab title="npm">
121
+ ```bash
122
+ npx playwright test
123
+ ```
124
+ </Tab>
125
+ <Tab title="yarn">
126
+ ```bash
127
+ yarn playwright test
128
+ ```
129
+ </Tab>
130
+ <Tab title="pnpm">
131
+ ```bash
132
+ pnpm exec playwright test
133
+ ```
134
+ </Tab>
135
+ </Tabs>
136
+
137
+ </Step>
138
+ </Steps>
139
+
140
+ ## Setup `@testdriver.ai/playwright`
141
+
142
+ <Steps>
143
+ <Step title="Install TestDriver">
144
+ `@testdriver.ai/playwright` as a backwards-compatible wrapper around `@playwright/test`:
145
+
146
+ <Tabs>
147
+ <Tab title="npm">
148
+ ```bash
149
+ npm install @testdriver.ai/playwright
150
+ ```
151
+ </Tab>
152
+ <Tab title="yarn">
153
+ ```bash
154
+ yarn add @testdriver.ai/playwright
155
+ ```
156
+ </Tab>
157
+ <Tab title="pnpm">
158
+ ```bash
159
+ pnpm add @testdriver.ai/playwright
160
+ ```
161
+ </Tab>
162
+ </Tabs>
163
+
164
+ </Step>
165
+ <Step title="Run Playwright">
166
+ Before we start using TestDriver in our tests, run Playwright in [UI Mode](https://playwright.dev/docs/test-ui-mode):
167
+
168
+ <Tabs>
169
+ <Tab title="npm">
170
+ ```bash
171
+ npx playwright test --ui
172
+ ```
173
+ </Tab>
174
+ <Tab title="yarn">
175
+ ```bash
176
+ yarn playwright test --ui
177
+ ```
178
+ </Tab>
179
+ <Tab title="pnpm">
180
+ ```bash
181
+ pnpm exec playwright test --ui
182
+ ```
183
+ </Tab>
184
+ </Tabs>
185
+ ![Playwright UI Mode](https://playwright.dev/assets/ideal-img/ui-mode.4e54d6b.3598.png)
186
+
187
+ Clicking the ▶️ button should successfully run the tests in the UI,
188
+ just as they did before with `playwright test` in the CLI.
189
+
190
+ </Step>
191
+ <Step title="Import TestDriver">
192
+ For the sake of simplicity, we'll be working with one test file for now.
193
+
194
+ Open `tests/example.spec.ts` in your editor & rename the `@playwright/test`
195
+ import to `@testdriver.ai/playwright`:
196
+
197
+ ```typescript tests/example.spec.ts icon=square-js
198
+ import { test, expect } from '@playwright/test'; // [!code --]
199
+ import { test, expect } from '@testdriver.ai/playwright'; // [!code ++]
200
+ ```
201
+
202
+ Click the <Icon icon="play" /> button to run the test and verify everything still works.
203
+
204
+ <Tip>
205
+ Click the <Icon icon="eye" /> button to automatically re-run tests on save.
206
+ </Tip>
207
+
208
+ </Step>
209
+ </Steps>
210
+
211
+ ## Usage
212
+
213
+ Because TestDriver uses AI vision instead of selectors, we can use natural language for
214
+ [assertions](#assertions-with-expect-tomatchprompt),
215
+ [locating](#locating-elements-with-testdriver-locate),
216
+ performing [actions](#performing-actions-with-testdriver-act),
217
+ or even having an [agent](#agentic-tests-with-test-agent) test for you!
218
+
219
+ ### Assertions with `expect.toMatchPrompt`
220
+
221
+ Replace `toBeVisible` with `toMatchPrompt` to assert that the element is visible on the screen:
222
+
223
+ ```typescript tests/example.spec.ts icon=square-js
224
+ // [!code --:2]
225
+ // Expects page to have a heading with the name of Installation.
226
+ await expect(page.getByRole("heading", { name: "Installation" })).toBeVisible();
227
+ // [!code ++:2]
228
+ await expect(page).toMatchPrompt("'Installation' heading is visible");
229
+ ```
230
+
231
+ Before, the test needed code comments to describe what the assertion is _actually checking_.
232
+
233
+ With `toMatchPrompt`, natural language acts as a description, selector, and assertion in one
234
+
235
+ <Tip>
236
+ TestDriver can reduce the amount of complexity in your tests, but you can
237
+ still "opt-in" to Playwright assertions and selectors if you need to (e.g.
238
+ validating accessibility with `page.getByRole`).
239
+ </Tip>
240
+
241
+ ### Locating elements with `testdriver.locate`
242
+
243
+ TestDriver can replace `data-testid`s, `getByRole`, and CSS selectors with natural language.
244
+
245
+ First, update your test to get access to the `testdriver` fixture:
246
+
247
+ ```typescript tests/example.spec.ts icon=square-js
248
+ // [!code --]
249
+ test('get started link', async ({ page, }) => {
250
+ // [!code ++]
251
+ test('get started link', async ({ page, testdriver }) => {
252
+ ```
253
+
254
+ Then, replace `getByRole` with `testdriver.locate`:
255
+
256
+ ```typescript tests/example.spec.ts icon=square-js
257
+ test('get started link', async ({ page, testdriver }) => {
258
+ await page.goto('https://playwright.dev/');
259
+
260
+ // [!code --:2]
261
+ // Click the get started link.
262
+ await page.getByRole("link", { name: "Get started" }).click();
263
+ // [!code ++:2]
264
+ const link = await testdriver(page).locate("Get started link");
265
+ await link.click();
266
+
267
+ await expect(page).toMatchPrompt("'Installation' heading is visible");
268
+ ```
269
+
270
+ Now, our test uses natural language to both describe & locate the element.
271
+
272
+ <Tip>
273
+ In the example above, you can still use Playwright to assert that the element is indeed a link for accessibility:
274
+
275
+ ```typescript tests/example.spec.ts icon=square-js
276
+ const link = await testdriver(page).locate("Get started link");
277
+ // [!code ++]
278
+ expect(link).toHaveRole("link");
279
+ await link.click();
280
+ ```
281
+
282
+ This way you can write user-centric tests _and_ validate the implementation.
283
+
284
+ </Tip>
285
+
286
+ ### Performing actions with `testdriver.act`
287
+
288
+ We can combine `locate` and `click` from the previous example into one line with `testdriver.act`:
289
+
290
+ ```typescript tests/example.spec.ts icon=square-js
291
+ test("get started link", async ({ page, testdriver }) => {
292
+ await page.goto("https://playwright.dev/");
293
+
294
+ // [!code --:2]
295
+ const link = await testdriver(page).locate("Get started link");
296
+ await link.click();
297
+ // [!code ++]
298
+ await testdriver(page).act("Click the 'Get started' link");
299
+
300
+ await expect(page).toMatchPrompt("'Installation' heading is visible");
301
+ });
302
+ ```
303
+
304
+ Now the test uses the page the way a user would!
305
+
306
+ ### Agentic tests with `test.agent`
307
+
308
+ TestDriver can automatically perform the entire test for you with an AI agent:
309
+
310
+ ```typescript tests/example.spec.ts icon=square-js
311
+ // [!code --:6]
312
+ test("get started link", async ({ page, testdriver }) => {
313
+ await page.goto("https://playwright.dev/");
314
+ await testdriver(page).act("Click the 'Get started' link");
315
+ await expect(page).toMatchPrompt("'Installation' heading is visible");
316
+ });
317
+
318
+ // [!code ++:7]
319
+ test.describe("get started link", () => {
320
+ test.beforeEach(async ({ page }) => page.goto("https://playwright.dev/"));
321
+ test.agent(`
322
+ - Click the 'Get started' link
323
+ - Verify the 'Installation' heading is visible
324
+ `);
325
+ });
326
+ ```
327
+
328
+ Instead of writing the test implementation, we've used [`test.describe`](https://playwright.dev/docs/api/class-test#test-describe) to describe the test still,
329
+ but replaced the `test` itself with `test.agent`.
330
+
331
+ <Tip>
332
+ Use `test.beforeEach` to prepare the page for the agent (e.g.
333
+ [`page.goto`](https://playwright.dev/docs/api/class-page#page-goto), calling
334
+ an API to create a user). Use
335
+ [`test.afterEach`](https://playwright.dev/docs/api/class-test#test-after-each)
336
+ to clean up after the agent (e.g. `page.close`) or perform additional logic
337
+ (e.g. clearing the session).
338
+ </Tip>
339
+
340
+ ## Conclusion
341
+
342
+ With `@testdriver.ai/playwright`, you can use as much or as little of Playwright's _or_ TestDriver's API as you need to validate correctness. It's up to you!
@@ -0,0 +1,223 @@
1
+ ---
2
+ title: "Chrome Extension Testing"
3
+ sidebarTitle: "Chrome Extensions"
4
+ description: "Test Chrome extensions with Chrome for Testing"
5
+ icon: "puzzle-piece"
6
+ ---
7
+
8
+ ## Overview
9
+
10
+ Test Chrome extensions by loading them into Chrome for Testing. This preset uses the `launchChromeExtension()` helper to launch Chrome with a specific extension loaded by its Chrome Web Store ID.
11
+
12
+ ## Quick Start
13
+
14
+ ```javascript
15
+ import { test } from 'vitest';
16
+ import TestDriver from 'testdriverai';
17
+ import {
18
+ runPrerunChromeExtension,
19
+ runPostrun
20
+ } from 'testdriverai/testdriver/acceptance-sdk/setup/lifecycleHelpers.mjs';
21
+
22
+ test('test chrome extension', async () => {
23
+ const client = await TestDriver.create({
24
+ apiKey: process.env.TD_API_KEY,
25
+ os: "linux",
26
+ verbosity: 1,
27
+ });
28
+
29
+ // Launch Chrome with extension loaded
30
+ // Extension ID from Chrome Web Store
31
+ await runPrerunChromeExtension(client, "cjpalhdlnbpafiamejdnhcphjbkeiagm");
32
+
33
+ // Your test code here
34
+ await client.focusApplication("Google Chrome");
35
+
36
+ // ... test extension functionality
37
+
38
+ await runPostrun(client);
39
+ await client.cleanup();
40
+ });
41
+ ```
42
+
43
+ ## Finding Extension IDs
44
+
45
+ Extension IDs can be found in the Chrome Web Store URL:
46
+
47
+ ```
48
+ https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm
49
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
50
+ This is the extension ID
51
+ ```
52
+
53
+ ## Popular Extensions
54
+
55
+ | Extension | ID |
56
+ |-----------|---|
57
+ | uBlock Origin | `cjpalhdlnbpafiamejdnhcphjbkeiagm` |
58
+ | React Developer Tools | `fmkadmapgofadopljbjfkapdkoienihi` |
59
+ | Redux DevTools | `lmhkpmbekcpmknklioeibfkpmmfibljd` |
60
+ | Bitwarden | `nngceckbapebfimnlniiiahkandclblb` |
61
+
62
+ ## Loading Multiple Extensions
63
+
64
+ Load multiple extensions by separating IDs with commas:
65
+
66
+ ```javascript
67
+ await launchChromeExtension(
68
+ client,
69
+ "cjpalhdlnbpafiamejdnhcphjbkeiagm,nngceckbapebfimnlniiiahkandclblb"
70
+ );
71
+ ```
72
+
73
+ ## Complete Example
74
+
75
+ ```javascript
76
+ import { describe, it, beforeAll, afterAll } from 'vitest';
77
+ import TestDriver from 'testdriverai';
78
+ import {
79
+ runPrerunChromeExtension,
80
+ runPostrun
81
+ } from 'testdriverai/testdriver/acceptance-sdk/setup/lifecycleHelpers.mjs';
82
+
83
+ describe('Chrome Extension Testing', () => {
84
+ let client;
85
+ let dashcamUrl;
86
+
87
+ beforeAll(async () => {
88
+ client = await TestDriver.create({
89
+ apiKey: process.env.TD_API_KEY,
90
+ os: "linux",
91
+ verbosity: 1,
92
+ });
93
+
94
+ // Load uBlock Origin extension
95
+ await runPrerunChromeExtension(client, "cjpalhdlnbpafiamejdnhcphjbkeiagm");
96
+ });
97
+
98
+ afterAll(async () => {
99
+ if (client) {
100
+ dashcamUrl = await runPostrun(client);
101
+ await client.cleanup();
102
+ }
103
+ });
104
+
105
+ it('should verify extension is loaded', async () => {
106
+ await client.focusApplication("Google Chrome");
107
+
108
+ // Navigate to a page
109
+ const element = await client.find("TestDriver.ai Sandbox");
110
+ expect(element.found()).toBe(true);
111
+
112
+ // Test extension-specific functionality
113
+ // For example, checking if ads are blocked with uBlock
114
+ });
115
+
116
+ it('should access extension popup', async () => {
117
+ await client.focusApplication("Google Chrome");
118
+
119
+ // Open extension management
120
+ await client.exec(
121
+ "sh",
122
+ `xdotool key --clearmodifiers ctrl+shift+e`,
123
+ 5000,
124
+ true
125
+ );
126
+
127
+ // Wait for extensions page
128
+ await new Promise((resolve) => setTimeout(resolve, 2000));
129
+ });
130
+ });
131
+ ```
132
+
133
+ ## Environment Setup
134
+
135
+ Chrome for Testing is pre-installed in the E2B sandbox environment at:
136
+
137
+ ```
138
+ /opt/chrome-for-testing/chrome
139
+ /usr/local/bin/chrome-for-testing (symlink)
140
+ ```
141
+
142
+ ## Direct API Usage
143
+
144
+ Use the lower-level API for more control:
145
+
146
+ ```javascript
147
+ import { launchChromeExtension } from 'testdriverai/testdriver/acceptance-sdk/setup/lifecycleHelpers.mjs';
148
+
149
+ // Launch with specific extension and URL
150
+ await launchChromeExtension(
151
+ client,
152
+ "cjpalhdlnbpafiamejdnhcphjbkeiagm",
153
+ "https://example.com"
154
+ );
155
+ ```
156
+
157
+ ## Testing Extension Features
158
+
159
+ ### Test Extension Popup
160
+
161
+ ```javascript
162
+ it('opens extension popup', async () => {
163
+ // Click extension icon (varies by extension)
164
+ await client.click('extension icon in toolbar');
165
+
166
+ // Interact with popup
167
+ const popup = await client.find('extension popup window');
168
+ expect(popup.found()).toBe(true);
169
+ });
170
+ ```
171
+
172
+ ### Test Extension Settings
173
+
174
+ ```javascript
175
+ it('configures extension settings', async () => {
176
+ // Right-click extension icon
177
+ await client.rightClick('extension icon');
178
+
179
+ // Click options
180
+ await client.click('Options');
181
+
182
+ // Configure settings
183
+ await client.click('Enable feature X');
184
+ await client.click('Save');
185
+ });
186
+ ```
187
+
188
+ ### Test Content Scripts
189
+
190
+ ```javascript
191
+ it('verifies content script injection', async () => {
192
+ // Navigate to a page
193
+ await client.exec('sh', 'xdotool key ctrl+l', 5000, true);
194
+ await client.type('https://example.com');
195
+ await client.pressKeys('Enter');
196
+
197
+ // Check for extension-injected elements
198
+ const injected = await client.find('element added by extension');
199
+ expect(injected.found()).toBe(true);
200
+ });
201
+ ```
202
+
203
+ ## Troubleshooting
204
+
205
+ ### Extension Not Loading
206
+
207
+ 1. Verify the extension ID is correct
208
+ 2. Check Chrome for Testing is installed in the sandbox
209
+ 3. Ensure extension is compatible with Chrome for Testing version
210
+
211
+ ### Extension Permissions
212
+
213
+ Some extensions may require additional permissions or setup. You may need to:
214
+
215
+ 1. Navigate to `chrome://extensions/`
216
+ 2. Enable developer mode
217
+ 3. Grant required permissions
218
+
219
+ ## See Also
220
+
221
+ - [Web Apps (Chrome)](/v7/presets/chrome) - Regular Chrome browser testing
222
+ - [Desktop Apps (Electron)](/v7/presets/electron) - Electron app testing
223
+ - [Lifecycle Helpers](/v7/guides/lifecycle) - Prerun/postrun functions