testdriverai 7.8.0-test.4 → 7.8.0-test.40

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.
Files changed (87) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/agent/index.js +6 -5
  3. package/agent/lib/commands.js +3 -2
  4. package/agent/lib/http.js +144 -0
  5. package/agent/lib/sandbox.js +326 -164
  6. package/agent/lib/sdk.js +4 -2
  7. package/agent/lib/system.js +25 -65
  8. package/ai/skills/testdriver-cache/SKILL.md +221 -0
  9. package/ai/skills/testdriver-errors/SKILL.md +246 -0
  10. package/ai/skills/testdriver-events/SKILL.md +356 -0
  11. package/ai/skills/testdriver-mcp/SKILL.md +7 -0
  12. package/ai/skills/testdriver-provision/SKILL.md +331 -0
  13. package/ai/skills/testdriver-redraw/SKILL.md +214 -0
  14. package/ai/skills/testdriver-running-tests/SKILL.md +1 -1
  15. package/ai/skills/testdriver-screenshots/SKILL.md +184 -0
  16. package/docs/_data/examples-manifest.json +46 -46
  17. package/docs/changelog.mdx +155 -3
  18. package/docs/docs.json +44 -37
  19. package/docs/images/content/vscode/v7-chat.png +0 -0
  20. package/docs/images/content/vscode/v7-choose-agent.png +0 -0
  21. package/docs/images/content/vscode/v7-full.png +0 -0
  22. package/docs/images/content/vscode/v7-onboarding.png +0 -0
  23. package/docs/v7/cache.mdx +223 -0
  24. package/docs/v7/copilot/auto-healing.mdx +265 -0
  25. package/docs/v7/copilot/creating-tests.mdx +156 -0
  26. package/docs/v7/copilot/github.mdx +143 -0
  27. package/docs/v7/copilot/running-tests.mdx +149 -0
  28. package/docs/v7/copilot/setup.mdx +143 -0
  29. package/docs/v7/enterprise.mdx +3 -110
  30. package/docs/v7/errors.mdx +248 -0
  31. package/docs/v7/events.mdx +358 -0
  32. package/docs/v7/examples/ai.mdx +1 -1
  33. package/docs/v7/examples/assert.mdx +1 -1
  34. package/docs/v7/examples/captcha-api.mdx +1 -1
  35. package/docs/v7/examples/chrome-extension.mdx +1 -1
  36. package/docs/v7/examples/drag-and-drop.mdx +1 -1
  37. package/docs/v7/examples/element-not-found.mdx +1 -1
  38. package/docs/v7/examples/exec-output.mdx +85 -0
  39. package/docs/v7/examples/exec-pwsh.mdx +83 -0
  40. package/docs/v7/examples/focus-window.mdx +62 -0
  41. package/docs/v7/examples/hover-image.mdx +1 -1
  42. package/docs/v7/examples/hover-text.mdx +1 -1
  43. package/docs/v7/examples/installer.mdx +1 -1
  44. package/docs/v7/examples/launch-vscode-linux.mdx +1 -1
  45. package/docs/v7/examples/match-image.mdx +1 -1
  46. package/docs/v7/examples/press-keys.mdx +1 -1
  47. package/docs/v7/examples/scroll-keyboard.mdx +1 -1
  48. package/docs/v7/examples/scroll-until-image.mdx +1 -1
  49. package/docs/v7/examples/scroll-until-text.mdx +1 -1
  50. package/docs/v7/examples/scroll.mdx +1 -1
  51. package/docs/v7/examples/type.mdx +1 -1
  52. package/docs/v7/examples/windows-installer.mdx +1 -1
  53. package/docs/v7/{cloud.mdx → hosted.mdx} +43 -5
  54. package/docs/v7/mcp.mdx +9 -0
  55. package/docs/v7/provision.mdx +333 -0
  56. package/docs/v7/quickstart.mdx +30 -2
  57. package/docs/v7/redraw.mdx +216 -0
  58. package/docs/v7/running-tests.mdx +1 -1
  59. package/docs/v7/screenshots.mdx +186 -0
  60. package/docs/v7/self-hosted.mdx +127 -44
  61. package/interfaces/logger.js +0 -12
  62. package/interfaces/vitest-plugin.mjs +53 -43
  63. package/lib/core/Dashcam.js +30 -23
  64. package/lib/environments.json +18 -0
  65. package/lib/github-comment.mjs +58 -40
  66. package/lib/resolve-channel.js +4 -3
  67. package/lib/sentry.js +5 -0
  68. package/{examples → manual}/drag-and-drop.test.mjs +1 -1
  69. package/mcp-server/dist/server.mjs +4 -0
  70. package/mcp-server/src/server.ts +5 -0
  71. package/package.json +3 -3
  72. package/sdk.js +3 -3
  73. package/setup/aws/install-dev-runner.sh +79 -0
  74. package/setup/aws/spawn-runner.sh +134 -0
  75. package/vitest.config.mjs +20 -32
  76. package/vitest.runner.config.mjs +33 -0
  77. /package/{examples → manual}/flake-diffthreshold-001.test.mjs +0 -0
  78. /package/{examples → manual}/flake-diffthreshold-01.test.mjs +0 -0
  79. /package/{examples → manual}/flake-diffthreshold-05.test.mjs +0 -0
  80. /package/{examples → manual}/flake-noredraw-cache.test.mjs +0 -0
  81. /package/{examples → manual}/flake-noredraw-nocache.test.mjs +0 -0
  82. /package/{examples → manual}/flake-redraw-cache.test.mjs +0 -0
  83. /package/{examples → manual}/flake-redraw-nocache.test.mjs +0 -0
  84. /package/{examples → manual}/flake-rocket-match.test.mjs +0 -0
  85. /package/{examples → manual}/flake-shared.mjs +0 -0
  86. /package/{examples → manual}/no-provision.test.mjs +0 -0
  87. /package/{examples → manual}/scroll-until-text.test.mjs +0 -0
