@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,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared test logic for popup-loading variants.
|
|
3
|
+
* Each variant file imports this and calls it with specific options.
|
|
4
|
+
*/
|
|
5
|
+
import { describe, expect, it } from "vitest";
|
|
6
|
+
import { TestDriver } from "../lib/vitest/hooks.mjs";
|
|
7
|
+
|
|
8
|
+
export function popupLoadingTest(label, options = {}) {
|
|
9
|
+
describe(`Popup with Loading (${label})`, () => {
|
|
10
|
+
it("should accept cookies and wait for completion", async (context) => {
|
|
11
|
+
const testdriver = TestDriver(context, {
|
|
12
|
+
preview: 'ide',
|
|
13
|
+
ip: context.ip || process.env.TD_IP,
|
|
14
|
+
...options,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
await testdriver.provision.chrome({
|
|
18
|
+
url: "https://v0-popup-with-loading-bar.vercel.app/",
|
|
19
|
+
});
|
|
20
|
+
await testdriver.screenshot();
|
|
21
|
+
|
|
22
|
+
// Accept the cookie banner to trigger the loading process
|
|
23
|
+
let acceptButton = await testdriver.find("Accept All button on the cookie banner", {timeout: 10000});
|
|
24
|
+
|
|
25
|
+
if (await acceptButton.found()) {
|
|
26
|
+
await acceptButton.click();
|
|
27
|
+
} else {
|
|
28
|
+
console.log('no cookie banner found, proceeding without accepting cookies');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
await testdriver.find('Start button').click();
|
|
32
|
+
|
|
33
|
+
// Wait for "All done!" to appear with 120s timeout
|
|
34
|
+
const allDone = await testdriver.find("All done! text or heading in a modal or popup", { timeout: 120000 });
|
|
35
|
+
await testdriver.screenshot();
|
|
36
|
+
|
|
37
|
+
const result = await testdriver.assert("The text 'All done!' is visible on the page");
|
|
38
|
+
expect(result).toBeTruthy();
|
|
39
|
+
|
|
40
|
+
// Click Continue to proceed to the image grid
|
|
41
|
+
await testdriver.find("Continue button in the modal").click();
|
|
42
|
+
|
|
43
|
+
// Wait for the 5x5 grid of images to fully load (up to 60s) and click the rocket
|
|
44
|
+
await testdriver.find("The icon of a rocket in the 5x5 grid of images", { timeout: 60000, zoom: true }).click();
|
|
45
|
+
|
|
46
|
+
// Assert the success message appears
|
|
47
|
+
const rocketResult = await testdriver.assert("The text 'You found the rocket!' is visible on the page");
|
|
48
|
+
expect(rocketResult).toBeTruthy();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TestDriver SDK - No-Provision Test with Dashcam (Vitest)
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates manual dashcam control without using provision methods.
|
|
5
|
+
* When not using provision.chrome(), provision.vscode(), etc., you need
|
|
6
|
+
* to manually start and stop dashcam recording.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, it } from "vitest";
|
|
10
|
+
import { TestDriver } from "../lib/vitest/hooks.mjs";
|
|
11
|
+
import { getDefaults } from "./config.mjs";
|
|
12
|
+
|
|
13
|
+
describe("No-Provision with Dashcam", () => {
|
|
14
|
+
it("should record dashcam while asserting desktop is visible", async (context) => {
|
|
15
|
+
const testdriver = TestDriver(context, { ...getDefaults(context) });
|
|
16
|
+
|
|
17
|
+
// Start dashcam recording manually (provision methods do this automatically)
|
|
18
|
+
await testdriver.dashcam.start();
|
|
19
|
+
|
|
20
|
+
await testdriver.exec('sh', 'gedit >/dev/null 2>&1 &'); // Example command to keep the test running for a bit
|
|
21
|
+
|
|
22
|
+
await testdriver.assert('untitled document is visible');
|
|
23
|
+
|
|
24
|
+
// Stop dashcam and get the recording URL
|
|
25
|
+
const dashcamUrl = await testdriver.dashcam.stop();
|
|
26
|
+
if (dashcamUrl) {
|
|
27
|
+
console.log(`๐ฅ Dashcam recording: ${dashcamUrl}`);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packer AMI Integration Test
|
|
3
|
+
*
|
|
4
|
+
* Builds a fresh AMI via `packer build`, then runs the hover-image test suite
|
|
5
|
+
* against it. This is an end-to-end validation that a newly built runner image
|
|
6
|
+
* can provision a sandbox, execute commands, and interact with a browser.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* TD_API_ROOT=http://localhost:1337 \
|
|
10
|
+
* TD_API_KEY=<key> \
|
|
11
|
+
* npx vitest run examples/packer-hover-image.test.mjs
|
|
12
|
+
*
|
|
13
|
+
* The packer build takes ~25 minutes, and the hover-image test ~5-10 minutes,
|
|
14
|
+
* so the overall test timeout is set to 60 minutes.
|
|
15
|
+
*
|
|
16
|
+
* Set TD_SANDBOX_AMI to skip the packer build and use an existing AMI.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { describe, expect, it, beforeAll, afterAll } from "vitest";
|
|
20
|
+
import { TestDriver } from "../lib/vitest/hooks.mjs";
|
|
21
|
+
import { getDefaults } from "../examples/config.mjs";
|
|
22
|
+
import { execSync } from "child_process";
|
|
23
|
+
import path from "path";
|
|
24
|
+
import { fileURLToPath } from "url";
|
|
25
|
+
|
|
26
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
27
|
+
const __dirname = path.dirname(__filename);
|
|
28
|
+
const PACKER_DIR = path.resolve(__dirname, "../../runner/packer");
|
|
29
|
+
|
|
30
|
+
// 60 minute timeout for the entire suite (packer build + test)
|
|
31
|
+
const SUITE_TIMEOUT = 60 * 60 * 1000;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Build a fresh AMI using packer.
|
|
35
|
+
* Returns the AMI ID string (e.g. "ami-0337d8cd7cff854a4").
|
|
36
|
+
*/
|
|
37
|
+
function buildAmi() {
|
|
38
|
+
console.log("[packer] Starting AMI build โ this takes ~25 minutes...");
|
|
39
|
+
const startTime = Date.now();
|
|
40
|
+
|
|
41
|
+
// packer build outputs "us-east-2: ami-XXXX" on the last relevant line
|
|
42
|
+
// Use -machine-readable for reliable parsing
|
|
43
|
+
const output = execSync("packer build -machine-readable .", {
|
|
44
|
+
cwd: PACKER_DIR,
|
|
45
|
+
encoding: "utf-8",
|
|
46
|
+
timeout: 45 * 60 * 1000, // 45 minute hard limit on packer
|
|
47
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
48
|
+
env: { ...process.env },
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Machine-readable output has lines like:
|
|
52
|
+
// timestamp,target,type,data
|
|
53
|
+
// ...,artifact,0,id,us-east-2:ami-XXXXXXXXXXXX
|
|
54
|
+
const amiMatch = output.match(/,artifact,\d+,id,[\w-]+:(ami-[a-f0-9]+)/);
|
|
55
|
+
if (!amiMatch) {
|
|
56
|
+
// Fallback: try human-readable format
|
|
57
|
+
const humanMatch = output.match(/[\w-]+:\s*(ami-[a-f0-9]+)/);
|
|
58
|
+
if (!humanMatch) {
|
|
59
|
+
console.error("[packer] Build output (last 2000 chars):", output.slice(-2000));
|
|
60
|
+
throw new Error("Failed to extract AMI ID from packer build output");
|
|
61
|
+
}
|
|
62
|
+
const elapsed = ((Date.now() - startTime) / 1000 / 60).toFixed(1);
|
|
63
|
+
console.log(`[packer] AMI built: ${humanMatch[1]} (${elapsed} min)`);
|
|
64
|
+
return humanMatch[1];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const amiId = amiMatch[1];
|
|
68
|
+
const elapsed = ((Date.now() - startTime) / 1000 / 60).toFixed(1);
|
|
69
|
+
console.log(`[packer] AMI built: ${amiId} (${elapsed} min)`);
|
|
70
|
+
return amiId;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Deregister an AMI and delete its backing snapshot.
|
|
75
|
+
* Best-effort โ failures are logged but don't fail the test.
|
|
76
|
+
*/
|
|
77
|
+
function cleanupAmi(amiId) {
|
|
78
|
+
if (!amiId) return;
|
|
79
|
+
try {
|
|
80
|
+
console.log(`[cleanup] Deregistering AMI ${amiId}...`);
|
|
81
|
+
// Get snapshot IDs before deregistering
|
|
82
|
+
const describeOutput = execSync(
|
|
83
|
+
`aws ec2 describe-images --image-ids ${amiId} --query "Images[0].BlockDeviceMappings[*].Ebs.SnapshotId" --output text`,
|
|
84
|
+
{ encoding: "utf-8", timeout: 15000 },
|
|
85
|
+
).trim();
|
|
86
|
+
|
|
87
|
+
execSync(`aws ec2 deregister-image --image-id ${amiId}`, {
|
|
88
|
+
timeout: 15000,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Delete backing snapshots
|
|
92
|
+
if (describeOutput && describeOutput !== "None") {
|
|
93
|
+
for (const snapId of describeOutput.split(/\s+/)) {
|
|
94
|
+
if (snapId.startsWith("snap-")) {
|
|
95
|
+
console.log(`[cleanup] Deleting snapshot ${snapId}...`);
|
|
96
|
+
execSync(`aws ec2 delete-snapshot --snapshot-id ${snapId}`, {
|
|
97
|
+
timeout: 15000,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
console.log(`[cleanup] AMI ${amiId} cleaned up`);
|
|
103
|
+
} catch (err) {
|
|
104
|
+
console.warn(`[cleanup] Failed to clean up AMI ${amiId}: ${err.message}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// โโ Hover-Image login helper โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
109
|
+
|
|
110
|
+
async function performLogin(client, username = "standard_user") {
|
|
111
|
+
await client.focusApplication("Google Chrome");
|
|
112
|
+
const password = await client.extract("the password");
|
|
113
|
+
const usernameField = await client.find("username input");
|
|
114
|
+
await usernameField.click();
|
|
115
|
+
await client.type(username);
|
|
116
|
+
await client.pressKeys(["tab"]);
|
|
117
|
+
await client.type(password, { secret: true });
|
|
118
|
+
await client.pressKeys(["tab"]);
|
|
119
|
+
await client.pressKeys(["enter"]);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// โโ Test Suite โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
123
|
+
|
|
124
|
+
describe("Packer AMI โ Hover Image", { timeout: SUITE_TIMEOUT }, () => {
|
|
125
|
+
let amiId;
|
|
126
|
+
let builtAmi = false;
|
|
127
|
+
|
|
128
|
+
beforeAll(() => {
|
|
129
|
+
// If TD_SANDBOX_AMI is set, skip the packer build
|
|
130
|
+
if (process.env.TD_SANDBOX_AMI) {
|
|
131
|
+
amiId = process.env.TD_SANDBOX_AMI;
|
|
132
|
+
console.log(`[packer] Using existing AMI: ${amiId}`);
|
|
133
|
+
} else {
|
|
134
|
+
amiId = buildAmi();
|
|
135
|
+
builtAmi = true;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
afterAll(() => {
|
|
140
|
+
// Only clean up AMIs we built (don't delete pre-existing ones)
|
|
141
|
+
if (builtAmi && amiId && process.env.TD_PACKER_CLEANUP !== "false") {
|
|
142
|
+
cleanupAmi(amiId);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it(
|
|
147
|
+
"should click on shopping cart icon and verify empty cart",
|
|
148
|
+
{ timeout: SUITE_TIMEOUT },
|
|
149
|
+
async (context) => {
|
|
150
|
+
const testdriver = TestDriver(context, {
|
|
151
|
+
...getDefaults(context),
|
|
152
|
+
os: "windows",
|
|
153
|
+
sandboxAmi: amiId,
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Provision Chrome on the freshly-built AMI
|
|
157
|
+
await testdriver.provision.chrome({
|
|
158
|
+
url: "http://testdriver-sandbox.vercel.app/login",
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Perform login
|
|
162
|
+
await performLogin(testdriver);
|
|
163
|
+
|
|
164
|
+
// Click on the shopping cart icon
|
|
165
|
+
await testdriver.focusApplication("Google Chrome");
|
|
166
|
+
const cartIcon = await testdriver.find(
|
|
167
|
+
"shopping cart icon next to the Cart text in the top right corner",
|
|
168
|
+
);
|
|
169
|
+
await cartIcon.click();
|
|
170
|
+
|
|
171
|
+
// Assert that you see an empty shopping cart
|
|
172
|
+
const result = await testdriver.assert("Your cart is empty");
|
|
173
|
+
expect(result).toBeTruthy();
|
|
174
|
+
},
|
|
175
|
+
);
|
|
176
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TestDriver SDK - Scroll Until Text Test (Vitest)
|
|
3
|
+
* Converted from: testdriver/acceptance/scroll-until-text.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
|
+
/**
|
|
11
|
+
* Perform login flow for SauceLabs demo app
|
|
12
|
+
* @param {TestDriver} client - TestDriver client
|
|
13
|
+
* @param {string} username - Username (default: 'standard_user')
|
|
14
|
+
*/
|
|
15
|
+
async function performLogin(client, username = "standard_user") {
|
|
16
|
+
await client.focusApplication("Google Chrome");
|
|
17
|
+
const password = await client.extract("the password");
|
|
18
|
+
const usernameField = await client.find(
|
|
19
|
+
"username input",
|
|
20
|
+
);
|
|
21
|
+
await usernameField.click();
|
|
22
|
+
await client.type(username);
|
|
23
|
+
await client.pressKeys(["tab"]);
|
|
24
|
+
await client.type(password, { secret: true });
|
|
25
|
+
await client.pressKeys(["tab"]);
|
|
26
|
+
await client.pressKeys(["enter"]);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe("Scroll Until Text Test", () => {
|
|
30
|
+
it('should scroll until "testdriver socks" appears', async (context) => {
|
|
31
|
+
const testdriver = TestDriver(context, { ...getDefaults(context), headless: true });
|
|
32
|
+
await testdriver.provision.chrome({ url: 'http://testdriver-sandbox.vercel.app/login' });
|
|
33
|
+
|
|
34
|
+
//
|
|
35
|
+
// Perform login first
|
|
36
|
+
await performLogin(testdriver);
|
|
37
|
+
|
|
38
|
+
// Scroll until text appears
|
|
39
|
+
await testdriver.focusApplication("Google Chrome");
|
|
40
|
+
|
|
41
|
+
await testdriver.find('TestDriver.ai Sandbox heading').click();
|
|
42
|
+
|
|
43
|
+
// Scroll until text appears
|
|
44
|
+
let found = false;
|
|
45
|
+
let scrollCount = 0;
|
|
46
|
+
const maxScrolls = 10;
|
|
47
|
+
|
|
48
|
+
while (!found && scrollCount < maxScrolls) {
|
|
49
|
+
const findResult = await testdriver.find("testdriver socks product text is fully visible");
|
|
50
|
+
|
|
51
|
+
if (findResult.found()) {
|
|
52
|
+
found = true;
|
|
53
|
+
} else {
|
|
54
|
+
await testdriver.scroll();
|
|
55
|
+
scrollCount++;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!found) {
|
|
60
|
+
throw new Error(`Failed to find "testdriver socks" after ${maxScrolls} scrolls`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Assert testdriver socks appears on screen
|
|
64
|
+
await testdriver.focusApplication("Google Chrome");
|
|
65
|
+
const result = await testdriver.assert("TestDriver Socks appears on screen");
|
|
66
|
+
expect(result).toBeTruthy();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Test Init Command
|
|
5
|
+
*
|
|
6
|
+
* This script tests the `testdriverai init` command by:
|
|
7
|
+
* 1. Creating a temporary test project
|
|
8
|
+
* 2. Running the init command
|
|
9
|
+
* 3. Verifying all files were created correctly
|
|
10
|
+
* 4. Running the generated test
|
|
11
|
+
* 5. Cleaning up
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* node manual/test-init-command.js
|
|
15
|
+
*
|
|
16
|
+
* Requirements:
|
|
17
|
+
* - TD_API_KEY environment variable must be set
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const fs = require('fs');
|
|
21
|
+
const path = require('path');
|
|
22
|
+
const { execSync } = require('child_process');
|
|
23
|
+
const os = require('os');
|
|
24
|
+
|
|
25
|
+
// Colors for terminal output
|
|
26
|
+
const colors = {
|
|
27
|
+
reset: '\x1b[0m',
|
|
28
|
+
green: '\x1b[32m',
|
|
29
|
+
red: '\x1b[31m',
|
|
30
|
+
cyan: '\x1b[36m',
|
|
31
|
+
yellow: '\x1b[33m',
|
|
32
|
+
gray: '\x1b[90m',
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
function log(message, color = 'reset') {
|
|
36
|
+
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function success(message) {
|
|
40
|
+
log(`โ ${message}`, 'green');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function error(message) {
|
|
44
|
+
log(`โ ${message}`, 'red');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function info(message) {
|
|
48
|
+
log(message, 'cyan');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function step(message) {
|
|
52
|
+
log(`\n${message}`, 'cyan');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Main test function
|
|
56
|
+
async function testInitCommand() {
|
|
57
|
+
// Check for API key
|
|
58
|
+
if (!process.env.TD_API_KEY) {
|
|
59
|
+
error('TD_API_KEY environment variable is required');
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const testDir = path.join(os.tmpdir(), `test-init-${Date.now()}`);
|
|
64
|
+
const cliPath = path.join(__dirname, '..');
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
step('๐ฆ Creating test directory...');
|
|
68
|
+
fs.mkdirSync(testDir, { recursive: true });
|
|
69
|
+
success(`Created: ${testDir}`);
|
|
70
|
+
|
|
71
|
+
step('๐ง Setting up .env file...');
|
|
72
|
+
const envContent = `TD_API_KEY=${process.env.TD_API_KEY}\n`;
|
|
73
|
+
fs.writeFileSync(path.join(testDir, '.env'), envContent);
|
|
74
|
+
success('Created .env with API key');
|
|
75
|
+
|
|
76
|
+
step('๐ Running init command...');
|
|
77
|
+
try {
|
|
78
|
+
execSync(`node ${path.join(cliPath, 'bin/testdriverai.js')} init`, {
|
|
79
|
+
cwd: testDir,
|
|
80
|
+
stdio: 'inherit',
|
|
81
|
+
env: { ...process.env, TD_API_KEY: process.env.TD_API_KEY }
|
|
82
|
+
});
|
|
83
|
+
success('Init command completed');
|
|
84
|
+
} catch (err) {
|
|
85
|
+
error('Init command failed');
|
|
86
|
+
throw err;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
step('๐ Verifying project structure...');
|
|
90
|
+
|
|
91
|
+
const expectedFiles = [
|
|
92
|
+
'package.json',
|
|
93
|
+
'vitest.config.js',
|
|
94
|
+
'tests/example.test.js',
|
|
95
|
+
'tests/login.js',
|
|
96
|
+
'.env',
|
|
97
|
+
'.gitignore',
|
|
98
|
+
'.github/workflows/testdriver.yml'
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
for (const file of expectedFiles) {
|
|
102
|
+
const filePath = path.join(testDir, file);
|
|
103
|
+
if (!fs.existsSync(filePath)) {
|
|
104
|
+
error(`Missing file: ${file}`);
|
|
105
|
+
throw new Error(`Expected file not found: ${file}`);
|
|
106
|
+
}
|
|
107
|
+
success(`Found: ${file}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
step('๐ Verifying vitest.config.js contents...');
|
|
111
|
+
const vitestConfig = fs.readFileSync(path.join(testDir, 'vitest.config.js'), 'utf8');
|
|
112
|
+
|
|
113
|
+
if (!vitestConfig.includes('TestDriver()')) {
|
|
114
|
+
error('TestDriver reporter not found in vitest.config.js');
|
|
115
|
+
console.log(vitestConfig);
|
|
116
|
+
throw new Error('TestDriver reporter not configured');
|
|
117
|
+
}
|
|
118
|
+
success('TestDriver reporter is configured');
|
|
119
|
+
|
|
120
|
+
if (!vitestConfig.includes('setupFiles') || !vitestConfig.includes('testdriverai/vitest/setup')) {
|
|
121
|
+
error('setupFiles not configured correctly');
|
|
122
|
+
console.log(vitestConfig);
|
|
123
|
+
throw new Error('setupFiles not configured');
|
|
124
|
+
}
|
|
125
|
+
success('setupFiles is configured correctly');
|
|
126
|
+
|
|
127
|
+
if (!vitestConfig.includes('reporters')) {
|
|
128
|
+
error('reporters array not found');
|
|
129
|
+
console.log(vitestConfig);
|
|
130
|
+
throw new Error('reporters not configured');
|
|
131
|
+
}
|
|
132
|
+
success('reporters array includes TestDriver');
|
|
133
|
+
|
|
134
|
+
step('๐ Verifying example test contents...');
|
|
135
|
+
const testFile = fs.readFileSync(path.join(testDir, 'tests/example.test.js'), 'utf8');
|
|
136
|
+
|
|
137
|
+
if (!testFile.includes('.provision.chrome')) {
|
|
138
|
+
error('Test does not use .provision.chrome');
|
|
139
|
+
console.log(testFile);
|
|
140
|
+
throw new Error('Test does not use .provision pattern');
|
|
141
|
+
}
|
|
142
|
+
success('Test uses .provision.chrome');
|
|
143
|
+
|
|
144
|
+
if (!testFile.includes("from 'testdriverai/vitest/hooks'")) {
|
|
145
|
+
error('Test does not import from testdriverai/vitest/hooks');
|
|
146
|
+
console.log(testFile);
|
|
147
|
+
throw new Error('Test does not import TestDriver from vitest/hooks');
|
|
148
|
+
}
|
|
149
|
+
success('Test imports TestDriver from vitest/hooks');
|
|
150
|
+
|
|
151
|
+
if (!testFile.includes("from './login.js'")) {
|
|
152
|
+
error('Test does not import login from ./login.js');
|
|
153
|
+
console.log(testFile);
|
|
154
|
+
throw new Error('Test does not import login snippet');
|
|
155
|
+
}
|
|
156
|
+
success('Test imports login snippet');
|
|
157
|
+
|
|
158
|
+
step('๐ Verifying login snippet contents...');
|
|
159
|
+
const loginFile = fs.readFileSync(path.join(testDir, 'tests/login.js'), 'utf8');
|
|
160
|
+
|
|
161
|
+
if (!loginFile.includes('.extract(')) {
|
|
162
|
+
error('Login snippet does not use .extract()');
|
|
163
|
+
console.log(loginFile);
|
|
164
|
+
throw new Error('Login snippet does not demonstrate .extract()');
|
|
165
|
+
}
|
|
166
|
+
success('Login snippet demonstrates .extract()');
|
|
167
|
+
|
|
168
|
+
if (!loginFile.includes('secret: true')) {
|
|
169
|
+
error('Login snippet does not use secret option');
|
|
170
|
+
console.log(loginFile);
|
|
171
|
+
throw new Error('Login snippet does not demonstrate secret typing');
|
|
172
|
+
}
|
|
173
|
+
success('Login snippet demonstrates secret typing');
|
|
174
|
+
|
|
175
|
+
step('๐งช Running generated test...');
|
|
176
|
+
try {
|
|
177
|
+
execSync('npm test', {
|
|
178
|
+
cwd: testDir,
|
|
179
|
+
stdio: 'inherit',
|
|
180
|
+
env: { ...process.env, TD_API_KEY: process.env.TD_API_KEY }
|
|
181
|
+
});
|
|
182
|
+
success('Test execution completed successfully');
|
|
183
|
+
} catch (err) {
|
|
184
|
+
error('Test execution failed');
|
|
185
|
+
throw err;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
step('โ
All checks passed!');
|
|
189
|
+
log('\nTest summary:', 'green');
|
|
190
|
+
log(' โข Init command executed successfully', 'green');
|
|
191
|
+
log(' โข All expected files created', 'green');
|
|
192
|
+
log(' โข Configuration files are correct', 'green');
|
|
193
|
+
log(' โข Example test has proper patterns', 'green');
|
|
194
|
+
log(' โข Generated test runs successfully', 'green');
|
|
195
|
+
|
|
196
|
+
} catch (err) {
|
|
197
|
+
step('โ Test failed!');
|
|
198
|
+
error(err.message);
|
|
199
|
+
if (err.stack) {
|
|
200
|
+
log(err.stack, 'gray');
|
|
201
|
+
}
|
|
202
|
+
process.exit(1);
|
|
203
|
+
} finally {
|
|
204
|
+
// Optional: Clean up test directory
|
|
205
|
+
// Commented out so you can inspect the generated files
|
|
206
|
+
// step('๐งน Cleaning up...');
|
|
207
|
+
// if (fs.existsSync(testDir)) {
|
|
208
|
+
// fs.rmSync(testDir, { recursive: true, force: true });
|
|
209
|
+
// success('Cleaned up test directory');
|
|
210
|
+
// }
|
|
211
|
+
|
|
212
|
+
info(`\nTest project preserved at: ${testDir}`);
|
|
213
|
+
info('To clean up manually, run:');
|
|
214
|
+
log(` rm -rf ${testDir}`, 'gray');
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Run the test
|
|
219
|
+
testInitCommand().catch(err => {
|
|
220
|
+
error('Unexpected error:');
|
|
221
|
+
console.error(err);
|
|
222
|
+
process.exit(1);
|
|
223
|
+
});
|