testdriverai 7.5.26 → 7.6.0-test.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/CHANGELOG.md +28 -19
- package/README.md +1 -0
- package/agent/lib/config.js +3 -1
- package/agent/lib/sandbox.js +6 -4
- package/ai/agents/testdriver.md +0 -3
- package/ai/skills/testdriver-exec/SKILL.md +23 -40
- package/ai/skills/testdriver-test-writer/SKILL.md +0 -3
- package/ai/skills/testdriver-testdriver/SKILL.md +0 -3
- package/channel.json +9 -0
- package/docs/images/content/parse/output.png +0 -0
- package/docs/v6/commands/exec.mdx +15 -21
- package/docs/v7/_drafts/agents.mdx +4 -13
- package/docs/v7/_drafts/commands/exec.mdx +15 -21
- package/docs/v7/exec.mdx +36 -64
- package/docs/v7/quickstart.mdx +1 -1
- package/interfaces/cli/commands/init.js +2 -1
- package/interfaces/vitest-plugin.mjs +23 -2
- package/lib/core/Dashcam.js +23 -2
- package/lib/init-project.js +67 -27
- package/lib/vitest/hooks.mjs +2 -1
- package/mcp-server/README.md +12 -2
- package/mcp-server/dist/codegen.js +1 -1
- package/mcp-server/dist/server.mjs +55 -5
- package/mcp-server/src/codegen.ts +1 -1
- package/mcp-server/src/server.ts +49 -5
- package/package.json +6 -2
- package/sdk.d.ts +2 -2
- package/sdk.js +49 -4
- package/vitest.config.mjs +56 -12
package/sdk.js
CHANGED
|
@@ -1402,7 +1402,7 @@ function normalizeRedrawOptions(opts) {
|
|
|
1402
1402
|
* @typedef {'up' | 'down' | 'left' | 'right'} ScrollDirection
|
|
1403
1403
|
* @typedef {'keyboard' | 'mouse'} ScrollMethod
|
|
1404
1404
|
* @typedef {'ai' | 'turbo'} TextMatchMethod
|
|
1405
|
-
* @typedef {'
|
|
1405
|
+
* @typedef {'sh' | 'pwsh'} ExecLanguage
|
|
1406
1406
|
* @typedef {'\\t' | '\n' | '\r' | ' ' | '!' | '"' | '#' | '$' | '%' | '&' | "'" | '(' | ')' | '*' | '+' | ',' | '-' | '.' | '/' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '[' | '\\' | ']' | '^' | '_' | '`' | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' | '{' | '|' | '}' | '~' | 'accept' | 'add' | 'alt' | 'altleft' | 'altright' | 'apps' | 'backspace' | 'browserback' | 'browserfavorites' | 'browserforward' | 'browserhome' | 'browserrefresh' | 'browsersearch' | 'browserstop' | 'capslock' | 'clear' | 'convert' | 'ctrl' | 'ctrlleft' | 'ctrlright' | 'decimal' | 'del' | 'delete' | 'divide' | 'down' | 'end' | 'enter' | 'esc' | 'escape' | 'execute' | 'f1' | 'f10' | 'f11' | 'f12' | 'f13' | 'f14' | 'f15' | 'f16' | 'f17' | 'f18' | 'f19' | 'f2' | 'f20' | 'f21' | 'f22' | 'f23' | 'f24' | 'f3' | 'f4' | 'f5' | 'f6' | 'f7' | 'f8' | 'f9' | 'final' | 'fn' | 'hanguel' | 'hangul' | 'hanja' | 'help' | 'home' | 'insert' | 'junja' | 'kana' | 'kanji' | 'launchapp1' | 'launchapp2' | 'launchmail' | 'launchmediaselect' | 'left' | 'modechange' | 'multiply' | 'nexttrack' | 'nonconvert' | 'num0' | 'num1' | 'num2' | 'num3' | 'num4' | 'num5' | 'num6' | 'num7' | 'num8' | 'num9' | 'numlock' | 'pagedown' | 'pageup' | 'pause' | 'pgdn' | 'pgup' | 'playpause' | 'prevtrack' | 'print' | 'printscreen' | 'prntscrn' | 'prtsc' | 'prtscr' | 'return' | 'right' | 'scrolllock' | 'select' | 'separator' | 'shift' | 'shiftleft' | 'shiftright' | 'sleep' | 'space' | 'stop' | 'subtract' | 'tab' | 'up' | 'volumedown' | 'volumemute' | 'volumeup' | 'win' | 'winleft' | 'winright' | 'yen' | 'command' | 'option' | 'optionleft' | 'optionright'} KeyboardKey
|
|
1407
1407
|
*/
|
|
1408
1408
|
|
|
@@ -1910,7 +1910,7 @@ class TestDriverSDK {
|
|
|
1910
1910
|
// Add web log tracking with domain wildcard pattern, then start dashcam
|
|
1911
1911
|
if (this.dashcamEnabled) {
|
|
1912
1912
|
const domainPattern = this._getUrlDomainPattern(url);
|
|
1913
|
-
|
|
1913
|
+
await this.dashcam.addWebLog(domainPattern, "Web Logs");
|
|
1914
1914
|
|
|
1915
1915
|
// Start dashcam recording after logs are configured
|
|
1916
1916
|
if (!(await this.dashcam.isRecording())) {
|
|
@@ -2477,7 +2477,7 @@ with zipfile.ZipFile(io.BytesIO(zip_data)) as zf:
|
|
|
2477
2477
|
const pattern = this._provisionedChromeUrl
|
|
2478
2478
|
? this._getUrlDomainPattern(this._provisionedChromeUrl)
|
|
2479
2479
|
: "**";
|
|
2480
|
-
|
|
2480
|
+
await this.dashcam.addWebLog(pattern, "Web Logs");
|
|
2481
2481
|
}
|
|
2482
2482
|
|
|
2483
2483
|
// Start recording if not already recording
|
|
@@ -2864,6 +2864,9 @@ CAPTCHA_SOLVER_EOF`,
|
|
|
2864
2864
|
sandboxId: this.instance?.instanceId,
|
|
2865
2865
|
});
|
|
2866
2866
|
|
|
2867
|
+
// Log environment info (non-blocking, skip on stable)
|
|
2868
|
+
this._logEnvironmentInfo();
|
|
2869
|
+
|
|
2867
2870
|
return this.instance;
|
|
2868
2871
|
}
|
|
2869
2872
|
|
|
@@ -2892,8 +2895,10 @@ CAPTCHA_SOLVER_EOF`,
|
|
|
2892
2895
|
|
|
2893
2896
|
// Always close the sandbox WebSocket connection to clean up resources
|
|
2894
2897
|
// This ensures we don't leave orphaned connections even if connect() failed
|
|
2898
|
+
// Must be awaited so presence.leave() completes before we return —
|
|
2899
|
+
// otherwise the concurrency counter on the API stays stale.
|
|
2895
2900
|
if (this.sandbox && typeof this.sandbox.close === "function") {
|
|
2896
|
-
this.sandbox.close();
|
|
2901
|
+
await this.sandbox.close();
|
|
2897
2902
|
}
|
|
2898
2903
|
|
|
2899
2904
|
// Remove all event listeners on the emitter to release references
|
|
@@ -3801,6 +3806,46 @@ CAPTCHA_SOLVER_EOF`,
|
|
|
3801
3806
|
* Set up logging for the SDK
|
|
3802
3807
|
* @private
|
|
3803
3808
|
*/
|
|
3809
|
+
/**
|
|
3810
|
+
* Log environment info (version, API URL, git commit) after connect.
|
|
3811
|
+
* Fires asynchronously so it never blocks the test.
|
|
3812
|
+
* Suppressed when the API reports the "stable" channel.
|
|
3813
|
+
* @private
|
|
3814
|
+
*/
|
|
3815
|
+
_logEnvironmentInfo() {
|
|
3816
|
+
const apiRoot = this.config?.TD_API_ROOT || 'unknown';
|
|
3817
|
+
const sdkVersion = require('./package.json').version;
|
|
3818
|
+
const http = apiRoot.startsWith('https') ? require('https') : require('http');
|
|
3819
|
+
|
|
3820
|
+
const url = apiRoot + '/api/entrance/version';
|
|
3821
|
+
const req = http.get(url, { timeout: 5000 }, (res) => {
|
|
3822
|
+
let data = '';
|
|
3823
|
+
res.on('data', (chunk) => { data += chunk; });
|
|
3824
|
+
res.on('end', () => {
|
|
3825
|
+
try {
|
|
3826
|
+
const info = JSON.parse(data);
|
|
3827
|
+
if (info.channel === 'stable') return; // don't show on stable
|
|
3828
|
+
const commit = info.commit || 'unknown';
|
|
3829
|
+
const shortCommit = commit.substring(0, 7);
|
|
3830
|
+
const commitUrl = commit !== 'unknown'
|
|
3831
|
+
? `https://github.com/testdriverai/mono/commit/${commit}`
|
|
3832
|
+
: null;
|
|
3833
|
+
const lines = [
|
|
3834
|
+
'',
|
|
3835
|
+
` TestDriver SDK v${sdkVersion}`,
|
|
3836
|
+
` API: ${apiRoot} (${info.channel || 'unknown'} v${info.version || '?'})`,
|
|
3837
|
+
commitUrl
|
|
3838
|
+
? ` Commit: ${shortCommit} → ${commitUrl}`
|
|
3839
|
+
: ` Commit: ${shortCommit}`,
|
|
3840
|
+
'',
|
|
3841
|
+
];
|
|
3842
|
+
console.log(lines.join('\n'));
|
|
3843
|
+
} catch (_) { /* ignore parse errors */ }
|
|
3844
|
+
});
|
|
3845
|
+
});
|
|
3846
|
+
req.on('error', () => { /* ignore network errors */ });
|
|
3847
|
+
}
|
|
3848
|
+
|
|
3804
3849
|
_setupLogging() {
|
|
3805
3850
|
// Track the last fatal error message to throw on exit
|
|
3806
3851
|
let lastFatalError = null;
|
package/vitest.config.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import TestDriver from "testdriverai/vitest";
|
|
2
2
|
import { defineConfig } from "vitest/config";
|
|
3
|
+
import { readFileSync, existsSync } from "fs";
|
|
4
|
+
import { resolve } from "path";
|
|
3
5
|
|
|
4
6
|
// Always include AWS setup - it will be a no-op unless TD_OS=windows
|
|
5
7
|
// Note: dotenv is loaded automatically by the TestDriver SDK
|
|
@@ -8,19 +10,61 @@ const setupFiles = [
|
|
|
8
10
|
"testdriverai/vitest/setup-aws"
|
|
9
11
|
];
|
|
10
12
|
|
|
13
|
+
const sharedTestConfig = {
|
|
14
|
+
retry: 0,
|
|
15
|
+
testTimeout: 900000,
|
|
16
|
+
hookTimeout: 900000,
|
|
17
|
+
maxConcurrency: 100,
|
|
18
|
+
disableConsoleIntercept: false,
|
|
19
|
+
silent: false,
|
|
20
|
+
reporters: [
|
|
21
|
+
"verbose",
|
|
22
|
+
TestDriver()
|
|
23
|
+
],
|
|
24
|
+
setupFiles,
|
|
25
|
+
include: ["examples/**/*.test.mjs"],
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// ── Parse a simple KEY=VALUE .env file ──────────────────────────────
|
|
29
|
+
function parseEnvFile(filePath) {
|
|
30
|
+
if (!existsSync(filePath)) return {};
|
|
31
|
+
const env = {};
|
|
32
|
+
for (const line of readFileSync(filePath, "utf-8").split("\n")) {
|
|
33
|
+
const trimmed = line.trim();
|
|
34
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
35
|
+
const idx = trimmed.indexOf("=");
|
|
36
|
+
if (idx === -1) continue;
|
|
37
|
+
env[trimmed.slice(0, idx)] = trimmed.slice(idx + 1);
|
|
38
|
+
}
|
|
39
|
+
return env;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ── Load base .env + per-environment overlay ────────────────────────
|
|
43
|
+
const monoRoot = resolve(import.meta.dirname, "..");
|
|
44
|
+
const baseEnv = parseEnvFile(resolve(monoRoot, ".env"));
|
|
45
|
+
|
|
46
|
+
const environments = ["dev", "test", "canary", "stable"];
|
|
47
|
+
|
|
48
|
+
function envForProject(envName) {
|
|
49
|
+
const overlay = parseEnvFile(resolve(monoRoot, "envs", `${envName}.env`));
|
|
50
|
+
return { ...baseEnv, ...overlay };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ── If TD_ENV is set (e.g. from CLI), only run that environment ─────
|
|
54
|
+
// Usage: TD_ENV=dev vitest run
|
|
55
|
+
// TD_ENV=canary vitest run examples/assert.test.mjs
|
|
56
|
+
// vitest run --project dev
|
|
57
|
+
// vitest run --project canary --project stable
|
|
11
58
|
export default defineConfig({
|
|
12
59
|
test: {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
TestDriver()
|
|
23
|
-
],
|
|
24
|
-
setupFiles,
|
|
60
|
+
...sharedTestConfig,
|
|
61
|
+
env: envForProject(process.env.TD_ENV || "dev"),
|
|
62
|
+
projects: environments.map((envName) => ({
|
|
63
|
+
extends: true,
|
|
64
|
+
test: {
|
|
65
|
+
name: envName,
|
|
66
|
+
env: envForProject(envName),
|
|
67
|
+
},
|
|
68
|
+
})),
|
|
25
69
|
},
|
|
26
70
|
});
|