package/lib/sentry.js CHANGED
@@ -85,6 +85,11 @@ if (isEnabled()) {
85
85
  return null;
86
86
  }
87
87
 
88
+ // Filter out ElementNotFoundError - expected test outcome, not a crash
89
+ if (error && error.name === "ElementNotFoundError") {
90
+ return null;
91
+ }
92
+
88
93
  return event;
89
94
  },
90
95
  });
@@ -46,7 +46,7 @@ describe("Drag and Drop Test", () => {
46
46
 
47
47
  const recycleBin = await testdriver.find(
48
48
  "Recycle Bin, recycle bin icon in the top left corner of the desktop",
49
- );
49
+ ).hover();
50
50
  await recycleBin.mouseUp();
51
51
 
52
52
  // Assert "New Text Document" icon is not on the Desktop
@@ -84,6 +84,10 @@ if (isSentryEnabled()) {
84
84
  if (error && typeof error === "object" && "name" in error && error.name === "TestFailure") {
85
85
  return null;
86
86
  }
87
+ // Filter out ElementNotFoundError - expected test outcome, not a crash
88
+ if (error && typeof error === "object" && "name" in error && error.name === "ElementNotFoundError") {
89
+ return null;
90
+ }
87
91
  return event;
88
92
  },
89
93
  });
@@ -99,6 +99,11 @@ if (isSentryEnabled()) {
99
99
  if (error && typeof error === "object" && "name" in error && (error as { name: string }).name === "TestFailure") {
100
100
  return null;
101
101
  }
102
+
103
+ // Filter out ElementNotFoundError - expected test outcome, not a crash
104
+ if (error && typeof error === "object" && "name" in error && (error as { name: string }).name === "ElementNotFoundError") {
105
+ return null;
106
+ }
102
107
 
103
108
  return event;
104
109
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "7.8.0-test.4",
3
+ "version": "7.8.0-test.40",
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",
@@ -37,8 +37,8 @@
37
37
  "start": "node bin/testdriverai.js",
38
38
  "dev": "DEV=true node bin/testdriverai.js",
39
39
  "debug": "DEV=true VERBOSE=true node bin/testdriverai.js",
40
- "docs": "npm run docs:skills && cd docs && npx mint@latest dev",
41
- "docs:dev": "cd docs && npx mint dev",
40
+ "docs": "npm run docs:skills && cd docs && npx mint@latest dev --port 3002",
41
+ "docs:dev": "cd docs && npx mint dev --port 3002",
42
42
  "docs:build": "npm run docs:skills && cd docs && npx mint@latest build",
43
43
  "docs:links": "node docs/_scripts/link-replacer.js",
44
44
  "docs:skills": "node docs/_scripts/generate-skills.js",
package/sdk.js CHANGED
@@ -2749,6 +2749,9 @@ CAPTCHA_SOLVER_EOF`,
2749
2749
  }
2750
2750
  }
2751
2751
 
2752
+ // Log environment info immediately so it's visible even if auth fails
2753
+ this._logEnvironmentInfo();
2754
+
2752
2755
  // Authenticate first if not already authenticated
2753
2756
  if (!this.authenticated) {
2754
2757
  await this.auth();
@@ -2865,9 +2868,6 @@ CAPTCHA_SOLVER_EOF`,
2865
2868
  sandboxId: this.instance?.instanceId,
2866
2869
  });
