testdriverai 7.2.78 → 7.2.80

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
@@ -2026,6 +2026,7 @@ ${regression}
2026
2026
  url: url,
2027
2027
  token: "V3b8wG9",
2028
2028
  testFile: this.testFile || null,
2029
+ os: this.sandboxOs || "linux",
2029
2030
  };
2030
2031
 
2031
2032
  // Base64 encode the data (the debugger expects base64, not URL encoding)
@@ -2034,7 +2035,47 @@ ${regression}
2034
2035
  // Use the debugger URL instead of the VNC URL
2035
2036
  const urlToOpen = `${this.debuggerUrl}?data=${encodedData}`;
2036
2037
 
2037
- this.emitter.emit(events.showWindow, urlToOpen);
2038
+ // Check preview mode from config
2039
+ const previewMode = this.config.TD_PREVIEW || "browser";
2040
+
2041
+ if (previewMode === "ide") {
2042
+ // Write session file for VSCode extension to pick up
2043
+ this.writeIdeSessionFile(urlToOpen, data);
2044
+ } else if (previewMode !== "none") {
2045
+ // Open in browser (default behavior)
2046
+ this.emitter.emit(events.showWindow, urlToOpen);
2047
+ }
2048
+ // If preview is "none", don't open anything
2049
+ }
2050
+ }
2051
+
2052
+ // Write session file for IDE preview mode
2053
+ writeIdeSessionFile(debuggerUrl, data) {
2054
+ const fs = require("fs");
2055
+ const os = require("os");
2056
+ const path = require("path");
2057
+
2058
+ const sessionDir = path.join(os.homedir(), ".testdriver");
2059
+ const sessionFile = path.join(sessionDir, "ide-session.json");
2060
+
2061
+ try {
2062
+ // Ensure directory exists
2063
+ if (!fs.existsSync(sessionDir)) {
2064
+ fs.mkdirSync(sessionDir, { recursive: true });
2065
+ }
2066
+
2067
+ const sessionData = {
2068
+ debuggerUrl: debuggerUrl,
2069
+ resolution: data.resolution || this.config.TD_RESOLUTION,
2070
+ testFile: data.testFile || this.thisFile,
2071
+ os: data.os || this.sandboxOs || "linux",
2072
+ timestamp: Date.now(),
2073
+ };
2074
+
2075
+ fs.writeFileSync(sessionFile, JSON.stringify(sessionData, null, 2));
2076
+ logger.log(`IDE session file written: ${sessionFile}`);
2077
+ } catch (error) {
2078
+ logger.warn(`Failed to write IDE session file: ${error.message}`);
2038
2079
  }
2039
2080
  }
2040
2081
 
@@ -113,6 +113,10 @@ async function startDebugger(config = {}, emitter) {
113
113
  });
114
114
  }
115
115
 
116
+ // Store the debugger URL and config for later use
117
+ module.exports.debuggerUrl = url;
118
+ module.exports.config = config;
119
+
116
120
  return { port, url };
