@testdriverai/agent 7.8.0-test.38
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,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vitest Setup File for AWS Self-Hosted TestDriver Instances
|
|
3
|
+
*
|
|
4
|
+
* This setup file spawns a fresh AWS instance before each test
|
|
5
|
+
* and terminates it after each test completes.
|
|
6
|
+
*
|
|
7
|
+
* Usage in vitest.config.mjs:
|
|
8
|
+
* ```js
|
|
9
|
+
* export default defineConfig({
|
|
10
|
+
* test: {
|
|
11
|
+
* setupFiles: [
|
|
12
|
+
* 'testdriverai/vitest/setup',
|
|
13
|
+
* 'testdriverai/vitest/setup-aws'
|
|
14
|
+
* ],
|
|
15
|
+
* },
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* Required environment variables:
|
|
20
|
+
* - AWS_ACCESS_KEY_ID
|
|
21
|
+
* - AWS_SECRET_ACCESS_KEY
|
|
22
|
+
* - AWS_REGION (default: us-east-2)
|
|
23
|
+
* - AWS_LAUNCH_TEMPLATE_ID
|
|
24
|
+
* - AMI_ID
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { execSync, spawn } from "child_process";
|
|
28
|
+
import { dirname, join } from "path";
|
|
29
|
+
import { fileURLToPath } from "url";
|
|
30
|
+
import { beforeEach } from "vitest";
|
|
31
|
+
|
|
32
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
33
|
+
const __dirname = dirname(__filename);
|
|
34
|
+
|
|
35
|
+
// Store instance info per test
|
|
36
|
+
const testInstances = new Map();
|
|
37
|
+
|
|
38
|
+
// Global object to share instance termination callbacks with hooks.mjs
|
|
39
|
+
globalThis.__testdriverAWS = globalThis.__testdriverAWS || {
|
|
40
|
+
instances: testInstances,
|
|
41
|
+
/**
|
|
42
|
+
* Terminate the instance for a given test ID
|
|
43
|
+
* Called by hooks.mjs after dashcam.stop() completes
|
|
44
|
+
*/
|
|
45
|
+
async terminateInstance(testId) {
|
|
46
|
+
const instanceInfo = testInstances.get(testId);
|
|
47
|
+
if (!instanceInfo) {
|
|
48
|
+
return; // No instance was spawned for this test
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const { instanceId, awsRegion } = instanceInfo;
|
|
52
|
+
|
|
53
|
+
console.log(`[TestDriver] Terminating AWS instance: ${instanceId}`);
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
execSync(
|
|
57
|
+
`aws ec2 terminate-instances --region "${awsRegion}" --instance-ids "${instanceId}"`,
|
|
58
|
+
{
|
|
59
|
+
encoding: "utf-8",
|
|
60
|
+
env: process.env,
|
|
61
|
+
stdio: "inherit",
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
console.log(`[TestDriver] Instance terminated: ${instanceId}`);
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error(
|
|
68
|
+
"[TestDriver] Failed to terminate instance:",
|
|
69
|
+
error.message,
|
|
70
|
+
);
|
|
71
|
+
// Don't throw - we don't want to fail the test because of cleanup issues
|
|
72
|
+
} finally {
|
|
73
|
+
testInstances.delete(testId);
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Cleanup function to terminate all running instances
|
|
80
|
+
* Called on process exit to ensure no orphaned instances
|
|
81
|
+
*/
|
|
82
|
+
function cleanupAllInstances() {
|
|
83
|
+
if (testInstances.size === 0) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log(
|
|
88
|
+
`[TestDriver] Emergency cleanup: terminating ${testInstances.size} instance(s)`,
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
for (const [testId, instanceInfo] of testInstances.entries()) {
|
|
92
|
+
const { instanceId, awsRegion } = instanceInfo;
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
console.log(`[TestDriver] Terminating instance: ${instanceId}`);
|
|
96
|
+
execSync(
|
|
97
|
+
`aws ec2 terminate-instances --region "${awsRegion}" --instance-ids "${instanceId}"`,
|
|
98
|
+
{
|
|
99
|
+
encoding: "utf-8",
|
|
100
|
+
stdio: "inherit",
|
|
101
|
+
},
|
|
102
|
+
);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error(
|
|
105
|
+
`[TestDriver] Failed to terminate instance ${instanceId}:`,
|
|
106
|
+
error.message,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
testInstances.clear();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Register cleanup handlers for various exit scenarios
|
|
115
|
+
process.on("exit", cleanupAllInstances);
|
|
116
|
+
process.on("SIGINT", () => {
|
|
117
|
+
cleanupAllInstances();
|
|
118
|
+
// Don't call process.exit here - let the signal handler do its job
|
|
119
|
+
});
|
|
120
|
+
process.on("SIGTERM", () => {
|
|
121
|
+
cleanupAllInstances();
|
|
122
|
+
// Don't call process.exit here - let the signal handler do its job
|
|
123
|
+
});
|
|
124
|
+
process.on("uncaughtException", (error) => {
|
|
125
|
+
console.error("[TestDriver] Uncaught exception:", error);
|
|
126
|
+
cleanupAllInstances();
|
|
127
|
+
// Don't call process.exit here - let Node.js handle the exception
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
beforeEach(async (context) => {
|
|
131
|
+
// Only spawn if TD_OS=windows (indicates Windows self-hosted mode)
|
|
132
|
+
if (process.env.TD_OS !== "windows") {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// If TD_IP is already set, use it and skip spawning
|
|
137
|
+
if (process.env.TD_IP) {
|
|
138
|
+
console.log(`[TestDriver] Using existing instance at ${process.env.TD_IP}`);
|
|
139
|
+
context.ip = process.env.TD_IP;
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// If ip is provided via plugin options, skip spawning
|
|
144
|
+
const pluginIp = globalThis.__testdriverPlugin?.state?.testDriverOptions?.ip;
|
|
145
|
+
if (pluginIp) {
|
|
146
|
+
console.log(`[TestDriver] Using ip from plugin options: ${pluginIp}`);
|
|
147
|
+
context.ip = pluginIp;
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!process.env.AWS_LAUNCH_TEMPLATE_ID || !process.env.AMI_ID) {
|
|
152
|
+
throw new Error(
|
|
153
|
+
"[TestDriver] TD_OS=windows requires AWS_LAUNCH_TEMPLATE_ID and AMI_ID environment variables",
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Check if AWS CLI is installed
|
|
158
|
+
try {
|
|
159
|
+
execSync("which aws", { stdio: "ignore" });
|
|
160
|
+
} catch (error) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
"[TestDriver] AWS CLI is not installed. Install it from https://aws.amazon.com/cli/",
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const testId = context.task.id;
|
|
167
|
+
|
|
168
|
+
console.log(
|
|
169
|
+
`[TestDriver] Spawning AWS instance for test: ${context.task.name}`,
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
// Find the spawn-runner.sh script (relative to this file)
|
|
174
|
+
const spawnScriptPath = join(__dirname, "../../setup/aws/spawn-runner.sh");
|
|
175
|
+
|
|
176
|
+
// Execute spawn-runner.sh with live output streaming
|
|
177
|
+
const output = await new Promise((resolve, reject) => {
|
|
178
|
+
const child = spawn("bash", [spawnScriptPath], {
|
|
179
|
+
env: {
|
|
180
|
+
...process.env,
|
|
181
|
+
AWS_REGION: process.env.AWS_REGION || "us-east-2",
|
|
182
|
+
RESOLUTION: process.env.RESOLUTION || "1920x1080",
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
let stdout = "";
|
|
187
|
+
let stderr = "";
|
|
188
|
+
|
|
189
|
+
// Stream stdout in real-time
|
|
190
|
+
child.stdout.on("data", (data) => {
|
|
191
|
+
const str = data.toString();
|
|
192
|
+
process.stdout.write(str); // Show output immediately
|
|
193
|
+
stdout += str;
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// Stream stderr in real-time
|
|
197
|
+
child.stderr.on("data", (data) => {
|
|
198
|
+
const str = data.toString();
|
|
199
|
+
process.stderr.write(str); // Show errors immediately
|
|
200
|
+
stderr += str;
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
child.on("close", (code) => {
|
|
204
|
+
if (code !== 0) {
|
|
205
|
+
reject(
|
|
206
|
+
new Error(`spawn-runner.sh exited with code ${code}\n${stderr}`),
|
|
207
|
+
);
|
|
208
|
+
} else {
|
|
209
|
+
resolve(stdout);
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
child.on("error", (err) => {
|
|
214
|
+
reject(err);
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// Parse the output
|
|
219
|
+
const publicIpMatch = output.match(/PUBLIC_IP=(.+)/);
|
|
220
|
+
const instanceIdMatch = output.match(/INSTANCE_ID=(.+)/);
|
|
221
|
+
const awsRegionMatch = output.match(/AWS_REGION=(.+)/);
|
|
222
|
+
|
|
223
|
+
if (!publicIpMatch || !instanceIdMatch || !awsRegionMatch) {
|
|
224
|
+
throw new Error("Failed to parse spawn-runner.sh output");
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const publicIp = publicIpMatch[1].trim();
|
|
228
|
+
const instanceId = instanceIdMatch[1].trim();
|
|
229
|
+
const awsRegion = awsRegionMatch[1].trim();
|
|
230
|
+
|
|
231
|
+
// Store instance info for this test
|
|
232
|
+
testInstances.set(testId, { publicIp, instanceId, awsRegion });
|
|
233
|
+
|
|
234
|
+
// Set IP on test context (not process.env to avoid conflicts in parallel tests)
|
|
235
|
+
context.ip = publicIp;
|
|
236
|
+
context.instanceId = instanceId;
|
|
237
|
+
|
|
238
|
+
console.log(`[TestDriver] Instance spawned: ${instanceId} at ${publicIp}`);
|
|
239
|
+
} catch (error) {
|
|
240
|
+
console.error("[TestDriver] Failed to spawn AWS instance:", error.message);
|
|
241
|
+
throw error;
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// NOTE: No afterEach hook here!
|
|
246
|
+
// Instance termination is now handled by hooks.mjs AFTER dashcam.stop() completes.
|
|
247
|
+
// This ensures dashcam can properly stop before the instance is terminated.
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vitest Setup File for Self-Hosted TestDriver Instances
|
|
3
|
+
*
|
|
4
|
+
* This setup file spawns a fresh AWS instance before each test
|
|
5
|
+
* and terminates it after each test completes.
|
|
6
|
+
*
|
|
7
|
+
* Usage in vitest.config.mjs:
|
|
8
|
+
* ```js
|
|
9
|
+
* export default defineConfig({
|
|
10
|
+
* test: {
|
|
11
|
+
* setupFiles: [
|
|
12
|
+
* 'testdriverai/vitest/setup',
|
|
13
|
+
* 'testdriverai/vitest/setup-self-hosted'
|
|
14
|
+
* ],
|
|
15
|
+
* },
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* Required environment variables:
|
|
20
|
+
* - AWS_ACCESS_KEY_ID
|
|
21
|
+
* - AWS_SECRET_ACCESS_KEY
|
|
22
|
+
* - AWS_REGION (default: us-east-2)
|
|
23
|
+
* - AWS_LAUNCH_TEMPLATE_ID
|
|
24
|
+
* - AMI_ID
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { execSync } from 'child_process';
|
|
28
|
+
import { dirname, join } from 'path';
|
|
29
|
+
import { fileURLToPath } from 'url';
|
|
30
|
+
import { beforeEach } from 'vitest';
|
|
31
|
+
|
|
32
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
33
|
+
const __dirname = dirname(__filename);
|
|
34
|
+
|
|
35
|
+
// Store instance info per test
|
|
36
|
+
const testInstances = new Map();
|
|
37
|
+
|
|
38
|
+
// Global object to share instance termination callbacks with hooks.mjs
|
|
39
|
+
// Use the same global as setup-aws.mjs for consistency
|
|
40
|
+
if (!globalThis.__testdriverAWS) {
|
|
41
|
+
globalThis.__testdriverAWS = {
|
|
42
|
+
instances: testInstances,
|
|
43
|
+
/**
|
|
44
|
+
* Terminate the instance for a given test ID
|
|
45
|
+
* Called by hooks.mjs after dashcam.stop() completes
|
|
46
|
+
*/
|
|
47
|
+
async terminateInstance(testId) {
|
|
48
|
+
const instanceInfo = testInstances.get(testId);
|
|
49
|
+
if (!instanceInfo) {
|
|
50
|
+
return; // No instance was spawned for this test
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const { instanceId, awsRegion } = instanceInfo;
|
|
54
|
+
|
|
55
|
+
console.log(`[TestDriver] Terminating AWS instance: ${instanceId}`);
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
execSync(
|
|
59
|
+
`aws ec2 terminate-instances --region "${awsRegion}" --instance-ids "${instanceId}"`,
|
|
60
|
+
{
|
|
61
|
+
encoding: 'utf-8',
|
|
62
|
+
env: process.env,
|
|
63
|
+
stdio: 'inherit',
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
console.log(`[TestDriver] Instance terminated: ${instanceId}`);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error('[TestDriver] Failed to terminate instance:', error.message);
|
|
70
|
+
// Don't throw - we don't want to fail the test because of cleanup issues
|
|
71
|
+
} finally {
|
|
72
|
+
testInstances.delete(testId);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
beforeEach(async (context) => {
|
|
79
|
+
// Only spawn if TD_OS=windows (indicates Windows self-hosted mode)
|
|
80
|
+
if (process.env.TD_OS !== 'windows') {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// If TD_IP is already set, use it and skip spawning
|
|
85
|
+
if (process.env.TD_IP) {
|
|
86
|
+
console.log(`[TestDriver] Using existing instance at ${process.env.TD_IP}`);
|
|
87
|
+
context.ip = process.env.TD_IP;
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// If ip is provided via plugin options, skip spawning
|
|
92
|
+
const pluginIp = globalThis.__testdriverPlugin?.state?.testDriverOptions?.ip;
|
|
93
|
+
if (pluginIp) {
|
|
94
|
+
console.log(`[TestDriver] Using ip from plugin options: ${pluginIp}`);
|
|
95
|
+
context.ip = pluginIp;
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Verify AWS credentials are available
|
|
100
|
+
if (!process.env.AWS_ACCESS_KEY_ID || !process.env.AWS_LAUNCH_TEMPLATE_ID || !process.env.AMI_ID) {
|
|
101
|
+
throw new Error('[TestDriver] TD_OS=windows requires AWS credentials (AWS_ACCESS_KEY_ID, AWS_LAUNCH_TEMPLATE_ID, AMI_ID)');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const testId = context.task.id;
|
|
105
|
+
|
|
106
|
+
console.log(`[TestDriver] Spawning AWS instance for test: ${context.task.name}`);
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
// Find the spawn-runner.sh script (relative to this file)
|
|
110
|
+
const spawnScriptPath = join(__dirname, '../../setup/aws/spawn-runner.sh');
|
|
111
|
+
|
|
112
|
+
// Execute spawn-runner.sh
|
|
113
|
+
const output = execSync(`sh ${spawnScriptPath}`, {
|
|
114
|
+
encoding: 'utf-8',
|
|
115
|
+
env: {
|
|
116
|
+
...process.env,
|
|
117
|
+
AWS_REGION: process.env.AWS_REGION || 'us-east-2',
|
|
118
|
+
RESOLUTION: process.env.RESOLUTION || '1920x1080',
|
|
119
|
+
},
|
|
120
|
+
stdio: ['pipe', 'pipe', 'inherit'], // Inherit stderr for real-time logs
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Parse the output
|
|
124
|
+
const publicIpMatch = output.match(/PUBLIC_IP=(.+)/);
|
|
125
|
+
const instanceIdMatch = output.match(/INSTANCE_ID=(.+)/);
|
|
126
|
+
const awsRegionMatch = output.match(/AWS_REGION=(.+)/);
|
|
127
|
+
|
|
128
|
+
if (!publicIpMatch || !instanceIdMatch || !awsRegionMatch) {
|
|
129
|
+
throw new Error('Failed to parse spawn-runner.sh output');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const publicIp = publicIpMatch[1].trim();
|
|
133
|
+
const instanceId = instanceIdMatch[1].trim();
|
|
134
|
+
const awsRegion = awsRegionMatch[1].trim();
|
|
135
|
+
|
|
136
|
+
// Store instance info for this test (use global's map)
|
|
137
|
+
globalThis.__testdriverAWS.instances.set(testId, { publicIp, instanceId, awsRegion });
|
|
138
|
+
|
|
139
|
+
// Set IP on test context (not process.env to avoid conflicts in parallel tests)
|
|
140
|
+
context.ip = publicIp;
|
|
141
|
+
|
|
142
|
+
console.log(`[TestDriver] Instance spawned: ${instanceId} at ${publicIp}`);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error('[TestDriver] Failed to spawn AWS instance:', error.message);
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// NOTE: No afterEach hook here!
|
|
150
|
+
// Instance termination is now handled by hooks.mjs AFTER dashcam.stop() completes.
|
|
151
|
+
// This ensures dashcam can properly stop before the instance is terminated.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vitest Setup File for TestDriver
|
|
3
|
+
*
|
|
4
|
+
* This file is run by Vitest before each test file to set up
|
|
5
|
+
* the TestDriver plugin state and global helpers.
|
|
6
|
+
*
|
|
7
|
+
* Usage in vitest.config.mjs:
|
|
8
|
+
* ```js
|
|
9
|
+
* export default defineConfig({
|
|
10
|
+
* test: {
|
|
11
|
+
* setupFiles: ['testdriverai/vitest/setup'],
|
|
12
|
+
* },
|
|
13
|
+
* });
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
clearDashcamUrls,
|
|
19
|
+
clearSuiteTestRun,
|
|
20
|
+
getAllDashcamUrls,
|
|
21
|
+
getDashcamUrl,
|
|
22
|
+
getPluginState,
|
|
23
|
+
getSuiteTestRun,
|
|
24
|
+
pluginState,
|
|
25
|
+
registerDashcamUrl,
|
|
26
|
+
setSuiteTestRun,
|
|
27
|
+
} from '../../interfaces/vitest-plugin.mjs';
|
|
28
|
+
|
|
29
|
+
// Set up global TestDriver plugin interface
|
|
30
|
+
// This allows tests and the SDK to communicate with the reporter
|
|
31
|
+
globalThis.__testdriverPlugin = {
|
|
32
|
+
state: pluginState,
|
|
33
|
+
registerDashcamUrl,
|
|
34
|
+
getDashcamUrl,
|
|
35
|
+
getAllDashcamUrls,
|
|
36
|
+
clearDashcamUrls,
|
|
37
|
+
getPluginState,
|
|
38
|
+
getSuiteTestRun,
|
|
39
|
+
setSuiteTestRun,
|
|
40
|
+
clearSuiteTestRun,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Log that setup is complete (only in debug mode)
|
|
44
|
+
if (process.env.TD_LOG_LEVEL?.toLowerCase() === 'debug') {
|
|
45
|
+
console.log('[TestDriver] Setup file initialized, global plugin interface available');
|
|
46
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test for testdriver.captcha() API
|
|
3
|
+
* Clean, simple API for solving captchas
|
|
4
|
+
*/
|
|
5
|
+
import { describe, expect, it } from "vitest";
|
|
6
|
+
import { TestDriver } from "../lib/vitest/hooks.mjs";
|
|
7
|
+
import { getDefaults } from "./config.mjs";
|
|
8
|
+
|
|
9
|
+
console.log("DEBUG: process.env.TD_OS:", process.env.TD_OS);
|
|
10
|
+
|
|
11
|
+
describe("testdriver.captcha() API", () => {
|
|
12
|
+
it("should solve reCAPTCHA v3 with auto-detect", async (context) => {
|
|
13
|
+
const testdriver = TestDriver(context, { ...getDefaults(context) });
|
|
14
|
+
|
|
15
|
+
// Launch Chrome (remote debugging is enabled automatically on Linux)
|
|
16
|
+
await testdriver.provision.chrome({
|
|
17
|
+
url: "https://2captcha.com/demo/recaptcha-v3",
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
await testdriver.screenshot();
|
|
21
|
+
|
|
22
|
+
// Solve the captcha with just the API key - everything else is auto-detected!
|
|
23
|
+
const result = await testdriver.captcha({
|
|
24
|
+
apiKey: process.env.TWOCAPTCHA_API_KEY,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
console.log("Captcha result:", result);
|
|
28
|
+
await testdriver.screenshot();
|
|
29
|
+
|
|
30
|
+
expect(result.success).toBe(true);
|
|
31
|
+
}, 180000);
|
|
32
|
+
|
|
33
|
+
it("should solve Cloudflare Turnstile", async (context) => {
|
|
34
|
+
const testdriver = TestDriver(context, { ...getDefaults(context) });
|
|
35
|
+
|
|
36
|
+
await testdriver.provision.chrome({
|
|
37
|
+
url: "https://2captcha.com/demo/cloudflare-turnstile",
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
await testdriver.screenshot();
|
|
41
|
+
|
|
42
|
+
const result = await testdriver.captcha({
|
|
43
|
+
apiKey: process.env.TWOCAPTCHA_API_KEY,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
console.log("Turnstile result:", result);
|
|
47
|
+
await testdriver.screenshot();
|
|
48
|
+
|
|
49
|
+
expect(result.success).toBe(true);
|
|
50
|
+
}, 180000);
|
|
51
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TestDriver SDK - Drag and Drop Test (Vitest)
|
|
3
|
+
* Converted from: testdriver/acceptance/drag-and-drop.yaml
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, it } from "vitest";
|
|
7
|
+
import { TestDriver } from "../lib/vitest/hooks.mjs";
|
|
8
|
+
import { getDefaults } from "./config.mjs";
|
|
9
|
+
|
|
10
|
+
const isLinux = (process.env.TD_OS || "linux") === "linux";
|
|
11
|
+
|
|
12
|
+
describe("Drag and Drop Test", () => {
|
|
13
|
+
it.skipIf(isLinux)(
|
|
14
|
+
'should drag "New Text Document" to "Recycle Bin"',
|
|
15
|
+
async (context) => {
|
|
16
|
+
const testdriver = TestDriver(context, { ...getDefaults(context), headless: true });
|
|
17
|
+
await testdriver.provision.chrome({ url: 'http://testdriver-sandbox.vercel.app/login' });
|
|
18
|
+
|
|
19
|
+
//
|
|
20
|
+
// Show the desktop
|
|
21
|
+
await testdriver.pressKeys(["win", "d"]);
|
|
22
|
+
|
|
23
|
+
// Open the context menu
|
|
24
|
+
await testdriver.pressKeys(["shift", "f10"]);
|
|
25
|
+
|
|
26
|
+
// Hover over "New" in the context menu
|
|
27
|
+
const newOption = await testdriver.find(
|
|
28
|
+
"New, new option in the open context menu on the desktop",
|
|
29
|
+
);
|
|
30
|
+
await newOption.hover();
|
|
31
|
+
|
|
32
|
+
// Click "Text Document" in the context menu
|
|
33
|
+
const textDocOption = await testdriver.find(
|
|
34
|
+
"Text Document, text document option in the new submenu of the desktop context menu",
|
|
35
|
+
);
|
|
36
|
+
await textDocOption.click();
|
|
37
|
+
|
|
38
|
+
// Unfocus the "Text Document" text field
|
|
39
|
+
await testdriver.pressKeys(["esc"]);
|
|
40
|
+
|
|
41
|
+
// Drag the "New Text Document" icon to the "Recycle Bin"
|
|
42
|
+
const textDoc = await testdriver.find(
|
|
43
|
+
"New Text Document, new text document icon in the center of the desktop",
|
|
44
|
+
);
|
|
45
|
+
await textDoc.mouseDown();
|
|
46
|
+
|
|
47
|
+
const recycleBin = await testdriver.find(
|
|
48
|
+
"Recycle Bin, recycle bin icon in the top left corner of the desktop",
|
|
49
|
+
).hover();
|
|
50
|
+
await recycleBin.mouseUp();
|
|
51
|
+
|
|
52
|
+
// Assert "New Text Document" icon is not on the Desktop
|
|
53
|
+
const result = await testdriver.assert(
|
|
54
|
+
'the "New Text Document" icon is not visible on the Desktop',
|
|
55
|
+
);
|
|
56
|
+
expect(result).toBeTruthy();
|
|
57
|
+
},
|
|
58
|
+
);
|
|
59
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Popup Loading - Skip straight to the rocket match (skipToIcons=true)
|
|
3
|
+
*/
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
import { TestDriver } from "../lib/vitest/hooks.mjs";
|
|
6
|
+
|
|
7
|
+
describe("Rocket Match (skipToIcons)", () => {
|
|
8
|
+
it("should find the rocket in the icon grid", async (context) => {
|
|
9
|
+
const testdriver = TestDriver(context, {
|
|
10
|
+
preview: "ide",
|
|
11
|
+
ip: context.ip || process.env.TD_IP,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
await testdriver.provision.chrome({
|
|
15
|
+
url: "https://v0-popup-with-loading-bar.vercel.app/?skipToIcons=true",
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Wait for the 5x5 grid of images to fully load and click the rocket
|
|
19
|
+
await testdriver.find("The icon of a rocket in the 5x5 grid of images", {
|
|
20
|
+
timeout: 60000,
|
|
21
|
+
zoom: 1,
|
|
22
|
+
}).click();
|
|
23
|
+
|
|
24
|
+
// Assert the success message appears
|
|
25
|
+
const rocketResult = await testdriver.assert(
|
|
26
|
+
"The text 'You found the rocket!' is visible on the page"
|
|
27
|
+
);
|
|
28
|
+
expect(rocketResult).toBeTruthy();
|
|
29
|
+
});
|
|
30
|
+
});
|