testdriverai 6.0.17 → 6.0.18
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/agent/index.js +105 -3
- package/package.json +1 -1
- package/testdriver/examples/chrome-extension/{install-extension-from-webstore.yaml → lifecycle/provision.yaml} +0 -2
- package/testdriver/examples/web/lifecycle/provision.yaml +2 -56
- package/testdriver/examples/chrome-extension/lifecycle/prerun.yaml +0 -66
- package/testdriver/examples/desktop/desktop.yaml +0 -46
- package/testdriver/examples/vscode-extension/desktop.yaml +0 -4
- package/testdriver/examples/vscode-extension/readme.md +0 -4
- package/testdriver/examples/web/example.yaml +0 -6
- /package/testdriver/examples/desktop/lifecycle/{prerun.yaml → provision.yaml} +0 -0
- /package/testdriver/examples/vscode-extension/lifecycle/{prerun.yaml → provision.yaml} +0 -0
package/agent/index.js
CHANGED
|
@@ -152,9 +152,23 @@ class TestDriverAgent extends EventEmitter2 {
|
|
|
152
152
|
// temporary file for command history
|
|
153
153
|
this.commandHistoryFile = path.join(os.homedir(), ".testdriver_history");
|
|
154
154
|
|
|
155
|
+
// Flag to indicate if the agent should stop execution
|
|
156
|
+
this.stopped = false;
|
|
157
|
+
|
|
155
158
|
this.emitter.emit(events.log.log, JSON.stringify(environment));
|
|
156
159
|
this.emitter.emit(events.log.log, JSON.stringify(cliArgs));
|
|
157
160
|
}
|
|
161
|
+
|
|
162
|
+
// Stop method to immediately halt execution
|
|
163
|
+
stop() {
|
|
164
|
+
this.stopped = true;
|
|
165
|
+
this.emitter.emit(
|
|
166
|
+
events.log.narration,
|
|
167
|
+
theme.dim("stopping execution..."),
|
|
168
|
+
true,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
158
172
|
// single function to handle all program exits
|
|
159
173
|
// allows us to save the current state, run lifecycle hooks, and track analytics
|
|
160
174
|
async exit(failed = true, shouldSave = false, shouldRunPostrun = false) {
|
|
@@ -328,6 +342,16 @@ class TestDriverAgent extends EventEmitter2 {
|
|
|
328
342
|
// this checks that the task is "really done" using a screenshot of the desktop state
|
|
329
343
|
// it's likely that the task will not be complete and the AI will respond with more codeblocks to execute
|
|
330
344
|
async check() {
|
|
345
|
+
// Check if execution has been stopped
|
|
346
|
+
if (this.stopped) {
|
|
347
|
+
this.emitter.emit(
|
|
348
|
+
events.log.narration,
|
|
349
|
+
theme.dim("execution stopped"),
|
|
350
|
+
true,
|
|
351
|
+
);
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
|
|
331
355
|
this.checkCount++;
|
|
332
356
|
|
|
333
357
|
if (this.checkCount >= this.checkLimit) {
|
|
@@ -469,8 +493,28 @@ class TestDriverAgent extends EventEmitter2 {
|
|
|
469
493
|
dry = false,
|
|
470
494
|
shouldSave = false,
|
|
471
495
|
) {
|
|
496
|
+
// Check if execution has been stopped
|
|
497
|
+
if (this.stopped) {
|
|
498
|
+
this.emitter.emit(
|
|
499
|
+
events.log.narration,
|
|
500
|
+
theme.dim("execution stopped"),
|
|
501
|
+
true,
|
|
502
|
+
);
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
|
|
472
506
|
if (commands?.length) {
|
|
473
507
|
for (const command of commands) {
|
|
508
|
+
// Check if execution has been stopped before each command
|
|
509
|
+
if (this.stopped) {
|
|
510
|
+
this.emitter.emit(
|
|
511
|
+
events.log.narration,
|
|
512
|
+
theme.dim("execution stopped"),
|
|
513
|
+
true,
|
|
514
|
+
);
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
|
|
474
518
|
// Update current command tracking
|
|
475
519
|
const commandIndex = commands.indexOf(command);
|
|
476
520
|
this.sourceMapper.setCurrentCommand(commandIndex);
|
|
@@ -507,9 +551,29 @@ class TestDriverAgent extends EventEmitter2 {
|
|
|
507
551
|
dry = false,
|
|
508
552
|
shouldSave = false,
|
|
509
553
|
) {
|
|
554
|
+
// Check if execution has been stopped
|
|
555
|
+
if (this.stopped) {
|
|
556
|
+
this.emitter.emit(
|
|
557
|
+
events.log.narration,
|
|
558
|
+
theme.dim("execution stopped"),
|
|
559
|
+
true,
|
|
560
|
+
);
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
|
|
510
564
|
depth = depth + 1;
|
|
511
565
|
|
|
512
566
|
for (const codeblock of codeblocks) {
|
|
567
|
+
// Check if execution has been stopped before each codeblock
|
|
568
|
+
if (this.stopped) {
|
|
569
|
+
this.emitter.emit(
|
|
570
|
+
events.log.narration,
|
|
571
|
+
theme.dim("execution stopped"),
|
|
572
|
+
true,
|
|
573
|
+
);
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
|
|
513
577
|
let commands;
|
|
514
578
|
|
|
515
579
|
try {
|
|
@@ -542,8 +606,22 @@ class TestDriverAgent extends EventEmitter2 {
|
|
|
542
606
|
validateAndLoop = false,
|
|
543
607
|
dry = false,
|
|
544
608
|
shouldSave = false,
|
|
609
|
+
isLoopContinuation = false,
|
|
545
610
|
) {
|
|
546
|
-
|
|
611
|
+
// Check if execution has been stopped
|
|
612
|
+
if (this.stopped) {
|
|
613
|
+
this.emitter.emit(
|
|
614
|
+
events.log.narration,
|
|
615
|
+
theme.dim("execution stopped"),
|
|
616
|
+
true,
|
|
617
|
+
);
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// Only create new execution history entry if this is not a loop continuation
|
|
622
|
+
if (!isLoopContinuation) {
|
|
623
|
+
this.executionHistory.push({ prompt: this.lastPrompt, commands: [] });
|
|
624
|
+
}
|
|
547
625
|
|
|
548
626
|
if (shouldSave) {
|
|
549
627
|
await this.save({ silent: true });
|
|
@@ -583,7 +661,13 @@ class TestDriverAgent extends EventEmitter2 {
|
|
|
583
661
|
"check thinks more needs to be done",
|
|
584
662
|
);
|
|
585
663
|
|
|
586
|
-
return await this.aiExecute(
|
|
664
|
+
return await this.aiExecute(
|
|
665
|
+
response,
|
|
666
|
+
validateAndLoop,
|
|
667
|
+
dry,
|
|
668
|
+
shouldSave,
|
|
669
|
+
true,
|
|
670
|
+
);
|
|
587
671
|
} else {
|
|
588
672
|
this.emitter.emit(events.log.debug, "seems complete, returning");
|
|
589
673
|
|
|
@@ -738,6 +822,16 @@ commands:
|
|
|
738
822
|
validateAndLoop = false,
|
|
739
823
|
shouldSave = true,
|
|
740
824
|
) {
|
|
825
|
+
// Check if execution has been stopped
|
|
826
|
+
if (this.stopped) {
|
|
827
|
+
this.emitter.emit(
|
|
828
|
+
events.log.narration,
|
|
829
|
+
theme.dim("execution stopped"),
|
|
830
|
+
true,
|
|
831
|
+
);
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
|
|
741
835
|
this.lastPrompt = currentTask;
|
|
742
836
|
this.checkCount = 0;
|
|
743
837
|
|
|
@@ -1867,7 +1961,15 @@ Please check your network connection, TD_API_KEY, or the service status.`,
|
|
|
1867
1961
|
}
|
|
1868
1962
|
}
|
|
1869
1963
|
if (lifecycleFile) {
|
|
1870
|
-
|
|
1964
|
+
// Store current source mapping state before running lifecycle file
|
|
1965
|
+
const previousContext = this.sourceMapper.saveContext();
|
|
1966
|
+
|
|
1967
|
+
try {
|
|
1968
|
+
await this.run(lifecycleFile, false, false);
|
|
1969
|
+
} finally {
|
|
1970
|
+
// Restore previous source mapping state after lifecycle file execution
|
|
1971
|
+
this.sourceMapper.restoreContext(previousContext);
|
|
1972
|
+
}
|
|
1871
1973
|
}
|
|
1872
1974
|
} // Unified command definitions that work for both CLI and interactive modes
|
|
1873
1975
|
getCommandDefinitions() {
|
package/package.json
CHANGED
|
@@ -11,7 +11,6 @@ steps:
|
|
|
11
11
|
- command: wait-for-text
|
|
12
12
|
text: Add to Chrome
|
|
13
13
|
timeout: 15000
|
|
14
|
-
|
|
15
14
|
- prompt: Install the extension by clicking Add to Chrome
|
|
16
15
|
commands:
|
|
17
16
|
- command: hover-text
|
|
@@ -21,7 +20,6 @@ steps:
|
|
|
21
20
|
- command: wait-for-text
|
|
22
21
|
text: Add extension
|
|
23
22
|
timeout: 5000
|
|
24
|
-
|
|
25
23
|
- prompt: Confirm extension installation
|
|
26
24
|
commands:
|
|
27
25
|
- command: hover-text
|
|
@@ -1,65 +1,11 @@
|
|
|
1
1
|
version: 6.0.0
|
|
2
|
-
session: 67f00511acbd9ccac373edf7
|
|
3
2
|
steps:
|
|
4
3
|
- prompt: launch chrome
|
|
5
4
|
commands:
|
|
6
5
|
- command: exec
|
|
7
6
|
lang: pwsh
|
|
8
7
|
code: |
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
cd $env:TEMP
|
|
12
|
-
Write-Host "Changed directory to TEMP: $env:TEMP"
|
|
13
|
-
|
|
14
|
-
Write-Host "Running 'npm init -y'..."
|
|
15
|
-
npm init -y
|
|
16
|
-
|
|
17
|
-
Write-Host "Installing dependencies: @puppeteer/browsers and dashcam-chrome..."
|
|
18
|
-
npm install @puppeteer/browsers dashcam-chrome
|
|
19
|
-
|
|
20
|
-
Write-Host "Installing Chromium via '@puppeteer/browsers'..."
|
|
21
|
-
npx @puppeteer/browsers install chrome
|
|
22
|
-
|
|
23
|
-
# Define paths
|
|
24
|
-
$extensionPath = Join-Path (Get-Location) "node_modules/dashcam-chrome/build"
|
|
25
|
-
$profilePath = Join-Path $env:TEMP "chrome-profile-$(Get-Random)"
|
|
26
|
-
$defaultDir = Join-Path $profilePath "Default"
|
|
27
|
-
$prefsPath = Join-Path $defaultDir "Preferences"
|
|
28
|
-
|
|
29
|
-
Write-Host "Extension path: $extensionPath"
|
|
30
|
-
Write-Host "Chrome user data dir: $profilePath"
|
|
31
|
-
|
|
32
|
-
# Create a clean profile + Preferences to disable password manager & autofill
|
|
33
|
-
Remove-Item $profilePath -Recurse -Force -ErrorAction SilentlyContinue
|
|
34
|
-
New-Item $defaultDir -ItemType Directory -Force | Out-Null
|
|
35
|
-
|
|
36
|
-
$prefs = @{
|
|
37
|
-
"credentials_enable_service" = $false
|
|
38
|
-
"profile" = @{
|
|
39
|
-
"password_manager_enabled" = $false
|
|
40
|
-
}
|
|
41
|
-
"autofill" = @{
|
|
42
|
-
"profile_enabled" = $false
|
|
43
|
-
"address_enabled" = $false
|
|
44
|
-
"credit_card_enabled" = $false
|
|
45
|
-
}
|
|
46
|
-
} | ConvertTo-Json -Depth 6
|
|
47
|
-
|
|
48
|
-
# Write Preferences before Chrome starts (ASCII/UTF8 is fine)
|
|
49
|
-
$prefs | Set-Content -Path $prefsPath -Encoding ASCII
|
|
50
|
-
|
|
51
|
-
# Build args
|
|
52
|
-
$chromeArgs = @(
|
|
53
|
-
"--start-maximized",
|
|
54
|
-
"--load-extension=$extensionPath",
|
|
55
|
-
"--user-data-dir=$profilePath",
|
|
56
|
-
"--no-first-run",
|
|
57
|
-
"--no-default-browser-check",
|
|
58
|
-
"--disable-infobars"
|
|
59
|
-
"${TD_WEBSITE}"
|
|
60
|
-
) -join ' '
|
|
61
|
-
|
|
62
|
-
Start-Process "cmd.exe" -ArgumentList "/c", "npx @puppeteer/browsers launch chrome -- $chromeArgs"
|
|
8
|
+
Start-Process "C:/Program Files/Google/Chrome/Application/chrome.exe" -ArgumentList "--start-maximized", "--guest", "https://testdriver-sandbox.vercel.app/login"
|
|
63
9
|
- command: wait-for-text
|
|
64
|
-
text:
|
|
10
|
+
text: "TestDriver.ai Sandbox"
|
|
65
11
|
timeout: 60000
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
version: 6.0.0
|
|
2
|
-
session: 67f00511acbd9ccac373edf7
|
|
3
|
-
steps:
|
|
4
|
-
- prompt: Setup environment and variables
|
|
5
|
-
commands:
|
|
6
|
-
- command: exec
|
|
7
|
-
lang: pwsh
|
|
8
|
-
code: |
|
|
9
|
-
# Enable strict mode and verbose output
|
|
10
|
-
Set-StrictMode -Version Latest
|
|
11
|
-
$ErrorActionPreference = "Stop"
|
|
12
|
-
|
|
13
|
-
# Set Chrome and extension info
|
|
14
|
-
$chromeInstallerUrl = "https://dl.google.com/chrome/install/latest/chrome_installer.exe"
|
|
15
|
-
$chromeInstallPath = "$env:ProgramFiles\Google\Chrome\Application\chrome.exe"
|
|
16
|
-
$extensionId = "aapbdbdomjkkjkaonfhkkikfgjllcleb" # Google Translate
|
|
17
|
-
|
|
18
|
-
Write-Host "Chrome installer URL: $chromeInstallerUrl"
|
|
19
|
-
Write-Host "Chrome install path: $chromeInstallPath"
|
|
20
|
-
Write-Host "Extension ID: $extensionId"
|
|
21
|
-
|
|
22
|
-
- prompt: Check and install Chrome if needed
|
|
23
|
-
commands:
|
|
24
|
-
- command: exec
|
|
25
|
-
lang: pwsh
|
|
26
|
-
code: |
|
|
27
|
-
$chromeInstallerUrl = "https://dl.google.com/chrome/install/latest/chrome_installer.exe"
|
|
28
|
-
$chromeInstallPath = "$env:ProgramFiles\Google\Chrome\Application\chrome.exe"
|
|
29
|
-
|
|
30
|
-
# Download Chrome if not installed
|
|
31
|
-
if (!(Test-Path $chromeInstallPath)) {
|
|
32
|
-
Write-Host "Chrome not found at $chromeInstallPath. Downloading..."
|
|
33
|
-
$chromeInstaller = "$env:TEMP\chrome_installer.exe"
|
|
34
|
-
try {
|
|
35
|
-
Write-Host "Downloading Chrome installer..."
|
|
36
|
-
Invoke-WebRequest -Uri $chromeInstallerUrl -OutFile $chromeInstaller
|
|
37
|
-
Write-Host "Installing Chrome..."
|
|
38
|
-
Start-Process -FilePath $chromeInstaller -Wait
|
|
39
|
-
Write-Host "Chrome installation completed."
|
|
40
|
-
} catch {
|
|
41
|
-
Write-Error "Failed to install Chrome: $_"
|
|
42
|
-
exit 1
|
|
43
|
-
}
|
|
44
|
-
} else {
|
|
45
|
-
Write-Host "Chrome is already installed at: $chromeInstallPath"
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
- prompt: Launch Chrome and install extension from Chrome Web Store
|
|
49
|
-
commands:
|
|
50
|
-
- command: exec
|
|
51
|
-
lang: pwsh
|
|
52
|
-
code: |
|
|
53
|
-
$chromeInstallPath = "$env:ProgramFiles\Google\Chrome\Application\chrome.exe"
|
|
54
|
-
$extensionId = "aapbdbdomjkkjkaonfhkkikfgjllcleb" # Google Translate
|
|
55
|
-
$webStoreUrl = "https://chrome.google.com/webstore/detail/$extensionId"
|
|
56
|
-
|
|
57
|
-
# Launch Chrome with the Web Store page for the extension
|
|
58
|
-
try {
|
|
59
|
-
Write-Host "Launching Chrome and opening Chrome Web Store for extension..."
|
|
60
|
-
Start-Process -FilePath $chromeInstallPath -ArgumentList "--start-maximized", "--new-window", "$webStoreUrl"
|
|
61
|
-
Write-Host "Chrome launched successfully. Extension page should be open."
|
|
62
|
-
Write-Host "You can now use TestDriver to automate clicking 'Add to Chrome' button."
|
|
63
|
-
} catch {
|
|
64
|
-
Write-Error "Failed to launch Chrome: $_"
|
|
65
|
-
exit 1
|
|
66
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
version: 6.0.6
|
|
2
|
-
session: 687eb092664035296ec57e6a
|
|
3
|
-
steps:
|
|
4
|
-
- prompt: click the right arrow in arc browser
|
|
5
|
-
commands:
|
|
6
|
-
- command: focus-application
|
|
7
|
-
name: Arc
|
|
8
|
-
- command: hover-image
|
|
9
|
-
description: right arrow button in the Arc browser
|
|
10
|
-
action: click
|
|
11
|
-
method: turbo
|
|
12
|
-
- prompt: >-
|
|
13
|
-
/explore complete the arc onboarding. when asked to log in, use the email
|
|
14
|
-
11354345965.1@testdriver.ai and password FakePassword123
|
|
15
|
-
commands:
|
|
16
|
-
- command: hover-text
|
|
17
|
-
text: Sign In
|
|
18
|
-
description: sign-in link on the onboarding page
|
|
19
|
-
action: click
|
|
20
|
-
- prompt: >-
|
|
21
|
-
/explore complete the arc onboarding. when asked to log in, use the email
|
|
22
|
-
11354345965.1@testdriver.ai and password FakePassword123
|
|
23
|
-
commands:
|
|
24
|
-
- command: hover-text
|
|
25
|
-
text: Email
|
|
26
|
-
description: email input field
|
|
27
|
-
action: click
|
|
28
|
-
- command: type
|
|
29
|
-
text: 11354345965.1@testdriver.ai
|
|
30
|
-
- command: hover-text
|
|
31
|
-
text: Password
|
|
32
|
-
description: password input field
|
|
33
|
-
action: click
|
|
34
|
-
- command: type
|
|
35
|
-
text: FakePassword123
|
|
36
|
-
- command: hover-text
|
|
37
|
-
text: Sign In
|
|
38
|
-
description: sign-in button to log in
|
|
39
|
-
action: click
|
|
40
|
-
- prompt: click the rigth arrow in arc browser
|
|
41
|
-
commands:
|
|
42
|
-
- command: hover-image
|
|
43
|
-
description: >-
|
|
44
|
-
white button with a right arrow in the center of the screen below the
|
|
45
|
-
text "Meet the internet, again."
|
|
46
|
-
action: click
|
|
File without changes
|
|
File without changes
|