@testdriverai/agent 7.8.0-canary.10
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.
- package/.claude/settings.local.json +7 -0
- package/.env.example +4 -0
- package/.prettierignore +4 -0
- package/.prettierrc +1 -0
- package/CHANGELOG.md +953 -0
- package/README.md +81 -0
- package/agent/events.js +135 -0
- package/agent/index.js +2450 -0
- package/agent/interface.js +35 -0
- package/agent/lib/analytics.js +22 -0
- package/agent/lib/censorship.js +75 -0
- package/agent/lib/commander.js +246 -0
- package/agent/lib/commands.js +1684 -0
- package/agent/lib/config.js +60 -0
- package/agent/lib/generator.js +91 -0
- package/agent/lib/http.js +144 -0
- package/agent/lib/logger.js +56 -0
- package/agent/lib/outputs.js +29 -0
- package/agent/lib/parser.js +209 -0
- package/agent/lib/redraw.js +386 -0
- package/agent/lib/resources/cursor-2.png +0 -0
- package/agent/lib/sandbox.js +1104 -0
- package/agent/lib/sdk.js +633 -0
- package/agent/lib/session.js +25 -0
- package/agent/lib/source-mapper.js +342 -0
- package/agent/lib/subimage/index.js +77 -0
- package/agent/lib/subimage/opencv.js +69 -0
- package/agent/lib/system.js +204 -0
- package/agent/lib/theme.js +14 -0
- package/agent/lib/valid-version.js +21 -0
- package/agent/lib/validation.js +169 -0
- package/ai/.claude-plugin/plugin.json +9 -0
- package/ai/agents/testdriver.md +638 -0
- package/ai/skills/testdriver-ai/SKILL.md +204 -0
- package/ai/skills/testdriver-assert/SKILL.md +315 -0
- package/ai/skills/testdriver-aws-setup/SKILL.md +448 -0
- package/ai/skills/testdriver-cache/SKILL.md +221 -0
- package/ai/skills/testdriver-caching/SKILL.md +124 -0
- package/ai/skills/testdriver-captcha/SKILL.md +158 -0
- package/ai/skills/testdriver-ci-cd/SKILL.md +602 -0
- package/ai/skills/testdriver-click/SKILL.md +286 -0
- package/ai/skills/testdriver-client/SKILL.md +477 -0
- package/ai/skills/testdriver-cloud/SKILL.md +119 -0
- package/ai/skills/testdriver-customizing-devices/SKILL.md +319 -0
- package/ai/skills/testdriver-dashcam/SKILL.md +418 -0
- package/ai/skills/testdriver-debugging-with-screenshots/SKILL.md +401 -0
- package/ai/skills/testdriver-device-config/SKILL.md +317 -0
- package/ai/skills/testdriver-double-click/SKILL.md +102 -0
- package/ai/skills/testdriver-elements/SKILL.md +605 -0
- package/ai/skills/testdriver-enterprise/SKILL.md +114 -0
- package/ai/skills/testdriver-errors/SKILL.md +246 -0
- package/ai/skills/testdriver-events/SKILL.md +356 -0
- package/ai/skills/testdriver-examples/SKILL.md +7 -0
- package/ai/skills/testdriver-exec/SKILL.md +317 -0
- package/ai/skills/testdriver-find/SKILL.md +829 -0
- package/ai/skills/testdriver-focus-application/SKILL.md +293 -0
- package/ai/skills/testdriver-generating-tests/SKILL.md +36 -0
- package/ai/skills/testdriver-hover/SKILL.md +278 -0
- package/ai/skills/testdriver-locating-elements/SKILL.md +71 -0
- package/ai/skills/testdriver-making-assertions/SKILL.md +32 -0
- package/ai/skills/testdriver-mcp/SKILL.md +7 -0
- package/ai/skills/testdriver-mcp-workflow/SKILL.md +410 -0
- package/ai/skills/testdriver-mouse-down/SKILL.md +161 -0
- package/ai/skills/testdriver-mouse-up/SKILL.md +164 -0
- package/ai/skills/testdriver-parse/SKILL.md +236 -0
- package/ai/skills/testdriver-performing-actions/SKILL.md +54 -0
- package/ai/skills/testdriver-press-keys/SKILL.md +348 -0
- package/ai/skills/testdriver-provision/SKILL.md +331 -0
- package/ai/skills/testdriver-quickstart/SKILL.md +144 -0
- package/ai/skills/testdriver-redraw/SKILL.md +214 -0
- package/ai/skills/testdriver-reusable-code/SKILL.md +249 -0
- package/ai/skills/testdriver-right-click/SKILL.md +123 -0
- package/ai/skills/testdriver-running-tests/SKILL.md +185 -0
- package/ai/skills/testdriver-screenshot/SKILL.md +248 -0
- package/ai/skills/testdriver-screenshots/SKILL.md +184 -0
- package/ai/skills/testdriver-scroll/SKILL.md +335 -0
- package/ai/skills/testdriver-secrets/SKILL.md +115 -0
- package/ai/skills/testdriver-self-hosted/SKILL.md +65 -0
- package/ai/skills/testdriver-test-writer/SKILL.md +448 -0
- package/ai/skills/testdriver-testdriver/SKILL.md +628 -0
- package/ai/skills/testdriver-testdriver-mechanic/SKILL.md +165 -0
- package/ai/skills/testdriver-type/SKILL.md +357 -0
- package/ai/skills/testdriver-variables/SKILL.md +111 -0
- package/ai/skills/testdriver-wait/SKILL.md +50 -0
- package/ai/skills/testdriver-waiting-for-elements/SKILL.md +90 -0
- package/ai/skills/testdriver-what-is-testdriver/SKILL.md +54 -0
- package/bin/testdriverai.js +22 -0
- package/debugger/bg.png +0 -0
- package/debugger/icon.png +0 -0
- package/debugger/index.html +469 -0
- package/debugger/td.png +0 -0
- package/debugger/tray-buffered.png +0 -0
- package/debugger/tray.png +0 -0
- package/docs/GITHUB_COMMENTS.md +330 -0
- package/docs/GITHUB_COMMENTS_ANNOUNCEMENT.md +167 -0
- package/docs/QUICK-START-GITHUB-COMMENTS.md +84 -0
- package/docs/TEST-GITHUB-COMMENTS.md +129 -0
- package/docs/_data/examples-manifest.json +177 -0
- package/docs/_data/examples-manifest.schema.json +41 -0
- package/docs/_scripts/extract-example-urls.js +165 -0
- package/docs/_scripts/generate-examples.js +560 -0
- package/docs/_scripts/generate-skills.js +154 -0
- package/docs/_scripts/link-replacer.js +164 -0
- package/docs/_scripts/upload-docs-to-openai.js +284 -0
- package/docs/changelog.mdx +161 -0
- package/docs/claude-mcp-plugin.mdx +160 -0
- package/docs/docs.json +442 -0
- package/docs/github-integration-setup.md +266 -0
- package/docs/guide/best-practices-polling.mdx +174 -0
- package/docs/images/content/account/newprojectsettings.png +0 -0
- package/docs/images/content/account/projectpage.png +0 -0
- package/docs/images/content/account/projectreplays.png +0 -0
- package/docs/images/content/account/team-manage.png +0 -0
- package/docs/images/content/account/teampage.png +0 -0
- package/docs/images/content/extension/cursor.svg +1 -0
- package/docs/images/content/extension/vscode.svg +57 -0
- package/docs/images/content/extension/windsurf.svg +3 -0
- package/docs/images/content/parse/output.png +0 -0
- package/docs/images/content/self-hosted/launchtemplateid.png +0 -0
- package/docs/images/content/side-by-side.png +0 -0
- package/docs/images/content/vscode/ide-full.png +0 -0
- package/docs/images/content/vscode/running.png +0 -0
- package/docs/images/content/vscode/v7-chat.png +0 -0
- package/docs/images/content/vscode/v7-choose-agent.png +0 -0
- package/docs/images/content/vscode/v7-full.png +0 -0
- package/docs/images/content/vscode/v7-onboarding.png +0 -0
- package/docs/images/content/vscode/vscode-2-assert.png +0 -0
- package/docs/images/content/vscode/vscode-agent-preview.png +0 -0
- package/docs/images/content/vscode/vscode-copilot-ask.png +0 -0
- package/docs/images/content/vscode/vscode-file-creation.png +0 -0
- package/docs/images/content/vscode/vscode-install.png +0 -0
- package/docs/images/content/vscode/vscode-overview.png +0 -0
- package/docs/images/content/vscode/vscode-setup-walkthrough.png +0 -0
- package/docs/images/content/vscode/vscode-stopchat.png +0 -0
- package/docs/images/content/vscode/vscode-stoptest.png +0 -0
- package/docs/images/content/vscode/vscode-tdservice.png +0 -0
- package/docs/images/content/vscode/vscode-test-output.png +0 -0
- package/docs/images/content/vscode/vscode-testhistory.png +0 -0
- package/docs/images/content/vscode/vscode-testpane-runtests.png +0 -0
- package/docs/images/content/vscode/vscode-testpane.png +0 -0
- package/docs/images/template/dark.png +0 -0
- package/docs/images/template/icon.png +0 -0
- package/docs/images/template/light.png +0 -0
- package/docs/snippets/calendar-link.mdx +4 -0
- package/docs/snippets/gitignore-warning.mdx +7 -0
- package/docs/snippets/lifecycle-warning.mdx +6 -0
- package/docs/snippets/test-prereqs.mdx +12 -0
- package/docs/snippets/tests/assert-replay.mdx +7 -0
- package/docs/snippets/tests/assert-yaml.mdx +8 -0
- package/docs/snippets/tests/exec-js-replay.mdx +7 -0
- package/docs/snippets/tests/exec-js-yaml.mdx +32 -0
- package/docs/snippets/tests/exec-shell-replay.mdx +7 -0
- package/docs/snippets/tests/exec-shell-yaml.mdx +15 -0
- package/docs/snippets/tests/hover-image-replay.mdx +7 -0
- package/docs/snippets/tests/hover-image-yaml.mdx +17 -0
- package/docs/snippets/tests/hover-text-replay.mdx +7 -0
- package/docs/snippets/tests/hover-text-with-description-replay.mdx +7 -0
- package/docs/snippets/tests/hover-text-with-description-yaml.mdx +24 -0
- package/docs/snippets/tests/hover-text-yaml.mdx +14 -0
- package/docs/snippets/tests/match-image-replay.mdx +7 -0
- package/docs/snippets/tests/match-image-yaml.mdx +17 -0
- package/docs/snippets/tests/press-keys-replay.mdx +7 -0
- package/docs/snippets/tests/press-keys-yaml.mdx +36 -0
- package/docs/snippets/tests/remember-replay.mdx +7 -0
- package/docs/snippets/tests/remember-yaml.mdx +28 -0
- package/docs/snippets/tests/scroll-replay.mdx +7 -0
- package/docs/snippets/tests/scroll-until-image-replay.mdx +7 -0
- package/docs/snippets/tests/scroll-until-image-yaml.mdx +14 -0
- package/docs/snippets/tests/scroll-until-text-replay.mdx +7 -0
- package/docs/snippets/tests/scroll-until-text-yaml.mdx +17 -0
- package/docs/snippets/tests/scroll-yaml.mdx +30 -0
- package/docs/snippets/tests/type-repeated-replay.mdx +7 -0
- package/docs/snippets/tests/type-repeated-yaml.mdx +22 -0
- package/docs/snippets/tests/type-replay.mdx +7 -0
- package/docs/snippets/tests/type-yaml.mdx +28 -0
- package/docs/snippets/tests/wait-for-image-replay.mdx +7 -0
- package/docs/snippets/tests/wait-for-image-yaml.mdx +18 -0
- package/docs/snippets/tests/wait-for-text-replay.mdx +7 -0
- package/docs/snippets/tests/wait-for-text-yaml.mdx +18 -0
- package/docs/snippets/tests/wait-replay.mdx +7 -0
- package/docs/snippets/tests/wait-yaml.mdx +13 -0
- package/docs/styles.css +65 -0
- package/docs/v6/account/dashboard.mdx +16 -0
- package/docs/v6/account/enterprise.mdx +110 -0
- package/docs/v6/account/pricing.mdx +33 -0
- package/docs/v6/account/projects.mdx +33 -0
- package/docs/v6/account/team.mdx +35 -0
- package/docs/v6/action/ami.mdx +109 -0
- package/docs/v6/action/performance.mdx +105 -0
- package/docs/v6/action/secrets.mdx +93 -0
- package/docs/v6/apps/chrome-extensions.mdx +48 -0
- package/docs/v6/apps/desktop-apps.mdx +93 -0
- package/docs/v6/apps/mobile-apps.mdx +26 -0
- package/docs/v6/apps/static-websites.mdx +54 -0
- package/docs/v6/apps/tauri-apps.mdx +361 -0
- package/docs/v6/bugs/jira.mdx +232 -0
- package/docs/v6/cli/overview.mdx +66 -0
- package/docs/v6/commands/assert.mdx +45 -0
- package/docs/v6/commands/exec.mdx +276 -0
- package/docs/v6/commands/focus-application.mdx +44 -0
- package/docs/v6/commands/hover-image.mdx +69 -0
- package/docs/v6/commands/hover-text.mdx +47 -0
- package/docs/v6/commands/if.mdx +53 -0
- package/docs/v6/commands/match-image.mdx +67 -0
- package/docs/v6/commands/press-keys.mdx +87 -0
- package/docs/v6/commands/remember.mdx +49 -0
- package/docs/v6/commands/run.mdx +44 -0
- package/docs/v6/commands/scroll-until-image.mdx +66 -0
- package/docs/v6/commands/scroll-until-text.mdx +60 -0
- package/docs/v6/commands/scroll.mdx +69 -0
- package/docs/v6/commands/type.mdx +45 -0
- package/docs/v6/commands/wait-for-image.mdx +54 -0
- package/docs/v6/commands/wait-for-text.mdx +48 -0
- package/docs/v6/commands/wait.mdx +45 -0
- package/docs/v6/exporting/junit.mdx +218 -0
- package/docs/v6/exporting/playwright.mdx +197 -0
- package/docs/v6/features/auto-healing.mdx +144 -0
- package/docs/v6/features/generation.mdx +116 -0
- package/docs/v6/features/parallel-testing.mdx +151 -0
- package/docs/v6/features/reusable-snippets.mdx +131 -0
- package/docs/v6/features/selectorless.mdx +80 -0
- package/docs/v6/features/visual-assertions.mdx +139 -0
- package/docs/v6/getting-started/ci.mdx +146 -0
- package/docs/v6/getting-started/cli.mdx +91 -0
- package/docs/v6/getting-started/editing.mdx +100 -0
- package/docs/v6/getting-started/playwright.mdx +342 -0
- package/docs/v6/getting-started/running.mdx +48 -0
- package/docs/v6/getting-started/self-hosting.mdx +408 -0
- package/docs/v6/getting-started/vscode.mdx +88 -0
- package/docs/v6/guide/assertions.mdx +189 -0
- package/docs/v6/guide/authentication.mdx +136 -0
- package/docs/v6/guide/code.mdx +65 -0
- package/docs/v6/guide/dashcam.mdx +118 -0
- package/docs/v6/guide/environment-variables.mdx +26 -0
- package/docs/v6/guide/lifecycle.mdx +242 -0
- package/docs/v6/guide/locating.mdx +141 -0
- package/docs/v6/guide/protips.mdx +43 -0
- package/docs/v6/guide/variables.mdx +143 -0
- package/docs/v6/guide/waiting.mdx +130 -0
- package/docs/v6/importing/csv.mdx +196 -0
- package/docs/v6/importing/gherkin.mdx +143 -0
- package/docs/v6/importing/jira.mdx +164 -0
- package/docs/v6/importing/testrail.mdx +162 -0
- package/docs/v6/integrations/electron.mdx +146 -0
- package/docs/v6/integrations/netlify.mdx +100 -0
- package/docs/v6/integrations/vercel.mdx +125 -0
- package/docs/v6/interactive/explore.mdx +99 -0
- package/docs/v6/interactive/run.mdx +52 -0
- package/docs/v6/interactive/save.mdx +63 -0
- package/docs/v6/overview/comparison.mdx +101 -0
- package/docs/v6/overview/faq.mdx +162 -0
- package/docs/v6/overview/performance.mdx +52 -0
- package/docs/v6/overview/quickstart.mdx +137 -0
- package/docs/v6/overview/what-is-testdriver.mdx +85 -0
- package/docs/v6/scenarios/ai-chatbot.mdx +28 -0
- package/docs/v6/scenarios/cookie-banner.mdx +32 -0
- package/docs/v6/scenarios/file-upload.mdx +33 -0
- package/docs/v6/scenarios/form-filling.mdx +32 -0
- package/docs/v6/scenarios/log-in.mdx +75 -0
- package/docs/v6/scenarios/pdf-generation.mdx +25 -0
- package/docs/v6/scenarios/spell-check.mdx +22 -0
- package/docs/v6/security/action.mdx +84 -0
- package/docs/v6/security/agent.mdx +73 -0
- package/docs/v6/security/platform.mdx +77 -0
- package/docs/v6/tutorials/advanced-test.mdx +81 -0
- package/docs/v6/tutorials/basic-test.mdx +45 -0
- package/docs/v7/_drafts/agents.mdx +843 -0
- package/docs/v7/_drafts/architecture.mdx +399 -0
- package/docs/v7/_drafts/auto-cache-key.mdx +167 -0
- package/docs/v7/_drafts/awesome-logs-quick-ref.mdx +100 -0
- package/docs/v7/_drafts/best-practices.mdx +486 -0
- package/docs/v7/_drafts/caching-ai.mdx +215 -0
- package/docs/v7/_drafts/caching-selectors.mdx +424 -0
- package/docs/v7/_drafts/caching.mdx +366 -0
- package/docs/v7/_drafts/cli-to-sdk-migration.mdx +425 -0
- package/docs/v7/_drafts/commands/assert.mdx +45 -0
- package/docs/v7/_drafts/commands/exec.mdx +276 -0
- package/docs/v7/_drafts/commands/focus-application.mdx +44 -0
- package/docs/v7/_drafts/commands/hover-image.mdx +69 -0
- package/docs/v7/_drafts/commands/hover-text.mdx +47 -0
- package/docs/v7/_drafts/commands/if.mdx +53 -0
- package/docs/v7/_drafts/commands/match-image.mdx +67 -0
- package/docs/v7/_drafts/commands/press-keys.mdx +87 -0
- package/docs/v7/_drafts/commands/remember.mdx +49 -0
- package/docs/v7/_drafts/commands/run.mdx +44 -0
- package/docs/v7/_drafts/commands/scroll-until-image.mdx +66 -0
- package/docs/v7/_drafts/commands/scroll-until-text.mdx +60 -0
- package/docs/v7/_drafts/commands/scroll.mdx +69 -0
- package/docs/v7/_drafts/commands/type.mdx +45 -0
- package/docs/v7/_drafts/commands/wait-for-image.mdx +54 -0
- package/docs/v7/_drafts/commands/wait-for-text.mdx +48 -0
- package/docs/v7/_drafts/commands/wait.mdx +45 -0
- package/docs/v7/_drafts/configuration.mdx +378 -0
- package/docs/v7/_drafts/contributing.mdx +174 -0
- package/docs/v7/_drafts/core.mdx +458 -0
- package/docs/v7/_drafts/dashcam-title-feature.mdx +89 -0
- package/docs/v7/_drafts/debugging.mdx +349 -0
- package/docs/v7/_drafts/error-handling.mdx +501 -0
- package/docs/v7/_drafts/faq.mdx +393 -0
- package/docs/v7/_drafts/hooks.mdx +360 -0
- package/docs/v7/_drafts/init-command.mdx +95 -0
- package/docs/v7/_drafts/installation.mdx +420 -0
- package/docs/v7/_drafts/migration.mdx +562 -0
- package/docs/v7/_drafts/observable.mdx +604 -0
- package/docs/v7/_drafts/playwright.mdx +342 -0
- package/docs/v7/_drafts/plugin-migration.mdx +220 -0
- package/docs/v7/_drafts/powerful.mdx +419 -0
- package/docs/v7/_drafts/presets.mdx +210 -0
- package/docs/v7/_drafts/progressive-disclosure.mdx +230 -0
- package/docs/v7/_drafts/prompt-cache.mdx +200 -0
- package/docs/v7/_drafts/provision.mdx +390 -0
- package/docs/v7/_drafts/quick-start-test-recording.mdx +214 -0
- package/docs/v7/_drafts/readme.mdx +135 -0
- package/docs/v7/_drafts/reports.mdx +414 -0
- package/docs/v7/_drafts/scalable.mdx +763 -0
- package/docs/v7/_drafts/screenshot.mdx +155 -0
- package/docs/v7/_drafts/sdk-awesome-logs.mdx +468 -0
- package/docs/v7/_drafts/sdk-browser-rendering.mdx +167 -0
- package/docs/v7/_drafts/sdk-migration.mdx +474 -0
- package/docs/v7/_drafts/sdk-v7-complete.mdx +345 -0
- package/docs/v7/_drafts/self-hosting.mdx +369 -0
- package/docs/v7/_drafts/test-recording.mdx +382 -0
- package/docs/v7/_drafts/troubleshooting.mdx +526 -0
- package/docs/v7/_drafts/vitest-plugin.mdx +477 -0
- package/docs/v7/_drafts/vitest.mdx +535 -0
- package/docs/v7/_drafts/writing-tests.mdx +25 -0
- package/docs/v7/ai.mdx +205 -0
- package/docs/v7/assert.mdx +316 -0
- package/docs/v7/aws-setup.mdx +449 -0
- package/docs/v7/cache.mdx +223 -0
- package/docs/v7/caching.mdx +128 -0
- package/docs/v7/captcha.mdx +159 -0
- package/docs/v7/ci-cd.mdx +603 -0
- package/docs/v7/click.mdx +287 -0
- package/docs/v7/client.mdx +478 -0
- package/docs/v7/copilot/auto-healing.mdx +265 -0
- package/docs/v7/copilot/creating-tests.mdx +156 -0
- package/docs/v7/copilot/github.mdx +143 -0
- package/docs/v7/copilot/running-tests.mdx +149 -0
- package/docs/v7/copilot/setup.mdx +143 -0
- package/docs/v7/customizing-devices.mdx +319 -0
- package/docs/v7/dashcam.mdx +419 -0
- package/docs/v7/debugging-with-screenshots.mdx +402 -0
- package/docs/v7/device-config.mdx +317 -0
- package/docs/v7/double-click.mdx +102 -0
- package/docs/v7/elements.mdx +606 -0
- package/docs/v7/enterprise.mdx +9 -0
- package/docs/v7/errors.mdx +248 -0
- package/docs/v7/events.mdx +358 -0
- package/docs/v7/examples/ai.mdx +72 -0
- package/docs/v7/examples/assert.mdx +72 -0
- package/docs/v7/examples/captcha-api.mdx +92 -0
- package/docs/v7/examples/chrome-extension.mdx +132 -0
- package/docs/v7/examples/drag-and-drop.mdx +100 -0
- package/docs/v7/examples/element-not-found.mdx +67 -0
- package/docs/v7/examples/exec-output.mdx +85 -0
- package/docs/v7/examples/exec-pwsh.mdx +83 -0
- package/docs/v7/examples/focus-window.mdx +62 -0
- package/docs/v7/examples/hover-image.mdx +94 -0
- package/docs/v7/examples/hover-text.mdx +69 -0
- package/docs/v7/examples/installer.mdx +91 -0
- package/docs/v7/examples/launch-vscode-linux.mdx +101 -0
- package/docs/v7/examples/match-image.mdx +96 -0
- package/docs/v7/examples/press-keys.mdx +92 -0
- package/docs/v7/examples/scroll-keyboard.mdx +79 -0
- package/docs/v7/examples/scroll-until-image.mdx +81 -0
- package/docs/v7/examples/scroll-until-text.mdx +109 -0
- package/docs/v7/examples/scroll.mdx +81 -0
- package/docs/v7/examples/type.mdx +92 -0
- package/docs/v7/examples/windows-installer.mdx +89 -0
- package/docs/v7/exec.mdx +318 -0
- package/docs/v7/find.mdx +830 -0
- package/docs/v7/focus-application.mdx +294 -0
- package/docs/v7/generating-tests.mdx +36 -0
- package/docs/v7/hosted.mdx +158 -0
- package/docs/v7/hover.mdx +279 -0
- package/docs/v7/locating-elements.mdx +71 -0
- package/docs/v7/making-assertions.mdx +32 -0
- package/docs/v7/mcp.mdx +9 -0
- package/docs/v7/mouse-down.mdx +161 -0
- package/docs/v7/mouse-up.mdx +164 -0
- package/docs/v7/parse.mdx +237 -0
- package/docs/v7/performing-actions.mdx +54 -0
- package/docs/v7/press-keys.mdx +349 -0
- package/docs/v7/provision.mdx +333 -0
- package/docs/v7/quickstart.mdx +173 -0
- package/docs/v7/redraw.mdx +216 -0
- package/docs/v7/reusable-code.mdx +249 -0
- package/docs/v7/right-click.mdx +123 -0
- package/docs/v7/running-tests.mdx +185 -0
- package/docs/v7/screenshot.mdx +249 -0
- package/docs/v7/screenshots.mdx +186 -0
- package/docs/v7/scroll.mdx +336 -0
- package/docs/v7/secrets.mdx +115 -0
- package/docs/v7/self-hosted.mdx +149 -0
- package/docs/v7/type.mdx +358 -0
- package/docs/v7/variables.mdx +111 -0
- package/docs/v7/wait.mdx +52 -0
- package/docs/v7/waiting-for-elements.mdx +90 -0
- package/docs/v7/what-is-testdriver.mdx +54 -0
- package/eslint.config.js +67 -0
- package/examples/ai.test.mjs +31 -0
- package/examples/assert.test.mjs +47 -0
- package/examples/chrome-extension.test.mjs +97 -0
- package/examples/config.mjs +5 -0
- package/examples/element-not-found.test.mjs +27 -0
- package/examples/exec-output.test.mjs +60 -0
- package/examples/exec-pwsh.test.mjs +58 -0
- package/examples/findall-coffee-icons.test.mjs +42 -0
- package/examples/focus-window.test.mjs +37 -0
- package/examples/formatted-logging.test.mjs +27 -0
- package/examples/hover-image.test.mjs +53 -0
- package/examples/hover-text-with-description.test.mjs +57 -0
- package/examples/hover-text.test.mjs +28 -0
- package/examples/installer.test.mjs +50 -0
- package/examples/launch-vscode-linux.test.mjs +55 -0
- package/examples/match-image.test.mjs +55 -0
- package/examples/parse.test.mjs +19 -0
- package/examples/press-keys.test.mjs +44 -0
- package/examples/prompt.test.mjs +34 -0
- package/examples/scroll-keyboard.test.mjs +38 -0
- package/examples/scroll-until-image.test.mjs +40 -0
- package/examples/scroll.test.mjs +42 -0
- package/examples/type.test.mjs +46 -0
- package/examples/windows-installer.test.mjs +54 -0
- package/index.js +2 -0
- package/interfaces/cli/commands/init.js +438 -0
- package/interfaces/cli/commands/setup.js +382 -0
- package/interfaces/cli/lib/base.js +285 -0
- package/interfaces/cli.js +20 -0
- package/interfaces/junit-reporter.js +290 -0
- package/interfaces/logger.js +388 -0
- package/interfaces/readline.js +234 -0
- package/interfaces/shared-test-state.mjs +64 -0
- package/interfaces/vitest-plugin.d.ts +115 -0
- package/interfaces/vitest-plugin.mjs +1698 -0
- package/lib/captcha/solver.js +358 -0
- package/lib/core/Dashcam.js +533 -0
- package/lib/core/index.d.ts +172 -0
- package/lib/core/index.js +12 -0
- package/lib/environments.json +18 -0
- package/lib/github-comment-formatter.js +263 -0
- package/lib/github-comment.mjs +452 -0
- package/lib/init-project.js +575 -0
- package/lib/presets/index.mjs +331 -0
- package/lib/resolve-channel.js +46 -0
- package/lib/sentry.js +417 -0
- package/lib/vitest/hooks.d.ts +57 -0
- package/lib/vitest/hooks.mjs +674 -0
- package/lib/vitest/setup-aws.mjs +247 -0
- package/lib/vitest/setup-self-hosted.mjs +151 -0
- package/lib/vitest/setup.mjs +46 -0
- package/manual/captcha-api.test.mjs +51 -0
- package/manual/drag-and-drop.test.mjs +59 -0
- package/manual/flake-diffthreshold-001.test.mjs +9 -0
- package/manual/flake-diffthreshold-01.test.mjs +9 -0
- package/manual/flake-diffthreshold-05.test.mjs +9 -0
- package/manual/flake-noredraw-cache.test.mjs +9 -0
- package/manual/flake-noredraw-nocache.test.mjs +9 -0
- package/manual/flake-redraw-cache.test.mjs +9 -0
- package/manual/flake-redraw-nocache.test.mjs +9 -0
- package/manual/flake-rocket-match.test.mjs +30 -0
- package/manual/flake-shared.mjs +51 -0
- package/manual/no-provision.test.mjs +31 -0
- package/manual/packer-hover-image.test.mjs +176 -0
- package/manual/scroll-until-text.test.mjs +68 -0
- package/manual/test-init-command.js +223 -0
- package/mcp-server/README.md +322 -0
- package/mcp-server/dist/codegen.d.ts +9 -0
- package/mcp-server/dist/codegen.js +165 -0
- package/mcp-server/dist/mcp-app.html +114 -0
- package/mcp-server/dist/package.json +1 -0
- package/mcp-server/dist/provision-types.d.ts +290 -0
- package/mcp-server/dist/provision-types.js +174 -0
- package/mcp-server/dist/server.d.ts +6 -0
- package/mcp-server/dist/server.mjs +1925 -0
- package/mcp-server/dist/session.d.ts +85 -0
- package/mcp-server/dist/session.js +152 -0
- package/mcp-server/mcp-app.html +28 -0
- package/mcp-server/mcp-config.example.json +19 -0
- package/mcp-server/package-lock.json +4027 -0
- package/mcp-server/package.json +31 -0
- package/mcp-server/src/codegen.ts +189 -0
- package/mcp-server/src/mcp-app.css +360 -0
- package/mcp-server/src/mcp-app.ts +547 -0
- package/mcp-server/src/provision-types.ts +209 -0
- package/mcp-server/src/server.ts +2391 -0
- package/mcp-server/src/session.ts +194 -0
- package/mcp-server/tsconfig.json +16 -0
- package/mcp-server/vite.config.ts +23 -0
- package/package.json +158 -0
- package/schema.json +1046 -0
- package/scripts/generate-skills.js +94 -0
- package/sdk-log-formatter.js +1157 -0
- package/sdk.d.ts +1486 -0
- package/sdk.js +4336 -0
- package/setup/aws/cloudformation.yaml +463 -0
- package/setup/aws/disable-defender.sh +42 -0
- package/setup/aws/install-dev-runner.sh +79 -0
- package/setup/aws/spawn-runner.sh +289 -0
- package/test/captcha-solver.test.mjs +152 -0
- package/test/chrome-remote-debugging.test.mjs +66 -0
- package/test/duckduckgo/experiment.test.mjs +28 -0
- package/test/duckduckgo/setup.test.mjs +29 -0
- package/test/manual/debug-locate-response.js +82 -0
- package/test/manual/reconnect-provision.test.mjs +49 -0
- package/test/manual/test-console-logs.test.mjs +42 -0
- package/test/manual/test-find-api.js +73 -0
- package/test/manual/test-init.sh +54 -0
- package/test/manual/test-prompt-cache.js +97 -0
- package/test/manual/test-provision-auth.mjs +22 -0
- package/test/manual/test-sandbox-render.js +29 -0
- package/test/manual/test-sdk-methods.js +15 -0
- package/test/manual/test-sdk-refactor.js +53 -0
- package/test/manual/test-stack-trace.mjs +57 -0
- package/test/manual/verify-element-api.js +89 -0
- package/test/manual/verify-types.js +0 -0
- package/test/manual-unawaited-promise.test.mjs +31 -0
- package/vitest.config.mjs +58 -0
- package/vitest.runner.config.mjs +33 -0
- package/vscode-extension/.vscodeignore +12 -0
- package/vscode-extension/README.md +94 -0
- package/vscode-extension/media/icon.png +0 -0
- package/vscode-extension/package-lock.json +4126 -0
- package/vscode-extension/package.json +86 -0
- package/vscode-extension/src/extension.ts +829 -0
- package/vscode-extension/testdriverai-0.1.0.vsix +0 -0
- package/vscode-extension/tsconfig.json +16 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "parse()"
|
|
3
|
+
sidebarTitle: "parse"
|
|
4
|
+
description: "Detect all UI elements on screen using OmniParser"
|
|
5
|
+
icon: "diagram-project"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Parse the current screen using OmniParser v2 to detect all visible UI elements. Returns structured data including element types, text content, interactivity levels, and bounding box coordinates.
|
|
11
|
+
|
|
12
|
+
This method analyzes the entire screen and returns every detected element. It's useful for:
|
|
13
|
+
- Understanding the full UI layout of a screen
|
|
14
|
+
- Finding all clickable or interactive elements
|
|
15
|
+
- Building custom element-based logic
|
|
16
|
+
- Debugging what elements TestDriver can detect
|
|
17
|
+
- Accessibility auditing
|
|
18
|
+
|
|
19
|
+
<Note>
|
|
20
|
+
**Availability**: `parse()` requires an enterprise or self-hosted plan. It uses OmniParser v2 server-side for element detection.
|
|
21
|
+
</Note>
|
|
22
|
+
|
|
23
|
+
## Syntax
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
const result = await testdriver.parse()
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Parameters
|
|
30
|
+
|
|
31
|
+
None.
|
|
32
|
+
|
|
33
|
+
## Returns
|
|
34
|
+
|
|
35
|
+
`Promise<ParseResult>` - Object containing detected UI elements
|
|
36
|
+
|
|
37
|
+
### ParseResult
|
|
38
|
+
|
|
39
|
+
| Property | Type | Description |
|
|
40
|
+
|----------|------|-------------|
|
|
41
|
+
| `elements` | `ParsedElement[]` | Array of detected UI elements |
|
|
42
|
+
| `annotatedImageUrl` | `string` | URL of the annotated screenshot with bounding boxes |
|
|
43
|
+
| `imageWidth` | `number` | Width of the analyzed screenshot |
|
|
44
|
+
| `imageHeight` | `number` | Height of the analyzed screenshot |
|
|
45
|
+
|
|
46
|
+
### ParsedElement
|
|
47
|
+
|
|
48
|
+
| Property | Type | Description |
|
|
49
|
+
|----------|------|-------------|
|
|
50
|
+
| `index` | `number` | Element index |
|
|
51
|
+
| `type` | `string` | Element type (e.g. `"text"`, `"icon"`, `"button"`) |
|
|
52
|
+
| `content` | `string` | Text content or description of the element |
|
|
53
|
+
| `interactivity` | `string` | Interactivity level (e.g. `"clickable"`, `"non-interactive"`) |
|
|
54
|
+
| `bbox` | `object` | Bounding box in pixel coordinates `{x0, y0, x1, y1}` |
|
|
55
|
+
| `boundingBox` | `object` | Bounding box as `{left, top, width, height}` |
|
|
56
|
+
|
|
57
|
+
## Examples
|
|
58
|
+
|
|
59
|
+
### Get All Elements on Screen
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
const result = await testdriver.parse();
|
|
63
|
+
console.log(`Found ${result.elements.length} elements`);
|
|
64
|
+
|
|
65
|
+
result.elements.forEach((el, i) => {
|
|
66
|
+
console.log(`${i + 1}. [${el.type}] "${el.content}" (${el.interactivity})`);
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Find Clickable Elements
|
|
71
|
+
|
|
72
|
+
```javascript
|
|
73
|
+
const result = await testdriver.parse();
|
|
74
|
+
|
|
75
|
+
const clickable = result.elements.filter(e => e.interactivity === 'clickable');
|
|
76
|
+
console.log(`Found ${clickable.length} clickable elements`);
|
|
77
|
+
|
|
78
|
+
clickable.forEach(el => {
|
|
79
|
+
console.log(`- "${el.content}" at (${el.bbox.x0}, ${el.bbox.y0})`);
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Find and Click an Element by Content
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
const result = await testdriver.parse();
|
|
87
|
+
|
|
88
|
+
// Find a "Submit" button
|
|
89
|
+
const submitBtn = result.elements.find(e =>
|
|
90
|
+
e.content.toLowerCase().includes('submit') && e.interactivity === 'clickable'
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
if (submitBtn) {
|
|
94
|
+
// Calculate center of the bounding box
|
|
95
|
+
const x = Math.round((submitBtn.bbox.x0 + submitBtn.bbox.x1) / 2);
|
|
96
|
+
const y = Math.round((submitBtn.bbox.y0 + submitBtn.bbox.y1) / 2);
|
|
97
|
+
|
|
98
|
+
await testdriver.click({ x, y });
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Filter by Element Type
|
|
103
|
+
|
|
104
|
+
```javascript
|
|
105
|
+
const result = await testdriver.parse();
|
|
106
|
+
|
|
107
|
+
// Get all text elements
|
|
108
|
+
const textElements = result.elements.filter(e => e.type === 'text');
|
|
109
|
+
textElements.forEach(e => console.log(`Text: "${e.content}"`));
|
|
110
|
+
|
|
111
|
+
// Get all icons
|
|
112
|
+
const icons = result.elements.filter(e => e.type === 'icon');
|
|
113
|
+
console.log(`Found ${icons.length} icons`);
|
|
114
|
+
|
|
115
|
+
// Get all buttons
|
|
116
|
+
const buttons = result.elements.filter(e => e.type === 'button');
|
|
117
|
+
console.log(`Found ${buttons.length} buttons`);
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Build Custom Assertions
|
|
121
|
+
|
|
122
|
+
```javascript
|
|
123
|
+
import { describe, expect, it } from "vitest";
|
|
124
|
+
import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
|
|
125
|
+
|
|
126
|
+
describe("Login Page", () => {
|
|
127
|
+
it("should have expected form elements", async (context) => {
|
|
128
|
+
const testdriver = TestDriver(context);
|
|
129
|
+
|
|
130
|
+
await testdriver.provision.chrome({
|
|
131
|
+
url: 'https://myapp.com/login',
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const result = await testdriver.parse();
|
|
135
|
+
|
|
136
|
+
// Assert expected elements exist
|
|
137
|
+
const textContent = result.elements.map(e => e.content.toLowerCase());
|
|
138
|
+
expect(textContent).toContain('email');
|
|
139
|
+
expect(textContent).toContain('password');
|
|
140
|
+
|
|
141
|
+
// Assert there are clickable elements
|
|
142
|
+
const clickable = result.elements.filter(e => e.interactivity === 'clickable');
|
|
143
|
+
expect(clickable.length).toBeGreaterThan(0);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Use Bounding Box Coordinates
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
const result = await testdriver.parse();
|
|
152
|
+
|
|
153
|
+
result.elements.forEach(el => {
|
|
154
|
+
// Pixel coordinates
|
|
155
|
+
console.log(`Element "${el.content}":`);
|
|
156
|
+
console.log(` bbox: (${el.bbox.x0}, ${el.bbox.y0}) to (${el.bbox.x1}, ${el.bbox.y1})`);
|
|
157
|
+
console.log(` size: ${el.boundingBox.width}x${el.boundingBox.height}`);
|
|
158
|
+
console.log(` position: left=${el.boundingBox.left}, top=${el.boundingBox.top}`);
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### View Annotated Screenshot
|
|
163
|
+
|
|
164
|
+
```javascript
|
|
165
|
+
const result = await testdriver.parse();
|
|
166
|
+
|
|
167
|
+
// The annotated image shows all detected elements with bounding boxes
|
|
168
|
+
console.log('Annotated screenshot:', result.annotatedImageUrl);
|
|
169
|
+
console.log(`Image dimensions: ${result.imageWidth}x${result.imageHeight}`);
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## How It Works
|
|
173
|
+
|
|
174
|
+
1. TestDriver captures a screenshot of the current screen
|
|
175
|
+
2. The image is sent to the TestDriver API
|
|
176
|
+
3. OmniParser v2 analyzes the image to detect all UI elements
|
|
177
|
+
4. Each element is classified by type (text, icon, button, etc.) and interactivity
|
|
178
|
+
5. Bounding box coordinates are returned in pixel coordinates matching the screen resolution
|
|
179
|
+
|
|
180
|
+
<Note>
|
|
181
|
+
OmniParser detects elements visually — it works with any UI framework, native apps, and even non-standard interfaces. It does not rely on DOM or accessibility trees.
|
|
182
|
+
</Note>
|
|
183
|
+
|
|
184
|
+
## Best Practices
|
|
185
|
+
|
|
186
|
+
<AccordionGroup>
|
|
187
|
+
<Accordion title="Use find() for targeting specific elements">
|
|
188
|
+
For locating and interacting with a specific element, prefer `find()` which uses AI vision. Use `parse()` when you need a complete inventory of all elements on screen.
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
// Prefer this for clicking a specific element
|
|
192
|
+
await testdriver.find("Submit button").click();
|
|
193
|
+
|
|
194
|
+
// Use parse() for full UI analysis
|
|
195
|
+
const result = await testdriver.parse();
|
|
196
|
+
const allButtons = result.elements.filter(e => e.type === 'button');
|
|
197
|
+
```
|
|
198
|
+
</Accordion>
|
|
199
|
+
|
|
200
|
+
<Accordion title="Filter by interactivity">
|
|
201
|
+
Use the `interactivity` field to distinguish between clickable and non-interactive elements.
|
|
202
|
+
|
|
203
|
+
```javascript
|
|
204
|
+
const result = await testdriver.parse();
|
|
205
|
+
const interactive = result.elements.filter(e => e.interactivity === 'clickable');
|
|
206
|
+
const static_ = result.elements.filter(e => e.interactivity === 'non-interactive');
|
|
207
|
+
```
|
|
208
|
+
</Accordion>
|
|
209
|
+
|
|
210
|
+
<Accordion title="Wait for content to load">
|
|
211
|
+
If elements aren't being detected, the page may not be fully loaded. Add a wait first.
|
|
212
|
+
|
|
213
|
+
```javascript
|
|
214
|
+
// Wait for page to stabilize
|
|
215
|
+
await testdriver.wait(2000);
|
|
216
|
+
|
|
217
|
+
// Then parse
|
|
218
|
+
const result = await testdriver.parse();
|
|
219
|
+
```
|
|
220
|
+
</Accordion>
|
|
221
|
+
|
|
222
|
+
<Accordion title="Use the annotated image for debugging">
|
|
223
|
+
The `annotatedImageUrl` provides a visual overlay showing all detected elements with their bounding boxes — great for debugging.
|
|
224
|
+
|
|
225
|
+
```javascript
|
|
226
|
+
const result = await testdriver.parse();
|
|
227
|
+
console.log('View annotated screenshot:', result.annotatedImageUrl);
|
|
228
|
+
```
|
|
229
|
+
</Accordion>
|
|
230
|
+
</AccordionGroup>
|
|
231
|
+
|
|
232
|
+
## Related
|
|
233
|
+
|
|
234
|
+
- [find()](/v7/find) - AI-powered element location
|
|
235
|
+
- [assert()](/v7/assert) - Make AI-powered assertions about screen state
|
|
236
|
+
- [screenshot()](/v7/screenshot) - Capture screenshots
|
|
237
|
+
- [Elements Reference](/v7/elements) - Complete Element API
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Performing Actions"
|
|
3
|
+
description: "Click, type, hover, scroll and more with TestDriver"
|
|
4
|
+
icon: "computer-mouse"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Performing Actions
|
|
8
|
+
|
|
9
|
+
TestDriver provides a variety of actions you can perform, like [clicking](/v7/click), [typing](/v7/type), [hovering](/v7/hover), and [scrolling](/v7/scroll). For a full list, see the [API Reference](/v7/click).
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
// Clicking
|
|
13
|
+
await testdriver.find('submit button').click();
|
|
14
|
+
await testdriver.find('file item').doubleClick();
|
|
15
|
+
await testdriver.find('text area').rightClick();
|
|
16
|
+
|
|
17
|
+
// Typing
|
|
18
|
+
await testdriver.find('email input').type('user@example.com');
|
|
19
|
+
await testdriver.find('password input').type('secret', { secret: true });
|
|
20
|
+
|
|
21
|
+
// Keyboard shortcuts
|
|
22
|
+
await testdriver.pressKeys(['enter']);
|
|
23
|
+
await testdriver.pressKeys(['ctrl', 'c']);
|
|
24
|
+
|
|
25
|
+
// Hovering
|
|
26
|
+
await testdriver.find('dropdown menu').hover();
|
|
27
|
+
|
|
28
|
+
// Scrolling
|
|
29
|
+
await testdriver.scroll('down', 500);
|
|
30
|
+
await testdriver.scrollUntilText('Footer content');
|
|
31
|
+
|
|
32
|
+
// Waiting
|
|
33
|
+
await testdriver.wait(2000); // Wait 2 seconds for animation/state change
|
|
34
|
+
|
|
35
|
+
// Extracting information from screen
|
|
36
|
+
const price = await testdriver.extract('the total price');
|
|
37
|
+
const orderNumber = await testdriver.extract('the order confirmation number');
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Chaining Actions
|
|
41
|
+
|
|
42
|
+
TestDriver supports method chaining for cleaner code:
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
// Chain find() with actions
|
|
46
|
+
const button = await testdriver.find('submit button').click();
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Or save element reference for later use:
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
const button = await testdriver.find('submit button');
|
|
53
|
+
await button.click();
|
|
54
|
+
```
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "pressKeys()"
|
|
3
|
+
sidebarTitle: "pressKeys"
|
|
4
|
+
description: "Press keyboard keys and shortcuts"
|
|
5
|
+
icon: "keyboard"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Press one or more keyboard keys simultaneously, useful for keyboard shortcuts, navigation, and special keys.
|
|
11
|
+
|
|
12
|
+
## Syntax
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
await testdriver.pressKeys(keys)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Parameters
|
|
19
|
+
|
|
20
|
+
<ParamField path="keys" type="Array<string>" required>
|
|
21
|
+
Array of keys to press simultaneously
|
|
22
|
+
</ParamField>
|
|
23
|
+
|
|
24
|
+
## Returns
|
|
25
|
+
|
|
26
|
+
`Promise<void>`
|
|
27
|
+
|
|
28
|
+
## Common Keys
|
|
29
|
+
|
|
30
|
+
### Special Keys
|
|
31
|
+
- `'enter'`, `'tab'`, `'escape'`, `'backspace'`, `'delete'`
|
|
32
|
+
- `'space'`, `'up'`, `'down'`, `'left'`, `'right'`
|
|
33
|
+
- `'home'`, `'end'`, `'pageup'`, `'pagedown'`
|
|
34
|
+
|
|
35
|
+
### Modifier Keys
|
|
36
|
+
- `'ctrl'`, `'alt'`, `'shift'`
|
|
37
|
+
- `'command'` (macOS), `'win'` (Windows)
|
|
38
|
+
- `'ctrlleft'`, `'ctrlright'`, `'shiftleft'`, `'shiftright'`
|
|
39
|
+
|
|
40
|
+
### Function Keys
|
|
41
|
+
- `'f1'` through `'f24'`
|
|
42
|
+
|
|
43
|
+
## Examples
|
|
44
|
+
|
|
45
|
+
### Navigation
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
// Tab to next field
|
|
49
|
+
await testdriver.pressKeys(['tab']);
|
|
50
|
+
|
|
51
|
+
// Shift+Tab to previous field
|
|
52
|
+
await testdriver.pressKeys(['shift', 'tab']);
|
|
53
|
+
|
|
54
|
+
// Arrow keys
|
|
55
|
+
await testdriver.pressKeys(['down']);
|
|
56
|
+
await testdriver.pressKeys(['up']);
|
|
57
|
+
await testdriver.pressKeys(['left']);
|
|
58
|
+
await testdriver.pressKeys(['right']);
|
|
59
|
+
|
|
60
|
+
// Home/End
|
|
61
|
+
await testdriver.pressKeys(['home']); // Start of line
|
|
62
|
+
await testdriver.pressKeys(['end']); // End of line
|
|
63
|
+
|
|
64
|
+
// Page navigation
|
|
65
|
+
await testdriver.pressKeys(['pagedown']);
|
|
66
|
+
await testdriver.pressKeys(['pageup']);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Keyboard Shortcuts
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
// Copy (Ctrl+C / Cmd+C)
|
|
73
|
+
await testdriver.pressKeys(['ctrl', 'c']);
|
|
74
|
+
|
|
75
|
+
// Paste (Ctrl+V / Cmd+V)
|
|
76
|
+
await testdriver.pressKeys(['ctrl', 'v']);
|
|
77
|
+
|
|
78
|
+
// Save (Ctrl+S)
|
|
79
|
+
await testdriver.pressKeys(['ctrl', 's']);
|
|
80
|
+
|
|
81
|
+
// Select All (Ctrl+A)
|
|
82
|
+
await testdriver.pressKeys(['ctrl', 'a']);
|
|
83
|
+
|
|
84
|
+
// Undo (Ctrl+Z)
|
|
85
|
+
await testdriver.pressKeys(['ctrl', 'z']);
|
|
86
|
+
|
|
87
|
+
// Redo (Ctrl+Y)
|
|
88
|
+
await testdriver.pressKeys(['ctrl', 'y']);
|
|
89
|
+
|
|
90
|
+
// Find (Ctrl+F)
|
|
91
|
+
await testdriver.pressKeys(['ctrl', 'f']);
|
|
92
|
+
|
|
93
|
+
// New tab (Ctrl+T)
|
|
94
|
+
await testdriver.pressKeys(['ctrl', 't']);
|
|
95
|
+
|
|
96
|
+
// Close tab (Ctrl+W)
|
|
97
|
+
await testdriver.pressKeys(['ctrl', 'w']);
|
|
98
|
+
|
|
99
|
+
// Refresh (F5 or Ctrl+R)
|
|
100
|
+
await testdriver.pressKeys(['f5']);
|
|
101
|
+
await testdriver.pressKeys(['ctrl', 'r']);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### System Shortcuts
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
// Alt+Tab (Windows - switch apps)
|
|
108
|
+
await testdriver.pressKeys(['alt', 'tab']);
|
|
109
|
+
|
|
110
|
+
// Alt+F4 (Windows - close window)
|
|
111
|
+
await testdriver.pressKeys(['alt', 'f4']);
|
|
112
|
+
|
|
113
|
+
// Win+D (Windows - show desktop)
|
|
114
|
+
await testdriver.pressKeys(['winleft', 'd']);
|
|
115
|
+
|
|
116
|
+
// Win+L (Windows - lock screen)
|
|
117
|
+
await testdriver.pressKeys(['winleft', 'l']);
|
|
118
|
+
|
|
119
|
+
// Cmd+Tab (macOS - switch apps)
|
|
120
|
+
await testdriver.pressKeys(['command', 'tab']);
|
|
121
|
+
|
|
122
|
+
// Cmd+Q (macOS - quit app)
|
|
123
|
+
await testdriver.pressKeys(['command', 'q']);
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Form Submission
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
// Submit form
|
|
130
|
+
await testdriver.pressKeys(['enter']);
|
|
131
|
+
|
|
132
|
+
// Cancel/Close
|
|
133
|
+
await testdriver.pressKeys(['escape']);
|
|
134
|
+
|
|
135
|
+
// Check checkbox
|
|
136
|
+
await testdriver.pressKeys(['space']);
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Text Editing
|
|
140
|
+
|
|
141
|
+
```javascript
|
|
142
|
+
// Delete selected text
|
|
143
|
+
await testdriver.pressKeys(['delete']);
|
|
144
|
+
|
|
145
|
+
// Backspace
|
|
146
|
+
await testdriver.pressKeys(['backspace']);
|
|
147
|
+
|
|
148
|
+
// Select all and delete
|
|
149
|
+
await testdriver.pressKeys(['ctrl', 'a']);
|
|
150
|
+
await testdriver.pressKeys(['delete']);
|
|
151
|
+
|
|
152
|
+
// Cut text
|
|
153
|
+
await testdriver.pressKeys(['ctrl', 'x']);
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Best Practices
|
|
157
|
+
|
|
158
|
+
<Check>
|
|
159
|
+
**Wait after shortcuts**
|
|
160
|
+
|
|
161
|
+
Some keyboard shortcuts trigger animations or navigation:
|
|
162
|
+
|
|
163
|
+
```javascript
|
|
164
|
+
await testdriver.pressKeys(['ctrl', 't']); // New tab
|
|
165
|
+
await new Promise(r => setTimeout(r, 500)); // Wait for tab
|
|
166
|
+
await testdriver.pressKeys(['ctrl', 'l']); // Focus URL bar
|
|
167
|
+
```
|
|
168
|
+
</Check>
|
|
169
|
+
|
|
170
|
+
<Check>
|
|
171
|
+
**Use Tab for form navigation**
|
|
172
|
+
|
|
173
|
+
Tab is more reliable than clicking multiple fields:
|
|
174
|
+
|
|
175
|
+
```javascript
|
|
176
|
+
const firstField = await testdriver.find('email input');
|
|
177
|
+
await firstField.click();
|
|
178
|
+
await testdriver.type('user@example.com');
|
|
179
|
+
|
|
180
|
+
await testdriver.pressKeys(['tab']);
|
|
181
|
+
await testdriver.type('password123');
|
|
182
|
+
|
|
183
|
+
await testdriver.pressKeys(['tab']);
|
|
184
|
+
await testdriver.pressKeys(['enter']); // Submit
|
|
185
|
+
```
|
|
186
|
+
</Check>
|
|
187
|
+
|
|
188
|
+
<Warning>
|
|
189
|
+
**Platform-specific keys**
|
|
190
|
+
|
|
191
|
+
Use the appropriate modifier key for the platform:
|
|
192
|
+
- Windows/Linux: `'ctrl'`
|
|
193
|
+
- macOS: `'command'`
|
|
194
|
+
|
|
195
|
+
```javascript
|
|
196
|
+
// For cross-platform, you might need to detect OS
|
|
197
|
+
const modKey = process.platform === 'darwin' ? 'command' : 'ctrl';
|
|
198
|
+
await testdriver.pressKeys([modKey, 'c']); // Copy
|
|
199
|
+
```
|
|
200
|
+
</Warning>
|
|
201
|
+
|
|
202
|
+
## Use Cases
|
|
203
|
+
|
|
204
|
+
<AccordionGroup>
|
|
205
|
+
<Accordion title="Form Navigation">
|
|
206
|
+
```javascript
|
|
207
|
+
// Fill form using Tab
|
|
208
|
+
const firstField = await testdriver.find('name field');
|
|
209
|
+
await firstField.click();
|
|
210
|
+
await testdriver.type('John Doe');
|
|
211
|
+
|
|
212
|
+
await testdriver.pressKeys(['tab']);
|
|
213
|
+
await testdriver.type('john@example.com');
|
|
214
|
+
|
|
215
|
+
await testdriver.pressKeys(['tab']);
|
|
216
|
+
await testdriver.type('555-0123');
|
|
217
|
+
|
|
218
|
+
await testdriver.pressKeys(['tab']);
|
|
219
|
+
await testdriver.pressKeys(['enter']); // Submit
|
|
220
|
+
```
|
|
221
|
+
</Accordion>
|
|
222
|
+
|
|
223
|
+
<Accordion title="Text Manipulation">
|
|
224
|
+
```javascript
|
|
225
|
+
const textArea = await testdriver.find('comment textarea');
|
|
226
|
+
await textArea.click();
|
|
227
|
+
|
|
228
|
+
// Select all existing text
|
|
229
|
+
await testdriver.pressKeys(['ctrl', 'a']);
|
|
230
|
+
|
|
231
|
+
// Copy it
|
|
232
|
+
await testdriver.pressKeys(['ctrl', 'c']);
|
|
233
|
+
|
|
234
|
+
// Type new text
|
|
235
|
+
await testdriver.type('New comment');
|
|
236
|
+
|
|
237
|
+
// Undo if needed
|
|
238
|
+
await testdriver.pressKeys(['ctrl', 'z']);
|
|
239
|
+
```
|
|
240
|
+
</Accordion>
|
|
241
|
+
|
|
242
|
+
<Accordion title="Browser Navigation">
|
|
243
|
+
```javascript
|
|
244
|
+
// Open new tab
|
|
245
|
+
await testdriver.pressKeys(['ctrl', 't']);
|
|
246
|
+
await new Promise(r => setTimeout(r, 500));
|
|
247
|
+
|
|
248
|
+
// Focus address bar
|
|
249
|
+
await testdriver.pressKeys(['ctrl', 'l']);
|
|
250
|
+
await testdriver.type('https://example.com');
|
|
251
|
+
await testdriver.pressKeys(['enter']);
|
|
252
|
+
|
|
253
|
+
// Refresh page
|
|
254
|
+
await testdriver.pressKeys(['f5']);
|
|
255
|
+
|
|
256
|
+
// Close tab
|
|
257
|
+
await testdriver.pressKeys(['ctrl', 'w']);
|
|
258
|
+
```
|
|
259
|
+
</Accordion>
|
|
260
|
+
|
|
261
|
+
<Accordion title="Application Shortcuts">
|
|
262
|
+
```javascript
|
|
263
|
+
// Save document
|
|
264
|
+
await testdriver.pressKeys(['ctrl', 's']);
|
|
265
|
+
|
|
266
|
+
// Print
|
|
267
|
+
await testdriver.pressKeys(['ctrl', 'p']);
|
|
268
|
+
|
|
269
|
+
// Find in page
|
|
270
|
+
await testdriver.pressKeys(['ctrl', 'f']);
|
|
271
|
+
await testdriver.type('search term');
|
|
272
|
+
await testdriver.pressKeys(['escape']); // Close find
|
|
273
|
+
```
|
|
274
|
+
</Accordion>
|
|
275
|
+
</AccordionGroup>
|
|
276
|
+
|
|
277
|
+
## Complete Example
|
|
278
|
+
|
|
279
|
+
```javascript
|
|
280
|
+
import { beforeAll, afterAll, describe, it } from 'vitest';
|
|
281
|
+
import TestDriver from 'testdriverai';
|
|
282
|
+
|
|
283
|
+
describe('Keyboard Navigation', () => {
|
|
284
|
+
let testdriver;
|
|
285
|
+
|
|
286
|
+
beforeAll(async () => {
|
|
287
|
+
client = new TestDriver(process.env.TD_API_KEY);
|
|
288
|
+
await testdriver.auth();
|
|
289
|
+
await testdriver.connect();
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
afterAll(async () => {
|
|
293
|
+
await testdriver.disconnect();
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('should navigate form with keyboard', async () => {
|
|
297
|
+
await testdriver.focusApplication('Google Chrome');
|
|
298
|
+
|
|
299
|
+
// Find first field
|
|
300
|
+
const emailField = await testdriver.find('email input');
|
|
301
|
+
await emailField.click();
|
|
302
|
+
await testdriver.type('user@example.com');
|
|
303
|
+
|
|
304
|
+
// Tab through fields
|
|
305
|
+
await testdriver.pressKeys(['tab']);
|
|
306
|
+
await testdriver.type('John');
|
|
307
|
+
|
|
308
|
+
await testdriver.pressKeys(['tab']);
|
|
309
|
+
await testdriver.type('Doe');
|
|
310
|
+
|
|
311
|
+
await testdriver.pressKeys(['tab']);
|
|
312
|
+
await testdriver.type('password123');
|
|
313
|
+
|
|
314
|
+
// Submit with Enter
|
|
315
|
+
await testdriver.pressKeys(['tab']);
|
|
316
|
+
await testdriver.pressKeys(['enter']);
|
|
317
|
+
|
|
318
|
+
await testdriver.assert('form submitted successfully');
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it('should use keyboard shortcuts', async () => {
|
|
322
|
+
// Open new browser tab
|
|
323
|
+
await testdriver.pressKeys(['ctrl', 't']);
|
|
324
|
+
await new Promise(r => setTimeout(r, 500));
|
|
325
|
+
|
|
326
|
+
// Focus address bar
|
|
327
|
+
await testdriver.pressKeys(['ctrl', 'l']);
|
|
328
|
+
await testdriver.type('https://example.com');
|
|
329
|
+
await testdriver.pressKeys(['enter']);
|
|
330
|
+
|
|
331
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
332
|
+
|
|
333
|
+
// Select all page content
|
|
334
|
+
await testdriver.pressKeys(['ctrl', 'a']);
|
|
335
|
+
|
|
336
|
+
// Copy
|
|
337
|
+
await testdriver.pressKeys(['ctrl', 'c']);
|
|
338
|
+
|
|
339
|
+
// Refresh page
|
|
340
|
+
await testdriver.pressKeys(['f5']);
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## Related Methods
|
|
346
|
+
|
|
347
|
+
- [`type()`](/v7/type) - Type text
|
|
348
|
+
- [`click()`](/v7/click) - Click elements
|
|
349
|
+
- [`scroll()`](/v7/scroll) - Scroll pages
|