testdriverai 7.2.54 → 7.2.56

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,21 +12,13 @@ Capture a screenshot of the current screen and automatically save it to a local
12
12
  ## Syntax
13
13
 
14
14
  ```javascript
15
- const filePath = await testdriver.screenshot(scale, silent, mouse)
15
+ const filePath = await testdriver.screenshot(filename)
16
16
  ```
17
17
 
18
18
  ## Parameters
19
19
 
20
- <ParamField path="scale" type="number" default="1">
21
- Scale factor for the screenshot (1 = original size, 0.5 = half size, 2 = double size)
22
- </ParamField>
23
-
24
- <ParamField path="silent" type="boolean" default="false">
25
- Whether to suppress the log message showing where the screenshot was saved
26
- </ParamField>
27
-
28
- <ParamField path="mouse" type="boolean" default="false">
29
- Whether to include the mouse cursor in the screenshot
20
+ <ParamField path="filename" type="string" optional>
21
+ Custom filename for the screenshot (without .png extension). If not provided, a timestamp-based filename is generated automatically.
30
22
  </ParamField>
31
23
 
32
24
  ## Returns
@@ -42,7 +34,7 @@ Screenshots are automatically saved to `.testdriver/screenshots/<test-file-name>
42
34
  screenshots/
43
35
  login.test/
44
36
  screenshot-1737633600000.png
45
- screenshot-1737633605000.png
37
+ login-page.png
46
38
  checkout.test/
47
39
  screenshot-1737633700000.png
48
40
  ```
@@ -56,23 +48,20 @@ Screenshots are automatically saved to `.testdriver/screenshots/<test-file-name>
56
48
  ### Basic Screenshot
57
49
 
58
50
  ```javascript
59
- // Capture a screenshot with default settings
51
+ // Capture a screenshot with auto-generated filename
60
52
  const screenshotPath = await testdriver.screenshot();
61
53
  console.log('Screenshot saved to:', screenshotPath);
62
54
  ```
63
55
 
64
- ### Screenshot with Mouse Cursor
56
+ ### Custom Filename
65
57
 
66
58
  ```javascript
