testdriverai 7.2.49 → 7.2.50
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 +29 -8
- package/debugger/index.html +67 -0
- package/interfaces/logger.js +4 -1
- package/interfaces/vitest-plugin.mjs +0 -1
- package/lib/vitest/hooks.mjs +3 -0
- package/package.json +1 -1
- package/sdk.js +31 -24
package/agent/index.js
CHANGED
|
@@ -1781,6 +1781,8 @@ ${regression}
|
|
|
1781
1781
|
ip: this.ip,
|
|
1782
1782
|
});
|
|
1783
1783
|
|
|
1784
|
+
// Mark instance socket as connected so console logs are forwarded
|
|
1785
|
+
this.sandbox.instanceSocketConnected = true;
|
|
1784
1786
|
this.emitter.emit(events.sandbox.connected);
|
|
1785
1787
|
|
|
1786
1788
|
this.instance = instance.instance;
|
|
@@ -2020,6 +2022,7 @@ ${regression}
|
|
|
2020
2022
|
resolution: this.config.TD_RESOLUTION,
|
|
2021
2023
|
url: url,
|
|
2022
2024
|
token: "V3b8wG9",
|
|
2025
|
+
testFile: this.testFile || null,
|
|
2023
2026
|
};
|
|
2024
2027
|
|
|
2025
2028
|
// Base64 encode the data (the debugger expects base64, not URL encoding)
|
|
@@ -2097,16 +2100,34 @@ Please check your network connection, TD_API_KEY, or the service status.`,
|
|
|
2097
2100
|
sandboxConfig.keepAlive = this.keepAlive;
|
|
2098
2101
|
}
|
|
2099
2102
|
|
|
2100
|
-
|
|
2103
|
+
const { formatter } = require("../sdk-log-formatter.js");
|
|
2104
|
+
const retryDelay = 15000; // 15 seconds between retries
|
|
2101
2105
|
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2106
|
+
while (true) {
|
|
2107
|
+
let response = await this.sandbox.send(sandboxConfig, 60000 * 8);
|
|
2108
|
+
|
|
2109
|
+
// Check if queued (all slots in use)
|
|
2110
|
+
if (response.type === 'create.queued') {
|
|
2111
|
+
this.emitter.emit(
|
|
2112
|
+
events.log.narration,
|
|
2113
|
+
formatter.getPrefix("queue") + " " + theme.yellow.bold("Waiting") + " " +
|
|
2114
|
+
theme.dim(response.message),
|
|
2115
|
+
);
|
|
2108
2116
|
|
|
2109
|
-
|
|
2117
|
+
// Wait then retry
|
|
2118
|
+
await new Promise(resolve => setTimeout(resolve, retryDelay));
|
|
2119
|
+
continue;
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
// Success - got a sandbox
|
|
2123
|
+
if (response.sandbox && response.sandbox.sandboxId) {
|
|
2124
|
+
this.saveLastSandboxId(response.sandbox.sandboxId, this.sandboxOs);
|
|
2125
|
+
} else if (response.sandbox && response.sandbox.instanceId) {
|
|
2126
|
+
this.saveLastSandboxId(response.sandbox.instanceId, this.sandboxOs);
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
return response;
|
|
2130
|
+
}
|
|
2110
2131
|
}
|
|
2111
2132
|
|
|
2112
2133
|
async newSession() {
|
package/debugger/index.html
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
2
|
<html>
|
|
3
3
|
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
4
5
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
5
6
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
6
7
|
<link
|
|
@@ -452,7 +453,29 @@
|
|
|
452
453
|
eventHandlers.get(event).push(callback);
|
|
453
454
|
};
|
|
454
455
|
|
|
456
|
+
// Activity tracking for title updates
|
|
457
|
+
let idleTimeout = null;
|
|
458
|
+
const IDLE_THRESHOLD = 5000; // 5 seconds
|
|
459
|
+
|
|
460
|
+
// Get test file name for title (use just filename, not full path)
|
|
461
|
+
const testFileName = parsedData?.testFile
|
|
462
|
+
? parsedData.testFile.split('/').pop().split('\\\\').pop()
|
|
463
|
+
: 'TestDriver';
|
|
464
|
+
|
|
465
|
+
const setTitle = (status) => {
|
|
466
|
+
document.title = `[${status}] ${testFileName}`;
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
const resetIdleTimer = () => {
|
|
470
|
+
setTitle("Running");
|
|
471
|
+
if (idleTimeout) clearTimeout(idleTimeout);
|
|
472
|
+
idleTimeout = setTimeout(() => {
|
|
473
|
+
setTitle("Idle");
|
|
474
|
+
}, IDLE_THRESHOLD);
|
|
475
|
+
};
|
|
476
|
+
|
|
455
477
|
ws.addEventListener("message", (message) => {
|
|
478
|
+
resetIdleTimer();
|
|
456
479
|
try {
|
|
457
480
|
const data = JSON.parse(message.data);
|
|
458
481
|
console.log("WebSocket message received:", data);
|
|
@@ -488,6 +511,8 @@
|
|
|
488
511
|
|
|
489
512
|
ws.addEventListener("close", () => {
|
|
490
513
|
console.log("WebSocket disconnected");
|
|
514
|
+
if (idleTimeout) clearTimeout(idleTimeout);
|
|
515
|
+
setTitle("Done");
|
|
491
516
|
document.getElementById("status").textContent = "Disconnected";
|
|
492
517
|
document.getElementById("status").classList.add("visible");
|
|
493
518
|
});
|
|
@@ -512,8 +537,50 @@
|
|
|
512
537
|
vm: {
|
|
513
538
|
show: "vm:show",
|
|
514
539
|
},
|
|
540
|
+
test: {
|
|
541
|
+
start: "test:start",
|
|
542
|
+
stop: "test:stop",
|
|
543
|
+
success: "test:success",
|
|
544
|
+
error: "test:error",
|
|
545
|
+
},
|
|
546
|
+
error: {
|
|
547
|
+
fatal: "error:fatal",
|
|
548
|
+
general: "error:general",
|
|
549
|
+
sdk: "error:sdk",
|
|
550
|
+
},
|
|
515
551
|
};
|
|
516
552
|
|
|
553
|
+
// Title state handlers for immediate feedback
|
|
554
|
+
addEventHandler(events.test.start, () => {
|
|
555
|
+
if (idleTimeout) clearTimeout(idleTimeout);
|
|
556
|
+
setTitle("Running");
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
addEventHandler(events.test.stop, () => {
|
|
560
|
+
if (idleTimeout) clearTimeout(idleTimeout);
|
|
561
|
+
setTitle("Stopped");
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
addEventHandler(events.test.success, () => {
|
|
565
|
+
if (idleTimeout) clearTimeout(idleTimeout);
|
|
566
|
+
setTitle("Passed");
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
addEventHandler(events.test.error, () => {
|
|
570
|
+
if (idleTimeout) clearTimeout(idleTimeout);
|
|
571
|
+
setTitle("Failed");
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
addEventHandler(events.error.fatal, () => {
|
|
575
|
+
if (idleTimeout) clearTimeout(idleTimeout);
|
|
576
|
+
setTitle("Error");
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
addEventHandler(events.error.sdk, () => {
|
|
580
|
+
if (idleTimeout) clearTimeout(idleTimeout);
|
|
581
|
+
setTitle("Error");
|
|
582
|
+
});
|
|
583
|
+
|
|
517
584
|
const effects = document.getElementById("effects");
|
|
518
585
|
const mouse = document.getElementById("mouse");
|
|
519
586
|
const screenshotElement = document.getElementById("screenshot");
|
package/interfaces/logger.js
CHANGED
|
@@ -14,14 +14,17 @@ class CustomTransport extends Transport {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
log(info, callback) {
|
|
17
|
+
|
|
17
18
|
try {
|
|
18
19
|
const { message } = info;
|
|
19
20
|
|
|
20
21
|
if (!this.sandbox) {
|
|
21
22
|
this.sandbox = require("../agent/lib/sandbox");
|
|
22
23
|
}
|
|
23
|
-
|
|
24
|
+
|
|
24
25
|
if (this.sandbox && this.sandbox.instanceSocketConnected) {
|
|
26
|
+
|
|
27
|
+
|
|
25
28
|
if (typeof message === "object") {
|
|
26
29
|
console.log(chalk.cyan("protecting against base64 error"));
|
|
27
30
|
console.log(message);
|
package/lib/vitest/hooks.mjs
CHANGED
|
@@ -251,6 +251,9 @@ export function TestDriver(context, options = {}) {
|
|
|
251
251
|
context.task.meta.testFile = testFile;
|
|
252
252
|
context.task.meta.testOrder = 0;
|
|
253
253
|
|
|
254
|
+
// Pass test file name to SDK for debugger display
|
|
255
|
+
testdriver.testFile = testFile;
|
|
256
|
+
|
|
254
257
|
// Auto-connect if enabled (default: true)
|
|
255
258
|
const autoConnect = config.autoConnect !== undefined ? config.autoConnect : true;
|
|
256
259
|
const debugConsoleSpy = process.env.TD_DEBUG_CONSOLE_SPY === 'true';
|
package/package.json
CHANGED
package/sdk.js
CHANGED
|
@@ -428,28 +428,28 @@ class Element {
|
|
|
428
428
|
|
|
429
429
|
// Use default cacheKey from SDK constructor if not provided in find() options
|
|
430
430
|
// BUT only if cache is not explicitly disabled via cache: false option
|
|
431
|
-
if (!cacheKey && this.sdk.options?.cacheKey && this.sdk.
|
|
431
|
+
if (!cacheKey && this.sdk.options?.cacheKey && !this.sdk._cacheExplicitlyDisabled) {
|
|
432
432
|
cacheKey = this.sdk.options.cacheKey;
|
|
433
433
|
}
|
|
434
434
|
|
|
435
435
|
// Determine threshold:
|
|
436
|
-
// - If cache is explicitly disabled
|
|
437
|
-
// - If cacheKey is provided, enable cache
|
|
438
|
-
// - If no cacheKey, disable cache
|
|
436
|
+
// - If cache is explicitly disabled, don't use cache even with cacheKey
|
|
437
|
+
// - If cacheKey is provided, enable cache with threshold
|
|
438
|
+
// - If no cacheKey, disable cache
|
|
439
439
|
let threshold;
|
|
440
|
-
if (this.sdk.
|
|
441
|
-
// Cache explicitly disabled via cache: false option
|
|
440
|
+
if (this.sdk._cacheExplicitlyDisabled) {
|
|
441
|
+
// Cache explicitly disabled via cache: false option or TD_NO_CACHE env
|
|
442
442
|
threshold = -1;
|
|
443
443
|
cacheKey = null; // Clear any cacheKey to ensure cache is truly disabled
|
|
444
444
|
} else if (cacheKey) {
|
|
445
445
|
// cacheKey provided - enable cache with threshold
|
|
446
|
-
threshold = cacheThreshold ?? 0.01;
|
|
446
|
+
threshold = cacheThreshold ?? this.sdk.cacheThresholds?.find ?? 0.01;
|
|
447
447
|
} else if (cacheThreshold !== null) {
|
|
448
448
|
// Explicit threshold provided without cacheKey
|
|
449
449
|
threshold = cacheThreshold;
|
|
450
450
|
} else {
|
|
451
|
-
// No cacheKey, no explicit threshold -
|
|
452
|
-
threshold =
|
|
451
|
+
// No cacheKey, no explicit threshold - disable cache
|
|
452
|
+
threshold = -1;
|
|
453
453
|
}
|
|
454
454
|
|
|
455
455
|
// Store the threshold for debugging
|
|
@@ -1263,21 +1263,23 @@ class TestDriverSDK {
|
|
|
1263
1263
|
// By default, cache is DISABLED (threshold = -1) to avoid unnecessary AI costs
|
|
1264
1264
|
// To enable cache, provide a cacheKey when calling find() or findAll()
|
|
1265
1265
|
// Also support TD_NO_CACHE environment variable and cache: false option for backwards compatibility
|
|
1266
|
-
const
|
|
1266
|
+
const cacheExplicitlyDisabled =
|
|
1267
1267
|
options.cache === false || process.env.TD_NO_CACHE === "true";
|
|
1268
1268
|
|
|
1269
|
-
|
|
1269
|
+
// Track whether cache was explicitly disabled (not just default)
|
|
1270
|
+
this._cacheExplicitlyDisabled = cacheExplicitlyDisabled;
|
|
1271
|
+
|
|
1272
|
+
if (cacheExplicitlyDisabled) {
|
|
1270
1273
|
// Explicit cache disabled via option or env var
|
|
1271
1274
|
this.cacheThresholds = {
|
|
1272
1275
|
find: -1,
|
|
1273
1276
|
findAll: -1,
|
|
1274
1277
|
};
|
|
1275
1278
|
} else {
|
|
1276
|
-
// Cache
|
|
1277
|
-
// Note: The threshold value here is the fallback when cacheKey is NOT provided
|
|
1279
|
+
// Cache enabled by default when cacheKey is provided
|
|
1278
1280
|
this.cacheThresholds = {
|
|
1279
|
-
find: options.cacheThreshold?.find ??
|
|
1280
|
-
findAll: options.cacheThreshold?.findAll ??
|
|
1281
|
+
find: options.cacheThreshold?.find ?? 0.01, // Default: 1% threshold
|
|
1282
|
+
findAll: options.cacheThreshold?.findAll ?? 0.01,
|
|
1281
1283
|
};
|
|
1282
1284
|
}
|
|
1283
1285
|
|
|
@@ -2274,6 +2276,11 @@ with zipfile.ZipFile(io.BytesIO(zip_data)) as zf:
|
|
|
2274
2276
|
// Set redrawThreshold on agent's cliArgs.options
|
|
2275
2277
|
this.agent.cliArgs.options.redrawThreshold = this.redrawThreshold;
|
|
2276
2278
|
|
|
2279
|
+
// Pass test file name to agent for debugger display
|
|
2280
|
+
if (this.testFile) {
|
|
2281
|
+
this.agent.testFile = this.testFile;
|
|
2282
|
+
}
|
|
2283
|
+
|
|
2277
2284
|
// Use the agent's buildEnv method which handles all the connection logic
|
|
2278
2285
|
await this.agent.buildEnv(buildEnvOptions);
|
|
2279
2286
|
|
|
@@ -2460,28 +2467,28 @@ with zipfile.ZipFile(io.BytesIO(zip_data)) as zf:
|
|
|
2460
2467
|
|
|
2461
2468
|
// Use default cacheKey from SDK constructor if not provided in findAll() options
|
|
2462
2469
|
// BUT only if cache is not explicitly disabled via cache: false option
|
|
2463
|
-
if (!cacheKey && this.options?.cacheKey && this.
|
|
2470
|
+
if (!cacheKey && this.options?.cacheKey && !this._cacheExplicitlyDisabled) {
|
|
2464
2471
|
cacheKey = this.options.cacheKey;
|
|
2465
2472
|
}
|
|
2466
2473
|
|
|
2467
2474
|
// Determine threshold:
|
|
2468
|
-
// - If cache is explicitly disabled
|
|
2469
|
-
// - If cacheKey is provided, enable cache
|
|
2470
|
-
// - If no cacheKey, disable cache
|
|
2475
|
+
// - If cache is explicitly disabled, don't use cache even with cacheKey
|
|
2476
|
+
// - If cacheKey is provided, enable cache with threshold
|
|
2477
|
+
// - If no cacheKey, disable cache
|
|
2471
2478
|
let threshold;
|
|
2472
|
-
if (this.
|
|
2473
|
-
// Cache explicitly disabled via cache: false option
|
|
2479
|
+
if (this._cacheExplicitlyDisabled) {
|
|
2480
|
+
// Cache explicitly disabled via cache: false option or TD_NO_CACHE env
|
|
2474
2481
|
threshold = -1;
|
|
2475
2482
|
cacheKey = null; // Clear any cacheKey to ensure cache is truly disabled
|
|
2476
2483
|
} else if (cacheKey) {
|
|
2477
2484
|
// cacheKey provided - enable cache with threshold
|
|
2478
|
-
threshold = cacheThreshold ?? 0.01;
|
|
2485
|
+
threshold = cacheThreshold ?? this.cacheThresholds?.findAll ?? 0.01;
|
|
2479
2486
|
} else if (cacheThreshold !== null) {
|
|
2480
2487
|
// Explicit threshold provided without cacheKey
|
|
2481
2488
|
threshold = cacheThreshold;
|
|
2482
2489
|
} else {
|
|
2483
|
-
// No cacheKey, no explicit threshold -
|
|
2484
|
-
threshold =
|
|
2490
|
+
// No cacheKey, no explicit threshold - disable cache
|
|
2491
|
+
threshold = -1;
|
|
2485
2492
|
}
|
|
2486
2493
|
|
|
2487
2494
|
// Debug log threshold
|