testdriverai 6.0.18 → 6.0.19

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/events.js CHANGED
@@ -85,6 +85,7 @@ const events = {
85
85
  load: "file:load",
86
86
  save: "file:save",
87
87
  modification: "file:modification",
88
+ diff: "file:diff",
88
89
  error: "file:error",
89
90
  status: "file:status",
90
91
  },
package/agent/index.js CHANGED
@@ -15,6 +15,7 @@ const path = require("path");
15
15
  const yaml = require("js-yaml");
16
16
  const sanitizeFilename = require("sanitize-filename");
17
17
  const { EventEmitter2 } = require("eventemitter2");
18
+ const diff = require("diff");
18
19
 
19
20
  // global utilities
20
21
  const generator = require("./lib/generator.js");
@@ -1117,11 +1118,110 @@ ${yml}
1117
1118
  return;
1118
1119
  }
1119
1120
 
1121
+ // Read existing file content for diff comparison
1122
+ let existingContent = "";
1123
+ let fileExists = false;
1124
+ try {
1125
+ if (fs.existsSync(filepath)) {
1126
+ existingContent = fs.readFileSync(filepath, "utf8");
1127
+ fileExists = true;
1128
+ }
1129
+ } catch {
1130
+ // File doesn't exist or can't be read, treat as empty
1131
+ existingContent = "";
1132
+ }
1133
+
1120
1134
  // write reply to /tmp/testdriver-summary.md
1121
1135
  let regression = await generator.dumpToYML(
1122
1136
  this.executionHistory,
1123
1137
  this.session,
1124
1138
  );
1139
+
1140
+ // Create diff if file exists and content has changed
1141
+ let diffResult = null;
1142
+ console.log("Checking for diff. File exists:", fileExists);
1143
+ console.log(
1144
+ "Content changed:",
1145
+ fileExists && existingContent !== regression,
1146
+ );
1147
+ if (fileExists) {
1148
+ console.log(
1149
+ "Existing content preview:",
1150
+ existingContent.substring(0, 100),
1151
+ );
1152
+ console.log("New content preview:", regression.substring(0, 100));
1153
+ }
1154
+
1155
+ if (fileExists && existingContent !== regression) {
1156
+ console.log("Creating diff - content has changed");
1157
+ const patches = diff.structuredPatch(
1158
+ filepath,
1159
+ filepath,
1160
+ existingContent,
1161
+ regression,
1162
+ `${new Date().toISOString()} (before)`,
1163
+ `${new Date().toISOString()} (after)`,
1164
+ );
1165
+
1166
+ // Create source map-like information for VS Code
1167
+ const diffLines = diff.diffLines(existingContent, regression);
1168
+ const sourceMaps = [];
1169
+ let oldLineNumber = 1;
1170
+ let newLineNumber = 1;
1171
+
1172
+ diffLines.forEach((part) => {
1173
+ const lineCount = part.value.split("\n").length - 1;
1174
+ if (part.added) {
1175
+ sourceMaps.push({
1176
+ type: "addition",
1177
+ oldStart: oldLineNumber,
1178
+ oldEnd: oldLineNumber,
1179
+ newStart: newLineNumber,
1180
+ newEnd: newLineNumber + lineCount,
1181
+ content: part.value,
1182
+ lines: lineCount,
1183
+ });
1184
+ newLineNumber += lineCount;
1185
+ } else if (part.removed) {
1186
+ sourceMaps.push({
1187
+ type: "deletion",
1188
+ oldStart: oldLineNumber,
1189
+ oldEnd: oldLineNumber + lineCount,
1190
+ newStart: newLineNumber,
1191
+ newEnd: newLineNumber,
1192
+ content: part.value,
1193
+ lines: lineCount,
1194
+ });
1195
+ oldLineNumber += lineCount;
1196
+ } else {
1197
+ // unchanged
1198
+ sourceMaps.push({
1199
+ type: "unchanged",
1200
+ oldStart: oldLineNumber,
1201
+ oldEnd: oldLineNumber + lineCount,
1202
+ newStart: newLineNumber,
1203
+ newEnd: newLineNumber + lineCount,
1204
+ content: part.value,
1205
+ lines: lineCount,
1206
+ });
1207
+ oldLineNumber += lineCount;
1208
+ newLineNumber += lineCount;
1209
+ }
1210
+ });
1211
+
1212
+ diffResult = {
1213
+ patches,
1214
+ sourceMaps,
1215
+ summary: {
1216
+ additions: diffLines.filter((part) => part.added).length,
1217
+ deletions: diffLines.filter((part) => part.removed).length,
1218
+ modifications: diffLines.filter(
1219
+ (part) => !part.added && !part.removed,
1220
+ ).length,
1221
+ },
1222
+ };
1223
+ }
1224
+
1125
1225
  try {
1126
1226
  fs.writeFileSync(filepath, regression);
1127
1227
 
@@ -1134,6 +1234,17 @@ ${yml}
1134
1234
  timestamp: endTime,
1135
1235
  });