67
- // Capture a screenshot showing the mouse cursor position
68
- const screenshotPath = await testdriver.screenshot(1, false, true);
69
- ```
70
-
71
- ### Silent Screenshot
59
+ // Save with a descriptive filename
60
+ await testdriver.screenshot("login-page");
61
+ // Saves to: .testdriver/screenshots/<test>/login-page.png
72
62
 
73
- ```javascript
74
- // Capture without logging the save location
75
- await testdriver.screenshot(1, true);
63
+ await testdriver.screenshot("after-click");
64
+ // Saves to: .testdriver/screenshots/<test>/after-click.png
76
65
  ```
77
66
 
78
67
  ### Debugging with Screenshots
@@ -14,9 +14,7 @@ import { TestDriver } from "../lib/vitest/hooks.mjs";
14
14
  async function performLogin(client, username = "standard_user") {
15
15
  await client.focusApplication("Google Chrome");
16
16
  const password = await client.extract("the password");
17
- const usernameField = await client.find(
18
- "username input",
19
- );
17
+ const usernameField = await client.find("username input");
20
18
  await usernameField.click();
21
19
  await client.type(username);
22
20
  await client.pressKeys(["tab"]);
@@ -27,8 +25,13 @@ async function performLogin(client, username = "standard_user") {
27
25
 
28
26
  describe("Hover Text With Description Test", () => {
29
27
  it("should add TestDriver Hat to cart and verify", async (context) => {
30
- const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP, headless: true });
31
- await testdriver.provision.chrome({ url: 'http://testdriver-sandbox.vercel.app/login' });
28
+ const testdriver = TestDriver(context, {
29
+ ip: context.ip || process.env.TD_IP,
30
+ headless: true,
31
+ });
32
+ await testdriver.provision.chrome({
33
+ url: "http://testdriver-sandbox.vercel.app/login",
34
+ });
32
35
 
33
36
  //
34
37
  // Perform login first
@@ -47,7 +50,7 @@ describe("Hover Text With Description Test", () => {
47
50
  await cartButton.click();
48
51
 
49
52
  // Assert the TestDriver Hat is in the cart
50
- const result = await testdriver.assert("TestDriver Hat is in the cart");
53
+ const result = await testdriver.assert("There is an item in the cart");
51
54
  expect(result).toBeTruthy();
52
55
  });
53
56
  });
@@ -37,16 +37,22 @@ class InitCommand extends BaseCommand {
37
37
  if (fs.existsSync(envPath)) {
38
38
  const envContent = fs.readFileSync(envPath, "utf8");
39
39
  if (envContent.includes("TD_API_KEY=")) {
40
- console.log(chalk.gray("\n API key already configured in .env, skipping...\n"));
40
+ console.log(
41
+ chalk.gray("\n API key already configured in .env, skipping...\n"),
42
+ );
41
43
  return;
42
44
  }
43
45
  }
44
46
 
45
47
  console.log(chalk.cyan(" Setting up your TestDriver API key...\n"));
46
- console.log(chalk.gray(" Get your API key from: https://console.testdriver.ai/team"));
48
+ console.log(
49
+ chalk.gray(" Get your API key from: https://console.testdriver.ai/team"),
50
+ );
47
51
 
48
52
  // Ask if user wants to open the browser
49
- const shouldOpen = await this.askYesNo(" Open API keys page in browser? (Y/n): ");
53
+ const shouldOpen = await this.askYesNo(
54
+ " Open API keys page in browser? (Y/n): ",
55
+ );
50
56
  if (shouldOpen) {
51
57
  try {
52
58
  // Dynamic import for ES module
@@ -54,12 +60,16 @@ class InitCommand extends BaseCommand {
54
60
  await open("https://console.testdriver.ai/team");
55
61
  console.log(chalk.gray(" Opening browser...\n"));
56
62
  } catch (error) {
57
- console.log(chalk.yellow(" ⚠️ Could not open browser automatically\n"));
63
+ console.log(
64
+ chalk.yellow(" ⚠️ Could not open browser automatically\n"),
65
+ );
58
66
  }
59
67
  }
60
68
 
61
69
  // Prompt for API key with hidden input
62
- const apiKey = await this.promptHidden(" Enter your API key (input will be hidden): ");
70
+ const apiKey = await this.promptHidden(
71
+ " Enter your API key (input will be hidden): ",
72
+ );
63
73
 
64
74
  if (apiKey && apiKey.trim()) {
65
75
  // Save to .env
@@ -70,7 +80,11 @@ class InitCommand extends BaseCommand {
70
80
  fs.writeFileSync(envPath, envContent + `TD_API_KEY=${apiKey.trim()}\n`);
71
81
  console.log(chalk.green("\n ✓ API key saved to .env\n"));
72
82
  } else {
73
- console.log(chalk.yellow("\n ⚠️ No API key entered. You can add it later to .env:\n"));
83
+ console.log(
84
+ chalk.yellow(
85
+ "\n ⚠️ No API key entered. You can add it later to .env:\n",
86
+ ),
87
+ );
74
88
  console.log(chalk.gray(" TD_API_KEY=your_api_key\n"));
75
89
  }
76
90
  }
@@ -81,7 +95,7 @@ class InitCommand extends BaseCommand {
81
95
  async promptHidden(question) {
82
96
  return new Promise((resolve) => {
83
97
  process.stdout.write(question);
84
-
98
+
85
99
  const stdin = process.stdin;
86
100
  const wasRaw = stdin.isRaw;
87
101
  stdin.setRawMode(true);
@@ -131,7 +145,9 @@ class InitCommand extends BaseCommand {
131
145
  rl.question(question, (answer) => {
132
146
  rl.close();
133
147
  const normalized = answer.toLowerCase().trim();
134
- resolve(normalized === "" || normalized === "y" || normalized === "yes");
148
+ resolve(
149
+ normalized === "" || normalized === "y" || normalized === "yes",
150
+ );
135
151
  });
136
152
  });
137
153
  }
@@ -153,17 +169,20 @@ class InitCommand extends BaseCommand {
153
169
  scripts: {
154
170
  test: "vitest run",
155
171
  "test:watch": "vitest",
156
- "test:ui": "vitest --ui"
172
+ "test:ui": "vitest --ui",
157
173
  },
158
174
  keywords: ["testdriver", "testing", "e2e"],
159
175
  author: "",
160
176
  license: "ISC",
161
177
  engines: {
162
- node: ">=20.19.0"
163
- }
178
+ node: ">=20.19.0",
179
+ },
164
180
  };
165
181
 
166
- fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n");
182
+ fs.writeFileSync(
183
+ packageJsonPath,
184
+ JSON.stringify(packageJson, null, 2) + "\n",
185
+ );
167
186
  console.log(chalk.green(` Created package.json`));
168
187
  } else {
169
188
  console.log(chalk.gray(" package.json already exists, skipping..."));
@@ -249,7 +268,7 @@ test('should login and add item to cart', async (context) => {
249
268
  await cartButton.click();
250
269
 
251
270
  // Verify item in cart
252
- const result = await testdriver.assert('TestDriver Hat is in the cart');
271
+ const result = await testdriver.assert('There is an item in the cart');
253
272
  expect(result).toBeTruthy();
254
273
 
255
274
  });
@@ -283,7 +302,6 @@ export default defineConfig({
283
302
  fs.writeFileSync(configFile, configContent);
284
303
  console.log(chalk.green(` Created config file: ${configFile}`));
285
304
  }
286
-
287
305
  }
288
306
 
289
307
  /**
@@ -387,10 +405,13 @@ jobs:
387
405
  console.log(chalk.cyan("\n Installing dependencies...\n"));
388
406
 
389
407
  try {
390
- execSync("npm install -D vitest testdriverai@beta && npm install dotenv", {
391
- cwd: process.cwd(),
392
- stdio: "inherit"
393
- });
408
+ execSync(
409
+ "npm install -D vitest testdriverai@beta && npm install dotenv",
410
+ {
411
+ cwd: process.cwd(),
412
+ stdio: "inherit",
413
+ },
414
+ );
394
415
  console.log(chalk.green("\n Dependencies installed successfully!"));
395
416
  } catch (error) {
396
417
  console.log(
@@ -410,10 +431,16 @@ jobs:
410
431
  console.log(chalk.cyan("Next steps:\n"));
411
432
  console.log(" 1. Run your tests:");
412
433
  console.log(chalk.gray(" npx vitest run\n"));
413
- console.log(" 2. For CI/CD, add TD_API_KEY to your GitHub repository secrets");
414
- console.log(chalk.gray(" Settings → Secrets → Actions → New repository secret\n"));
415
434
  console.log(
416
- chalk.cyan("Learn more at https://docs.testdriver.ai/v7/getting-started/\n"),
435
+ " 2. For CI/CD, add TD_API_KEY to your GitHub repository secrets",
436
+ );
437
+ console.log(
438
+ chalk.gray(" Settings → Secrets → Actions → New repository secret\n"),
439
+ );
440
+ console.log(
441
+ chalk.cyan(
442
+ "Learn more at https://docs.testdriver.ai/v7/getting-started/\n",
443
+ ),
417
444
  );
418
445
  }
419
446
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "7.2.54",
3
+ "version": "7.2.56",
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.d.ts CHANGED
@@ -1137,25 +1137,19 @@ export default class TestDriverSDK {
1137
1137
 
1138
1138
  /**
1139
1139
  * Capture a screenshot of the current screen and save it to .testdriver/screenshots
1140
- * @param scale - Scale factor for the screenshot (default: 1 = original size)
1141
- * @param silent - Whether to suppress logging (default: false)
1142
- * @param mouse - Whether to include mouse cursor (default: false)
1140
+ * @param filename - Custom filename (without .png extension)
1143
1141
  * @returns The file path where the screenshot was saved
1144
1142
  *
1145
1143
  * @example
1146
- * // Capture a screenshot (saves to .testdriver/screenshots)
1147
- * const screenshotPath = await client.screenshot();
1148
- * console.log('Screenshot saved to:', screenshotPath);
1144
+ * // Capture a screenshot with auto-generated filename
1145
+ * const screenshotPath = await testdriver.screenshot();
1149
1146
  *
1150
1147
  * @example
1151
- * // Capture with mouse cursor visible
1152
- * const screenshotPath = await client.screenshot(1, false, true);
1148
+ * // Capture with custom filename
1149
+ * const screenshotPath = await testdriver.screenshot("login-page");
1150
+ * // Saves to: .testdriver/screenshots/<test>/login-page.png
1153
1151
  */
1154
- screenshot(
1155
- scale?: number,
1156
- silent?: boolean,
1157
- mouse?: boolean,
1158
- ): Promise<string>;
1152
+ screenshot(filename?: string): Promise<string>;
1159
1153
 
1160
1154
  /**
1161
1155
  * Wait for specified time
package/sdk.js CHANGED
@@ -2772,24 +2772,27 @@ with zipfile.ZipFile(io.BytesIO(zip_data)) as zf:
2772
2772
  // ====================================
2773
2773
 
2774
2774
  /**
2775
- * Capture a screenshot of the current screen and save it to .testdriverai/screenshots
2776
- * @param {number} [scale=1] - Scale factor for the screenshot (1 = original size)
2777
- * @param {boolean} [silent=false] - Whether to suppress logging
2778
- * @param {boolean} [mouse=false] - Whether to include mouse cursor
2775
+ * Capture a screenshot of the current screen and save it to .testdriver/screenshots
2776
+ * @param {string} [filename] - Custom filename (without .png extension)
2779
2777
  * @returns {Promise<string>} The file path where the screenshot was saved
2780
2778
  *
2781
2779
  * @example
2782
- * // Capture a screenshot (saves to .testdriverai/screenshots)
2783
- * const screenshotPath = await client.screenshot();
2784
- * console.log('Screenshot saved to:', screenshotPath);
2780
+ * // Capture a screenshot with auto-generated filename
2781
+ * const screenshotPath = await testdriver.screenshot();
2785
2782
  *
2786
2783
  * @example
2787
- * // Capture with mouse cursor visible
2788
- * const screenshotPath = await client.screenshot(1, false, true);
2784
+ * // Capture with custom filename
2785
+ * const screenshotPath = await testdriver.screenshot("login-page");
2786
+ * // Saves to: .testdriver/screenshots/<test>/login-page.png
2789
2787
  */
2790
- async screenshot(scale = 1, silent = false, mouse = false) {
2788
+ async screenshot(filename) {
2791
2789
  this._ensureConnected();
2792
- const base64Data = await this.system.captureScreenBase64(scale, silent, mouse);
2790
+
2791
+ const finalFilename = filename
2792
+ ? (filename.endsWith('.png') ? filename : `${filename}.png`)
2793
+ : `screenshot-${Date.now()}.png`;
2794
+
2795
+ const base64Data = await this.system.captureScreenBase64(1, false, false);
2793
2796
 
2794
2797
  // Save to .testdriver/screenshots/<test-file-name> directory
2795
2798
  let screenshotsDir = path.join(process.cwd(), ".testdriver", "screenshots");
@@ -2801,8 +2804,7 @@ with zipfile.ZipFile(io.BytesIO(zip_data)) as zf:
2801
2804
  fs.mkdirSync(screenshotsDir, { recursive: true });
2802
2805
  }
2803
2806
 
2804
- const filename = `screenshot-${Date.now()}.png`;
2805
- const filePath = path.join(screenshotsDir, filename);
2807
+ const filePath = path.join(screenshotsDir, finalFilename);
2806
2808
 
2807
2809
  // Remove data:image/png;base64, prefix if present
2808
2810
  const cleanBase64 = base64Data.replace(/^data:image\/\w+;base64,/, "");
@@ -2810,9 +2812,7 @@ with zipfile.ZipFile(io.BytesIO(zip_data)) as zf:
2810
2812
 
2811
2813
  fs.writeFileSync(filePath, buffer);
2812
2814
 
2813
- if (!silent) {
2814
- this.emitter.emit("log:info", `📸 Screenshot saved to: ${filePath}`);
2815
- }
2815
+ this.emitter.emit("log:info", `📸 Screenshot saved to: ${filePath}`);
2816
2816
 
2817
2817
  return filePath;
2818
2818
  }