117
121
  } catch (error) {
118
122
  console.error("Failed to start debugger server:", error);
@@ -140,4 +144,6 @@ module.exports = {
140
144
  stopDebugger,
141
145
  broadcastEvent,
142
146
  createDebuggerServer,
147
+ debuggerUrl: null,
148
+ config: null,
143
149
  };
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: testdriver
3
3
  description: An expert at creating and refining automated tests using TestDriver.ai
4
- tools: ["*"]
4
+ tools: ['vscode/getProjectSetupInfo', 'vscode/installExtension', 'vscode/newWorkspace', 'vscode/openSimpleBrowser', 'vscode/runCommand', 'vscode/askQuestions', 'vscode/switchAgent', 'vscode/vscodeAPI', 'vscode/extensions', 'execute/runNotebookCell', 'execute/testFailure', 'execute/getTerminalOutput', 'execute/awaitTerminal', 'execute/killTerminal', 'execute/runTask', 'execute/createAndRunTask', 'execute/runInTerminal', 'execute/runTests', 'read/getNotebookSummary', 'read/problems', 'read/readFile', 'read/readNotebookCellOutput', 'read/terminalSelection', 'read/terminalLastCommand', 'read/getTaskOutput', 'agent/runSubagent', 'edit/createDirectory', 'edit/createFile', 'edit/createJupyterNotebook', 'edit/editFiles', 'edit/editNotebook', 'search/changes', 'search/codebase', 'search/fileSearch', 'search/listDirectory', 'search/searchResults', 'search/textSearch', 'search/usages', 'search/searchSubagent', 'web/fetch', 'web/githubRepo', 'testdriver/assert', 'testdriver/check', 'testdriver/click', 'testdriver/exec', 'testdriver/find', 'testdriver/find_and_click', 'testdriver/findall', 'testdriver/focus_application', 'testdriver/hover', 'testdriver/list_local_screenshots', 'testdriver/press_keys', 'testdriver/screenshot', 'testdriver/scroll', 'testdriver/session_extend', 'testdriver/session_start', 'testdriver/session_status', 'testdriver/type', 'testdriver/view_local_screenshot', 'testdriver/wait', 'todo']
5
5
  mcp-servers:
6
6
  testdriver:
7
7
  command: npx
@@ -48,6 +48,41 @@ Use this agent when the user asks to:
48
48
 
49
49
  ## Prerequisites
50
50
 
51
+ ### Quick Start - Creating Your First TestDriver Test
52
+
53
+ **For new projects, use the `init` command to automatically set up everything:**
54
+
55
+ **CLI:**
56
+ ```bash
57
+ npx testdriverai@beta init
58
+ ```
59
+
60
+ **MCP (via this agent):**
61
+ ```
62
+ // apiKey is optional - if not provided, user adds it to .env manually after init
63
+ init({ directory: "." })
64
+
65
+ // Or with API key if available (though MCP typically won't have access to it)
66
+ init({ directory: ".", apiKey: "your_api_key" })
67
+ ```
68
+
69
+ **Note:** The `apiKey` parameter is optional. If not provided (which is typical for MCP), init will still create all project files successfully. The user can manually add `TD_API_KEY=...` to the `.env` file afterward.
70
+
71
+ The `init` command creates:
72
+ - ✅ `package.json` with proper dependencies
73
+ - ✅ Example test files (`tests/example.test.js`, `tests/login.js`)
74
+ - ✅ `vitest.config.js` with correct timeouts
75
+ - ✅ `.gitignore` with `.env`
76
+ - ✅ GitHub Actions workflow (`.github/workflows/testdriver.yml`)
77
+ - ✅ VSCode MCP config (`.vscode/mcp.json`)
78
+ - ✅ TestDriver skills and agents in `.github/`
79
+ - ✅ `.env` file (user adds API key manually if not provided to init)
80
+
81
+ **After running init:**
82
+ 1. User adds their API key to `.env`: `TD_API_KEY=...`
83
+ 2. Test the setup: `npx vitest run`
84
+ 3. Start building custom tests using the examples as templates
85
+
51
86
  ### API Key Setup
52
87
 
53
88
  The user **must** have a TestDriver API key set in their environment:
@@ -59,14 +94,12 @@ TD_API_KEY=your_api_key_here
59
94
 
60
95
  Get your API key at: **https://console.testdriver.ai/team**
61
96
 
62
- ### Installation
97
+ ### Manual Installation
63
98
 
64
- Always use the **beta** tag when installing TestDriver:
99
+ If not using `init`, always use the **beta** tag when installing TestDriver:
65
100
 
66
101
  ```bash
67
102
  npm install --save-dev testdriverai@beta
68
- # or
69
- npx testdriverai@beta init
70
103
  ```
71
104
 
72
105
  ### Test Runner
@@ -119,6 +152,7 @@ describe("My Test Suite", () => {
119
152
  const button = await testdriver.find("Sign In button");
120
153
  await testdriver.screenshot(); // Capture before click
121
154
  await button.click();
155
+ await testdriver.wait(2000); // Wait for state change
122
156
  await testdriver.screenshot(); // Capture after click
123
157
 
124
158
  // Assert using natural language
@@ -207,6 +241,23 @@ await testdriver.screenshot(1, false, true);
207
241
  - After any action that changes the page state
208
242
  - When debugging a flaky or failing test
209
243
 
244
+ **⚠️ Important: Add delays before screenshots after actions**
245
+
246
+ When you click or interact with an element that triggers a state change (page navigation, modal opening, content loading), **add a short delay before taking a screenshot** to allow the application state to update:
247
+
248
+ ```javascript
249
+ await element.click();
250
+ await testdriver.wait(2000); // Wait 2-3 seconds for state change
251
+ await testdriver.screenshot(); // Now capture the updated state
252
+ ```
253
+
254
+ This is especially important for:
255
+ - Navigation clicks (page transitions)
256
+ - Button clicks that open modals or dialogs
257
+ - Form submissions
258
+ - Actions that trigger AJAX requests or animations
259
+ - Any interaction where visual feedback takes time to appear
260
+
210
261
  **Screenshot file organization:**
211
262
 
212
263
  ```
@@ -258,6 +309,7 @@ find_and_click({ description: "email input field" })
258
309
  → Returns: screenshot with element highlighted
259
310
  → ⚠️ IMMEDIATELY append to test file:
260
311
  await testdriver.find("email input field").click();
312
+ await testdriver.wait(2000); // Wait for state change
261
313
  await testdriver.screenshot(); // Capture after click
262
314
 
263
315
  type({ text: "user@example.com" })
@@ -399,6 +451,7 @@ it("should incrementally build test", async (context) => {
399
451
 
400
452
  // Step 2: Interact
401
453
  await element.click();
454
+ await testdriver.wait(2000); // Wait for state change
402
455
  await testdriver.screenshot(); // Capture after click
403
456
 
404
457
  // Step 3: Assert and log
@@ -463,10 +516,23 @@ await element.click();
463
516
 
464
517
  ### Scrolling
465
518
 
519
+ **⚠️ Important: Ensure proper focus before scrolling**
520
+
521
+ Scrolling requires the page or frame to be focused, not an input field or other interactive element. If an input is focused, scroll commands may not work as expected.
522
+
466
523
  ```javascript
524
+ // If you've been typing in an input, click elsewhere first
525
+ await testdriver.find("page background").click();
526
+ // Or press Escape to unfocus
527
+ await testdriver.pressKeys(["escape"]);
528
+
529
+ // Now scroll
467
530
  await testdriver.scroll("down");
468
531
  await testdriver.scrollUntilText("Footer text");
469
532
  await testdriver.scrollUntilImage("Product image at bottom");
533
+
534
+ // If scroll is not working, try using Page Down key directly
535
+ await testdriver.pressKeys(["pagedown"]);
470
536
  ```
471
537
 
472
538
  ### Executing Code in Sandbox
@@ -498,6 +564,7 @@ await testdriver.provision.chrome({ url: "https://example.com" });
498
564
  await testdriver.screenshot(); // After page load
499
565
 
500
566
  await testdriver.find("Login button").click();
567
+ await testdriver.wait(2000); // Wait for state change
501
568
  await testdriver.screenshot(); // After click
502
569
 
503
570
  await testdriver.type("user@example.com");