1136
1236
 
1237
+ // Emit diff event if there were changes
1238
+ if (diffResult) {
1239
+ this.emitter.emit(events.file.diff, {
1240
+ filePath: filepath,
1241
+ diff: diffResult,
1242
+ timestamp: endTime,
1243
+ });
1244
+ } else {
1245
+ console.log("No diff result to emit");
1246
+ }
1247
+
1137
1248
  // Emit file save completion event
1138
1249
  this.emitter.emit(events.file.stop, {
1139
1250
  operation: "save",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "6.0.18",
3
+ "version": "6.0.19",
4
4
  "description": "Next generation autonomous AI agent for end-to-end testing of web & desktop",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -41,6 +41,7 @@
41
41
  "chalk": "^4.1.2",
42
42
  "cli-progress": "^3.12.0",
43
43
  "datadog-winston": "^1.6.0",
44
+ "diff": "^8.0.2",
44
45
  "dotenv": "^16.4.5",
45
46
  "eventemitter2": "^6.4.9",
46
47
  "jimp": "^0.22.12",
@@ -1,52 +1,74 @@
1
1
  version: 6.0.0
2
2
  session: 67f00511acbd9ccac373edf7
3
3
  steps:
4
- - prompt: Focus Chrome and navigate to extension in Chrome Web Store
4
+ - prompt: launch chrome
5
5
  commands:
6
- - command: focus-application
7
- name: Google Chrome
8
- - command: wait-for-text
9
- text: chrome.google.com/webstore
10
- timeout: 10000
11
- - command: wait-for-text
12
- text: Add to Chrome
13
- timeout: 15000
14
- - prompt: Install the extension by clicking Add to Chrome
15
- commands:
16
- - command: hover-text
17
- text: Add to Chrome
18
- description: blue Add to Chrome button
19
- action: click
20
- - command: wait-for-text
21
- text: Add extension
22
- timeout: 5000
23
- - prompt: Confirm extension installation
24
- commands:
25
- - command: hover-text
26
- text: Add extension
27
- description: confirmation dialog Add extension button
28
- action: click
29
- - command: wait-for-text
30
- text: Extension added
31
- timeout: 10000
32
-
33
- - prompt: Pin extension to toolbar
34
- commands:
35
- - command: hover-image
36
- description: puzzle piece icon for extensions
37
- action: click
38
- - command: hover-text
39
- text: Google Translate
40
- description: Google Translate extension in dropdown
41
- action: click
42
- - command: hover-image
43
- description: pin icon next to Google Translate
44
- action: click
45
-
46
- - prompt: Test the extension is working
47
- commands:
48
- - command: hover-image
49
- description: Google Translate extension icon in toolbar
50
- action: click
51
- - command: assert
52
- expect: Google Translate extension popup is visible
6
+ - command: exec
7
+ lang: pwsh
8
+ code: |
9
+ Write-Host "Cloning Chrome extension samples..."
10
+ $repoUrl = "https://github.com/GoogleChrome/chrome-extensions-samples.git"
11
+ $clonePath = Join-Path $env:TEMP "chrome-extensions-samples"
12
+ if (!(Test-Path $clonePath)) {
13
+ git clone $repoUrl $clonePath
14
+ } else {
15
+ Write-Host "Repo already cloned at $clonePath"
16
+ }
17
+ Write-Host "Repo ready at $clonePath"
18
+
19
+ Write-Host "Initializing new npm project..."
20
+ cd $env:TEMP
21
+ Write-Host "Changed directory to TEMP: $env:TEMP"
22
+
23
+ Write-Host "Running 'npm init -y'..."
24
+ npm init -y
25
+
26
+ Write-Host "Installing dependencies: @puppeteer/browsers and dashcam-chrome..."
27
+ npm install @puppeteer/browsers dashcam-chrome
28
+
29
+ Write-Host "Installing Chromium via '@puppeteer/browsers'..."
30
+ npx @puppeteer/browsers install chrome
31
+
32
+ # Define paths - redefining variables for this script
33
+ $extensionPath = Join-Path (Join-Path $env:TEMP "chrome-extensions-samples") "functional-samples/tutorial.hello-world"
34
+ $profilePath = Join-Path $env:TEMP "chrome-profile-$(Get-Random)"
35
+ $defaultDir = Join-Path $profilePath "Default"
36
+ $prefsPath = Join-Path $defaultDir "Preferences"
37
+
38
+ Write-Host "Extension path (hello-world): $extensionPath"
39
+ Write-Host "Chrome user data dir: $profilePath"
40
+
41
+ # Create a clean profile + Preferences to disable password manager & autofill
42
+ Remove-Item $profilePath -Recurse -Force -ErrorAction SilentlyContinue
43
+ New-Item $defaultDir -ItemType Directory -Force | Out-Null
44
+
45
+ $prefs = @{
46
+ "credentials_enable_service" = $false
47
+ "profile" = @{
48
+ "password_manager_enabled" = $false
49
+ }
50
+ "autofill" = @{
51
+ "profile_enabled" = $false
52
+ "address_enabled" = $false
53
+ "credit_card_enabled" = $false
54
+ }
55
+ } | ConvertTo-Json -Depth 6
56
+
57
+ # Write Preferences before Chrome starts (ASCII/UTF8 is fine)
58
+ $prefs | Set-Content -Path $prefsPath -Encoding ASCII
59
+
60
+ # Build args - load only hello-world extension
61
+ $chromeArgs = @(
62
+ "--start-maximized",
63
+ "--load-extension=$extensionPath",
64
+ "--user-data-dir=$profilePath",
65
+ "--no-first-run",
66
+ "--no-default-browser-check",
67
+ "--disable-infobars"
68
+ "https://testdriver.ai"
69
+ ) -join ' '
70
+
71
+ Start-Process "cmd.exe" -ArgumentList "/c", "npx @puppeteer/browsers launch chrome -- $chromeArgs"
72
+
73
+ Write-Host "Script complete."
74
+ exit
@@ -1,24 +1,64 @@
1
1
  version: 6.0.0
2
2
  session: 67f00511acbd9ccac373edf7
3
3
  steps:
4
- - prompt: download arc browser
4
+ - prompt: download and install Spotify
5
5
  commands:
6
6
  - command: exec
7
7
  lang: pwsh
8
8
  code: |
9
- Get-NetIPAddress -AddressFamily IPv6
10
- # URL for the Arc browser installer
11
- $installerUrl = "https://releases.arc.net/windows/ArcInstaller.exe"
12
- # Location to save the installer
13
- $installerPath = "$env:USERPROFILE\Downloads\ArcInstaller.exe"
14
- # Download the Arc browser installer
15
- Write-Host "Downloading Arc browser installer..."
16
- Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath
17
- # Check if the download was successful
18
- if (Test-Path $installerPath) {
19
- Write-Host "Download successful. Running the installer..."
20
- Start-Process -FilePath $installerPath -ArgumentList '/silent' -Wait
21
- Start-Sleep -Seconds 10
9
+ $spotifyUrl = "https://download.scdn.co/SpotifySetup.exe"
10
+ $installerPath = "$env:TEMP\SpotifySetup.exe"
11
+
12
+ Write-Host "Downloading Spotify installer..."
13
+ Invoke-WebRequest -Uri $spotifyUrl -OutFile $installerPath -UseBasicParsing
14
+
15
+ Write-Host "Downloaded to $installerPath"
16
+ - command: exec
17
+ lang: pwsh
18
+ code: |
19
+ $installerPath = "$env:TEMP\SpotifySetup.exe"
20
+
21
+ if (-Not (Test-Path $installerPath)) {
22
+ Write-Error "Spotify installer not found at $installerPath"
23
+ exit 1
24
+ }
25
+
26
+ Write-Host "Installing Spotify silently..."
27
+ $process = Start-Process -FilePath $installerPath -ArgumentList "/silent" -Wait -PassThru
28
+
29
+ if ($process.ExitCode -eq 0) {
30
+ Write-Host "Spotify installed successfully."
31
+ Remove-Item $installerPath -Force
32
+ exit 0
33
+ } else {
34
+ Write-Error "Installation failed with exit code $($process.ExitCode)"
35
+ exit $process.ExitCode
36
+ }
37
+ - command: exec
38
+ lang: pwsh
39
+ code: |
40
+ # patch-path.ps1
41
+
42
+ $spotifyPath = "$env:APPDATA\Spotify"
43
+
44
+ if (-not ($env:PATH -like "*$spotifyPath*")) {
45
+ Write-Host "Temporarily appending Spotify to PATH for current session."
46
+ $env:PATH += ";$spotifyPath"
47
+ } else {
48
+ Write-Host "Spotify path already in PATH."
49
+ }
50
+ - command: exec
51
+ lang: pwsh
52
+ code: |
53
+ # launch-spotify.ps1
54
+
55
+ Write-Host "Launching Spotify..."
56
+ $spotifyExe = "$env:APPDATA\Spotify\Spotify.exe"
57
+
58
+ if (Test-Path $spotifyExe) {
59
+ Start-Process $spotifyExe
60
+ Write-Host "Spotify launched successfully."
22
61
  } else {
23
- Write-Host "Failed to download the Arc browser installer."
62
+ Write-Error "Spotify executable not found at $spotifyExe"
63
+ exit 1
24
64
  }
@@ -1,8 +0,0 @@
1
- version: 6.0.0
2
- steps:
3
- - commands:
4
- - command: exec
5
- lang: pwsh
6
- code: |
7
- npm init
8
- Start-Process "C:\Program Files\Google\Chrome\Application\chrome.exe" -ArgumentList "--start-maximized --disable-infobars --disable-fre --no-default-browser-check --no-first-run --guest --load-extension=$(pwd)/node_modules/dashcam-chrome/build", "${TD_WEBSITE}"
@@ -1,10 +0,0 @@
1
- version: 5.1.1
2
- session: 67f00511acbd9ccac373edf7
3
- steps:
4
- - prompt: execute powershell multiline
5
- commands:
6
- - command: exec
7
- lang: pwsh
8
- code: |
9
- Start-Process "C:/Program Files/Google/Chrome/Application/chrome.exe" -ArgumentList "--start-maximized", "--guest", "${TD_WEBSITE}"
10
- exit
@@ -1,23 +0,0 @@
1
- version: 5.7.7
2
- session: 682f6071811bd5a322c0e6dd
3
- steps:
4
- - prompt: focus chrome
5
- commands:
6
- - command: focus-application
7
- name: Google Chrome
8
- - prompt: enter a username
9
- commands:
10
- - command: hover-text
11
- text: Username
12
- description: username input field
13
- action: click
14
- - command: type
15
- text: standard_user
16
- - prompt: >-
17
- enter a valid password
18
- - prompt: click sign in
19
- commands:
20
- - command: hover-text
21
- text: Sign in
22
- description: sign in button
23
- action: click
@@ -1,6 +0,0 @@
1
- version: 5.7.7
2
- session: 682f6071811bd5a322c0e6dd
3
- steps:
4
- - commands:
5
- - command: run
6
- file: testdriver/prompt-in-middle.yaml