@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,289 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# --- Config (reads from env) ---
|
|
5
|
+
: "${AWS_REGION:?Set AWS_REGION}"
|
|
6
|
+
: "${AMI_ID:?Set AMI_ID (TestDriver Ami)}"
|
|
7
|
+
: "${AWS_LAUNCH_TEMPLATE_ID:?Set AWS_LAUNCH_TEMPLATE_ID}"
|
|
8
|
+
: "${AWS_LAUNCH_TEMPLATE_VERSION:=\$Latest}"
|
|
9
|
+
: "${AWS_TAG_PREFIX:=td}"
|
|
10
|
+
: "${RUNNER_CLASS_ID:=default}"
|
|
11
|
+
: "${RESOLUTION:=1440x900}"
|
|
12
|
+
|
|
13
|
+
TAG_NAME="${AWS_TAG_PREFIX}-"$(date +%s)
|
|
14
|
+
|
|
15
|
+
echo "Launching AWS Instance..."
|
|
16
|
+
|
|
17
|
+
# --- 1) Launch instance ---
|
|
18
|
+
RUN_JSON=$(aws ec2 run-instances \
|
|
19
|
+
--region "$AWS_REGION" \
|
|
20
|
+
--image-id "$AMI_ID" \
|
|
21
|
+
--launch-template "LaunchTemplateId=$AWS_LAUNCH_TEMPLATE_ID,Version=$AWS_LAUNCH_TEMPLATE_VERSION" \
|
|
22
|
+
--tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=${TAG_NAME}},{Key=Class,Value=${RUNNER_CLASS_ID}},{Key=TD_RESOLUTION,Value=${RESOLUTION}}]" \
|
|
23
|
+
--output json)
|
|
24
|
+
|
|
25
|
+
INSTANCE_ID=$(jq -r '.Instances[0].InstanceId' <<<"$RUN_JSON")
|
|
26
|
+
|
|
27
|
+
echo "Launched: $INSTANCE_ID"
|
|
28
|
+
echo "Instance details:"
|
|
29
|
+
echo " Region: $AWS_REGION"
|
|
30
|
+
echo " AMI ID: $AMI_ID"
|
|
31
|
+
echo " Launch Template ID: $AWS_LAUNCH_TEMPLATE_ID"
|
|
32
|
+
echo " Launch Template Version: $AWS_LAUNCH_TEMPLATE_VERSION"
|
|
33
|
+
|
|
34
|
+
echo "Waiting for instance to be running..."
|
|
35
|
+
|
|
36
|
+
# --- 2) Wait for running + status checks ---
|
|
37
|
+
aws ec2 wait instance-running --region "$AWS_REGION" --instance-ids "$INSTANCE_ID"
|
|
38
|
+
echo "✓ Instance is now running"
|
|
39
|
+
|
|
40
|
+
echo "Waiting for instance to pass status checks..."
|
|
41
|
+
|
|
42
|
+
aws ec2 wait instance-status-ok --region "$AWS_REGION" --instance-ids "$INSTANCE_ID"
|
|
43
|
+
echo "✓ Instance passed all status checks"
|
|
44
|
+
|
|
45
|
+
# Additional validation - check instance state details
|
|
46
|
+
echo "Validating instance readiness..."
|
|
47
|
+
INSTANCE_STATE=$(aws ec2 describe-instances --region "$AWS_REGION" --instance-ids "$INSTANCE_ID" \
|
|
48
|
+
--query 'Reservations[0].Instances[0].{State:State.Name,StatusChecks:StateTransitionReason}' \
|
|
49
|
+
--output json)
|
|
50
|
+
echo "Instance state details: $INSTANCE_STATE"
|
|
51
|
+
|
|
52
|
+
# --- 3) Ensure SSM connectivity ---
|
|
53
|
+
echo "Waiting for SSM connectivity..."
|
|
54
|
+
echo "This can take several minutes for the SSM agent to be fully ready..."
|
|
55
|
+
|
|
56
|
+
# First, check if the instance is registered with SSM
|
|
57
|
+
echo "Checking SSM instance registration..."
|
|
58
|
+
TRIES=0; MAX_TRIES=60
|
|
59
|
+
while :; do
|
|
60
|
+
echo "Attempt $((TRIES+1))/$MAX_TRIES: Checking if instance is registered with SSM..."
|
|
61
|
+
|
|
62
|
+
# Check if instance appears in SSM managed instances
|
|
63
|
+
if aws ssm describe-instance-information \
|
|
64
|
+
--region "$AWS_REGION" \
|
|
65
|
+
--filters "Key=InstanceIds,Values=$INSTANCE_ID" \
|
|
66
|
+
--query 'InstanceInformationList[0].InstanceId' \
|
|
67
|
+
--output text 2>/dev/null | grep -q "$INSTANCE_ID"; then
|
|
68
|
+
echo "✓ Instance is registered with SSM"
|
|
69
|
+
break
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
TRIES=$((TRIES+1))
|
|
73
|
+
if [ $TRIES -ge $MAX_TRIES ]; then
|
|
74
|
+
echo "❌ SSM registration timeout - instance may not have proper IAM role or SSM agent"
|
|
75
|
+
echo "Checking instance details for debugging..."
|
|
76
|
+
aws ec2 describe-instances --region "$AWS_REGION" --instance-ids "$INSTANCE_ID" \
|
|
77
|
+
--query 'Reservations[0].Instances[0].{State:State.Name,IAMProfile:IamInstanceProfile.Arn,SecurityGroups:SecurityGroups[].GroupId}' \
|
|
78
|
+
--output table
|
|
79
|
+
exit 2
|
|
80
|
+
fi
|
|
81
|
+
echo "Instance not yet registered with SSM, waiting..."
|
|
82
|
+
sleep 10
|
|
83
|
+
done
|
|
84
|
+
|
|
85
|
+
# Now test SSM command execution
|
|
86
|
+
echo "Testing SSM command execution..."
|
|
87
|
+
TRIES=0; MAX_TRIES=30
|
|
88
|
+
while :; do
|
|
89
|
+
echo "Attempt $((TRIES+1))/$MAX_TRIES: Sending test SSM command..."
|
|
90
|
+
|
|
91
|
+
if CMD_JSON=$(aws ssm send-command \
|
|
92
|
+
--region "$AWS_REGION" \
|
|
93
|
+
--targets "Key=instanceIds,Values=$INSTANCE_ID" \
|
|
94
|
+
--document-name "AWS-RunPowerShellScript" \
|
|
95
|
+
--parameters 'commands=["echo SSM connectivity test successful"]' \
|
|
96
|
+
--output json 2>/dev/null); then
|
|
97
|
+
|
|
98
|
+
COMMAND_ID=$(jq -r '.Command.CommandId' <<<"$CMD_JSON")
|
|
99
|
+
echo "✓ SSM command sent successfully (Command ID: $COMMAND_ID)"
|
|
100
|
+
|
|
101
|
+
# Wait for command to complete and check status
|
|
102
|
+
echo "Waiting for command execution..."
|
|
103
|
+
if aws ssm wait command-executed --region "$AWS_REGION" --command-id "$COMMAND_ID" --instance-id "$INSTANCE_ID" 2>/dev/null; then
|
|
104
|
+
echo "✓ SSM connectivity confirmed"
|
|
105
|
+
break
|
|
106
|
+
else
|
|
107
|
+
echo "⚠ Command execution may have failed, checking status..."
|
|
108
|
+
CMD_STATUS=$(aws ssm get-command-invocation \
|
|
109
|
+
--region "$AWS_REGION" \
|
|
110
|
+
--command-id "$COMMAND_ID" \
|
|
111
|
+
--instance-id "$INSTANCE_ID" \
|
|
112
|
+
--query 'Status' \
|
|
113
|
+
--output text 2>/dev/null || echo "Unknown")
|
|
114
|
+
echo "Command status: $CMD_STATUS"
|
|
115
|
+
|
|
116
|
+
if [ "$CMD_STATUS" = "Success" ]; then
|
|
117
|
+
echo "✓ Command actually succeeded"
|
|
118
|
+
break
|
|
119
|
+
fi
|
|
120
|
+
fi
|
|
121
|
+
else
|
|
122
|
+
echo "⚠ Failed to send SSM command"
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
TRIES=$((TRIES+1))
|
|
126
|
+
if [ $TRIES -ge $MAX_TRIES ]; then
|
|
127
|
+
echo "❌ SSM command execution timeout"
|
|
128
|
+
echo "Final debugging information:"
|
|
129
|
+
|
|
130
|
+
# Get SSM agent status
|
|
131
|
+
echo "SSM Agent status on instance:"
|
|
132
|
+
aws ssm describe-instance-information \
|
|
133
|
+
--region "$AWS_REGION" \
|
|
134
|
+
--filters "Key=InstanceIds,Values=$INSTANCE_ID" \
|
|
135
|
+
--query 'InstanceInformationList[0].{PingStatus:PingStatus,LastPingDateTime:LastPingDateTime,AgentVersion:AgentVersion}' \
|
|
136
|
+
--output table 2>/dev/null || echo "Could not retrieve SSM status"
|
|
137
|
+
|
|
138
|
+
exit 2
|
|
139
|
+
fi
|
|
140
|
+
echo "Retrying in 20 seconds..."
|
|
141
|
+
sleep 20
|
|
142
|
+
done
|
|
143
|
+
|
|
144
|
+
# --- 4) Install/update runner ---
|
|
145
|
+
echo "Installing runner..."
|
|
146
|
+
|
|
147
|
+
# Determine environment and version
|
|
148
|
+
TD_ENV="${TD_ENV:-stable}"
|
|
149
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
150
|
+
SDK_PKG_JSON="${SCRIPT_DIR}/../../../sdk/package.json"
|
|
151
|
+
RUNNER_DIR="${SCRIPT_DIR}/../../../runner"
|
|
152
|
+
|
|
153
|
+
if [ -f "$SDK_PKG_JSON" ]; then
|
|
154
|
+
RUNNER_VERSION=$(jq -r '.version' "$SDK_PKG_JSON")
|
|
155
|
+
echo "Runner version from SDK: $RUNNER_VERSION"
|
|
156
|
+
else
|
|
157
|
+
RUNNER_VERSION="$TD_ENV"
|
|
158
|
+
echo "SDK package.json not found, using env tag: $RUNNER_VERSION"
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
if [ "$TD_ENV" = "dev" ]; then
|
|
162
|
+
echo "Dev mode: packing and uploading local runner to S3..."
|
|
163
|
+
|
|
164
|
+
# Pack local runner
|
|
165
|
+
TMPDIR=$(mktemp -d)
|
|
166
|
+
pushd "$RUNNER_DIR" > /dev/null
|
|
167
|
+
npm pack --pack-destination "$TMPDIR" > /dev/null 2>&1
|
|
168
|
+
TARBALL=$(ls "$TMPDIR"/*.tgz | head -1)
|
|
169
|
+
popd > /dev/null
|
|
170
|
+
|
|
171
|
+
# Upload to S3
|
|
172
|
+
S3_BUCKET="${AWS_BUCKET_IMAGE_TRANSFER:-v7-transfer}"
|
|
173
|
+
S3_KEY="runner-dev/$(date +%s)-$(openssl rand -hex 4)/runner.tgz"
|
|
174
|
+
aws s3 cp "$TARBALL" "s3://${S3_BUCKET}/${S3_KEY}" --region "$AWS_REGION"
|
|
175
|
+
|
|
176
|
+
# Generate presigned URL (15 min)
|
|
177
|
+
DOWNLOAD_URL=$(aws s3 presign "s3://${S3_BUCKET}/${S3_KEY}" --expires-in 900 --region "$AWS_REGION")
|
|
178
|
+
rm -rf "$TMPDIR"
|
|
179
|
+
|
|
180
|
+
# Build SSM parameters JSON in a temp file to avoid shell escaping issues with URL
|
|
181
|
+
PARAMS_FILE=$(mktemp)
|
|
182
|
+
cat > "$PARAMS_FILE" << 'PARAMS_EOF'
|
|
183
|
+
{
|
|
184
|
+
"commands": [
|
|
185
|
+
"Write-Host '=== Starting runner dev install ==='",
|
|
186
|
+
"Write-Host 'Stopping existing runner processes...'",
|
|
187
|
+
"Stop-ScheduledTask -TaskName RunTestDriverAgent -ErrorAction SilentlyContinue",
|
|
188
|
+
"Stop-Process -Name node -Force -ErrorAction SilentlyContinue",
|
|
189
|
+
"Start-Sleep -Seconds 2",
|
|
190
|
+
"Write-Host 'Current runner version:'",
|
|
191
|
+
"Get-Content 'C:\\testdriver\\sandbox-agent\\package.json' | ConvertFrom-Json | Select-Object -ExpandProperty version",
|
|
192
|
+
"Set-Location 'C:\\testdriver\\sandbox-agent'",
|
|
193
|
+
"Write-Host 'Dev mode: downloading runner from S3...'",
|
|
194
|
+
"$tarball = 'C:\\Windows\\Temp\\runner-dev.tgz'",
|
|
195
|
+
PARAMS_EOF
|
|
196
|
+
|
|
197
|
+
# Add the URL line with proper JSON escaping
|
|
198
|
+
echo " \"Invoke-WebRequest -Uri '$(echo "$DOWNLOAD_URL" | sed 's/"/\\"/g')' -OutFile \$tarball\"," >> "$PARAMS_FILE"
|
|
199
|
+
|
|
200
|
+
cat >> "$PARAMS_FILE" << 'PARAMS_EOF'
|
|
201
|
+
"Write-Host 'Downloaded tarball size:'",
|
|
202
|
+
"(Get-Item $tarball).Length",
|
|
203
|
+
"Write-Host 'Extracting runner...'",
|
|
204
|
+
"tar -xzf $tarball -C 'C:\\Windows\\Temp'",
|
|
205
|
+
"Write-Host 'Extracted package contents:'",
|
|
206
|
+
"Get-ChildItem 'C:\\Windows\\Temp\\package' -Recurse | Select-Object FullName",
|
|
207
|
+
"Write-Host 'New runner version in package:'",
|
|
208
|
+
"Get-Content 'C:\\Windows\\Temp\\package\\package.json' | ConvertFrom-Json | Select-Object -ExpandProperty version",
|
|
209
|
+
"Write-Host 'Clearing old lib folder...'",
|
|
210
|
+
"Remove-Item 'C:\\testdriver\\sandbox-agent\\lib' -Recurse -Force -ErrorAction SilentlyContinue",
|
|
211
|
+
"Write-Host 'Copying files to sandbox-agent...'",
|
|
212
|
+
"xcopy 'C:\\Windows\\Temp\\package\\*' 'C:\\testdriver\\sandbox-agent\\' /E /Y /I",
|
|
213
|
+
"Write-Host 'Files after copy:'",
|
|
214
|
+
"Get-ChildItem 'C:\\testdriver\\sandbox-agent' | Select-Object Name",
|
|
215
|
+
"Remove-Item 'C:\\Windows\\Temp\\package' -Recurse -Force -ErrorAction SilentlyContinue",
|
|
216
|
+
"Remove-Item $tarball -Force -ErrorAction SilentlyContinue",
|
|
217
|
+
"Write-Host 'Runner version after copy:'",
|
|
218
|
+
"Get-Content 'C:\\testdriver\\sandbox-agent\\package.json' | ConvertFrom-Json | Select-Object -ExpandProperty version",
|
|
219
|
+
"Write-Host 'Installing npm dependencies...'",
|
|
220
|
+
"npm install --omit=dev 2>&1 | Write-Host",
|
|
221
|
+
"Write-Host 'Final verification - ably-service.js exists:'",
|
|
222
|
+
"Test-Path 'C:\\testdriver\\sandbox-agent\\lib\\ably-service.js'",
|
|
223
|
+
"Write-Host 'Restarting RunTestDriverAgent scheduled task...'",
|
|
224
|
+
"Start-ScheduledTask -TaskName RunTestDriverAgent -ErrorAction SilentlyContinue",
|
|
225
|
+
"Write-Host '=== Runner install complete (dev) ==='"
|
|
226
|
+
]
|
|
227
|
+
}
|
|
228
|
+
PARAMS_EOF
|
|
229
|
+
|
|
230
|
+
echo "Sending SSM command to download and install runner from S3..."
|
|
231
|
+
INSTALL_CMD=$(aws ssm send-command \
|
|
232
|
+
--region "$AWS_REGION" \
|
|
233
|
+
--instance-ids "$INSTANCE_ID" \
|
|
234
|
+
--document-name "AWS-RunPowerShellScript" \
|
|
235
|
+
--parameters "file://$PARAMS_FILE" \
|
|
236
|
+
--timeout-seconds 180 \
|
|
237
|
+
--output json)
|
|
238
|
+
rm -f "$PARAMS_FILE"
|
|
239
|
+
else
|
|
240
|
+
echo "Installing @testdriverai/runner@${RUNNER_VERSION} via npm..."
|
|
241
|
+
INSTALL_CMD=$(aws ssm send-command \
|
|
242
|
+
--region "$AWS_REGION" \
|
|
243
|
+
--instance-ids "$INSTANCE_ID" \
|
|
244
|
+
--document-name "AWS-RunPowerShellScript" \
|
|
245
|
+
--parameters "commands=[
|
|
246
|
+
\"Set-Location 'C:\\\\testdriver\\\\sandbox-agent'\",
|
|
247
|
+
\"Write-Host 'Installing @testdriverai/runner@${RUNNER_VERSION}...'\",
|
|
248
|
+
\"npm install @testdriverai/runner@${RUNNER_VERSION} --omit=dev 2>&1 | Write-Host\",
|
|
249
|
+
\"Write-Host 'Stopping runner (config not yet provisioned)...'\",
|
|
250
|
+
\"Stop-Process -Name node -Force -ErrorAction SilentlyContinue\",
|
|
251
|
+
\"Stop-ScheduledTask -TaskName RunTestDriverAgent -ErrorAction SilentlyContinue\",
|
|
252
|
+
\"Start-Sleep -Seconds 2\",
|
|
253
|
+
\"Start-ScheduledTask -TaskName RunTestDriverAgent -ErrorAction SilentlyContinue\",
|
|
254
|
+
\"Write-Host 'Runner install complete'\"
|
|
255
|
+
]" \
|
|
256
|
+
--timeout-seconds 120 \
|
|
257
|
+
--output json)
|
|
258
|
+
fi
|
|
259
|
+
|
|
260
|
+
INSTALL_CMD_ID=$(jq -r '.Command.CommandId' <<<"$INSTALL_CMD")
|
|
261
|
+
echo "Runner install command sent (Command ID: $INSTALL_CMD_ID)"
|
|
262
|
+
|
|
263
|
+
# Wait for install to complete
|
|
264
|
+
echo "Waiting for runner install to complete..."
|
|
265
|
+
if aws ssm wait command-executed --region "$AWS_REGION" --command-id "$INSTALL_CMD_ID" --instance-id "$INSTANCE_ID" 2>/dev/null; then
|
|
266
|
+
echo "✓ Runner install succeeded"
|
|
267
|
+
else
|
|
268
|
+
INSTALL_STATUS=$(aws ssm get-command-invocation \
|
|
269
|
+
--region "$AWS_REGION" \
|
|
270
|
+
--command-id "$INSTALL_CMD_ID" \
|
|
271
|
+
--instance-id "$INSTANCE_ID" \
|
|
272
|
+
--output json 2>/dev/null || echo '{}')
|
|
273
|
+
echo "⚠ Runner install status: $(jq -r '.Status // "Unknown"' <<<"$INSTALL_STATUS")"
|
|
274
|
+
echo "Output: $(jq -r '.StandardOutputContent // "No output"' <<<"$INSTALL_STATUS" | head -20)"
|
|
275
|
+
echo "Errors: $(jq -r '.StandardErrorContent // "No errors"' <<<"$INSTALL_STATUS" | head -10)"
|
|
276
|
+
fi
|
|
277
|
+
|
|
278
|
+
echo "Getting Public IP..."
|
|
279
|
+
|
|
280
|
+
# --- 5) Get instance Public IP ---
|
|
281
|
+
DESC_JSON=$(aws ec2 describe-instances --region "$AWS_REGION" --instance-ids "$INSTANCE_ID" --output json)
|
|
282
|
+
PUBLIC_IP=$(jq -r '.Reservations[0].Instances[0].PublicIpAddress // empty' <<<"$DESC_JSON")
|
|
283
|
+
[ -n "$PUBLIC_IP" ] || PUBLIC_IP="No public IP assigned"
|
|
284
|
+
|
|
285
|
+
# --- 6) Output results ---
|
|
286
|
+
echo "Setup complete!"
|
|
287
|
+
echo "PUBLIC_IP=$PUBLIC_IP"
|
|
288
|
+
echo "INSTANCE_ID=$INSTANCE_ID"
|
|
289
|
+
echo "AWS_REGION=$AWS_REGION"
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the captcha solver script
|
|
3
|
+
* These tests verify the solver script is valid JavaScript and can be loaded correctly
|
|
4
|
+
*/
|
|
5
|
+
import { describe, expect, it } from "vitest";
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
9
|
+
import vm from "vm";
|
|
10
|
+
|
|
11
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const solverPath = path.join(__dirname, "..", "lib", "captcha", "solver.js");
|
|
13
|
+
|
|
14
|
+
// Extract safeParseJson function from the solver script for testing
|
|
15
|
+
function getSafeParseJson() {
|
|
16
|
+
const script = fs.readFileSync(solverPath, "utf8");
|
|
17
|
+
// Extract the safeParseJson function source
|
|
18
|
+
const funcMatch = script.match(
|
|
19
|
+
/function safeParseJson\(text\) \{[\s\S]*?^}/m,
|
|
20
|
+
);
|
|
21
|
+
if (!funcMatch) {
|
|
22
|
+
throw new Error("Could not find safeParseJson function in solver script");
|
|
23
|
+
}
|
|
24
|
+
// Create and return the function
|
|
25
|
+
const func = new Function("return " + funcMatch[0])();
|
|
26
|
+
return func;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe("Captcha Solver Script", () => {
|
|
30
|
+
it("should exist", () => {
|
|
31
|
+
expect(fs.existsSync(solverPath)).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("should be valid JavaScript syntax", () => {
|
|
35
|
+
const script = fs.readFileSync(solverPath, "utf8");
|
|
36
|
+
|
|
37
|
+
// This will throw if the syntax is invalid
|
|
38
|
+
expect(() => {
|
|
39
|
+
new vm.Script(script, { filename: "solver.js" });
|
|
40
|
+
}).not.toThrow();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should contain required functions and variables", () => {
|
|
44
|
+
const script = fs.readFileSync(solverPath, "utf8");
|
|
45
|
+
|
|
46
|
+
// Check for key components
|
|
47
|
+
expect(script).toContain('require("https")');
|
|
48
|
+
expect(script).toContain('require("chrome-remote-interface")');
|
|
49
|
+
expect(script).toContain("detectCaptchaScript");
|
|
50
|
+
expect(script).toContain("getInjectScript");
|
|
51
|
+
expect(script).toContain("autoSubmitScript");
|
|
52
|
+
expect(script).toContain("checkSuccessScript");
|
|
53
|
+
expect(script).toContain("2captcha.com");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should handle all supported captcha types", () => {
|
|
57
|
+
const script = fs.readFileSync(solverPath, "utf8");
|
|
58
|
+
|
|
59
|
+
// Check for captcha type handling
|
|
60
|
+
expect(script).toContain("recaptcha_v2");
|
|
61
|
+
expect(script).toContain("recaptcha_v3");
|
|
62
|
+
expect(script).toContain("hcaptcha");
|
|
63
|
+
expect(script).toContain("turnstile");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should have proper auto-detection for captcha elements", () => {
|
|
67
|
+
const script = fs.readFileSync(solverPath, "utf8");
|
|
68
|
+
|
|
69
|
+
// Check for DOM selectors used in auto-detection
|
|
70
|
+
expect(script).toContain(".g-recaptcha[data-sitekey]");
|
|
71
|
+
expect(script).toContain(".h-captcha[data-sitekey]");
|
|
72
|
+
expect(script).toContain(".cf-turnstile[data-sitekey]");
|
|
73
|
+
expect(script).toContain("[data-sitekey]");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("should properly inject tokens into response fields", () => {
|
|
77
|
+
const script = fs.readFileSync(solverPath, "utf8");
|
|
78
|
+
|
|
79
|
+
// Check for token injection selectors
|
|
80
|
+
expect(script).toContain("[name=g-recaptcha-response]");
|
|
81
|
+
expect(script).toContain("[name=h-captcha-response]");
|
|
82
|
+
expect(script).toContain("[name=cf-turnstile-response]");
|
|
83
|
+
expect(script).toContain("___grecaptcha_cfg");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("should contain safeParseJson function for robust JSON parsing", () => {
|
|
87
|
+
const script = fs.readFileSync(solverPath, "utf8");
|
|
88
|
+
expect(script).toContain("function safeParseJson");
|
|
89
|
+
expect(script).toContain("safeParseJson(await httpsGet");
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe("safeParseJson", () => {
|
|
94
|
+
let safeParseJson;
|
|
95
|
+
let extractionFailed = false;
|
|
96
|
+
|
|
97
|
+
// Try to extract the function for testing
|
|
98
|
+
try {
|
|
99
|
+
safeParseJson = getSafeParseJson();
|
|
100
|
+
} catch {
|
|
101
|
+
extractionFailed = true;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Use it.skipIf to clearly indicate skipped tests
|
|
105
|
+
const testFn = extractionFailed ? it.skip : it;
|
|
106
|
+
|
|
107
|
+
testFn("should parse valid JSON normally", () => {
|
|
108
|
+
const result = safeParseJson('{"status":1,"request":"abc123"}');
|
|
109
|
+
expect(result).toEqual({ status: 1, request: "abc123" });
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
testFn("should handle JSON with leading/trailing whitespace", () => {
|
|
113
|
+
const result = safeParseJson(' {"status":1} \n');
|
|
114
|
+
expect(result).toEqual({ status: 1 });
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
testFn("should extract first JSON object from concatenated responses", () => {
|
|
118
|
+
// This is the exact error case: multiple JSON objects concatenated
|
|
119
|
+
const result = safeParseJson('{"status":1}{"status":2}');
|
|
120
|
+
expect(result).toEqual({ status: 1 });
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
testFn("should handle JSON with trailing garbage characters", () => {
|
|
124
|
+
const result = safeParseJson('{"status":1}xxx');
|
|
125
|
+
expect(result).toEqual({ status: 1 });
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
testFn("should handle nested objects correctly", () => {
|
|
129
|
+
const result = safeParseJson('{"data":{"nested":true}}extra');
|
|
130
|
+
expect(result).toEqual({ data: { nested: true } });
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
testFn("should handle strings containing braces", () => {
|
|
134
|
+
const result = safeParseJson('{"text":"hello {world}"}extra');
|
|
135
|
+
expect(result).toEqual({ text: "hello {world}" });
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
testFn("should handle escaped quotes in strings", () => {
|
|
139
|
+
const result = safeParseJson('{"text":"say \\"hello\\""}extra');
|
|
140
|
+
expect(result).toEqual({ text: 'say "hello"' });
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
testFn("should throw for responses without JSON", () => {
|
|
144
|
+
expect(() => safeParseJson("not json at all")).toThrow(
|
|
145
|
+
"No JSON object found",
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
testFn("should throw for incomplete JSON", () => {
|
|
150
|
+
expect(() => safeParseJson('{"incomplete')).toThrow("Invalid JSON");
|
|
151
|
+
});
|
|
152
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test that validates Chrome remote debugging is working
|
|
3
|
+
* Installs chrome-remote-interface and connects to the active tab
|
|
4
|
+
*/
|
|
5
|
+
import { describe, expect, it } from "vitest";
|
|
6
|
+
import { TestDriver } from "../lib/vitest/hooks.mjs";
|
|
7
|
+
|
|
8
|
+
describe("Chrome Remote Debugging", () => {
|
|
9
|
+
|
|
10
|
+
it("should connect to Chrome via CDP and get page title", async (context) => {
|
|
11
|
+
const testdriver = TestDriver(context);
|
|
12
|
+
|
|
13
|
+
// Launch Chrome with a known URL
|
|
14
|
+
await testdriver.provision.chrome({
|
|
15
|
+
url: 'https://example.com',
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Take a screenshot to verify Chrome launched
|
|
19
|
+
await testdriver.screenshot();
|
|
20
|
+
|
|
21
|
+
// Install chrome-remote-interface (needs sudo for global install)
|
|
22
|
+
const installResult = await testdriver.exec(
|
|
23
|
+
'sh',
|
|
24
|
+
'sudo npm install -g chrome-remote-interface',
|
|
25
|
+
60000
|
|
26
|
+
);
|
|
27
|
+
console.log('Install result:', installResult);
|
|
28
|
+
|
|
29
|
+
// Write the CDP script to a file to avoid quoting issues
|
|
30
|
+
const cdpScript = `
|
|
31
|
+
const CDP = require('chrome-remote-interface');
|
|
32
|
+
(async () => {
|
|
33
|
+
try {
|
|
34
|
+
const client = await CDP();
|
|
35
|
+
const { Runtime } = client;
|
|
36
|
+
const result = await Runtime.evaluate({
|
|
37
|
+
expression: 'document.title'
|
|
38
|
+
});
|
|
39
|
+
console.log('PAGE_TITLE:' + result.result.value);
|
|
40
|
+
await client.close();
|
|
41
|
+
process.exit(0);
|
|
42
|
+
} catch (err) {
|
|
43
|
+
console.error('CDP_ERROR:' + err.message);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
})();
|
|
47
|
+
`;
|
|
48
|
+
|
|
49
|
+
// Write script to file
|
|
50
|
+
await testdriver.exec('sh', `cat > /tmp/cdp-test.js << 'SCRIPT'
|
|
51
|
+
${cdpScript}
|
|
52
|
+
SCRIPT`, 5000);
|
|
53
|
+
|
|
54
|
+
// Run the CDP script with NODE_PATH set to find globally installed modules
|
|
55
|
+
const cdpResult = await testdriver.exec(
|
|
56
|
+
'sh',
|
|
57
|
+
'NODE_PATH=/usr/lib/node_modules node /tmp/cdp-test.js 2>&1 || echo "CDP_EXIT_CODE:$?"',
|
|
58
|
+
30000
|
|
59
|
+
);
|
|
60
|
+
console.log('CDP result:', cdpResult);
|
|
61
|
+
|
|
62
|
+
// Verify we got the page title
|
|
63
|
+
expect(cdpResult).toContain('PAGE_TITLE:');
|
|
64
|
+
expect(cdpResult).toContain('Example Domain');
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Experiment file - reconnects to existing sandbox
|
|
3
|
+
* Run AFTER setup.test.mjs passes
|
|
4
|
+
*/
|
|
5
|
+
import { describe, expect, it } from "vitest";
|
|
6
|
+
import { TestDriver } from "../../lib/vitest/hooks.mjs";
|
|
7
|
+
|
|
8
|
+
describe("Experiment DuckDuckGo", () => {
|
|
9
|
+
it("should search for apples", async (context) => {
|
|
10
|
+
const testdriver = TestDriver(context, {
|
|
11
|
+
reconnect: true, // ← Key: reconnects to last sandbox
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// NO provision here! The sandbox is already running from setup.test.mjs
|
|
15
|
+
|
|
16
|
+
// Find search input and type
|
|
17
|
+
const searchInput = await testdriver.find("search input");
|
|
18
|
+
await searchInput.click();
|
|
19
|
+
await testdriver.type("apples");
|
|
20
|
+
await testdriver.pressKeys(["enter"]);
|
|
21
|
+
|
|
22
|
+
// Assert results
|
|
23
|
+
const result = await testdriver.assert(
|
|
24
|
+
"I can see search results for apples",
|
|
25
|
+
);
|
|
26
|
+
expect(result).toBeTruthy();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Setup file - MINIMAL steps to get to starting state
|
|
3
|
+
* Only add more steps AFTER this passes!
|
|
4
|
+
*/
|
|
5
|
+
import { afterAll, describe, expect, it } from "vitest";
|
|
6
|
+
import { TestDriver } from "../../lib/vitest/hooks.mjs";
|
|
7
|
+
|
|
8
|
+
describe("Setup DuckDuckGo", () => {
|
|
9
|
+
afterAll(async () => {
|
|
10
|
+
// DO NOT disconnect - keep sandbox alive for reconnect
|
|
11
|
+
console.log("Sandbox staying alive for 30 seconds (keepAlive)");
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should set up the application state", async (context) => {
|
|
15
|
+
const testdriver = TestDriver(context);
|
|
16
|
+
|
|
17
|
+
await testdriver.provision.chrome({
|
|
18
|
+
url: "https://duckduckgo.com",
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Start with just ONE assertion to verify we're on the right page
|
|
22
|
+
const result = await testdriver.assert(
|
|
23
|
+
"I can see the DuckDuckGo search page",
|
|
24
|
+
);
|
|
25
|
+
expect(result).toBeTruthy();
|
|
26
|
+
|
|
27
|
+
console.log("✅ Setup ready - run experiment.test.mjs now");
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Debug script to inspect the full locate API response
|
|
5
|
+
* Run this with: TD_API_KEY=your_key node debug-locate-response.js
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const TestDriverSDK = require("./sdk.js");
|
|
9
|
+
|
|
10
|
+
async function debugLocateResponse() {
|
|
11
|
+
const client = new TestDriverSDK(process.env.TD_API_KEY);
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
console.log("Connecting to sandbox (Linux)...");
|
|
15
|
+
await client.connect({ headless: true });
|
|
16
|
+
|
|
17
|
+
console.log("Opening a test page...");
|
|
18
|
+
await client.focusApplication("Google Chrome");
|
|
19
|
+
await client.type("https://example.com");
|
|
20
|
+
await client.pressKeys(["enter"]);
|
|
21
|
+
|
|
22
|
+
// Wait for page to load
|
|
23
|
+
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
24
|
+
|
|
25
|
+
console.log("\nFinding an element to inspect the response...");
|
|
26
|
+
const element = await client.find("the heading that says Example Domain");
|
|
27
|
+
|
|
28
|
+
console.log("\n=".repeat(60));
|
|
29
|
+
console.log("FULL LOCATE API RESPONSE:");
|
|
30
|
+
console.log("=".repeat(60));
|
|
31
|
+
|
|
32
|
+
const response = element.getResponse();
|
|
33
|
+
console.log(JSON.stringify(response, null, 2));
|
|
34
|
+
|
|
35
|
+
console.log("\n=".repeat(60));
|
|
36
|
+
console.log("RESPONSE KEYS:");
|
|
37
|
+
console.log("=".repeat(60));
|
|
38
|
+
|
|
39
|
+
if (response) {
|
|
40
|
+
Object.keys(response).forEach((key) => {
|
|
41
|
+
const value = response[key];
|
|
42
|
+
const type = Array.isArray(value) ? "array" : typeof value;
|
|
43
|
+
const preview =
|
|
44
|
+
typeof value === "string" && value.length > 100
|
|
45
|
+
? `${value.substring(0, 100)}... (${value.length} chars)`
|
|
46
|
+
: typeof value === "object"
|
|
47
|
+
? JSON.stringify(value)
|
|
48
|
+
: value;
|
|
49
|
+
|
|
50
|
+
console.log(` ${key} (${type}): ${preview}`);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
console.log("\n=".repeat(60));
|
|
55
|
+
console.log("ELEMENT PROPERTIES:");
|
|
56
|
+
console.log("=".repeat(60));
|
|
57
|
+
console.log(" found:", element.found());
|
|
58
|
+
console.log(" x:", element.x);
|
|
59
|
+
console.log(" y:", element.y);
|
|
60
|
+
console.log(" centerX:", element.centerX);
|
|
61
|
+
console.log(" centerY:", element.centerY);
|
|
62
|
+
console.log(" width:", element.width);
|
|
63
|
+
console.log(" height:", element.height);
|
|
64
|
+
console.log(" confidence:", element.confidence);
|
|
65
|
+
console.log(" text:", element.text);
|
|
66
|
+
console.log(" label:", element.label);
|
|
67
|
+
console.log(
|
|
68
|
+
" screenshot:",
|
|
69
|
+
element.screenshot ? `${element.screenshot.length} chars` : null,
|
|
70
|
+
);
|
|
71
|
+
console.log(" boundingBox:", element.boundingBox);
|
|
72
|
+
|
|
73
|
+
await client.disconnect();
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error("Error:", error.message);
|
|
76
|
+
console.error(error.stack);
|
|
77
|
+
await client.disconnect();
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
debugLocateResponse();
|