testdriverai 7.5.16 → 7.5.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/CHANGELOG.md +21 -0
- package/agent/lib/sandbox.js +56 -1
- package/agent/lib/sdk.js +15 -0
- package/docs/_scripts/generate-examples.js +27 -1
- package/docs/v7/examples/ai.mdx +1 -1
- package/docs/v7/examples/assert.mdx +1 -1
- package/docs/v7/examples/captcha-api.mdx +1 -1
- package/docs/v7/examples/chrome-extension.mdx +1 -1
- package/docs/v7/examples/drag-and-drop.mdx +1 -1
- package/docs/v7/examples/element-not-found.mdx +1 -1
- package/docs/v7/examples/hover-image.mdx +1 -1
- package/docs/v7/examples/hover-text.mdx +1 -1
- package/docs/v7/examples/installer.mdx +1 -1
- package/docs/v7/examples/launch-vscode-linux.mdx +1 -1
- package/docs/v7/examples/match-image.mdx +1 -1
- package/docs/v7/examples/press-keys.mdx +1 -1
- package/docs/v7/examples/scroll-keyboard.mdx +1 -1
- package/docs/v7/examples/scroll-until-image.mdx +1 -1
- package/docs/v7/examples/scroll-until-text.mdx +1 -1
- package/docs/v7/examples/scroll.mdx +1 -1
- package/docs/v7/examples/type.mdx +1 -1
- package/docs/v7/examples/windows-installer.mdx +1 -1
- package/package.json +1 -1
- package/lib/vitest/gate-server.mjs +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
## 7.5.18 (2026-03-09)
|
|
2
|
+
|
|
3
|
+
## 🔧 Maintenance
|
|
4
|
+
|
|
5
|
+
- Optimize monitoring performance by reducing transaction sampling rate [Image Worker] (adb2a35d)
|
|
6
|
+
|
|
7
|
+
## 7.5.17 (2026-03-07)
|
|
8
|
+
|
|
9
|
+
## ✨ Features
|
|
10
|
+
- Enhanced marketing website with new "How It Works" section and improved visual components (161c1c7b)
|
|
11
|
+
- Added new brand assets and workflow illustrations for better user onboarding (161c1c7b)
|
|
12
|
+
|
|
13
|
+
## 🐛 Bug Fixes
|
|
14
|
+
- Fixed Stripe checkout pricing and authentication issues [API] (161c1c7b)
|
|
15
|
+
- Resolved potential witness functionality issues [SDK] (161c1c7b)
|
|
16
|
+
|
|
17
|
+
## 🔧 Maintenance
|
|
18
|
+
- Updated SDK documentation examples with improved formatting and generation scripts [SDK] (161c1c7b)
|
|
19
|
+
- Enhanced sandbox authentication and SDK functionality [SDK] (161c1c7b)
|
|
20
|
+
- Improved development environment configuration and tooling (161c1c7b)
|
|
21
|
+
|
|
1
22
|
## 7.5.16 (2026-03-07)
|
|
2
23
|
|
|
3
24
|
## ✨ Features
|
package/agent/lib/sandbox.js
CHANGED
|
@@ -534,7 +534,17 @@ const createSandbox = function (emitter, analytics, sessionInstance) {
|
|
|
534
534
|
}
|
|
535
535
|
|
|
536
536
|
if (message.type === "direct") {
|
|
537
|
-
// If the API
|
|
537
|
+
// If the API returned agent config and we have an instanceId,
|
|
538
|
+
// provision the config to the instance via SSM (client-side).
|
|
539
|
+
// This runs from the user's infrastructure where AWS permissions exist,
|
|
540
|
+
// rather than from the API server.
|
|
541
|
+
if (reply.agentConfig && message.instanceId) {
|
|
542
|
+
logger.log('Provisioning agent config to instance ' + message.instanceId + ' via SSM...');
|
|
543
|
+
await this._provisionAgentConfig(message.instanceId, reply.agentConfig);
|
|
544
|
+
logger.log('Agent config provisioned successfully.');
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// If the API returned agent credentials (reply.agent present),
|
|
538
548
|
// wait for the runner agent to signal readiness before sending commands.
|
|
539
549
|
// Without this gate, commands published before the agent subscribes are lost.
|
|
540
550
|
var self = this;
|
|
@@ -934,6 +944,51 @@ const createSandbox = function (emitter, analytics, sessionInstance) {
|
|
|
934
944
|
this._lastConnectParams = null;
|
|
935
945
|
this.ps = {};
|
|
936
946
|
}
|
|
947
|
+
|
|
948
|
+
/**
|
|
949
|
+
* Write the agent config JSON to an EC2 instance via AWS SSM.
|
|
950
|
+
* Runs client-side so the API doesn't need AWS permissions on user infra.
|
|
951
|
+
*/
|
|
952
|
+
async _provisionAgentConfig(instanceId, agentConfig) {
|
|
953
|
+
const { execSync } = require('child_process');
|
|
954
|
+
const { writeFileSync, unlinkSync } = require('fs');
|
|
955
|
+
const { join } = require('path');
|
|
956
|
+
const { tmpdir } = require('os');
|
|
957
|
+
|
|
958
|
+
const configJson = JSON.stringify(agentConfig);
|
|
959
|
+
const region = process.env.AWS_REGION || 'us-east-2';
|
|
960
|
+
|
|
961
|
+
// Write SSM parameters to a temp file to avoid shell quoting issues
|
|
962
|
+
const paramsJson = JSON.stringify({
|
|
963
|
+
commands: [
|
|
964
|
+
"$config = '" + configJson.replace(/'/g, "''") + "'",
|
|
965
|
+
"[System.IO.File]::WriteAllText('C:\\Windows\\Temp\\testdriver-agent.json', $config)",
|
|
966
|
+
"Write-Host 'Config written for sandbox " + agentConfig.sandboxId + "'",
|
|
967
|
+
],
|
|
968
|
+
});
|
|
969
|
+
const tmpFile = join(tmpdir(), 'td-provision-' + Date.now() + '.json');
|
|
970
|
+
writeFileSync(tmpFile, paramsJson);
|
|
971
|
+
|
|
972
|
+
try {
|
|
973
|
+
const output = execSync(
|
|
974
|
+
'aws ssm send-command --region "' + region + '" --instance-ids "' + instanceId + '" ' +
|
|
975
|
+
'--document-name "AWS-RunPowerShellScript" ' +
|
|
976
|
+
'--parameters file://' + tmpFile + ' --output json',
|
|
977
|
+
{ encoding: 'utf-8', timeout: 30000 }
|
|
978
|
+
);
|
|
979
|
+
const cmdId = JSON.parse(output).Command.CommandId;
|
|
980
|
+
logger.log('SSM command sent: ' + cmdId);
|
|
981
|
+
|
|
982
|
+
// Wait for the command to complete
|
|
983
|
+
execSync(
|
|
984
|
+
'aws ssm wait command-executed --region "' + region + '" ' +
|
|
985
|
+
'--command-id "' + cmdId + '" --instance-id "' + instanceId + '"',
|
|
986
|
+
{ encoding: 'utf-8', timeout: 60000 }
|
|
987
|
+
);
|
|
988
|
+
} finally {
|
|
989
|
+
try { unlinkSync(tmpFile); } catch (e) { /* ignore */ }
|
|
990
|
+
}
|
|
991
|
+
}
|
|
937
992
|
}
|
|
938
993
|
|
|
939
994
|
return new Sandbox();
|
package/agent/lib/sdk.js
CHANGED
|
@@ -218,6 +218,7 @@ const createSDK = (emitter, config, sessionInstance) => {
|
|
|
218
218
|
method: "post",
|
|
219
219
|
headers: {
|
|
220
220
|
"Content-Type": "application/json",
|
|
221
|
+
"User-Agent": `TestDriverSDK/${version} (Node.js ${process.version})`,
|
|
221
222
|
},
|
|
222
223
|
timeout: 15000, // 15 second timeout for auth requests
|
|
223
224
|
data: {
|
|
@@ -309,6 +310,18 @@ const createSDK = (emitter, config, sessionInstance) => {
|
|
|
309
310
|
return rateLimitError;
|
|
310
311
|
}
|
|
311
312
|
|
|
313
|
+
// Forbidden (403) - likely Cloudflare or WAF blocking the request
|
|
314
|
+
if (status === 403) {
|
|
315
|
+
const forbiddenError = new Error(
|
|
316
|
+
"Request blocked (HTTP 403). This may be caused by a firewall or bot protection. " +
|
|
317
|
+
"If this persists, please contact support."
|
|
318
|
+
);
|
|
319
|
+
forbiddenError.code = "REQUEST_BLOCKED";
|
|
320
|
+
forbiddenError.isForbiddenError = true;
|
|
321
|
+
forbiddenError.originalError = error;
|
|
322
|
+
return forbiddenError;
|
|
323
|
+
}
|
|
324
|
+
|
|
312
325
|
// Other HTTP errors - return with context
|
|
313
326
|
const url = error.config?.url || apiRoot;
|
|
314
327
|
const genericError = new Error(
|
|
@@ -366,6 +379,7 @@ const createSDK = (emitter, config, sessionInstance) => {
|
|
|
366
379
|
method: "post",
|
|
367
380
|
headers: {
|
|
368
381
|
"Content-Type": "application/json",
|
|
382
|
+
"User-Agent": `TestDriverSDK/${version} (Node.js ${process.version})`,
|
|
369
383
|
...(token && { Authorization: `Bearer ${token}` }),
|
|
370
384
|
},
|
|
371
385
|
timeout: 15000,
|
|
@@ -430,6 +444,7 @@ const createSDK = (emitter, config, sessionInstance) => {
|
|
|
430
444
|
method: "post",
|
|
431
445
|
headers: {
|
|
432
446
|
"Content-Type": "application/json",
|
|
447
|
+
"User-Agent": `TestDriverSDK/${version} (Node.js ${process.version})`,
|
|
433
448
|
...(token && { Authorization: `Bearer ${token}` }), // Add the authorization bearer token only if token is set
|
|
434
449
|
...sentryHeaders, // Add Sentry distributed tracing headers
|
|
435
450
|
},
|
|
@@ -82,9 +82,35 @@ function getExampleFiles() {
|
|
|
82
82
|
.sort();
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
// Rewrite internal imports and helpers to their public equivalents
|
|
86
|
+
function transformContentForDocs(content) {
|
|
87
|
+
let transformed = content;
|
|
88
|
+
|
|
89
|
+
// Rewrite internal relative import to the public package path
|
|
90
|
+
transformed = transformed.replace(
|
|
91
|
+
/from\s+["']\.\.\/lib\/vitest\/hooks\.mjs["']/g,
|
|
92
|
+
'from "testdriverai/vitest/hooks"'
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// Remove internal config helper import
|
|
96
|
+
transformed = transformed.replace(
|
|
97
|
+
/import\s+\{[^}]*getDefaults[^}]*\}\s+from\s+["']\.\/config\.mjs["'];\n?/g,
|
|
98
|
+
''
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
// Replace getDefaults(context) spread with inline defaults
|
|
102
|
+
transformed = transformed.replace(
|
|
103
|
+
/\{\s*\.\.\.getDefaults\(context\)\s*/g,
|
|
104
|
+
'{ ip: context.ip || process.env.TD_IP'
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
return transformed;
|
|
108
|
+
}
|
|
109
|
+
|
|
85
110
|
// Parse test file to extract metadata
|
|
86
111
|
function parseTestFile(filePath) {
|
|
87
|
-
const
|
|
112
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
113
|
+
const content = transformContentForDocs(raw);
|
|
88
114
|
const filename = path.basename(filePath);
|
|
89
115
|
|
|
90
116
|
// Extract JSDoc comment at top of file
|
package/docs/v7/examples/ai.mdx
CHANGED
|
@@ -27,7 +27,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { describe, expect, it } from "vitest";
|
|
30
|
-
import { TestDriver } from "
|
|
30
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
31
31
|
|
|
32
32
|
describe("AI Test", () => {
|
|
33
33
|
it("should use ai to search for testdriver on Google", async (context) => {
|
|
@@ -27,7 +27,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { describe, expect, it } from "vitest";
|
|
30
|
-
import { TestDriver } from "
|
|
30
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
31
31
|
|
|
32
32
|
describe("Assert Test", () => {
|
|
33
33
|
it("should assert the testdriver login page shows", async (context) => {
|
|
@@ -26,7 +26,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
26
26
|
* TestDriver SDK - Captcha Test
|
|
27
27
|
*/
|
|
28
28
|
import { describe, expect, it } from "vitest";
|
|
29
|
-
import { TestDriver } from "
|
|
29
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
30
30
|
|
|
31
31
|
console.log("DEBUG: process.env.TD_OS:", process.env.TD_OS);
|
|
32
32
|
|
|
@@ -27,7 +27,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { describe, expect, it } from "vitest";
|
|
30
|
-
import { TestDriver } from "
|
|
30
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
31
31
|
|
|
32
32
|
describe("Chrome Extension Test", () => {
|
|
33
33
|
it("should load hello-world Chrome extension from local path", async (context) => {
|
|
@@ -27,7 +27,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { describe, expect, it } from "vitest";
|
|
30
|
-
import { TestDriver } from "
|
|
30
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
31
31
|
|
|
32
32
|
const isLinux = (process.env.TD_OS || "linux") === "linux";
|
|
33
33
|
|
|
@@ -27,7 +27,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { describe, expect, it } from "vitest";
|
|
30
|
-
import { TestDriver } from "
|
|
30
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
31
31
|
|
|
32
32
|
describe("Element Not Found Test", () => {
|
|
33
33
|
it("should handle non-existent element gracefully without timing out", async (context) => {
|
|
@@ -27,7 +27,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { describe, expect, it } from "vitest";
|
|
30
|
-
import { TestDriver } from "
|
|
30
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Perform login flow for SauceLabs demo app
|
|
@@ -27,7 +27,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { describe, expect, it } from "vitest";
|
|
30
|
-
import { TestDriver } from "
|
|
30
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
31
31
|
|
|
32
32
|
describe("Hover Text Test", () => {
|
|
33
33
|
it("should click Sign In and verify error message", async (context) => {
|
|
@@ -27,7 +27,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { describe, expect, it } from "vitest";
|
|
30
|
-
import { TestDriver } from "
|
|
30
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
31
31
|
|
|
32
32
|
const isLinux = (process.env.TD_OS || "linux") === "linux";
|
|
33
33
|
|
|
@@ -27,7 +27,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { describe, expect, it } from "vitest";
|
|
30
|
-
import { TestDriver } from "
|
|
30
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
31
31
|
|
|
32
32
|
const isLinux = (process.env.TD_OS || "linux") === "linux";
|
|
33
33
|
|
|
@@ -29,7 +29,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
29
29
|
import path, { dirname } from "path";
|
|
30
30
|
import { fileURLToPath } from "url";
|
|
31
31
|
import { describe, expect, it } from "vitest";
|
|
32
|
-
import { TestDriver } from "
|
|
32
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* Perform login flow for SauceLabs demo app
|
|
@@ -27,7 +27,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { describe, expect, it } from "vitest";
|
|
30
|
-
import { TestDriver } from "
|
|
30
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
31
31
|
|
|
32
32
|
describe("Press Keys Test", () => {
|
|
33
33
|
it("should create tabs and navigate using keyboard shortcuts", async (context) => {
|
|
@@ -27,7 +27,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { describe, expect, it } from "vitest";
|
|
30
|
-
import { TestDriver } from "
|
|
30
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
31
31
|
|
|
32
32
|
describe("Scroll Keyboard Test", () => {
|
|
33
33
|
it("should navigate to webhamster.com and scroll with keyboard", async (context) => {
|
|
@@ -27,7 +27,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { describe, expect, it } from "vitest";
|
|
30
|
-
import { TestDriver } from "
|
|
30
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
31
31
|
|
|
32
32
|
describe("Scroll Until Image Test", () => {
|
|
33
33
|
it.skip("should scroll until brown colored house image appears", async (context) => {
|
|
@@ -27,7 +27,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { describe, expect, it } from "vitest";
|
|
30
|
-
import { TestDriver } from "
|
|
30
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Perform login flow for SauceLabs demo app
|
|
@@ -27,7 +27,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { describe, expect, it } from "vitest";
|
|
30
|
-
import { TestDriver } from "
|
|
30
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
31
31
|
|
|
32
32
|
describe("Scroll Test", () => {
|
|
33
33
|
it("should navigate and scroll down the page", async (context) => {
|
|
@@ -27,7 +27,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { describe, expect, it } from "vitest";
|
|
30
|
-
import { TestDriver } from "
|
|
30
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
31
31
|
|
|
32
32
|
describe("Type Test", () => {
|
|
33
33
|
it("should enter standard_user in username field", async (context) => {
|
|
@@ -27,7 +27,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { describe, it } from "vitest";
|
|
30
|
-
import { TestDriver } from "
|
|
30
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
31
31
|
|
|
32
32
|
const isLinux = (process.env.TD_OS || "linux") === "linux";
|
|
33
33
|
|
package/package.json
CHANGED
|
File without changes
|