2867
2870
 
2868
- // Log environment info (non-blocking, skip on stable)
2869
- this._logEnvironmentInfo();
2870
-
2871
2871
  return this.instance;
2872
2872
  }
2873
2873
 
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # Usage: ./install-dev-runner.sh <instance-id>
5
+ INSTANCE_ID="${1:?Usage: $0 <instance-id>}"
6
+ AWS_REGION="${AWS_REGION:-us-east-2}"
7
+
8
+ RUNNER_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../runner" && pwd)"
9
+
10
+ echo "Packing local runner..."
11
+ TMPDIR=$(mktemp -d)
12
+ pushd "$RUNNER_DIR" > /dev/null
13
+ npm pack --pack-destination "$TMPDIR" > /dev/null 2>&1
14
+ TARBALL=$(ls "$TMPDIR"/*.tgz)
15
+ popd > /dev/null
16
+ echo "Tarball: $TARBALL"
17
+
18
+ echo "Uploading to S3..."
19
+ S3_KEY="runner-dev/$(date +%s)-$(openssl rand -hex 4)/runner.tgz"
20
+ aws s3 cp "$TARBALL" "s3://v7-transfer/${S3_KEY}" --region "$AWS_REGION" > /dev/null
21
+ DOWNLOAD_URL=$(aws s3 presign "s3://v7-transfer/${S3_KEY}" --expires-in 900 --region "$AWS_REGION")
22
+ rm -rf "$TMPDIR"
23
+
24
+ echo "Creating SSM params file..."
25
+
26
+ # Write Python script to temp file to generate valid JSON
27
+ PYTHON_SCRIPT=$(mktemp --suffix=.py)
28
+ cat > "$PYTHON_SCRIPT" << 'PYEOF'
29
+ import json
30
+ import sys
31
+
32
+ url = sys.argv[1]
33
+
34
+ commands = [
35
+ "Write-Host '=== Stopping runner ==='",
36
+ "Stop-ScheduledTask -TaskName RunTestDriverAgent -ErrorAction SilentlyContinue",
37
+ "Stop-Process -Name node -Force -ErrorAction SilentlyContinue",
38
+ "Start-Sleep -Seconds 2",
39
+ "Set-Location 'C:\\testdriver\\sandbox-agent'",
40
+ "$tarball = 'C:\\Windows\\Temp\\runner-dev.tgz'",
41
+ f"Invoke-WebRequest -Uri '{url}' -OutFile $tarball",
42
+ "Write-Host 'Tarball size:'; (Get-Item $tarball).Length",
43
+ "Remove-Item -Path lib -Recurse -Force -ErrorAction SilentlyContinue",
44
+ "tar -xzf $tarball --strip-components=1 -C .",
45
+ "Get-Content 'package.json' | ConvertFrom-Json | Select-Object -ExpandProperty version",
46
+ "Write-Host '=== Starting runner ==='",
47
+ "Start-ScheduledTask -TaskName RunTestDriverAgent",
48
+ "Start-Sleep -Seconds 3",
49
+ "Get-Content 'C:\\testdriver\\log.txt' -Tail 20"
50
+ ]
51
+
52
+ params = {"commands": commands}
53
+ print(json.dumps(params))
54
+ PYEOF
55
+
56
+ python3 "$PYTHON_SCRIPT" "$DOWNLOAD_URL" > /tmp/ssm-install-params.json
57
+ rm "$PYTHON_SCRIPT"
58
+
59
+ echo "Sending SSM command..."
60
+ CMD_JSON=$(aws ssm send-command \
61
+ --region "$AWS_REGION" \
62
+ --instance-ids "$INSTANCE_ID" \
63
+ --document-name "AWS-RunPowerShellScript" \
64
+ --parameters "file:///tmp/ssm-install-params.json" \
65
+ --output json)
66
+
67
+ COMMAND_ID=$(echo "$CMD_JSON" | jq -r '.Command.CommandId')
68
+ echo "Command ID: $COMMAND_ID"
69
+
70
+ echo "Waiting for completion..."
71
+ aws ssm wait command-executed --region "$AWS_REGION" --command-id "$COMMAND_ID" --instance-id "$INSTANCE_ID" || true
72
+
73
+ echo "Getting output..."
74
+ aws ssm get-command-invocation \
75
+ --region "$AWS_REGION" \
76
+ --command-id "$COMMAND_ID" \
77
+ --instance-id "$INSTANCE_ID" \
78
+ --query 'StandardOutputContent' \
79
+ --output text
@@ -141,6 +141,140 @@ while :; do
141
141
  sleep 20
142
142
  done
143
143
 
144
+ # --- 4) Install/update runner ---
145
+ echo "Installing runner..."
146
+
147
+ # Determine environment and version
148
+ TD_ENV="${TD_ENV:-stable}"
149
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
150
+ SDK_PKG_JSON="${SCRIPT_DIR}/../../../sdk/package.json"
151
+ RUNNER_DIR="${SCRIPT_DIR}/../../../runner"
152
+
153
+ if [ -f "$SDK_PKG_JSON" ]; then
154
+ RUNNER_VERSION=$(jq -r '.version' "$SDK_PKG_JSON")
155
+ echo "Runner version from SDK: $RUNNER_VERSION"
156
+ else
157
+ RUNNER_VERSION="$TD_ENV"
158
+ echo "SDK package.json not found, using env tag: $RUNNER_VERSION"
159
+ fi
160
+
161
+ if [ "$TD_ENV" = "dev" ]; then
162
+ echo "Dev mode: packing and uploading local runner to S3..."
163
+
164
+ # Pack local runner
165
+ TMPDIR=$(mktemp -d)
166
+ pushd "$RUNNER_DIR" > /dev/null
167
+ npm pack --pack-destination "$TMPDIR" > /dev/null 2>&1
168
+ TARBALL=$(ls "$TMPDIR"/*.tgz | head -1)
169
+ popd > /dev/null
170
+
171
+ # Upload to S3
172
+ S3_BUCKET="${AWS_BUCKET_IMAGE_TRANSFER:-v7-transfer}"
173
+ S3_KEY="runner-dev/$(date +%s)-$(openssl rand -hex 4)/runner.tgz"
174
+ aws s3 cp "$TARBALL" "s3://${S3_BUCKET}/${S3_KEY}" --region "$AWS_REGION"
175
+
176
+ # Generate presigned URL (15 min)
177
+ DOWNLOAD_URL=$(aws s3 presign "s3://${S3_BUCKET}/${S3_KEY}" --expires-in 900 --region "$AWS_REGION")
178
+ rm -rf "$TMPDIR"
179
+
180
+ # Build SSM parameters JSON in a temp file to avoid shell escaping issues with URL
181
+ PARAMS_FILE=$(mktemp)
182
+ cat > "$PARAMS_FILE" << 'PARAMS_EOF'
183
+ {
184
+ "commands": [
185
+ "Write-Host '=== Starting runner dev install ==='",
186
+ "Write-Host 'Stopping existing runner processes...'",
187
+ "Stop-ScheduledTask -TaskName RunTestDriverAgent -ErrorAction SilentlyContinue",
188
+ "Stop-Process -Name node -Force -ErrorAction SilentlyContinue",
189
+ "Start-Sleep -Seconds 2",
190
+ "Write-Host 'Current runner version:'",
191
+ "Get-Content 'C:\\testdriver\\sandbox-agent\\package.json' | ConvertFrom-Json | Select-Object -ExpandProperty version",
192
+ "Set-Location 'C:\\testdriver\\sandbox-agent'",
193
+ "Write-Host 'Dev mode: downloading runner from S3...'",
194
+ "$tarball = 'C:\\Windows\\Temp\\runner-dev.tgz'",
195
+ PARAMS_EOF
196
+
197
+ # Add the URL line with proper JSON escaping
198
+ echo " \"Invoke-WebRequest -Uri '$(echo "$DOWNLOAD_URL" | sed 's/"/\\"/g')' -OutFile \$tarball\"," >> "$PARAMS_FILE"
199
+
200
+ cat >> "$PARAMS_FILE" << 'PARAMS_EOF'
201
+ "Write-Host 'Downloaded tarball size:'",
202
+ "(Get-Item $tarball).Length",
203
+ "Write-Host 'Extracting runner...'",
204
+ "tar -xzf $tarball -C 'C:\\Windows\\Temp'",
205
+ "Write-Host 'Extracted package contents:'",
206
+ "Get-ChildItem 'C:\\Windows\\Temp\\package' -Recurse | Select-Object FullName",
207
+ "Write-Host 'New runner version in package:'",
208
+ "Get-Content 'C:\\Windows\\Temp\\package\\package.json' | ConvertFrom-Json | Select-Object -ExpandProperty version",
209
+ "Write-Host 'Clearing old lib folder...'",
210
+ "Remove-Item 'C:\\testdriver\\sandbox-agent\\lib' -Recurse -Force -ErrorAction SilentlyContinue",
211
+ "Write-Host 'Copying files to sandbox-agent...'",
212
+ "xcopy 'C:\\Windows\\Temp\\package\\*' 'C:\\testdriver\\sandbox-agent\\' /E /Y /I",
213
+ "Write-Host 'Files after copy:'",
214
+ "Get-ChildItem 'C:\\testdriver\\sandbox-agent' | Select-Object Name",
215
+ "Remove-Item 'C:\\Windows\\Temp\\package' -Recurse -Force -ErrorAction SilentlyContinue",
216
+ "Remove-Item $tarball -Force -ErrorAction SilentlyContinue",
217
+ "Write-Host 'Runner version after copy:'",
218
+ "Get-Content 'C:\\testdriver\\sandbox-agent\\package.json' | ConvertFrom-Json | Select-Object -ExpandProperty version",
219
+ "Write-Host 'Installing npm dependencies...'",
220
+ "npm install --omit=dev 2>&1 | Write-Host",
221
+ "Write-Host 'Final verification - ably-service.js exists:'",
222
+ "Test-Path 'C:\\testdriver\\sandbox-agent\\lib\\ably-service.js'",
223
+ "Write-Host 'Restarting RunTestDriverAgent scheduled task...'",
224
+ "Start-ScheduledTask -TaskName RunTestDriverAgent -ErrorAction SilentlyContinue",
225
+ "Write-Host '=== Runner install complete (dev) ==='"
226
+ ]
227
+ }
228
+ PARAMS_EOF
229
+
230
+ echo "Sending SSM command to download and install runner from S3..."
231
+ INSTALL_CMD=$(aws ssm send-command \
232
+ --region "$AWS_REGION" \
233
+ --instance-ids "$INSTANCE_ID" \
234
+ --document-name "AWS-RunPowerShellScript" \
235
+ --parameters "file://$PARAMS_FILE" \
236
+ --timeout-seconds 180 \
237
+ --output json)
238
+ rm -f "$PARAMS_FILE"
239
+ else
240
+ echo "Installing @testdriverai/runner@${RUNNER_VERSION} via npm..."
241
+ INSTALL_CMD=$(aws ssm send-command \
242
+ --region "$AWS_REGION" \
243
+ --instance-ids "$INSTANCE_ID" \
244
+ --document-name "AWS-RunPowerShellScript" \
245
+ --parameters "commands=[
246
+ \"Set-Location 'C:\\\\testdriver\\\\sandbox-agent'\",
247
+ \"Write-Host 'Installing @testdriverai/runner@${RUNNER_VERSION}...'\",
248
+ \"npm install @testdriverai/runner@${RUNNER_VERSION} --omit=dev 2>&1 | Write-Host\",
249
+ \"Write-Host 'Stopping runner (config not yet provisioned)...'\",
250
+ \"Stop-Process -Name node -Force -ErrorAction SilentlyContinue\",
251
+ \"Stop-ScheduledTask -TaskName RunTestDriverAgent -ErrorAction SilentlyContinue\",
252
+ \"Start-Sleep -Seconds 2\",
253
+ \"Start-ScheduledTask -TaskName RunTestDriverAgent -ErrorAction SilentlyContinue\",
254
+ \"Write-Host 'Runner install complete'\"
255
+ ]" \
256
+ --timeout-seconds 120 \
257
+ --output json)
258
+ fi
259
+
260
+ INSTALL_CMD_ID=$(jq -r '.Command.CommandId' <<<"$INSTALL_CMD")
261
+ echo "Runner install command sent (Command ID: $INSTALL_CMD_ID)"
262
+
263
+ # Wait for install to complete
264
+ echo "Waiting for runner install to complete..."
265
+ if aws ssm wait command-executed --region "$AWS_REGION" --command-id "$INSTALL_CMD_ID" --instance-id "$INSTANCE_ID" 2>/dev/null; then
266
+ echo "✓ Runner install succeeded"
267
+ else
268
+ INSTALL_STATUS=$(aws ssm get-command-invocation \
269
+ --region "$AWS_REGION" \
270
+ --command-id "$INSTALL_CMD_ID" \
271
+ --instance-id "$INSTANCE_ID" \
272
+ --output json 2>/dev/null || echo '{}')
273
+ echo "⚠ Runner install status: $(jq -r '.Status // "Unknown"' <<<"$INSTALL_STATUS")"
274
+ echo "Output: $(jq -r '.StandardOutputContent // "No output"' <<<"$INSTALL_STATUS" | head -20)"
275
+ echo "Errors: $(jq -r '.StandardErrorContent // "No errors"' <<<"$INSTALL_STATUS" | head -10)"
276
+ fi
277
+
144
278
  echo "Getting Public IP..."
145
279
 
146
280
  # --- 5) Get instance Public IP ---
package/vitest.config.mjs CHANGED
@@ -1,7 +1,9 @@
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
+ import { createRequire } from "module";
4
+
5
+ const require = createRequire(import.meta.url);
6
+ const { resolveEnv, getEnvironmentNames } = require("../shared/resolve-env");
5
7
 
6
8
  // Always include AWS setup - it will be a no-op unless TD_OS=windows
7
9
  // Note: dotenv is loaded automatically by the TestDriver SDK
@@ -25,45 +27,31 @@ const sharedTestConfig = {
25
27
  include: ["examples/**/*.test.mjs"],
26
28
  };
