testdriverai 7.0.0 → 7.1.1
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/.env.example +2 -0
- package/.github/workflows/linux-tests.yml +28 -0
- package/README.md +126 -0
- package/agent/index.js +7 -9
- package/agent/interface.js +13 -2
- package/agent/lib/commands.js +795 -136
- package/agent/lib/redraw.js +124 -39
- package/agent/lib/sandbox.js +40 -3
- package/agent/lib/sdk.js +21 -0
- package/agent/lib/valid-version.js +2 -2
- package/debugger/index.html +1 -1
- package/docs/docs.json +86 -71
- package/docs/guide/best-practices-polling.mdx +154 -0
- package/docs/v6/getting-started/self-hosting.mdx +3 -2
- package/docs/v7/_drafts/agents.mdx +852 -0
- package/docs/v7/_drafts/auto-cache-key.mdx +167 -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 +400 -0
- package/docs/v7/_drafts/caching.mdx +366 -0
- package/docs/v7/_drafts/cli-to-sdk-migration.mdx +425 -0
- package/docs/v7/_drafts/core.mdx +459 -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/implementation-plan.mdx +994 -0
- package/docs/v7/_drafts/init-command.mdx +95 -0
- package/docs/v7/_drafts/optimal-sdk-design.mdx +1348 -0
- package/docs/v7/_drafts/performance.mdx +517 -0
- package/docs/v7/_drafts/presets.mdx +210 -0
- package/docs/v7/_drafts/progressive-disclosure.mdx +230 -0
- package/docs/v7/_drafts/provision.mdx +266 -0
- package/docs/{QUICK_START_TEST_RECORDING.md → v7/_drafts/quick-start-test-recording.mdx} +3 -3
- package/docs/v7/_drafts/sdk-v7-complete.mdx +345 -0
- package/docs/v7/{guides → _drafts}/self-hosting.mdx +1 -1
- 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/api/{ai.mdx → act.mdx} +24 -24
- package/docs/v7/api/client.mdx +1 -1
- package/docs/v7/api/dashcam.mdx +497 -0
- package/docs/v7/api/doubleClick.mdx +102 -0
- package/docs/v7/api/elements.mdx +143 -41
- package/docs/v7/api/find.mdx +258 -0
- package/docs/v7/api/mouseDown.mdx +161 -0
- package/docs/v7/api/mouseUp.mdx +164 -0
- package/docs/v7/api/rightClick.mdx +123 -0
- package/docs/v7/api/type.mdx +51 -7
- package/docs/v7/features/ai-native.mdx +427 -0
- package/docs/v7/features/easy-to-write.mdx +351 -0
- package/docs/v7/features/enterprise.mdx +540 -0
- package/docs/v7/features/fast.mdx +424 -0
- package/docs/v7/features/observable.mdx +623 -0
- package/docs/v7/features/powerful.mdx +531 -0
- package/docs/v7/features/scalable.mdx +417 -0
- package/docs/v7/features/stable.mdx +514 -0
- package/docs/v7/getting-started/configuration.mdx +380 -0
- package/docs/v7/getting-started/generating-tests.mdx +525 -0
- package/docs/v7/getting-started/installation.mdx +486 -0
- package/docs/v7/getting-started/quickstart.mdx +320 -141
- package/docs/v7/getting-started/running-and-debugging.mdx +511 -0
- package/docs/v7/getting-started/setting-up-in-ci.mdx +612 -0
- package/docs/v7/getting-started/writing-tests.mdx +535 -0
- package/docs/v7/overview/what-is-testdriver.mdx +398 -0
- package/docs/v7/platforms/linux.mdx +308 -0
- package/docs/v7/platforms/macos.mdx +433 -0
- package/docs/v7/platforms/windows.mdx +430 -0
- package/docs/v7/playwright.mdx +3 -3
- package/docs/v7/presets/chrome-extension.mdx +223 -0
- package/docs/v7/presets/chrome.mdx +303 -0
- package/docs/v7/presets/electron.mdx +453 -0
- package/docs/v7/presets/vscode.mdx +417 -0
- package/docs/v7/presets/webapp.mdx +396 -0
- package/examples/run-tests-with-recording.sh +2 -2
- package/interfaces/cli/commands/init.js +358 -0
- package/interfaces/vitest-plugin.mjs +393 -103
- package/lib/core/Dashcam.js +506 -0
- package/lib/core/index.d.ts +150 -0
- package/lib/core/index.js +12 -0
- package/lib/presets/index.mjs +331 -0
- package/lib/vitest/hooks.d.ts +119 -0
- package/lib/vitest/hooks.mjs +316 -0
- package/lib/vitest/setup.mjs +44 -0
- package/package.json +13 -3
- package/sdk.d.ts +350 -44
- package/sdk.js +818 -105
- package/{self-hosted.yml → setup/aws/self-hosted.yml} +1 -1
- package/test/manual/test-console-logs.test.mjs +42 -0
- package/test/manual/test-init.sh +54 -0
- package/test/manual/test-provision-auth.mjs +22 -0
- package/test/testdriver/assert.test.mjs +41 -0
- package/test/testdriver/auto-cache-key-demo.test.mjs +56 -0
- package/test/testdriver/chrome-extension.test.mjs +89 -0
- package/{testdriver/acceptance-sdk → test/testdriver}/drag-and-drop.test.mjs +7 -19
- package/{testdriver/acceptance-sdk → test/testdriver}/element-not-found.test.mjs +6 -19
- package/{testdriver/acceptance-sdk → test/testdriver}/exec-js.test.mjs +6 -18
- package/{testdriver/acceptance-sdk → test/testdriver}/exec-output.test.mjs +9 -21
- package/{testdriver/acceptance-sdk → test/testdriver}/exec-pwsh.test.mjs +14 -26
- package/{testdriver/acceptance-sdk → test/testdriver}/focus-window.test.mjs +8 -20
- package/{testdriver/acceptance-sdk → test/testdriver}/formatted-logging.test.mjs +5 -20
- package/{testdriver/acceptance-sdk → test/testdriver}/hover-image.test.mjs +10 -19
- package/{testdriver/acceptance-sdk → test/testdriver}/hover-text-with-description.test.mjs +7 -19
- package/{testdriver/acceptance-sdk → test/testdriver}/hover-text.test.mjs +5 -19
- package/{testdriver/acceptance-sdk → test/testdriver}/match-image.test.mjs +7 -19
- package/{testdriver/acceptance-sdk → test/testdriver}/press-keys.test.mjs +5 -19
- package/{testdriver/acceptance-sdk → test/testdriver}/prompt.test.mjs +7 -19
- package/{testdriver/acceptance-sdk → test/testdriver}/scroll-keyboard.test.mjs +6 -20
- package/{testdriver/acceptance-sdk → test/testdriver}/scroll-until-image.test.mjs +6 -18
- package/test/testdriver/scroll-until-text.test.mjs +28 -0
- package/{testdriver/acceptance-sdk → test/testdriver}/scroll.test.mjs +12 -21
- package/test/testdriver/setup/lifecycleHelpers.mjs +262 -0
- package/{testdriver/acceptance-sdk → test/testdriver}/setup/testHelpers.mjs +25 -20
- package/test/testdriver/type.test.mjs +45 -0
- package/vitest.config.mjs +11 -56
- package/.github/dependabot.yml +0 -11
- package/.github/workflows/acceptance-linux.yml +0 -75
- package/.github/workflows/acceptance-sdk-tests.yml +0 -133
- package/.github/workflows/acceptance-tests.yml +0 -130
- package/.github/workflows/lint.yml +0 -27
- package/.github/workflows/publish-canary.yml +0 -40
- package/.github/workflows/publish-latest.yml +0 -61
- package/.github/workflows/test-install.yml +0 -29
- package/.vscode/extensions.json +0 -3
- package/.vscode/launch.json +0 -22
- package/.vscode/mcp.json +0 -9
- package/.vscode/settings.json +0 -14
- package/CODEOWNERS +0 -3
- package/MIGRATION.md +0 -389
- package/SDK_README.md +0 -1122
- package/_testdriver/acceptance/assert.yaml +0 -7
- package/_testdriver/acceptance/dashcam.yaml +0 -9
- package/_testdriver/acceptance/drag-and-drop.yaml +0 -49
- package/_testdriver/acceptance/embed.yaml +0 -9
- package/_testdriver/acceptance/exec-js.yaml +0 -29
- package/_testdriver/acceptance/exec-output.yaml +0 -43
- package/_testdriver/acceptance/exec-shell.yaml +0 -40
- package/_testdriver/acceptance/focus-window.yaml +0 -16
- package/_testdriver/acceptance/hover-image.yaml +0 -18
- package/_testdriver/acceptance/hover-text-with-description.yaml +0 -29
- package/_testdriver/acceptance/hover-text.yaml +0 -14
- package/_testdriver/acceptance/if-else.yaml +0 -31
- package/_testdriver/acceptance/match-image.yaml +0 -15
- package/_testdriver/acceptance/press-keys.yaml +0 -35
- package/_testdriver/acceptance/prompt.yaml +0 -11
- package/_testdriver/acceptance/remember.yaml +0 -27
- package/_testdriver/acceptance/screenshots/cart.png +0 -0
- package/_testdriver/acceptance/scroll-keyboard.yaml +0 -34
- package/_testdriver/acceptance/scroll-until-image.yaml +0 -26
- package/_testdriver/acceptance/scroll-until-text.yaml +0 -20
- package/_testdriver/acceptance/scroll.yaml +0 -33
- package/_testdriver/acceptance/snippets/login.yaml +0 -29
- package/_testdriver/acceptance/snippets/match-cart.yaml +0 -8
- package/_testdriver/acceptance/type.yaml +0 -29
- package/_testdriver/behavior/failure.yaml +0 -7
- package/_testdriver/behavior/hover-text.yaml +0 -13
- package/_testdriver/behavior/lifecycle/postrun.yaml +0 -10
- package/_testdriver/behavior/lifecycle/prerun.yaml +0 -8
- package/_testdriver/behavior/lifecycle/provision.yaml +0 -8
- package/_testdriver/behavior/secrets.yaml +0 -7
- package/_testdriver/edge-cases/dashcam-chrome.yaml +0 -8
- package/_testdriver/edge-cases/exec-pwsh-multiline.yaml +0 -10
- package/_testdriver/edge-cases/js-exception.yaml +0 -8
- package/_testdriver/edge-cases/js-promise.yaml +0 -19
- package/_testdriver/edge-cases/lifecycle/postrun.yaml +0 -10
- package/_testdriver/edge-cases/prompt-in-middle.yaml +0 -23
- package/_testdriver/edge-cases/prompt-nested.yaml +0 -7
- package/_testdriver/edge-cases/success-test.yaml +0 -9
- package/_testdriver/examples/android/example.yaml +0 -12
- package/_testdriver/examples/android/lifecycle/postrun.yaml +0 -11
- package/_testdriver/examples/android/lifecycle/provision.yaml +0 -47
- package/_testdriver/examples/android/readme.md +0 -7
- package/_testdriver/examples/chrome-extension/lifecycle/provision.yaml +0 -74
- package/_testdriver/examples/desktop/lifecycle/prerun.yaml +0 -0
- package/_testdriver/examples/desktop/lifecycle/provision.yaml +0 -64
- package/_testdriver/examples/vscode-extension/lifecycle/provision.yaml +0 -73
- package/_testdriver/examples/web/lifecycle/postrun.yaml +0 -7
- package/_testdriver/examples/web/lifecycle/prerun.yaml +0 -22
- package/_testdriver/lifecycle/postrun.yaml +0 -8
- package/_testdriver/lifecycle/prerun.yaml +0 -15
- package/_testdriver/lifecycle/provision.yaml +0 -25
- package/debug-screenshot-1763401388589.png +0 -0
- package/mcp-server/AI_GUIDELINES.md +0 -57
- package/scripts/view-test-results.mjs +0 -96
- package/styles/.vale-config/2-MDX.ini +0 -5
- package/styles/Microsoft/AMPM.yml +0 -9
- package/styles/Microsoft/Accessibility.yml +0 -30
- package/styles/Microsoft/Acronyms.yml +0 -64
- package/styles/Microsoft/Adverbs.yml +0 -272
- package/styles/Microsoft/Auto.yml +0 -11
- package/styles/Microsoft/Avoid.yml +0 -14
- package/styles/Microsoft/Contractions.yml +0 -50
- package/styles/Microsoft/Dashes.yml +0 -13
- package/styles/Microsoft/DateFormat.yml +0 -8
- package/styles/Microsoft/DateNumbers.yml +0 -40
- package/styles/Microsoft/DateOrder.yml +0 -8
- package/styles/Microsoft/Ellipses.yml +0 -9
- package/styles/Microsoft/FirstPerson.yml +0 -16
- package/styles/Microsoft/Foreign.yml +0 -13
- package/styles/Microsoft/Gender.yml +0 -8
- package/styles/Microsoft/GenderBias.yml +0 -42
- package/styles/Microsoft/GeneralURL.yml +0 -11
- package/styles/Microsoft/HeadingAcronyms.yml +0 -7
- package/styles/Microsoft/HeadingColons.yml +0 -8
- package/styles/Microsoft/HeadingPunctuation.yml +0 -13
- package/styles/Microsoft/Headings.yml +0 -28
- package/styles/Microsoft/Hyphens.yml +0 -14
- package/styles/Microsoft/Negative.yml +0 -13
- package/styles/Microsoft/Ordinal.yml +0 -13
- package/styles/Microsoft/OxfordComma.yml +0 -8
- package/styles/Microsoft/Passive.yml +0 -183
- package/styles/Microsoft/Percentages.yml +0 -7
- package/styles/Microsoft/Plurals.yml +0 -7
- package/styles/Microsoft/Quotes.yml +0 -7
- package/styles/Microsoft/RangeTime.yml +0 -13
- package/styles/Microsoft/Semicolon.yml +0 -8
- package/styles/Microsoft/SentenceLength.yml +0 -6
- package/styles/Microsoft/Spacing.yml +0 -8
- package/styles/Microsoft/Suspended.yml +0 -7
- package/styles/Microsoft/Terms.yml +0 -42
- package/styles/Microsoft/URLFormat.yml +0 -9
- package/styles/Microsoft/Units.yml +0 -16
- package/styles/Microsoft/Vocab.yml +0 -25
- package/styles/Microsoft/We.yml +0 -11
- package/styles/Microsoft/Wordiness.yml +0 -127
- package/styles/Microsoft/meta.json +0 -4
- package/styles/alex/Ablist.yml +0 -274
- package/styles/alex/Condescending.yml +0 -16
- package/styles/alex/Gendered.yml +0 -110
- package/styles/alex/LGBTQ.yml +0 -55
- package/styles/alex/OCD.yml +0 -10
- package/styles/alex/Press.yml +0 -12
- package/styles/alex/ProfanityLikely.yml +0 -1289
- package/styles/alex/ProfanityMaybe.yml +0 -282
- package/styles/alex/ProfanityUnlikely.yml +0 -251
- package/styles/alex/README.md +0 -27
- package/styles/alex/Race.yml +0 -85
- package/styles/alex/Suicide.yml +0 -26
- package/styles/alex/meta.json +0 -4
- package/styles/config/vocabularies/Docs/accept.txt +0 -47
- package/styles/config/vocabularies/Docs/reject.txt +0 -4
- package/styles/proselint/Airlinese.yml +0 -8
- package/styles/proselint/AnimalLabels.yml +0 -48
- package/styles/proselint/Annotations.yml +0 -9
- package/styles/proselint/Apologizing.yml +0 -8
- package/styles/proselint/Archaisms.yml +0 -52
- package/styles/proselint/But.yml +0 -8
- package/styles/proselint/Cliches.yml +0 -782
- package/styles/proselint/CorporateSpeak.yml +0 -30
- package/styles/proselint/Currency.yml +0 -5
- package/styles/proselint/Cursing.yml +0 -15
- package/styles/proselint/DateCase.yml +0 -7
- package/styles/proselint/DateMidnight.yml +0 -7
- package/styles/proselint/DateRedundancy.yml +0 -10
- package/styles/proselint/DateSpacing.yml +0 -7
- package/styles/proselint/DenizenLabels.yml +0 -52
- package/styles/proselint/Diacritical.yml +0 -95
- package/styles/proselint/GenderBias.yml +0 -45
- package/styles/proselint/GroupTerms.yml +0 -39
- package/styles/proselint/Hedging.yml +0 -8
- package/styles/proselint/Hyperbole.yml +0 -6
- package/styles/proselint/Jargon.yml +0 -11
- package/styles/proselint/LGBTOffensive.yml +0 -13
- package/styles/proselint/LGBTTerms.yml +0 -15
- package/styles/proselint/Malapropisms.yml +0 -8
- package/styles/proselint/Needless.yml +0 -358
- package/styles/proselint/Nonwords.yml +0 -38
- package/styles/proselint/Oxymorons.yml +0 -22
- package/styles/proselint/P-Value.yml +0 -6
- package/styles/proselint/RASSyndrome.yml +0 -30
- package/styles/proselint/README.md +0 -12
- package/styles/proselint/Skunked.yml +0 -13
- package/styles/proselint/Spelling.yml +0 -17
- package/styles/proselint/Typography.yml +0 -11
- package/styles/proselint/Uncomparables.yml +0 -50
- package/styles/proselint/Very.yml +0 -6
- package/styles/proselint/meta.json +0 -15
- package/styles/write-good/Cliches.yml +0 -702
- package/styles/write-good/E-Prime.yml +0 -32
- package/styles/write-good/Illusions.yml +0 -11
- package/styles/write-good/Passive.yml +0 -183
- package/styles/write-good/README.md +0 -27
- package/styles/write-good/So.yml +0 -5
- package/styles/write-good/ThereIs.yml +0 -6
- package/styles/write-good/TooWordy.yml +0 -221
- package/styles/write-good/Weasel.yml +0 -29
- package/styles/write-good/meta.json +0 -4
- package/test/mcp-example-test.yaml +0 -27
- package/test/test_parser.js +0 -47
- package/testdriver/acceptance-sdk/QUICK_REFERENCE.md +0 -61
- package/testdriver/acceptance-sdk/README.md +0 -128
- package/testdriver/acceptance-sdk/TEST_REPORTING.md +0 -245
- package/testdriver/acceptance-sdk/assert.test.mjs +0 -44
- package/testdriver/acceptance-sdk/scroll-until-text.test.mjs +0 -42
- package/testdriver/acceptance-sdk/setup/lifecycleHelpers.mjs +0 -239
- package/testdriver/acceptance-sdk/type-checking-demo.js +0 -49
- package/testdriver/acceptance-sdk/type.test.mjs +0 -84
- package/vale.ini +0 -18
- package/vitest.config.example.js +0 -19
- package/vitest.config.mjs.bak +0 -44
- /package/docs/{ARCHITECTURE.md → v7/_drafts/architecture.mdx} +0 -0
- /package/docs/{AWESOME_LOGS_QUICK_REF.md → v7/_drafts/awesome-logs-quick-ref.mdx} +0 -0
- /package/{CONTRIBUTING.md → docs/v7/_drafts/contributing.mdx} +0 -0
- /package/docs/v7/{guides → _drafts}/migration.mdx +0 -0
- /package/{PLUGIN_MIGRATION.md → docs/v7/_drafts/plugin-migration.mdx} +0 -0
- /package/{PROMPT_CACHE.md → docs/v7/_drafts/prompt-cache.mdx} +0 -0
- /package/docs/{SDK_AWESOME_LOGS.md → v7/_drafts/sdk-awesome-logs.mdx} +0 -0
- /package/docs/{sdk-browser-rendering.md → v7/_drafts/sdk-browser-rendering.mdx} +0 -0
- /package/{SDK_LOGGING.md → docs/v7/_drafts/sdk-logging.mdx} +0 -0
- /package/{SDK_MIGRATION.md → docs/v7/_drafts/sdk-migration.mdx} +0 -0
- /package/docs/{TEST_RECORDING.md → v7/_drafts/test-recording.mdx} +0 -0
- /package/docs/v7/{README.md → overview/readme.mdx} +0 -0
- /package/{debug-locate-response.js → test/manual/debug-locate-response.js} +0 -0
- /package/{test-find-api.js → test/manual/test-find-api.js} +0 -0
- /package/{test-prompt-cache.js → test/manual/test-prompt-cache.js} +0 -0
- /package/{test-sandbox-render.js → test/manual/test-sandbox-render.js} +0 -0
- /package/{test-sdk-methods.js → test/manual/test-sdk-methods.js} +0 -0
- /package/{test-sdk-refactor.js → test/manual/test-sdk-refactor.js} +0 -0
- /package/{test-stack-trace.mjs → test/manual/test-stack-trace.mjs} +0 -0
- /package/{verify-element-api.js → test/manual/verify-element-api.js} +0 -0
- /package/{verify-types.js → test/manual/verify-types.js} +0 -0
- /package/{testdriver/acceptance-sdk → test/testdriver}/setup/globalTeardown.mjs +0 -0
- /package/{testdriver/acceptance-sdk → test/testdriver}/setup/vitestSetup.mjs +0 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
const BaseCommand = require("../lib/base.js");
|
|
2
|
+
const { createCommandDefinitions } = require("../../../agent/interface.js");
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const chalk = require("chalk");
|
|
6
|
+
const { execSync } = require("child_process");
|
|
7
|
+
const readline = require("readline");
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Init command - scaffolds Vitest SDK example tests for TestDriver
|
|
11
|
+
*/
|
|
12
|
+
class InitCommand extends BaseCommand {
|
|
13
|
+
async run() {
|
|
14
|
+
await this.parse(InitCommand);
|
|
15
|
+
|
|
16
|
+
console.log(chalk.cyan("\n🚀 Initializing TestDriver project...\n"));
|
|
17
|
+
|
|
18
|
+
await this.setupPackageJson();
|
|
19
|
+
await this.createVitestExample();
|
|
20
|
+
await this.createGitHubWorkflow();
|
|
21
|
+
await this.createGitignore();
|
|
22
|
+
await this.installDependencies();
|
|
23
|
+
await this.promptForApiKey();
|
|
24
|
+
|
|
25
|
+
console.log(chalk.green("\n✅ Project initialized successfully!\n"));
|
|
26
|
+
this.printNextSteps();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Prompt user for API key and save to .env
|
|
31
|
+
*/
|
|
32
|
+
async promptForApiKey() {
|
|
33
|
+
const envPath = path.join(process.cwd(), ".env");
|
|
34
|
+
|
|
35
|
+
// Check if .env already exists with TD_API_KEY
|
|
36
|
+
if (fs.existsSync(envPath)) {
|
|
37
|
+
const envContent = fs.readFileSync(envPath, "utf8");
|
|
38
|
+
if (envContent.includes("TD_API_KEY=")) {
|
|
39
|
+
console.log(chalk.gray("\n API key already configured in .env, skipping...\n"));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
console.log(chalk.cyan(" Setting up your TestDriver API key...\n"));
|
|
45
|
+
console.log(chalk.gray(" Get your API key from: https://console.testdriver.ai/team"));
|
|
46
|
+
|
|
47
|
+
// Ask if user wants to open the browser
|
|
48
|
+
const shouldOpen = await this.askYesNo(" Open API keys page in browser? (Y/n): ");
|
|
49
|
+
if (shouldOpen) {
|
|
50
|
+
try {
|
|
51
|
+
// Dynamic import for ES module
|
|
52
|
+
const open = (await import("open")).default;
|
|
53
|
+
await open("https://console.testdriver.ai/team");
|
|
54
|
+
console.log(chalk.gray(" Opening browser...\n"));
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.log(chalk.yellow(" ⚠️ Could not open browser automatically\n"));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Prompt for API key with hidden input
|
|
61
|
+
const apiKey = await this.promptHidden(" Enter your API key (input will be hidden): ");
|
|
62
|
+
|
|
63
|
+
if (apiKey && apiKey.trim()) {
|
|
64
|
+
// Save to .env
|
|
65
|
+
const envContent = fs.existsSync(envPath)
|
|
66
|
+
? fs.readFileSync(envPath, "utf8") + "\n"
|
|
67
|
+
: "";
|
|
68
|
+
|
|
69
|
+
fs.writeFileSync(envPath, envContent + `TD_API_KEY=${apiKey.trim()}\n`);
|
|
70
|
+
console.log(chalk.green("\n ✓ API key saved to .env\n"));
|
|
71
|
+
} else {
|
|
72
|
+
console.log(chalk.yellow("\n ⚠️ No API key entered. You can add it later to .env:\n"));
|
|
73
|
+
console.log(chalk.gray(" TD_API_KEY=your_api_key\n"));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Prompt for hidden input (like password)
|
|
79
|
+
*/
|
|
80
|
+
async promptHidden(question) {
|
|
81
|
+
return new Promise((resolve) => {
|
|
82
|
+
const rl = readline.createInterface({
|
|
83
|
+
input: process.stdin,
|
|
84
|
+
output: process.stdout,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Mute output to hide the input
|
|
88
|
+
const stdin = process.stdin;
|
|
89
|
+
const muted = {
|
|
90
|
+
write: () => {},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
rl.question(question, (answer) => {
|
|
94
|
+
rl.close();
|
|
95
|
+
stdin.removeListener("data", muted.write);
|
|
96
|
+
console.log(""); // New line after hidden input
|
|
97
|
+
resolve(answer);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Mute stdin to hide input
|
|
101
|
+
stdin.on("data", (char) => {
|
|
102
|
+
// Don't write to output (hides the input)
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Ask a yes/no question
|
|
109
|
+
*/
|
|
110
|
+
async askYesNo(question) {
|
|
111
|
+
return new Promise((resolve) => {
|
|
112
|
+
const rl = readline.createInterface({
|
|
113
|
+
input: process.stdin,
|
|
114
|
+
output: process.stdout,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
rl.question(question, (answer) => {
|
|
118
|
+
rl.close();
|
|
119
|
+
const normalized = answer.toLowerCase().trim();
|
|
120
|
+
resolve(normalized === "" || normalized === "y" || normalized === "yes");
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Setup package.json if it doesn't exist
|
|
127
|
+
*/
|
|
128
|
+
async setupPackageJson() {
|
|
129
|
+
const packageJsonPath = path.join(process.cwd(), "package.json");
|
|
130
|
+
|
|
131
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
132
|
+
console.log(chalk.gray(" Creating package.json..."));
|
|
133
|
+
|
|
134
|
+
const packageJson = {
|
|
135
|
+
name: path.basename(process.cwd()),
|
|
136
|
+
version: "1.0.0",
|
|
137
|
+
description: "TestDriver.ai test suite",
|
|
138
|
+
type: "module",
|
|
139
|
+
scripts: {
|
|
140
|
+
test: "vitest run",
|
|
141
|
+
"test:watch": "vitest",
|
|
142
|
+
"test:ui": "vitest --ui"
|
|
143
|
+
},
|
|
144
|
+
keywords: ["testdriver", "testing", "e2e"],
|
|
145
|
+
author: "",
|
|
146
|
+
license: "ISC"
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n");
|
|
150
|
+
console.log(chalk.green(` Created package.json`));
|
|
151
|
+
} else {
|
|
152
|
+
console.log(chalk.gray(" package.json already exists, skipping..."));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Create a Vitest SDK example
|
|
158
|
+
*/
|
|
159
|
+
async createVitestExample() {
|
|
160
|
+
const testDir = path.join(process.cwd(), "tests");
|
|
161
|
+
const testFile = path.join(testDir, "example.test.js");
|
|
162
|
+
const configFile = path.join(process.cwd(), "vitest.config.js");
|
|
163
|
+
|
|
164
|
+
// Create test directory if it doesn't exist
|
|
165
|
+
if (!fs.existsSync(testDir)) {
|
|
166
|
+
fs.mkdirSync(testDir, { recursive: true });
|
|
167
|
+
console.log(chalk.gray(` Created directory: ${testDir}`));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Create example Vitest test
|
|
171
|
+
const vitestContent = `import { test, expect } from 'vitest';
|
|
172
|
+
import { chrome } from 'testdriverai/presets';
|
|
173
|
+
|
|
174
|
+
test('should navigate to example.com and find elements', async (context) => {
|
|
175
|
+
// The chrome preset handles connection, browser launch, and cleanup automatically
|
|
176
|
+
const { testdriver } = await chrome(context, {
|
|
177
|
+
url: 'https://example.com'
|
|
178
|
+
// apiKey automatically read from process.env.TD_API_KEY via .env file
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Find and verify elements
|
|
182
|
+
const heading = await testdriver.find('heading that says Example Domain');
|
|
183
|
+
expect(heading.found()).toBe(true);
|
|
184
|
+
|
|
185
|
+
const link = await testdriver.find('More information link');
|
|
186
|
+
expect(link.found()).toBe(true);
|
|
187
|
+
});
|
|
188
|
+
`;
|
|
189
|
+
|
|
190
|
+
fs.writeFileSync(testFile, vitestContent);
|
|
191
|
+
console.log(chalk.green(` Created test file: ${testFile}`));
|
|
192
|
+
|
|
193
|
+
// Create vitest config if it doesn't exist
|
|
194
|
+
if (!fs.existsSync(configFile)) {
|
|
195
|
+
const configContent = `import { defineConfig } from 'vitest/config';
|
|
196
|
+
import TestDriver from 'testdriverai/vitest';
|
|
197
|
+
import dotenv from 'dotenv';
|
|
198
|
+
|
|
199
|
+
// Load environment variables from .env file
|
|
200
|
+
dotenv.config();
|
|
201
|
+
|
|
202
|
+
export default defineConfig({
|
|
203
|
+
plugins: [TestDriver()],
|
|
204
|
+
test: {
|
|
205
|
+
testTimeout: 120000,
|
|
206
|
+
hookTimeout: 120000,
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
`;
|
|
210
|
+
|
|
211
|
+
fs.writeFileSync(configFile, configContent);
|
|
212
|
+
console.log(chalk.green(` Created config file: ${configFile}`));
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Create or update .gitignore to include .env
|
|
219
|
+
*/
|
|
220
|
+
async createGitignore() {
|
|
221
|
+
const gitignorePath = path.join(process.cwd(), ".gitignore");
|
|
222
|
+
|
|
223
|
+
let gitignoreContent = "";
|
|
224
|
+
if (fs.existsSync(gitignorePath)) {
|
|
225
|
+
gitignoreContent = fs.readFileSync(gitignorePath, "utf8");
|
|
226
|
+
|
|
227
|
+
// Check if .env is already in .gitignore
|
|
228
|
+
if (gitignoreContent.includes(".env")) {
|
|
229
|
+
console.log(chalk.gray(" .env already in .gitignore, skipping..."));
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Add common ignores including .env
|
|
235
|
+
const ignoresToAdd = [
|
|
236
|
+
"",
|
|
237
|
+
"# TestDriver.ai",
|
|
238
|
+
".env",
|
|
239
|
+
"node_modules/",
|
|
240
|
+
"test-results/",
|
|
241
|
+
"*.log",
|
|
242
|
+
];
|
|
243
|
+
|
|
244
|
+
const newContent = gitignoreContent.trim()
|
|
245
|
+
? gitignoreContent + "\n" + ignoresToAdd.join("\n") + "\n"
|
|
246
|
+
: ignoresToAdd.join("\n") + "\n";
|
|
247
|
+
|
|
248
|
+
fs.writeFileSync(gitignorePath, newContent);
|
|
249
|
+
console.log(chalk.green(" Updated .gitignore"));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Create GitHub Actions workflow
|
|
254
|
+
*/
|
|
255
|
+
async createGitHubWorkflow() {
|
|
256
|
+
const workflowDir = path.join(process.cwd(), ".github", "workflows");
|
|
257
|
+
const workflowFile = path.join(workflowDir, "testdriver.yml");
|
|
258
|
+
|
|
259
|
+
// Create .github/workflows directory if it doesn't exist
|
|
260
|
+
if (!fs.existsSync(workflowDir)) {
|
|
261
|
+
fs.mkdirSync(workflowDir, { recursive: true });
|
|
262
|
+
console.log(chalk.gray(` Created directory: ${workflowDir}`));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (!fs.existsSync(workflowFile)) {
|
|
266
|
+
const workflowContent = `name: TestDriver.ai Tests
|
|
267
|
+
|
|
268
|
+
on:
|
|
269
|
+
push:
|
|
270
|
+
branches: [ main, master ]
|
|
271
|
+
pull_request:
|
|
272
|
+
branches: [ main, master ]
|
|
273
|
+
|
|
274
|
+
jobs:
|
|
275
|
+
test:
|
|
276
|
+
runs-on: ubuntu-latest
|
|
277
|
+
|
|
278
|
+
steps:
|
|
279
|
+
- uses: actions/checkout@v4
|
|
280
|
+
|
|
281
|
+
- name: Setup Node.js
|
|
282
|
+
uses: actions/setup-node@v4
|
|
283
|
+
with:
|
|
284
|
+
node-version: '20'
|
|
285
|
+
cache: 'npm'
|
|
286
|
+
|
|
287
|
+
- name: Install dependencies
|
|
288
|
+
run: npm ci
|
|
289
|
+
|
|
290
|
+
- name: Run TestDriver.ai tests
|
|
291
|
+
env:
|
|
292
|
+
TD_API_KEY: \${{ secrets.TD_API_KEY }}
|
|
293
|
+
run: npm test
|
|
294
|
+
|
|
295
|
+
- name: Upload test results
|
|
296
|
+
if: always()
|
|
297
|
+
uses: actions/upload-artifact@v4
|
|
298
|
+
with:
|
|
299
|
+
name: test-results
|
|
300
|
+
path: test-results/
|
|
301
|
+
retention-days: 30
|
|
302
|
+
`;
|
|
303
|
+
|
|
304
|
+
fs.writeFileSync(workflowFile, workflowContent);
|
|
305
|
+
console.log(chalk.green(` Created GitHub workflow: ${workflowFile}`));
|
|
306
|
+
} else {
|
|
307
|
+
console.log(chalk.gray(" GitHub workflow already exists, skipping..."));
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Install dependencies
|
|
313
|
+
*/
|
|
314
|
+
async installDependencies() {
|
|
315
|
+
console.log(chalk.cyan("\n Installing dependencies...\n"));
|
|
316
|
+
|
|
317
|
+
try {
|
|
318
|
+
execSync("npm install -D vitest testdriverai && npm install dotenv", {
|
|
319
|
+
cwd: process.cwd(),
|
|
320
|
+
stdio: "inherit"
|
|
321
|
+
});
|
|
322
|
+
console.log(chalk.green("\n Dependencies installed successfully!"));
|
|
323
|
+
} catch (error) {
|
|
324
|
+
console.log(
|
|
325
|
+
chalk.yellow(
|
|
326
|
+
"\n⚠️ Failed to install dependencies automatically. Please run:",
|
|
327
|
+
),
|
|
328
|
+
);
|
|
329
|
+
console.log(chalk.gray(" npm install -D vitest testdriverai"));
|
|
330
|
+
console.log(chalk.gray(" npm install dotenv\n"));
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Print next steps
|
|
336
|
+
*/
|
|
337
|
+
printNextSteps() {
|
|
338
|
+
console.log(chalk.cyan("Next steps:\n"));
|
|
339
|
+
console.log(" 1. Run your tests:");
|
|
340
|
+
console.log(chalk.gray(" npm test\n"));
|
|
341
|
+
console.log(" 2. For CI/CD, add TD_API_KEY to your GitHub repository secrets");
|
|
342
|
+
console.log(chalk.gray(" Settings → Secrets → Actions → New repository secret\n"));
|
|
343
|
+
console.log(
|
|
344
|
+
chalk.cyan("Learn more at https://docs.testdriver.ai/getting-started\n"),
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Get command definition from interface.js
|
|
350
|
+
const tempAgent = { workingDir: process.cwd() };
|
|
351
|
+
const definitions = createCommandDefinitions(tempAgent);
|
|
352
|
+
const commandDef = definitions["init"];
|
|
353
|
+
|
|
354
|
+
InitCommand.description = commandDef?.description || "";
|
|
355
|
+
InitCommand.args = commandDef?.args || {};
|
|
356
|
+
InitCommand.flags = commandDef?.flags || {};
|
|
357
|
+
|
|
358
|
+
module.exports = InitCommand;
|