@testdriverai/mcp 7.9.115-test → 7.9.117-test

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 CHANGED
@@ -1992,29 +1992,50 @@ ${regression}
1992
1992
  // Write session file for IDE preview (VSCode extension watches for these)
1993
1993
  writeIdeSessionFile(debuggerUrl, data) {
1994
1994
  const fs = require("fs");
1995
+ const os = require("os");
1995
1996
  const path = require("path");
1996
1997
 
1997
- const sessionId = `${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
1998
- const previewsDir = path.join(process.cwd(), ".testdriver", ".previews");
1998
+ // Base dir for the preview file. `process.cwd()` is read-only in some hosts
1999
+ // (e.g. Vercel/Lambda serverless, where cwd is /var/task), which makes the
2000
+ // mkdir below throw. Allow an explicit override and otherwise fall back to a
2001
+ // writable temp dir, so a preview write never blocks the session.
2002
+ const baseDir =
2003
+ process.env.TD_PREVIEWS_DIR ||
2004
+ (this.config && this.config.TD_PREVIEWS_DIR) ||
2005
+ process.cwd();
2006
+ const previewsDir = path.join(baseDir, ".testdriver", ".previews");
1999
2007
 
2000
- // Create the previews directory if it doesn't exist
2001
- if (!fs.existsSync(previewsDir)) {
2002
- fs.mkdirSync(previewsDir, { recursive: true });
2003
- }
2008
+ const sessionId = `${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
2004
2009
 
2005
- const sessionData = {
2006
- sessionId,
2007
- debuggerUrl,
2008
- resolution: Array.isArray(data.resolution) ? data.resolution : (data.resolution ? data.resolution.split("x").map(Number) : [1920, 1080]),
2009
- testFile: data.testFile || this.testFile || null,
2010
- os: data.os || this.sandboxOs || "linux",
2011
- timestamp: Date.now(),
2012
- };
2010
+ // The IDE preview file is a best-effort convenience (the VSCode extension
2011
+ // watches for it). It must never break session start — if the target dir
2012
+ // isn't writable, fall back to os.tmpdir(), and if that also fails, log and
2013
+ // move on rather than throwing out of the provisioning path.
2014
+ try {
2015
+ const sessionData = {
2016
+ sessionId,
2017
+ debuggerUrl,
2018
+ resolution: Array.isArray(data.resolution) ? data.resolution : (data.resolution ? data.resolution.split("x").map(Number) : [1920, 1080]),
2019
+ testFile: data.testFile || this.testFile || null,
2020
+ os: data.os || this.sandboxOs || "linux",
2021
+ timestamp: Date.now(),
2022
+ };
2013
2023
 
2014
- const filePath = path.join(previewsDir, `${sessionId}.json`);
2015
- fs.writeFileSync(filePath, JSON.stringify(sessionData, null, 2));
2024
+ let dir = previewsDir;
2025
+ try {
2026
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
2027
+ } catch {
2028
+ // cwd/base wasn't writable — retry under the OS temp dir.
2029
+ dir = path.join(os.tmpdir(), ".testdriver", ".previews");
2030
+ fs.mkdirSync(dir, { recursive: true });
2031
+ }
2016
2032
 
2017
- logger.log(`IDE preview session written to ${filePath}`);
2033
+ const filePath = path.join(dir, `${sessionId}.json`);
2034
+ fs.writeFileSync(filePath, JSON.stringify(sessionData, null, 2));
2035
+ logger.log(`IDE preview session written to ${filePath}`);
2036
+ } catch (error) {
2037
+ logger.log(`Skipped IDE preview session file (non-fatal): ${error.message}`);
2038
+ }
2018
2039
  }
2019
2040
 
2020
2041
  // Find the VS Code instance that contains the test file
@@ -27,8 +27,65 @@ TestDriver requires an API key to authenticate with the TestDriver cloud. Store
27
27
 
28
28
  <Tabs>
29
29
  <Tab title="GitHub Actions">
30
+ ### Authenticate with OIDC (recommended)
31
+
32
+ If you've installed the [TestDriver GitHub App](https://console.testdriver.ai), your workflow can authenticate using GitHub's OIDC token — no long-lived `TD_API_KEY` secret to store or rotate. The workflow proves it's running inside your org, and TestDriver exchanges that proof for your team's API key at run time.
33
+
34
+ <Note>
35
+ This requires the TestDriver GitHub App to be authorized for your organization once (from the [console](https://console.testdriver.ai)). If your org authorized the App before OIDC support shipped, re-run the authorization once so the binding is created.
36
+ </Note>
37
+
38
+ Grant the job the `id-token: write` permission and exchange the OIDC token for your API key:
39
+
40
+ ```yaml .github/workflows/testdriver.yml
41
+ name: TestDriver Tests
42
+
43
+ on:
44
+ push:
45
+ branches: [main]
46
+ pull_request:
47
+ branches: [main]
48
+
49
+ jobs:
50
+ test:
51
+ runs-on: ubuntu-latest
52
+ permissions:
53
+ id-token: write # required to mint an OIDC token
54
+ contents: read
55
+
56
+ steps:
57
+ - uses: actions/checkout@v4
58
+
59
+ - uses: actions/setup-node@v4
60
+ with:
61
+ node-version: '20'
62
+ cache: 'npm'
63
+
64
+ - run: npm ci
65
+
66
+ - name: Authenticate to TestDriver via OIDC
67
+ run: |
68
+ OIDC_TOKEN=$(curl -sS \
69
+ -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
70
+ "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=testdriver" | jq -r '.value')
71
+ API_KEY=$(curl -sS -X POST https://api.testdriver.ai/github/actions/auth \
72
+ -H "Content-Type: application/json" \
73
+ -d "{\"token\":\"$OIDC_TOKEN\"}" | jq -r '.apiKey')
74
+ echo "::add-mask::$API_KEY"
75
+ echo "TD_API_KEY=$API_KEY" >> "$GITHUB_ENV"
76
+
77
+ - name: Run TestDriver tests
78
+ env:
79
+ TD_API_KEY: ${{ env.TD_API_KEY }}
80
+ run: vitest --run
81
+ ```
82
+
83
+ `ACTIONS_ID_TOKEN_REQUEST_TOKEN` and `ACTIONS_ID_TOKEN_REQUEST_URL` are injected automatically once `permissions: id-token: write` is set. `::add-mask::` keeps the resolved key out of the logs.
84
+
30
85
  ### Adding Secrets
31
-
86
+
87
+ Prefer OIDC above when possible. If you can't use the GitHub App (e.g. self-hosted runners without OIDC, or a non-GitHub registry), fall back to a stored API key:
88
+
32
89
  1. Navigate to your GitHub repository
33
90
  2. Go to **Settings** → **Secrets and variables** → **Actions**
34
91
  3. Click **New repository secret**
@@ -27,8 +27,65 @@ TestDriver requires an API key to authenticate with the TestDriver cloud. Store
27
27
 
28
28
  <Tabs>
29
29
  <Tab title="GitHub Actions">
30
+ ### Authenticate with OIDC (recommended)
31
+
32
+ If you've installed the [TestDriver GitHub App](https://console.testdriver.ai), your workflow can authenticate using GitHub's OIDC token — no long-lived `TD_API_KEY` secret to store or rotate. The workflow proves it's running inside your org, and TestDriver exchanges that proof for your team's API key at run time.
33
+
34
+ <Note>
35
+ This requires the TestDriver GitHub App to be authorized for your organization once (from the [console](https://console.testdriver.ai)). If your org authorized the App before OIDC support shipped, re-run the authorization once so the binding is created.
36
+ </Note>
37
+
38
+ Grant the job the `id-token: write` permission and exchange the OIDC token for your API key:
39
+
40
+ ```yaml .github/workflows/testdriver.yml
41
+ name: TestDriver Tests
42
+
43
+ on:
44
+ push:
45
+ branches: [main]
46
+ pull_request:
47
+ branches: [main]
48
+
49
+ jobs:
50
+ test:
51
+ runs-on: ubuntu-latest
52
+ permissions:
53
+ id-token: write # required to mint an OIDC token
54
+ contents: read
55
+
56
+ steps:
57
+ - uses: actions/checkout@v4
58
+
59
+ - uses: actions/setup-node@v4
60
+ with:
61
+ node-version: '20'
62
+ cache: 'npm'
63
+
64
+ - run: npm ci
65
+
66
+ - name: Authenticate to TestDriver via OIDC
67
+ run: |
68
+ OIDC_TOKEN=$(curl -sS \
69
+ -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
70
+ "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=testdriver" | jq -r '.value')
71
+ API_KEY=$(curl -sS -X POST https://api.testdriver.ai/github/actions/auth \
72
+ -H "Content-Type: application/json" \
73
+ -d "{\"token\":\"$OIDC_TOKEN\"}" | jq -r '.apiKey')
74
+ echo "::add-mask::$API_KEY"
75
+ echo "TD_API_KEY=$API_KEY" >> "$GITHUB_ENV"
76
+
77
+ - name: Run TestDriver tests
78
+ env:
79
+ TD_API_KEY: ${{ env.TD_API_KEY }}
80
+ run: vitest --run
81
+ ```
82
+
83
+ `ACTIONS_ID_TOKEN_REQUEST_TOKEN` and `ACTIONS_ID_TOKEN_REQUEST_URL` are injected automatically once `permissions: id-token: write` is set. `::add-mask::` keeps the resolved key out of the logs.
84
+
30
85
  ### Adding Secrets
31
-
86
+
87
+ Prefer OIDC above when possible. If you can't use the GitHub App (e.g. self-hosted runners without OIDC, or a non-GitHub registry), fall back to a stored API key:
88
+
32
89
  1. Navigate to your GitHub repository
33
90
  2. Go to **Settings** → **Secrets and variables** → **Actions**
34
91
  3. Click **New repository secret**
@@ -2,16 +2,16 @@
2
2
  "$schema": "./examples-manifest.schema.json",
3
3
  "examples": {
4
4
  "assert.test.mjs": {
5
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f2303acecfe43233fa69",
6
- "lastUpdated": "2026-06-17T01:02:40.284Z"
5
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7ca663fcb03ae03d95fe",
6
+ "lastUpdated": "2026-06-25T00:56:06.006Z"
7
7
  },
8
8
  "drag-and-drop.test.mjs": {
9
9
  "url": "https://console.testdriver.ai/runs/69a62b3aaa712ecd3dea730a/69a62b42fc0ac3cc632a918b",
10
10
  "lastUpdated": "2026-03-03T00:32:25.275Z"
11
11
  },
12
12
  "exec-pwsh.test.mjs": {
13
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f1493acecfe43233fa2f",
14
- "lastUpdated": "2026-06-17T01:05:51.377Z"
13
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7bbc63fcb03ae03d95e8",
14
+ "lastUpdated": "2026-06-25T00:59:30.997Z"
15
15
  },
16
16
  "match-image.test.mjs": {
17
17
  "url": "https://console-test.testdriver.ai/runs/69c8738614b73310c7839412/69c8738c14b73310c783941d",
@@ -22,88 +22,88 @@
22
22
  "lastUpdated": "2026-03-03T00:32:25.282Z"
23
23
  },
24
24
  "hover-text-with-description.test.mjs": {
25
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f15f3acecfe43233fa44",
26
- "lastUpdated": "2026-06-17T01:06:16.671Z"
25
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7bd363fcb03ae03d95e9",
26
+ "lastUpdated": "2026-06-25T00:59:53.824Z"
27
27
  },
28
28
  "windows-installer.test.mjs": {
29
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f1913acecfe43233fa5c",
30
- "lastUpdated": "2026-06-17T01:28:40.938Z"
29
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7c0463fcb03ae03d95f4",
30
+ "lastUpdated": "2026-06-25T01:18:30.616Z"
31
31
  },
32
32
  "exec-output.test.mjs": {
33
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f1923acecfe43233fa5e",
34
- "lastUpdated": "2026-06-17T01:14:42.920Z"
33
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7c0663fcb03ae03d95f5",
34
+ "lastUpdated": "2026-06-25T01:07:35.289Z"
35
35
  },
36
36
  "chrome-extension.test.mjs": {
37
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f1473acecfe43233fa2e",
38
- "lastUpdated": "2026-06-17T01:05:49.554Z"
37
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7bba63fcb03ae03d95e7",
38
+ "lastUpdated": "2026-06-25T00:59:28.703Z"
39
39
  },
40
40
  "launch-vscode-linux.test.mjs": {
41
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f18f3acecfe43233fa5b",
42
- "lastUpdated": "2026-06-17T01:14:39.897Z"
41
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7c0263fcb03ae03d95f2",
42
+ "lastUpdated": "2026-06-25T01:07:32.243Z"
43
43
  },
44
44
  "hover-image.test.mjs": {
45
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f1a83acecfe43233fa60",
46
- "lastUpdated": "2026-06-17T01:00:24.032Z"
45
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7c1f63fcb03ae03d95f6",
46
+ "lastUpdated": "2026-06-25T00:53:50.924Z"
47
47
  },
48
48
  "installer.test.mjs": {
49
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f1d53acecfe43233fa65",
50
- "lastUpdated": "2026-06-17T01:01:09.322Z"
49
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7c4963fcb03ae03d95f8",
50
+ "lastUpdated": "2026-06-25T00:54:33.314Z"
51
51
  },
52
52
  "type.test.mjs": {
53
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f2013acecfe43233fa67",
54
- "lastUpdated": "2026-06-17T01:16:31.116Z"
53
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7c7763fcb03ae03d95fc",
54
+ "lastUpdated": "2026-06-25T01:09:29.100Z"
55
55
  },
56
56
  "press-keys.test.mjs": {
57
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f2193acecfe43233fa68",
58
- "replayUrl": "https://console-test.testdriver.ai/replay/6a31f9dc2ba76486567fff8f?share=6fjthCPLK44GX6PUWgwXCw",
59
- "embedUrl": "https://console-test.testdriver.ai/replay/6a31f9dc2ba76486567fff8f?share=6fjthCPLK44GX6PUWgwXCw&embed=true",
60
- "lastUpdated": "2026-06-17T01:35:30.917Z"
57
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7c8e63fcb03ae03d95fd",
58
+ "replayUrl": "https://console-test.testdriver.ai/replay/6a3c835ca377db15ec79a1bd?share=FaNdmOecF7rCwJK30fmZ2g",
59
+ "embedUrl": "https://console-test.testdriver.ai/replay/6a3c835ca377db15ec79a1bd?share=FaNdmOecF7rCwJK30fmZ2g&embed=true",
60
+ "lastUpdated": "2026-06-25T01:24:50.989Z"
61
61
  },
62
62
  "scroll-keyboard.test.mjs": {
63
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f25f3acecfe43233fa6e",
64
- "lastUpdated": "2026-06-17T01:18:03.516Z"
63
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7cd563fcb03ae03d9600",
64
+ "lastUpdated": "2026-06-25T01:10:59.352Z"
65
65
  },
66
66
  "scroll.test.mjs": {
67
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f27a3acecfe43233fa72",
68
- "lastUpdated": "2026-06-17T01:11:35.519Z"
67
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7cf463fcb03ae03d9604",
68
+ "lastUpdated": "2026-06-25T01:04:32.288Z"
69
69
  },
70
70
  "scroll-until-image.test.mjs": {
71
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f2613acecfe43233fa6f",
72
- "lastUpdated": "2026-06-17T01:03:29.226Z"
71
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7cd763fcb03ae03d9601",
72
+ "lastUpdated": "2026-06-25T00:56:55.949Z"
73
73
  },
74
74
  "prompt.test.mjs": {
75
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f2623acecfe43233fa70",
76
- "lastUpdated": "2026-06-17T01:18:06.564Z"
75
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7cd963fcb03ae03d9602",
76
+ "lastUpdated": "2026-06-25T01:11:02.429Z"
77
77
  },
78
78
  "focus-window.test.mjs": {
79
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f2643acecfe43233fa71",
80
- "lastUpdated": "2026-06-17T01:18:07.992Z"
79
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7cdb63fcb03ae03d9603",
80
+ "lastUpdated": "2026-06-25T01:11:03.876Z"
81
81
  },
82
82
  "captcha-api.test.mjs": {
83
83
  "url": "https://console.testdriver.ai/runs/698f7df69e27ce1528d7d087/698f7fb0d3b320ad547d9d44",
84
84
  "lastUpdated": "2026-02-13T19:55:05.951Z"
85
85
  },
86
86
  "element-not-found.test.mjs": {
87
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f2923acecfe43233fa73",
88
- "lastUpdated": "2026-06-17T01:11:58.955Z"
87
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7d0b63fcb03ae03d9605",
88
+ "lastUpdated": "2026-06-25T01:04:52.990Z"
89
89
  },
90
90
  "formatted-logging.test.mjs": {
91
91
  "url": "https://console-test.testdriver.ai/runs/69c8738614b73310c7839412/69c873a714b73310c7839450",
92
92
  "lastUpdated": "2026-03-29T00:36:10.628Z"
93
93
  },
94
94
  "hover-text.test.mjs": {
95
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f2c03acecfe43233fa8a",
96
- "lastUpdated": "2026-06-17T01:12:45.620Z"
95
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7d3b63fcb03ae03d9607",
96
+ "lastUpdated": "2026-06-25T01:05:38.141Z"
97
97
  },
98
98
  "no-provision.test.mjs": {
99
99
  "url": "https://console.testdriver.ai/runs/69a62b3aaa712ecd3dea730a/69a62b7706a177a05bccd1cf",
100
100
  "lastUpdated": "2026-03-03T00:32:25.279Z"
101
101
  },
102
102
  "ai.test.mjs": {
103
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f2aa3acecfe43233fa7d",
104
- "replayUrl": "https://console-test.testdriver.ai/replay/6a31fbdb2ba76486567fff9b?share=uABlfildtvnk0hv9YFRpMg",
105
- "embedUrl": "https://console-test.testdriver.ai/replay/6a31fbdb2ba76486567fff9b?share=uABlfildtvnk0hv9YFRpMg&embed=true",
106
- "lastUpdated": "2026-06-17T01:44:01.712Z"
103
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7d2263fcb03ae03d9606",
104
+ "replayUrl": "https://console-test.testdriver.ai/replay/6a3c85bda377db15ec79a1cb?share=atuShrmwV3Td5vfB5wOXTw",
105
+ "embedUrl": "https://console-test.testdriver.ai/replay/6a3c85bda377db15ec79a1cb?share=atuShrmwV3Td5vfB5wOXTw&embed=true",
106
+ "lastUpdated": "2026-06-25T01:34:59.921Z"
107
107
  },
108
108
  "popup-loading.test.mjs": {
109
109
  "url": "https://console.testdriver.ai/runs/698bc89f7140c3fa7daaca8d/698bca7f7140c3fa7daacbf7",
@@ -138,12 +138,12 @@
138
138
  "lastUpdated": "2026-02-13T19:55:05.953Z"
139
139
  },
140
140
  "findall-coffee-icons.test.mjs": {
141
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f2463acecfe43233fa6a",
142
- "lastUpdated": "2026-06-17T01:03:02.212Z"
141
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7cbe63fcb03ae03d95ff",
142
+ "lastUpdated": "2026-06-25T00:56:30.004Z"
143
143
  },
144
144
  "parse.test.mjs": {
145
- "url": "https://console-test.testdriver.ai/runs/6a31f1303acecfe43233fa13/6a31f2d73acecfe43233fa8e",
146
- "lastUpdated": "2026-06-17T01:13:10.124Z"
145
+ "url": "https://console-test.testdriver.ai/runs/6a3c7ba263fcb03ae03d95e4/6a3c7d5363fcb03ae03d9609",
146
+ "lastUpdated": "2026-06-25T01:06:00.212Z"
147
147
  },
148
148
  "flake-diffthreshold-001.test.mjs": {
149
149
  "url": "https://console.testdriver.ai/runs/69a62b3aaa712ecd3dea730a/69a62bcafc0ac3cc632a91aa",
package/docs/v7/ci-cd.mdx CHANGED
@@ -28,8 +28,65 @@ TestDriver requires an API key to authenticate with the TestDriver cloud. Store
28
28
 
29
29
  <Tabs>
30
30
  <Tab title="GitHub Actions">
31
+ ### Authenticate with OIDC (recommended)
32
+
33
+ If you've installed the [TestDriver GitHub App](https://console.testdriver.ai), your workflow can authenticate using GitHub's OIDC token — no long-lived `TD_API_KEY` secret to store or rotate. The workflow proves it's running inside your org, and TestDriver exchanges that proof for your team's API key at run time.
34
+
35
+ <Note>
36
+ This requires the TestDriver GitHub App to be authorized for your organization once (from the [console](https://console.testdriver.ai)). If your org authorized the App before OIDC support shipped, re-run the authorization once so the binding is created.
37
+ </Note>
38
+
39
+ Grant the job the `id-token: write` permission and exchange the OIDC token for your API key:
40
+
41
+ ```yaml .github/workflows/testdriver.yml
42
+ name: TestDriver Tests
43
+
44
+ on:
45
+ push:
46
+ branches: [main]
47
+ pull_request:
48
+ branches: [main]
49
+
50
+ jobs:
51
+ test:
52
+ runs-on: ubuntu-latest
53
+ permissions:
54
+ id-token: write # required to mint an OIDC token
55
+ contents: read
56
+
57
+ steps:
58
+ - uses: actions/checkout@v4
59
+
60
+ - uses: actions/setup-node@v4
61
+ with:
62
+ node-version: '20'
63
+ cache: 'npm'
64
+
65
+ - run: npm ci
66
+
67
+ - name: Authenticate to TestDriver via OIDC
68
+ run: |
69
+ OIDC_TOKEN=$(curl -sS \
70
+ -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
71
+ "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=testdriver" | jq -r '.value')
72
+ API_KEY=$(curl -sS -X POST https://api.testdriver.ai/github/actions/auth \
73
+ -H "Content-Type: application/json" \
74
+ -d "{\"token\":\"$OIDC_TOKEN\"}" | jq -r '.apiKey')
75
+ echo "::add-mask::$API_KEY"
76
+ echo "TD_API_KEY=$API_KEY" >> "$GITHUB_ENV"
77
+
78
+ - name: Run TestDriver tests
79
+ env:
80
+ TD_API_KEY: ${{ env.TD_API_KEY }}
81
+ run: vitest --run
82
+ ```
83
+
84
+ `ACTIONS_ID_TOKEN_REQUEST_TOKEN` and `ACTIONS_ID_TOKEN_REQUEST_URL` are injected automatically once `permissions: id-token: write` is set. `::add-mask::` keeps the resolved key out of the logs.
85
+
31
86
  ### Adding Secrets
32
-
87
+
88
+ Prefer OIDC above when possible. If you can't use the GitHub App (e.g. self-hosted runners without OIDC, or a non-GitHub registry), fall back to a stored API key:
89
+
33
90
  1. Navigate to your GitHub repository
34
91
  2. Go to **Settings** → **Secrets and variables** → **Actions**
35
92
  3. Click **New repository secret**
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
12
12
 
13
13
  {/* ai.test.mjs output */}
14
14
  <iframe
15
- src="https://console-test.testdriver.ai/replay/6a31fbdb2ba76486567fff9b?share=uABlfildtvnk0hv9YFRpMg&embed=true"
15
+ src="https://console-test.testdriver.ai/replay/6a3c85bda377db15ec79a1cb?share=atuShrmwV3Td5vfB5wOXTw&embed=true"
16
16
  width="100%"
17
17
  height="390"
18
18
  style={{ border: "1px solid #333", borderRadius: "8px" }}
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
12
12
 
13
13
  {/* assert.test.mjs output */}
14
14
  <iframe
15
- src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a31f2303acecfe43233fa69/replay"
15
+ src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a3c7ca663fcb03ae03d95fe/replay"
16
16
  width="100%"
17
17
  height="390"
18
18
  style={{ border: "1px solid #333", borderRadius: "8px" }}
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
12
12
 
13
13
  {/* chrome-extension.test.mjs output */}
14
14
  <iframe
15
- src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a31f1473acecfe43233fa2e/replay"
15
+ src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a3c7bba63fcb03ae03d95e7/replay"
16
16
  width="100%"
17
17
  height="390"
18
18
  style={{ border: "1px solid #333", borderRadius: "8px" }}
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
12
12
 
13
13
  {/* element-not-found.test.mjs output */}
14
14
  <iframe
15
- src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a31f2923acecfe43233fa73/replay"
15
+ src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a3c7d0b63fcb03ae03d9605/replay"
16
16
  width="100%"
17
17
  height="390"
18
18
  style={{ border: "1px solid #333", borderRadius: "8px" }}
@@ -18,7 +18,7 @@ Watch this test execute in a real sandbox environment:
18
18
 
19
19
  {/* findall-coffee-icons.test.mjs output */}
20
20
  <iframe
21
- src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a31f2463acecfe43233fa6a/replay"
21
+ src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a3c7cbe63fcb03ae03d95ff/replay"
22
22
  width="100%"
23
23
  height="600"
24
24
  style={{ border: "1px solid #333", borderRadius: "8px" }}
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
12
12
 
13
13
  {/* hover-image.test.mjs output */}
14
14
  <iframe
15
- src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a31f1a83acecfe43233fa60/replay"
15
+ src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a3c7c1f63fcb03ae03d95f6/replay"
16
16
  width="100%"
17
17
  height="390"
18
18
  style={{ border: "1px solid #333", borderRadius: "8px" }}
@@ -18,7 +18,7 @@ Watch this test execute in a real sandbox environment:
18
18
 
19
19
  {/* hover-text-with-description.test.mjs output */}
20
20
  <iframe
21
- src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a31f15f3acecfe43233fa44/replay"
21
+ src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a3c7bd363fcb03ae03d95e9/replay"
22
22
  width="100%"
23
23
  height="600"
24
24
  style={{ border: "1px solid #333", borderRadius: "8px" }}
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
12
12
 
13
13
  {/* hover-text.test.mjs output */}
14
14
  <iframe
15
- src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a31f2c03acecfe43233fa8a/replay"
15
+ src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a3c7d3b63fcb03ae03d9607/replay"
16
16
  width="100%"
17
17
  height="390"
18
18
  style={{ border: "1px solid #333", borderRadius: "8px" }}
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
12
12
 
13
13
  {/* installer.test.mjs output */}
14
14
  <iframe
15
- src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a31f1d53acecfe43233fa65/replay"
15
+ src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a3c7c4963fcb03ae03d95f8/replay"
16
16
  width="100%"
17
17
  height="390"
18
18
  style={{ border: "1px solid #333", borderRadius: "8px" }}
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
12
12
 
13
13
  {/* launch-vscode-linux.test.mjs output */}
14
14
  <iframe
15
- src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a31f18f3acecfe43233fa5b/replay"
15
+ src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a3c7c0263fcb03ae03d95f2/replay"
16
16
  width="100%"
17
17
  height="390"
18
18
  style={{ border: "1px solid #333", borderRadius: "8px" }}
@@ -18,7 +18,7 @@ Watch this test execute in a real sandbox environment:
18
18
 
19
19
  {/* parse.test.mjs output */}
20
20
  <iframe
21
- src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a31f2d73acecfe43233fa8e/replay"
21
+ src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a3c7d5363fcb03ae03d9609/replay"
22
22
  width="100%"
23
23
  height="600"
24
24
  style={{ border: "1px solid #333", borderRadius: "8px" }}
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
12
12
 
13
13
  {/* press-keys.test.mjs output */}
14
14
  <iframe
15
- src="https://console-test.testdriver.ai/replay/6a31f9dc2ba76486567fff8f?share=6fjthCPLK44GX6PUWgwXCw&embed=true"
15
+ src="https://console-test.testdriver.ai/replay/6a3c835ca377db15ec79a1bd?share=FaNdmOecF7rCwJK30fmZ2g&embed=true"
16
16
  width="100%"
17
17
  height="390"
18
18
  style={{ border: "1px solid #333", borderRadius: "8px" }}
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
12
12
 
13
13
  {/* scroll-keyboard.test.mjs output */}
14
14
  <iframe
15
- src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a31f25f3acecfe43233fa6e/replay"
15
+ src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a3c7cd563fcb03ae03d9600/replay"
16
16
  width="100%"
17
17
  height="390"
18
18
  style={{ border: "1px solid #333", borderRadius: "8px" }}
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
12
12
 
13
13
  {/* scroll.test.mjs output */}
14
14
  <iframe
15
- src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a31f27a3acecfe43233fa72/replay"
15
+ src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a3c7cf463fcb03ae03d9604/replay"
16
16
  width="100%"
17
17
  height="390"
18
18
  style={{ border: "1px solid #333", borderRadius: "8px" }}
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
12
12
 
13
13
  {/* type.test.mjs output */}
14
14
  <iframe
15
- src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a31f2013acecfe43233fa67/replay"
15
+ src="https://api-test.testdriver.ai/api/v1/testdriver/testcase/6a3c7c7763fcb03ae03d95fc/replay"
16
16
  width="100%"
17
17
  height="390"
18
18
  style={{ border: "1px solid #333", borderRadius: "8px" }}