27
29
 
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"];
30
+ // ── Resolve env vars via shared/resolve-env.js ──────────────────────
31
+ // Uses: environments.json (URLs) + envs/{env}.env (overlay) + fixtures (API keys)
32
+ // TD_PLAN selects which plan's API key to use (default: enterprise)
33
+ const plan = process.env.TD_PLAN || "enterprise";
34
+ const defaultEnv = process.env.TD_ENV || "dev";
35
+ const environments = getEnvironmentNames();
47
36
 
48
- function envForProject(envName) {
49
- const overlay = parseEnvFile(resolve(monoRoot, "envs", `${envName}.env`));
50
- return { ...baseEnv, ...overlay };
51
- }
37
+ // Apply default env to the main process so the reporter/plugin picks it up
38
+ // (vitest's test.env only propagates to worker processes, not the main process)
39
+ const defaultResolved = resolveEnv(defaultEnv, plan);
40
+ Object.assign(process.env, defaultResolved);
52
41
 
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
42
+ // ── Usage ───────────────────────────────────────────────────────────
43
+ // TD_PLAN=enterprise vitest run --project dev
44
+ // TD_PLAN=free vitest run --project test examples/assert.test.mjs
45
+ // vitest run --project canary --project stable
58
46
  export default defineConfig({
59
47
  test: {
60
48
  ...sharedTestConfig,
61
- env: envForProject(process.env.TD_ENV || "dev"),
49
+ env: defaultResolved,
62
50
  projects: environments.map((envName) => ({
63
51
  extends: true,
64
52
  test: {
65
53
  name: envName,
66
- env: envForProject(envName),
54
+ env: resolveEnv(envName, plan),
67
55
  },
68
56
  })),
69
57
  },
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Vitest config for runner/packer tests.
3
+ * Lives under sdk/ so vitest resolves from sdk/node_modules,
4
+ * but uses shared/resolve-env.js for environment variable loading.
5
+ */
6
+ import { defineConfig } from "vitest/config";
7
+ import { createRequire } from "module";
8
+ import { dirname, resolve } from "path";
9
+ import { fileURLToPath } from "url";
10
+
11
+ const __dirname = dirname(fileURLToPath(import.meta.url));
12
+ const monoRoot = resolve(__dirname, "..");
13
+
14
+ const require = createRequire(import.meta.url);
15
+ const { resolveEnv } = require("../shared/resolve-env");
16
+
17
+ const plan = process.env.TD_PLAN || "enterprise";
18
+ const env = process.env.TD_ENV || "dev";
19
+ const resolved = resolveEnv(env, plan);
20
+
21
+ // Apply to the main process so test code sees the vars immediately
22
+ Object.assign(process.env, resolved);
23
+
24
+ export default defineConfig({
25
+ test: {
26
+ root: monoRoot,
27
+ testTimeout: 900_000, // 15 min per test
28
+ hookTimeout: 2_400_000, // 40 min for beforeAll (AMI build + spawn)
29
+ reporters: ["default"],
30
+ include: ["runner/packer/test/**/*.test.mjs"],
31
+ env: resolved,
32
+ },
33
+ });
File without changes
File without changes
File without changes