testdriverai 7.8.0-test.62 → 7.8.0-test.64

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.
@@ -12,19 +12,8 @@ import { getDefaults } from "./config.mjs";
12
12
  describe("Scroll Test", () => {
13
13
  it("should navigate and scroll down the page", async (context) => {
14
14
  const testdriver = TestDriver(context, { ...getDefaults(context), headless: true });
15
- await testdriver.provision.chrome({ url: 'http://testdriver-sandbox.vercel.app/login' });
15
+ await testdriver.provision.chrome({ url: 'https://www.webhamster.com/' });
16
16
 
17
- // Give Chrome a moment to fully render the UI
18
- await new Promise(resolve => setTimeout(resolve, 2000));
19
-
20
- // Navigate to webhamster.com - just look for the domain, not the full path
21
- const urlBar = await testdriver.find(
22
- "testdriver-sandbox.vercel.app, the URL in the address bar",
23
- );
24
- await urlBar.click();
25
- await testdriver.pressKeys(["ctrl", "a"]);
26
- await testdriver.type("https://www.webhamster.com/");
27
- await testdriver.pressKeys(["enter"]);
28
17
 
29
18
  // Wait for page to load and click heading
30
19
  const heading = await testdriver.find(
@@ -37,7 +37,7 @@ function initializeSentry() {
37
37
  dsn:
38
38
  process.env.SENTRY_DSN ||
39
39
  "https://452bd5a00dbd83a38ee8813e11c57694@o4510262629236736.ingest.us.sentry.io/4510480443637760",
40
- environment: "vitest",
40
+ environment: channelConfig.sentryEnvironment,
41
41
  release: version,
42
42
  sampleRate: 1.0,
43
43
  tracesSampleRate: 1.0,
@@ -1,18 +1,22 @@
1
1
  {
2
2
  "dev": {
3
3
  "apiRoot": "https://api-dev.testdriver.ai",
4
- "consoleUrl": "https://console-dev.testdriver.ai"
4
+ "consoleUrl": "https://console-dev.testdriver.ai",
5
+ "tdEnv": "dev"
5
6
  },
6
7
  "test": {
7
8
  "apiRoot": "https://api-test.testdriver.ai",
8
- "consoleUrl": "https://console-test.testdriver.ai"
9
+ "consoleUrl": "https://console-test.testdriver.ai",
10
+ "tdEnv": "staging"
9
11
  },
10
12
  "canary": {
11
13
  "apiRoot": "https://api-canary.testdriver.ai",
12
- "consoleUrl": "https://console-canary.testdriver.ai"
14
+ "consoleUrl": "https://console-canary.testdriver.ai",
15
+ "tdEnv": "production"
13
16
  },
14
17
  "stable": {
15
18
  "apiRoot": "https://api.testdriver.ai",
16
- "consoleUrl": "https://console.testdriver.ai"
19
+ "consoleUrl": "https://console.testdriver.ai",
20
+ "tdEnv": "production"
17
21
  }
18
22
  }
@@ -14,66 +14,11 @@ function runInstall(cmd, args, cwd, label) {
14
14
  return new Promise((resolve, reject) => {
15
15
  const child = spawn(cmd, args, {
16
16
  cwd,
17
- stdio: ["ignore", "pipe", "pipe"],
17
+ stdio: ["ignore", "inherit", "inherit"],
18
18
  shell: process.platform === "win32",
19
19
  });
20
20
 
21
- const spinnerFrames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
22
- const barWidth = 20;
23
- let frame = 0;
24
- let status = "resolving";
25
- let filled = 0;
26
-
27
- // Parse npm stderr for progress hints
28
- const handleData = (data) => {
29
- const text = data.toString();
30
- if (text.includes("idealTree")) {
31
- status = "resolving packages";
32
- filled = Math.max(filled, 3);
33
- } else if (text.includes("reify:")) {
34
- status = "installing";
35
- filled = Math.max(filled, 8);
36
- // Try to extract package name from reify output
37
- const match = text.match(/reify:([^\s:]+)/);
38
- if (match) {
39
- status = `installing ${match[1]}`;
40
- }
41
- } else if (text.includes("timing")) {
42
- filled = Math.max(filled, 14);
43
- status = "finalizing";
44
- } else if (text.includes("added")) {
45
- filled = barWidth;
46
- status = "done";
47
- }
48
- // Slowly increment to show activity
49
- if (filled < barWidth - 2) {
50
- filled = Math.min(filled + 1, barWidth - 2);
51
- }
52
- };
53
-
54
- child.stdout.on("data", handleData);
55
- child.stderr.on("data", handleData);
56
-
57
- const isTTY = process.stderr.isTTY;
58
-
59
- const interval = setInterval(() => {
60
- frame = (frame + 1) % spinnerFrames.length;
61
- const spinner = spinnerFrames[frame];
62
- const bar = "█".repeat(filled) + "░".repeat(barWidth - filled);
63
- const line = ` ${spinner} ${label} [${bar}] ${status}`;
64
- if (isTTY) {
65
- process.stderr.clearLine(0);
66
- process.stderr.cursorTo(0);
67
- process.stderr.write(line);
68
- }
69
- }, 80);
70
-
71
21
  child.on("close", (code) => {
72
- clearInterval(interval);
73
- if (isTTY) {
74
- process.stderr.clearLine(0);
75
- process.stderr.cursorTo(0);
76
- }
77
22
  if (code === 0) {
78
23
  resolve();
79
24
  } else {
@@ -82,11 +27,6 @@ function runInstall(cmd, args, cwd, label) {
82
27
  });
83
28
 
84
29
  child.on("error", (err) => {
85
- clearInterval(interval);
86
- if (isTTY) {
87
- process.stderr.clearLine(0);
88
- process.stderr.cursorTo(0);
89
- }
90
30
  reject(err);
91
31
  });
92
32
  });
@@ -1,11 +1,14 @@
1
1
  /**
2
2
  * Resolves the active release channel and API URLs.
3
3
  *
4
+ * TD_CHANNEL: dev | test | canary | stable (which release channel)
5
+ * TD_ENV: dev | staging | production (which infrastructure tier)
6
+ *
4
7
  * Channel is derived from (in priority order):
5
8
  * 1. TD_CHANNEL env var (explicit override)
6
- * 2. TD_ENV env var (set by envs/<name>.env)
9
+ * 2. TD_ENV env var if it holds a legacy channel name (dev/test/canary/stable)
7
10
  * 3. SDK package.json version prerelease tag (e.g. "7.6.0-test.5" → "test")
8
- * 4. "latest" for clean semver versions (stable releases)
11
+ * 4. "stable" for clean semver versions
9
12
  */
10
13
 
11
14
  const semver = require("semver");
@@ -15,20 +18,20 @@ const CHANNELS = {
15
18
  dev: "http://localhost:1337",
16
19
  test: environments.test.apiRoot,
17
20
  canary: environments.canary.apiRoot,
18
- latest: environments.stable.apiRoot,
21
+ stable: environments.stable.apiRoot,
19
22
  };
20
23
 
24
+ const VALID_ENVS = new Set(["dev", "staging", "production"]);
25
+
21
26
  function resolveActiveChannel() {
22
27
  // 1. Explicit channel override
23
28
  if (process.env.TD_CHANNEL && CHANNELS[process.env.TD_CHANNEL]) {
24
29
  return process.env.TD_CHANNEL;
25
30
  }
26
31
 
27
- // 2. Environment name from env file (mapped: stable latest)
28
- if (process.env.TD_ENV) {
29
- const envName = process.env.TD_ENV;
30
- if (CHANNELS[envName]) return envName;
31
- if (envName === "stable") return "latest";
32
+ // 2. TD_ENV if it holds a legacy channel name, use it as channel
33
+ if (process.env.TD_ENV && CHANNELS[process.env.TD_ENV]) {
34
+ return process.env.TD_ENV;
32
35
  }
33
36
 
34
37
  // 3. Fallback: derive from package.json prerelease tag
@@ -38,9 +41,35 @@ function resolveActiveChannel() {
38
41
  return pre[0];
39
42
  }
40
43
 
41
- return "latest";
44
+ return "stable";
42
45
  }
43
46
 
44
47
  const active = resolveActiveChannel();
45
48
 
46
- module.exports = { active, channels: CHANNELS };
49
+ /**
50
+ * Returns the infrastructure environment (dev | staging | production).
51
+ * Reads from environments.json tdEnv mapping.
52
+ */
53
+ function resolveTdEnv() {
54
+ // If TD_ENV is already new-format, use it directly
55
+ if (process.env.TD_ENV && VALID_ENVS.has(process.env.TD_ENV)) {
56
+ return process.env.TD_ENV;
57
+ }
58
+ // Derive from channel
59
+ const entry = environments[active];
60
+ return entry ? entry.tdEnv : "production";
61
+ }
62
+
63
+ const tdEnv = resolveTdEnv();
64
+
65
+ /**
66
+ * Resolves the Sentry environment name.
67
+ * Uses the infrastructure tier (dev | staging | production).
68
+ */
69
+ function resolveSentryEnvironment() {
70
+ return tdEnv;
71
+ }
72
+
73
+ const sentryEnvironment = resolveSentryEnvironment();
74
+
75
+ module.exports = { active, channels: CHANNELS, sentryEnvironment, tdEnv };
package/lib/sentry.js CHANGED
@@ -14,6 +14,7 @@ const Sentry = require("@sentry/node");
14
14
  const crypto = require("crypto");
15
15
  const os = require("os");
16
16
  const { version } = require("../package.json");
17
+ const { sentryEnvironment } = require("./resolve-channel");
17
18
  const logger = require("../agent/lib/logger");
18
19
 
19
20
  // Store trace contexts per session so concurrent tests don't overwrite each other.
@@ -41,7 +42,7 @@ if (isEnabled()) {
41
42
  dsn:
42
43
  process.env.SENTRY_DSN ||
43
44
  "https://452bd5a00dbd83a38ee8813e11c57694@o4510262629236736.ingest.us.sentry.io/4510480443637760",
44
- environment: "sdk",
45
+ environment: sentryEnvironment,
45
46
  release: version,
46
47
  sampleRate: 1.0,
47
48
  tracesSampleRate: 1.0, // Sample 20% of transactions for performance
@@ -53,6 +54,7 @@ if (isEnabled()) {
53
54
  platform: os.platform(),
54
55
  arch: os.arch(),
55
56
  nodeVersion: process.version,
57
+ runner: "sdk",
56
58
  },
57
59
  },
58
60
  // Filter out common non-errors and expected test failures
@@ -26,18 +26,33 @@ import { sessionManager } from "./session.js";
26
26
  const sdkRoot = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
27
27
  const packageJson = JSON.parse(fs.readFileSync(path.join(sdkRoot, "package.json"), "utf-8"));
28
28
  const version = packageJson.version || "1.0.0";
29
- // Derive release channel from package version prerelease tag (e.g. "7.6.0-test.5" → "test")
29
+ // Derive release channel and infrastructure environment from package version
30
30
  import semver from "semver";
31
- const KNOWN_CHANNELS = new Set(["dev", "test", "canary", "latest"]);
32
- function resolveReleaseChannel(ver) {
33
- if (process.env.TD_CHANNEL && KNOWN_CHANNELS.has(process.env.TD_CHANNEL))
31
+ const CHANNEL_TO_ENV = {
32
+ dev: "dev",
33
+ test: "staging",
34
+ canary: "production",
35
+ stable: "production",
36
+ };
37
+ const VALID_CHANNELS = new Set(Object.keys(CHANNEL_TO_ENV));
38
+ const VALID_ENVS = new Set(["dev", "staging", "production"]);
39
+ function resolveChannel(ver) {
40
+ if (process.env.TD_CHANNEL && VALID_CHANNELS.has(process.env.TD_CHANNEL))
34
41
  return process.env.TD_CHANNEL;
42
+ if (process.env.TD_ENV && VALID_CHANNELS.has(process.env.TD_ENV))
43
+ return process.env.TD_ENV;
35
44
  const pre = semver.prerelease(ver);
36
- if (pre && pre.length > 0 && KNOWN_CHANNELS.has(String(pre[0])))
45
+ if (pre && pre.length > 0 && VALID_CHANNELS.has(String(pre[0])))
37
46
  return String(pre[0]);
38
- return "latest";
47
+ return "stable";
48
+ }
49
+ function resolveSentryEnvironment(ver) {
50
+ if (process.env.TD_ENV && VALID_ENVS.has(process.env.TD_ENV))
51
+ return process.env.TD_ENV;
52
+ return CHANNEL_TO_ENV[resolveChannel(ver)] || "production";
39
53
  }
40
- const releaseChannel = resolveReleaseChannel(version);
54
+ const activeChannel = resolveChannel(version);
55
+ const sentryEnvironment = resolveSentryEnvironment(version);
41
56
  const isSentryEnabled = () => {
42
57
  if (process.env.TD_TELEMETRY === "false") {
43
58
  return false;
@@ -49,7 +64,7 @@ if (isSentryEnabled()) {
49
64
  Sentry.init({
50
65
  dsn: process.env.SENTRY_DSN ||
51
66
  "https://452bd5a00dbd83a38ee8813e11c57694@o4510262629236736.ingest.us.sentry.io/4510480443637760",
52
- environment: releaseChannel,
67
+ environment: sentryEnvironment,
53
68
  release: version,
54
69
  sampleRate: 1.0,
55
70
  tracesSampleRate: 1.0,
@@ -57,6 +72,7 @@ if (isSentryEnabled()) {
57
72
  integrations: [Sentry.httpIntegration(), Sentry.nodeContextIntegration()],
58
73
  initialScope: {
59
74
  tags: {
75
+ channel: activeChannel,
60
76
  platform: os.platform(),
61
77
  arch: os.arch(),
62
78
  nodeVersion: process.version,
@@ -34,16 +34,33 @@ const sdkRoot = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", ".
34
34
  const packageJson = JSON.parse(fs.readFileSync(path.join(sdkRoot, "package.json"), "utf-8"));
35
35
  const version = packageJson.version || "1.0.0";
36
36
 
37
- // Derive release channel from package version prerelease tag (e.g. "7.6.0-test.5" → "test")
37
+ // Derive release channel and infrastructure environment from package version
38
38
  import semver from "semver";
39
- const KNOWN_CHANNELS = new Set(["dev", "test", "canary", "latest"]);
40
- function resolveReleaseChannel(ver: string): string {
41
- if (process.env.TD_CHANNEL && KNOWN_CHANNELS.has(process.env.TD_CHANNEL)) return process.env.TD_CHANNEL;
39
+
40
+ const CHANNEL_TO_ENV: Record<string, string> = {
41
+ dev: "dev",
42
+ test: "staging",
43
+ canary: "production",
44
+ stable: "production",
45
+ };
46
+ const VALID_CHANNELS = new Set(Object.keys(CHANNEL_TO_ENV));
47
+ const VALID_ENVS = new Set(["dev", "staging", "production"]);
48
+
49
+ function resolveChannel(ver: string): string {
50
+ if (process.env.TD_CHANNEL && VALID_CHANNELS.has(process.env.TD_CHANNEL)) return process.env.TD_CHANNEL;
51
+ if (process.env.TD_ENV && VALID_CHANNELS.has(process.env.TD_ENV)) return process.env.TD_ENV;
42
52
  const pre = semver.prerelease(ver);
43
- if (pre && pre.length > 0 && KNOWN_CHANNELS.has(String(pre[0]))) return String(pre[0]);
44
- return "latest";
53
+ if (pre && pre.length > 0 && VALID_CHANNELS.has(String(pre[0]))) return String(pre[0]);
54
+ return "stable";
45
55
  }
46
- const releaseChannel = resolveReleaseChannel(version);
56
+
57
+ function resolveSentryEnvironment(ver: string): string {
58
+ if (process.env.TD_ENV && VALID_ENVS.has(process.env.TD_ENV)) return process.env.TD_ENV;
59
+ return CHANNEL_TO_ENV[resolveChannel(ver)] || "production";
60
+ }
61
+
62
+ const activeChannel = resolveChannel(version);
63
+ const sentryEnvironment = resolveSentryEnvironment(version);
47
64
 
48
65
  const isSentryEnabled = () => {
49
66
  if (process.env.TD_TELEMETRY === "false") {
@@ -58,7 +75,7 @@ if (isSentryEnabled()) {
58
75
  dsn:
59
76
  process.env.SENTRY_DSN ||
60
77
  "https://452bd5a00dbd83a38ee8813e11c57694@o4510262629236736.ingest.us.sentry.io/4510480443637760",
61
- environment: releaseChannel,
78
+ environment: sentryEnvironment,
62
79
  release: version,
63
80
  sampleRate: 1.0,
64
81
  tracesSampleRate: 1.0,
@@ -66,6 +83,7 @@ if (isSentryEnabled()) {
66
83
  integrations: [Sentry.httpIntegration(), Sentry.nodeContextIntegration()],
67
84
  initialScope: {
68
85
  tags: {
86
+ channel: activeChannel,
69
87
  platform: os.platform(),
70
88
  arch: os.arch(),
71
89
  nodeVersion: process.version,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "7.8.0-test.62",
3
+ "version": "7.8.0-test.64",
4
4
  "description": "Next generation autonomous AI agent for end-to-end testing of web & desktop",
5
5
  "main": "sdk.js",
6
6
  "types": "sdk.d.ts",
package/sdk.js CHANGED
@@ -3845,7 +3845,7 @@ CAPTCHA_SOLVER_EOF`,
3845
3845
  const apiRoot = this.config?.TD_API_ROOT || 'unknown';
3846
3846
  const apiKey = this.config?.TD_API_KEY || '';
3847
3847
  const maskedKey = apiKey.length > 4 ? '***' + apiKey.slice(-4) : '(not set)';
3848
- const env = process.env.TD_ENV || 'unknown';
3848
+ const env = process.env.TD_CHANNEL || process.env.TD_ENV || 'unknown';
3849
3849
  const os = this.agent?.options?.os || process.env.TD_OS || 'linux';
3850
3850
  const sdkVersion = require('./package.json').version;
3851
3851
 
@@ -145,7 +145,7 @@ done
145
145
  echo "Installing runner..."
146
146
 
147
147
  # Determine environment and version
148
- TD_ENV="${TD_ENV:-stable}"
148
+ TD_CHANNEL="${TD_CHANNEL:-stable}"
149
149
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
150
150
  SDK_PKG_JSON="${SCRIPT_DIR}/../../../sdk/package.json"
151
151
  RUNNER_DIR="${SCRIPT_DIR}/../../../runner"
@@ -154,11 +154,11 @@ if [ -f "$SDK_PKG_JSON" ]; then
154
154
  RUNNER_VERSION=$(jq -r '.version' "$SDK_PKG_JSON")
155
155
  echo "Runner version from SDK: $RUNNER_VERSION"
156
156
  else
157
- RUNNER_VERSION="$TD_ENV"
157
+ RUNNER_VERSION="$TD_CHANNEL"
158
158
  echo "SDK package.json not found, using env tag: $RUNNER_VERSION"
159
159
  fi
160
160
 
161
- if [ "$TD_ENV" = "dev" ]; then
161
+ if [ "$TD_CHANNEL" = "dev" ]; then
162
162
  echo "Dev mode: packing and uploading local runner to S3..."
163
163
 
164
164
  # Pack local runner
package/vitest.config.mjs CHANGED
@@ -31,7 +31,7 @@ const sharedTestConfig = {
31
31
  // Uses: environments.json (URLs) + envs/{env}.env (overlay) + fixtures (API keys)
32
32
  // TD_PLAN selects which plan's API key to use (default: enterprise)
33
33
  const plan = process.env.TD_PLAN || "enterprise";
34
- const defaultEnv = process.env.TD_ENV || "dev";
34
+ const defaultEnv = process.env.TD_CHANNEL || "dev";
35
35
  const environments = getEnvironmentNames();
36
36
 
37
37
  // Apply default env to the main process so the reporter/plugin picks it up
@@ -15,7 +15,7 @@ const require = createRequire(import.meta.url);
15
15
  const { resolveEnv } = require("../shared/resolve-env");
16
16
 
17
17
  const plan = process.env.TD_PLAN || "enterprise";
18
- const env = process.env.TD_ENV || "dev";
18
+ const env = process.env.TD_CHANNEL || "dev";
19
19
  const resolved = resolveEnv(env, plan);
20
20
 
21
21
  // Apply to the main process so test code sees the vars immediately