testdriverai 7.1.1 → 7.1.3
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/commands.js +7 -2
- package/docs/docs.json +23 -30
- package/docs/v7/getting-started/quickstart.mdx +11 -9
- package/docs/v7/getting-started/running-and-debugging.mdx +3 -2
- package/docs/v7/getting-started/writing-tests.mdx +4 -5
- package/docs/v7/presets/chrome.mdx +38 -41
- package/docs/v7/presets/electron.mdx +107 -100
- package/docs/v7/presets/webapp.mdx +40 -43
- package/interfaces/cli/commands/init.js +4 -4
- package/interfaces/vitest-plugin.mjs +36 -9
- package/lib/vitest/hooks.mjs +5 -1
- package/package.json +1 -1
- package/sdk.js +59 -6
- package/test/testdriver/exec-output.test.mjs +1 -1
- package/test/testdriver/exec-pwsh.test.mjs +1 -1
- package/test/testdriver/focus-window.test.mjs +1 -1
- package/test/testdriver/hover-image.test.mjs +1 -1
- package/test/testdriver/match-image.test.mjs +1 -1
- package/test/testdriver/scroll-keyboard.test.mjs +1 -1
- package/test/testdriver/scroll-until-image.test.mjs +1 -1
- package/test/testdriver/scroll-until-text.test.mjs +18 -1
- package/test/testdriver/scroll.test.mjs +1 -1
- package/test/testdriver/setup/lifecycleHelpers.mjs +105 -5
- package/test/testdriver/setup/testHelpers.mjs +6 -2
- package/vitest.config.mjs +2 -2
- package/test/testdriver/exec-js.test.mjs +0 -43
package/agent/lib/commands.js
CHANGED
|
@@ -283,6 +283,11 @@ const createCommands = (
|
|
|
283
283
|
* @param {number} [options.redraw.diffThreshold=0.1] - Screen diff threshold percentage
|
|
284
284
|
*/
|
|
285
285
|
const scroll = async (direction = 'down', options = {}) => {
|
|
286
|
+
// Convert number to object format
|
|
287
|
+
if (typeof options === 'number') {
|
|
288
|
+
options = { amount: options };
|
|
289
|
+
}
|
|
290
|
+
|
|
286
291
|
let { amount = 300 } = options;
|
|
287
292
|
const redrawOptions = extractRedrawOptions(options);
|
|
288
293
|
|
|
@@ -1151,7 +1156,7 @@ const createCommands = (
|
|
|
1151
1156
|
),
|
|
1152
1157
|
true,
|
|
1153
1158
|
);
|
|
1154
|
-
await scroll(
|
|
1159
|
+
await scroll(direction, { amount: incrementDistance });
|
|
1155
1160
|
scrollDistance = scrollDistance + incrementDistance;
|
|
1156
1161
|
}
|
|
1157
1162
|
}
|
|
@@ -1231,7 +1236,7 @@ const createCommands = (
|
|
|
1231
1236
|
theme.dim(`scrolling ${direction} ${incrementDistance} pixels...`),
|
|
1232
1237
|
true,
|
|
1233
1238
|
);
|
|
1234
|
-
await scroll(
|
|
1239
|
+
await scroll(direction, { amount: incrementDistance });
|
|
1235
1240
|
scrollDistance = scrollDistance + incrementDistance;
|
|
1236
1241
|
}
|
|
1237
1242
|
}
|
package/docs/docs.json
CHANGED
|
@@ -232,8 +232,28 @@
|
|
|
232
232
|
"/v7/presets/chrome",
|
|
233
233
|
"/v7/presets/chrome-extension",
|
|
234
234
|
"/v7/presets/vscode",
|
|
235
|
-
"/v7/presets/electron"
|
|
236
|
-
|
|
235
|
+
"/v7/presets/electron"
|
|
236
|
+
]
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
"group": "Actions",
|
|
240
|
+
"icon": "bolt",
|
|
241
|
+
"pages": [
|
|
242
|
+
"/v7/api/act",
|
|
243
|
+
"/v7/api/assert",
|
|
244
|
+
"/v7/api/assertions",
|
|
245
|
+
"/v7/api/click",
|
|
246
|
+
"/v7/api/doubleClick",
|
|
247
|
+
"/v7/api/exec",
|
|
248
|
+
"/v7/api/find",
|
|
249
|
+
"/v7/api/focusApplication",
|
|
250
|
+
"/v7/api/hover",
|
|
251
|
+
"/v7/api/mouseDown",
|
|
252
|
+
"/v7/api/mouseUp",
|
|
253
|
+
"/v7/api/pressKeys",
|
|
254
|
+
"/v7/api/rightClick",
|
|
255
|
+
"/v7/api/type",
|
|
256
|
+
"/v7/api/scroll"
|
|
237
257
|
]
|
|
238
258
|
},
|
|
239
259
|
{
|
|
@@ -241,35 +261,8 @@
|
|
|
241
261
|
"icon": "book",
|
|
242
262
|
"pages": [
|
|
243
263
|
"/v7/api/client",
|
|
264
|
+
"/v7/api/elements",
|
|
244
265
|
"/v7/api/sandbox",
|
|
245
|
-
{
|
|
246
|
-
"group": "Interactions",
|
|
247
|
-
"icon": "bolt",
|
|
248
|
-
"pages": [
|
|
249
|
-
"/v7/api/find",
|
|
250
|
-
"/v7/api/elements",
|
|
251
|
-
"/v7/api/click",
|
|
252
|
-
"/v7/api/doubleClick",
|
|
253
|
-
"/v7/api/rightClick",
|
|
254
|
-
"/v7/api/hover",
|
|
255
|
-
"/v7/api/mouseDown",
|
|
256
|
-
"/v7/api/mouseUp",
|
|
257
|
-
"/v7/api/type",
|
|
258
|
-
"/v7/api/pressKeys",
|
|
259
|
-
"/v7/api/scroll",
|
|
260
|
-
"/v7/api/focusApplication"
|
|
261
|
-
]
|
|
262
|
-
},
|
|
263
|
-
{
|
|
264
|
-
"group": "AI & Assertions",
|
|
265
|
-
"icon": "wand-magic-sparkles",
|
|
266
|
-
"pages": [
|
|
267
|
-
"/v7/api/act",
|
|
268
|
-
"/v7/api/assert",
|
|
269
|
-
"/v7/api/assertions"
|
|
270
|
-
]
|
|
271
|
-
},
|
|
272
|
-
"/v7/api/exec",
|
|
273
266
|
"/v7/api/dashcam"
|
|
274
267
|
]
|
|
275
268
|
}
|
|
@@ -44,14 +44,16 @@ TestDriver v7 lets you write AI-powered tests in JavaScript/TypeScript with full
|
|
|
44
44
|
<Tab title="Fast">
|
|
45
45
|
```javascript test.test.js
|
|
46
46
|
import { test } from 'vitest';
|
|
47
|
-
import {
|
|
47
|
+
import { TestDriver } from 'testdriverai/vitest/hooks';
|
|
48
48
|
|
|
49
49
|
test('my first test', async (context) => {
|
|
50
|
-
const
|
|
51
|
-
|
|
50
|
+
const testdriver = TestDriver(context, {
|
|
51
|
+
headless: true,
|
|
52
52
|
apiKey: 'tdai-1234567890abcdef' // Your API key from console.testdriver.ai
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
+
await testdriver.provision.chrome({ url: 'https://example.com' });
|
|
56
|
+
|
|
55
57
|
await testdriver.find('More information link').click();
|
|
56
58
|
await testdriver.assert('IANA page is visible');
|
|
57
59
|
});
|
|
@@ -73,13 +75,13 @@ TestDriver v7 lets you write AI-powered tests in JavaScript/TypeScript with full
|
|
|
73
75
|
|
|
74
76
|
```javascript test.test.js
|
|
75
77
|
import { test } from 'vitest';
|
|
76
|
-
import {
|
|
78
|
+
import { TestDriver } from 'testdriverai/vitest/hooks';
|
|
77
79
|
|
|
78
80
|
test('my first test', async (context) => {
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
});
|
|
81
|
+
const testdriver = TestDriver(context, { headless: true });
|
|
82
|
+
// apiKey automatically read from process.env.TD_API_KEY
|
|
83
|
+
|
|
84
|
+
await testdriver.provision.chrome({ url: 'https://example.com' });
|
|
83
85
|
|
|
84
86
|
await testdriver.find('More information link').click();
|
|
85
87
|
await testdriver.assert('IANA page is visible');
|
|
@@ -111,7 +113,7 @@ TestDriver v7 lets you write AI-powered tests in JavaScript/TypeScript with full
|
|
|
111
113
|
|
|
112
114
|
## What Just Happened?
|
|
113
115
|
|
|
114
|
-
The `chrome()`
|
|
116
|
+
The TestDriver hook with `provision.chrome()` automatically:
|
|
115
117
|
1. ✅ Connected to a TestDriver sandbox
|
|
116
118
|
2. ✅ Launched Chrome browser
|
|
117
119
|
3. ✅ Navigated to your URL
|
|
@@ -101,11 +101,12 @@ Every test automatically records a video replay:
|
|
|
101
101
|
<Step title="Get Replay URL">
|
|
102
102
|
```javascript
|
|
103
103
|
test('my test', async (context) => {
|
|
104
|
-
const
|
|
104
|
+
const testdriver = TestDriver(context, { headless: true });
|
|
105
|
+
await testdriver.provision.chrome({ url });
|
|
105
106
|
|
|
106
107
|
// Your test code
|
|
107
108
|
|
|
108
|
-
console.log('Replay:', dashcam.url);
|
|
109
|
+
console.log('Replay:', testdriver.dashcam.url);
|
|
109
110
|
});
|
|
110
111
|
```
|
|
111
112
|
|
|
@@ -12,13 +12,12 @@ Every TestDriver test follows this simple pattern:
|
|
|
12
12
|
|
|
13
13
|
```javascript
|
|
14
14
|
import { test } from 'vitest';
|
|
15
|
-
import {
|
|
15
|
+
import { TestDriver } from 'testdriverai/vitest/hooks';
|
|
16
16
|
|
|
17
17
|
test('descriptive test name', async (context) => {
|
|
18
18
|
// 1. Setup: Launch and navigate
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
});
|
|
19
|
+
const testdriver = TestDriver(context, { headless: true });
|
|
20
|
+
await testdriver.provision.chrome({ url: 'https://myapp.com' });
|
|
22
21
|
|
|
23
22
|
// 2. Act: Interact with your application
|
|
24
23
|
await testdriver.find('email input').type('user@example.com');
|
|
@@ -30,7 +29,7 @@ test('descriptive test name', async (context) => {
|
|
|
30
29
|
```
|
|
31
30
|
|
|
32
31
|
<Tip>
|
|
33
|
-
The
|
|
32
|
+
The TestDriver hook handles all setup and cleanup automatically - no need for manual browser management!
|
|
34
33
|
</Tip>
|
|
35
34
|
|
|
36
35
|
## Finding Elements
|
|
@@ -16,7 +16,7 @@ The `chrome()` preset automatically sets up a Chrome browser with TestDriver and
|
|
|
16
16
|
import { TestDriver } from 'testdriverai/vitest/hooks';
|
|
17
17
|
|
|
18
18
|
test('my test', async (context) => {
|
|
19
|
-
const testdriver = TestDriver(context);
|
|
19
|
+
const testdriver = TestDriver(context, { headless: true });
|
|
20
20
|
await testdriver.provision.chrome({ url: 'https://example.com' });
|
|
21
21
|
// ...
|
|
22
22
|
});
|
|
@@ -29,12 +29,12 @@ The `chrome()` preset automatically sets up a Chrome browser with TestDriver and
|
|
|
29
29
|
|
|
30
30
|
```javascript
|
|
31
31
|
import { test } from 'vitest';
|
|
32
|
-
import {
|
|
32
|
+
import { TestDriver } from 'testdriverai/vitest/hooks';
|
|
33
33
|
|
|
34
34
|
test('login test', async (context) => {
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
});
|
|
35
|
+
const testdriver = TestDriver(context, { headless: true });
|
|
36
|
+
|
|
37
|
+
await testdriver.provision.chrome({ url: 'https://myapp.com/login' });
|
|
38
38
|
|
|
39
39
|
await testdriver.find('email input').type('user@example.com');
|
|
40
40
|
await testdriver.find('password input').type('password123');
|
|
@@ -98,12 +98,12 @@ chrome(context, options): Promise<ChromeResult>
|
|
|
98
98
|
|
|
99
99
|
```javascript
|
|
100
100
|
import { test } from 'vitest';
|
|
101
|
-
import {
|
|
101
|
+
import { TestDriver } from 'testdriverai/vitest/hooks';
|
|
102
102
|
|
|
103
103
|
test('search functionality', async (context) => {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
});
|
|
104
|
+
const testdriver = TestDriver(context, { headless: true });
|
|
105
|
+
|
|
106
|
+
await testdriver.provision.chrome({ url: 'https://example.com' });
|
|
107
107
|
|
|
108
108
|
await testdriver.find('search input').type('TestDriver');
|
|
109
109
|
await testdriver.find('search button').click();
|
|
@@ -115,13 +115,12 @@ test('search functionality', async (context) => {
|
|
|
115
115
|
|
|
116
116
|
```javascript
|
|
117
117
|
import { test, expect } from 'vitest';
|
|
118
|
-
import {
|
|
118
|
+
import { TestDriver } from 'testdriverai/vitest/hooks';
|
|
119
119
|
|
|
120
120
|
test('checkout flow', async (context) => {
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
});
|
|
121
|
+
const testdriver = TestDriver(context, { headless: true });
|
|
122
|
+
|
|
123
|
+
await testdriver.provision.chrome({ url: 'https://shop.example.com' });
|
|
125
124
|
|
|
126
125
|
// Add items to cart
|
|
127
126
|
await testdriver.find('Add to Cart button').click();
|
|
@@ -149,22 +148,20 @@ test('checkout flow', async (context) => {
|
|
|
149
148
|
|
|
150
149
|
```javascript
|
|
151
150
|
import { test } from 'vitest';
|
|
152
|
-
import {
|
|
151
|
+
import { TestDriver } from 'testdriverai/vitest/hooks';
|
|
153
152
|
|
|
154
153
|
test('windows chrome test', async (context) => {
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
});
|
|
154
|
+
const testdriver = TestDriver(context, { headless: true, os: 'windows' });
|
|
155
|
+
|
|
156
|
+
await testdriver.provision.chrome({ url: 'https://myapp.com' });
|
|
159
157
|
|
|
160
158
|
await testdriver.find('Start').click();
|
|
161
159
|
});
|
|
162
160
|
|
|
163
161
|
test('mac chrome test', async (context) => {
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
});
|
|
162
|
+
const testdriver = TestDriver(context, { headless: true, os: 'mac' });
|
|
163
|
+
|
|
164
|
+
await testdriver.provision.chrome({ url: 'https://myapp.com' });
|
|
168
165
|
|
|
169
166
|
await testdriver.find('Start').click();
|
|
170
167
|
});
|
|
@@ -174,13 +171,12 @@ test('mac chrome test', async (context) => {
|
|
|
174
171
|
|
|
175
172
|
```javascript
|
|
176
173
|
import { test } from 'vitest';
|
|
177
|
-
import {
|
|
174
|
+
import { TestDriver } from 'testdriverai/vitest/hooks';
|
|
178
175
|
|
|
179
176
|
test('quick test without recording', async (context) => {
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
});
|
|
177
|
+
const testdriver = TestDriver(context, { headless: true, dashcam: false });
|
|
178
|
+
|
|
179
|
+
await testdriver.provision.chrome({ url: 'https://example.com' });
|
|
184
180
|
|
|
185
181
|
await testdriver.find('button').click();
|
|
186
182
|
});
|
|
@@ -190,13 +186,14 @@ test('quick test without recording', async (context) => {
|
|
|
190
186
|
|
|
191
187
|
```javascript
|
|
192
188
|
import { test } from 'vitest';
|
|
193
|
-
import {
|
|
189
|
+
import { TestDriver } from 'testdriverai/vitest/hooks';
|
|
194
190
|
|
|
195
191
|
test('chrome extension', async (context) => {
|
|
196
|
-
const
|
|
192
|
+
const testdriver = TestDriver(context, { headless: true });
|
|
193
|
+
|
|
194
|
+
await testdriver.provision.chrome({
|
|
197
195
|
url: 'chrome://extensions',
|
|
198
|
-
guest: false
|
|
199
|
-
maximized: true
|
|
196
|
+
guest: false // Need profile for extensions
|
|
200
197
|
});
|
|
201
198
|
|
|
202
199
|
await testdriver.find('Developer mode toggle').click();
|
|
@@ -226,9 +223,9 @@ At test end:
|
|
|
226
223
|
|
|
227
224
|
```javascript
|
|
228
225
|
test('user registration', async (context) => {
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
});
|
|
226
|
+
const testdriver = TestDriver(context, { headless: true });
|
|
227
|
+
|
|
228
|
+
await testdriver.provision.chrome({ url: 'https://myapp.com/register' });
|
|
232
229
|
|
|
233
230
|
await testdriver.find('email field').type('user@example.com');
|
|
234
231
|
await testdriver.find('password field').type('SecurePass123!');
|
|
@@ -244,9 +241,9 @@ test('user registration', async (context) => {
|
|
|
244
241
|
|
|
245
242
|
```javascript
|
|
246
243
|
test('multi-page navigation', async (context) => {
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
});
|
|
244
|
+
const testdriver = TestDriver(context, { headless: true });
|
|
245
|
+
|
|
246
|
+
await testdriver.provision.chrome({ url: 'https://myapp.com' });
|
|
250
247
|
|
|
251
248
|
// Navigate through pages
|
|
252
249
|
await testdriver.find('About link').click();
|
|
@@ -265,9 +262,9 @@ test('multi-page navigation', async (context) => {
|
|
|
265
262
|
```javascript
|
|
266
263
|
test('handles errors gracefully', async (context) => {
|
|
267
264
|
try {
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
});
|
|
265
|
+
const testdriver = TestDriver(context, { headless: true });
|
|
266
|
+
|
|
267
|
+
await testdriver.provision.chrome({ url: 'https://myapp.com' });
|
|
271
268
|
|
|
272
269
|
await testdriver.find('non-existent element').click();
|
|
273
270
|
} catch (error) {
|