testdriverai 7.2.53 → 7.2.55
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/lib/system.js +16 -5
- package/agents.md +3 -3
- package/docs/v7/screenshot.mdx +15 -26
- package/package.json +1 -1
- package/sdk.d.ts +8 -14
- package/sdk.js +19 -19
package/agent/lib/system.js
CHANGED
|
@@ -13,12 +13,18 @@ const createSystem = (emitter, sandbox, config) => {
|
|
|
13
13
|
});
|
|
14
14
|
|
|
15
15
|
if (!base64) {
|
|
16
|
-
|
|
17
|
-
} else {
|
|
18
|
-
let image = Buffer.from(base64, "base64");
|
|
19
|
-
fs.writeFileSync(options.filename, image);
|
|
20
|
-
return { filename: options.filename };
|
|
16
|
+
throw new Error("Failed to take screenshot: sandbox returned empty data");
|
|
21
17
|
}
|
|
18
|
+
|
|
19
|
+
let image = Buffer.from(base64, "base64");
|
|
20
|
+
|
|
21
|
+
// Verify we got actual image data (PNG header starts with these bytes)
|
|
22
|
+
if (image.length < 100) {
|
|
23
|
+
throw new Error(`Failed to take screenshot: received only ${image.length} bytes`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
fs.writeFileSync(options.filename, image);
|
|
27
|
+
return { filename: options.filename };
|
|
22
28
|
};
|
|
23
29
|
|
|
24
30
|
let primaryDisplay = null;
|
|
@@ -57,6 +63,11 @@ const createSystem = (emitter, sandbox, config) => {
|
|
|
57
63
|
|
|
58
64
|
// Load the screenshot image with Jimp
|
|
59
65
|
let image = await Jimp.read(step1);
|
|
66
|
+
|
|
67
|
+
// Validate the image was loaded correctly (not a 1x1 or tiny placeholder)
|
|
68
|
+
if (image.getWidth() < 10 || image.getHeight() < 10) {
|
|
69
|
+
throw new Error(`Screenshot appears corrupted: got ${image.getWidth()}x${image.getHeight()} pixels`);
|
|
70
|
+
}
|
|
60
71
|
|
|
61
72
|
// Resize the image
|
|
62
73
|
image.resize(
|
package/agents.md
CHANGED
|
@@ -151,7 +151,7 @@ element.found(); // check if found (boolean)
|
|
|
151
151
|
**Use `screenshot()` liberally during development** to see exactly what the sandbox screen looks like. Screenshots are saved locally and organized by test file.
|
|
152
152
|
|
|
153
153
|
```javascript
|
|
154
|
-
// Capture a screenshot - saved to .
|
|
154
|
+
// Capture a screenshot - saved to .testdriver/screenshots/<test-file>/
|
|
155
155
|
const screenshotPath = await testdriver.screenshot();
|
|
156
156
|
console.log('Screenshot saved to:', screenshotPath);
|
|
157
157
|
|
|
@@ -168,7 +168,7 @@ await testdriver.screenshot(1, false, true);
|
|
|
168
168
|
|
|
169
169
|
**Screenshot file organization:**
|
|
170
170
|
```
|
|
171
|
-
.
|
|
171
|
+
.testdriver/
|
|
172
172
|
screenshots/
|
|
173
173
|
login.test/ # Folder per test file
|
|
174
174
|
screenshot-1737633600000.png
|
|
@@ -443,7 +443,7 @@ console.log('Screenshot with mouse saved to: screenshot-with-mouse.png');
|
|
|
443
443
|
4. **Log element properties** to understand what the AI sees
|
|
444
444
|
5. **Use `assert()` with specific, descriptive natural language**
|
|
445
445
|
6. **Start simple** - get one step working before adding more
|
|
446
|
-
7. **Take screenshots liberally** - use `await testdriver.screenshot()` after key steps to debug what the sandbox actually shows. Check `.
|
|
446
|
+
7. **Take screenshots liberally** - use `await testdriver.screenshot()` after key steps to debug what the sandbox actually shows. Check `.testdriver/screenshots/<test-file>/` to review them.
|
|
447
447
|
8. **Always `await` async methods** - TestDriver will warn if you forget, but for TypeScript projects, add `@typescript-eslint/no-floating-promises` to your ESLint config to catch missing `await` at compile time:
|
|
448
448
|
```json
|
|
449
449
|
// eslint.config.js (for TypeScript projects)
|
package/docs/v7/screenshot.mdx
CHANGED
|
@@ -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(
|
|
15
|
+
const filePath = await testdriver.screenshot(filename)
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
## Parameters
|
|
19
19
|
|
|
20
|
-
<ParamField path="
|
|
21
|
-
|
|
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
|
|
@@ -35,14 +27,14 @@ const filePath = await testdriver.screenshot(scale, silent, mouse)
|
|
|
35
27
|
|
|
36
28
|
## File Organization
|
|
37
29
|
|
|
38
|
-
Screenshots are automatically saved to `.
|
|
30
|
+
Screenshots are automatically saved to `.testdriver/screenshots/<test-file-name>/` in your project root:
|
|
39
31
|
|
|
40
32
|
```
|
|
41
|
-
.
|
|
33
|
+
.testdriver/
|
|
42
34
|
screenshots/
|
|
43
35
|
login.test/
|
|
44
36
|
screenshot-1737633600000.png
|
|
45
|
-
|
|
37
|
+
login-page.png
|
|
46
38
|
checkout.test/
|
|
47
39
|
screenshot-1737633700000.png
|
|
48
40
|
```
|
|
@@ -56,23 +48,20 @@ Screenshots are automatically saved to `.testdriverai/screenshots/<test-file-nam
|
|
|
56
48
|
### Basic Screenshot
|
|
57
49
|
|
|
58
50
|
```javascript
|
|
59
|
-
// Capture a screenshot with
|
|
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
|
-
###
|
|
56
|
+
### Custom Filename
|
|
65
57
|
|
|
66
58
|
```javascript
|
|
67
|
-
//
|
|
68
|
-
|
|
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
|
-
|
|
74
|
-
//
|
|
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
|
|
@@ -136,11 +125,11 @@ describe("Login Flow", () => {
|
|
|
136
125
|
</Accordion>
|
|
137
126
|
|
|
138
127
|
<Accordion title="Add to .gitignore">
|
|
139
|
-
Add `.
|
|
128
|
+
Add `.testdriver/screenshots/` to your `.gitignore` to avoid committing screenshots to version control:
|
|
140
129
|
|
|
141
130
|
```
|
|
142
131
|
# .gitignore
|
|
143
|
-
.
|
|
132
|
+
.testdriver/screenshots/
|
|
144
133
|
```
|
|
145
134
|
</Accordion>
|
|
146
135
|
</AccordionGroup>
|
package/package.json
CHANGED
package/sdk.d.ts
CHANGED
|
@@ -1136,26 +1136,20 @@ export default class TestDriverSDK {
|
|
|
1136
1136
|
// Utility Methods
|
|
1137
1137
|
|
|
1138
1138
|
/**
|
|
1139
|
-
* Capture a screenshot of the current screen and save it to .
|
|
1140
|
-
* @param
|
|
1141
|
-
* @param silent - Whether to suppress logging (default: false)
|
|
1142
|
-
* @param mouse - Whether to include mouse cursor (default: false)
|
|
1139
|
+
* Capture a screenshot of the current screen and save it to .testdriver/screenshots
|
|
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
|
|
1147
|
-
* const screenshotPath = await
|
|
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
|
|
1152
|
-
* const screenshotPath = await
|
|
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
|
@@ -2118,7 +2118,7 @@ with zipfile.ZipFile(io.BytesIO(zip_data)) as zf:
|
|
|
2118
2118
|
// Clean up screenshots folder for this test file before running
|
|
2119
2119
|
if (this.testFile) {
|
|
2120
2120
|
const testFileName = path.basename(this.testFile, path.extname(this.testFile));
|
|
2121
|
-
const screenshotsDir = path.join(process.cwd(), ".
|
|
2121
|
+
const screenshotsDir = path.join(process.cwd(), ".testdriver", "screenshots", testFileName);
|
|
2122
2122
|
if (fs.existsSync(screenshotsDir)) {
|
|
2123
2123
|
fs.rmSync(screenshotsDir, { recursive: true, force: true });
|
|
2124
2124
|
}
|
|
@@ -2772,27 +2772,30 @@ 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 .
|
|
2776
|
-
* @param {
|
|
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
|
|
2783
|
-
* const screenshotPath = await
|
|
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
|
|
2788
|
-
* const screenshotPath = await
|
|
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(
|
|
2788
|
+
async screenshot(filename) {
|
|
2791
2789
|
this._ensureConnected();
|
|
2792
|
-
const base64Data = await this.system.captureScreenBase64(scale, silent, mouse);
|
|
2793
2790
|
|
|
2794
|
-
|
|
2795
|
-
|
|
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);
|
|
2796
|
+
|
|
2797
|
+
// Save to .testdriver/screenshots/<test-file-name> directory
|
|
2798
|
+
let screenshotsDir = path.join(process.cwd(), ".testdriver", "screenshots");
|
|
2796
2799
|
if (this.testFile) {
|
|
2797
2800
|
const testFileName = path.basename(this.testFile, path.extname(this.testFile));
|
|
2798
2801
|
screenshotsDir = path.join(screenshotsDir, testFileName);
|
|
@@ -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
|
|
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
|
-
|
|
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
|
}
|