testdriverai 7.1.2 → 7.1.4
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/.github/workflows/test-init.yml +145 -0
- package/agent/lib/commander.js +2 -2
- package/agent/lib/commands.js +10 -5
- package/docs/docs.json +29 -84
- package/docs/v7/_drafts/migration.mdx +3 -3
- package/docs/v7/api/act.mdx +1 -1
- package/docs/v7/api/assert.mdx +1 -1
- package/docs/v7/api/assertions.mdx +14 -14
- 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/overview/readme.mdx +1 -1
- 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 +79 -21
- package/interfaces/vitest-plugin.mjs +36 -9
- package/lib/vitest/hooks.mjs +5 -1
- package/manual/test-init-command.js +223 -0
- package/package.json +2 -2
- package/schema.json +5 -5
- package/sdk-log-formatter.js +1 -1
- package/sdk.d.ts +8 -8
- package/sdk.js +64 -14
- 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/hover-text-with-description.test.mjs +0 -3
- 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 +7 -2
- package/test/testdriver/exec-js.test.mjs +0 -43
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
name: Test Init Command
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main, develop ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main, develop ]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
test-init:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- name: Checkout CLI repository
|
|
16
|
+
uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Setup Node.js
|
|
19
|
+
uses: actions/setup-node@v4
|
|
20
|
+
with:
|
|
21
|
+
node-version: '20'
|
|
22
|
+
cache: 'npm'
|
|
23
|
+
|
|
24
|
+
- name: Install CLI dependencies
|
|
25
|
+
run: npm ci
|
|
26
|
+
|
|
27
|
+
- name: Create test directory
|
|
28
|
+
run: |
|
|
29
|
+
mkdir -p /tmp/test-init-project
|
|
30
|
+
cd /tmp/test-init-project
|
|
31
|
+
|
|
32
|
+
- name: Run init command (skip prompts)
|
|
33
|
+
working-directory: /tmp/test-init-project
|
|
34
|
+
run: |
|
|
35
|
+
# Create .env with API key first to skip the prompt
|
|
36
|
+
echo "TD_API_KEY=${{ secrets.TD_API_KEY }}" > .env
|
|
37
|
+
|
|
38
|
+
# Run init command using the CLI from the repo
|
|
39
|
+
node ${{ github.workspace }}/bin/testdriverai.js init
|
|
40
|
+
env:
|
|
41
|
+
TD_API_KEY: ${{ secrets.TD_API_KEY }}
|
|
42
|
+
|
|
43
|
+
- name: Verify project structure
|
|
44
|
+
working-directory: /tmp/test-init-project
|
|
45
|
+
run: |
|
|
46
|
+
echo "Checking generated files..."
|
|
47
|
+
|
|
48
|
+
# Check for package.json
|
|
49
|
+
if [ ! -f "package.json" ]; then
|
|
50
|
+
echo "❌ package.json not found"
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
echo "✓ package.json exists"
|
|
54
|
+
|
|
55
|
+
# Check for vitest config
|
|
56
|
+
if [ ! -f "vitest.config.js" ]; then
|
|
57
|
+
echo "❌ vitest.config.js not found"
|
|
58
|
+
exit 1
|
|
59
|
+
fi
|
|
60
|
+
echo "✓ vitest.config.js exists"
|
|
61
|
+
|
|
62
|
+
# Check for test file
|
|
63
|
+
if [ ! -f "tests/example.test.js" ]; then
|
|
64
|
+
echo "❌ tests/example.test.js not found"
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
echo "✓ tests/example.test.js exists"
|
|
68
|
+
|
|
69
|
+
# Check for .env file
|
|
70
|
+
if [ ! -f ".env" ]; then
|
|
71
|
+
echo "❌ .env not found"
|
|
72
|
+
exit 1
|
|
73
|
+
fi
|
|
74
|
+
echo "✓ .env exists"
|
|
75
|
+
|
|
76
|
+
# Check for .gitignore
|
|
77
|
+
if [ ! -f ".gitignore" ]; then
|
|
78
|
+
echo "❌ .gitignore not found"
|
|
79
|
+
exit 1
|
|
80
|
+
fi
|
|
81
|
+
echo "✓ .gitignore exists"
|
|
82
|
+
|
|
83
|
+
# Check for GitHub workflow
|
|
84
|
+
if [ ! -f ".github/workflows/testdriver.yml" ]; then
|
|
85
|
+
echo "❌ .github/workflows/testdriver.yml not found"
|
|
86
|
+
exit 1
|
|
87
|
+
fi
|
|
88
|
+
echo "✓ .github/workflows/testdriver.yml exists"
|
|
89
|
+
|
|
90
|
+
- name: Verify vitest config contents
|
|
91
|
+
working-directory: /tmp/test-init-project
|
|
92
|
+
run: |
|
|
93
|
+
echo "Checking vitest.config.js contents..."
|
|
94
|
+
|
|
95
|
+
# Check for TestDriver reporter
|
|
96
|
+
if ! grep -q "TestDriver()" vitest.config.js; then
|
|
97
|
+
echo "❌ TestDriver reporter not found in vitest.config.js"
|
|
98
|
+
cat vitest.config.js
|
|
99
|
+
exit 1
|
|
100
|
+
fi
|
|
101
|
+
echo "✓ TestDriver reporter is configured"
|
|
102
|
+
|
|
103
|
+
# Check for setupFiles
|
|
104
|
+
if ! grep -q "setupFiles.*testdriverai/vitest/setup" vitest.config.js; then
|
|
105
|
+
echo "❌ setupFiles not configured correctly"
|
|
106
|
+
cat vitest.config.js
|
|
107
|
+
exit 1
|
|
108
|
+
fi
|
|
109
|
+
echo "✓ setupFiles is configured"
|
|
110
|
+
|
|
111
|
+
- name: Verify test file contents
|
|
112
|
+
working-directory: /tmp/test-init-project
|
|
113
|
+
run: |
|
|
114
|
+
echo "Checking test file contents..."
|
|
115
|
+
|
|
116
|
+
# Check for .provision usage
|
|
117
|
+
if ! grep -q "\.provision\.chrome" tests/example.test.js; then
|
|
118
|
+
echo "❌ Test does not use .provision.chrome"
|
|
119
|
+
cat tests/example.test.js
|
|
120
|
+
exit 1
|
|
121
|
+
fi
|
|
122
|
+
echo "✓ Test uses .provision.chrome"
|
|
123
|
+
|
|
124
|
+
# Check for TestDriver import
|
|
125
|
+
if ! grep -q "from 'testdriverai/vitest/hooks'" tests/example.test.js; then
|
|
126
|
+
echo "❌ Test does not import from testdriverai/vitest/hooks"
|
|
127
|
+
cat tests/example.test.js
|
|
128
|
+
exit 1
|
|
129
|
+
fi
|
|
130
|
+
echo "✓ Test imports TestDriver from vitest/hooks"
|
|
131
|
+
|
|
132
|
+
- name: Run the generated test
|
|
133
|
+
working-directory: /tmp/test-init-project
|
|
134
|
+
run: npm test
|
|
135
|
+
env:
|
|
136
|
+
TD_API_KEY: ${{ secrets.TD_API_KEY }}
|
|
137
|
+
|
|
138
|
+
- name: Upload test results
|
|
139
|
+
if: always()
|
|
140
|
+
uses: actions/upload-artifact@v4
|
|
141
|
+
with:
|
|
142
|
+
name: test-init-results
|
|
143
|
+
path: /tmp/test-init-project/test-results/
|
|
144
|
+
retention-days: 7
|
|
145
|
+
if-no-files-found: warn
|
package/agent/lib/commander.js
CHANGED
|
@@ -178,9 +178,9 @@ commands:
|
|
|
178
178
|
emitter.emit(events.log.log, generator.jsonToManual(object));
|
|
179
179
|
response = await commands["focus-application"](object.name);
|
|
180
180
|
break;
|
|
181
|
-
case "
|
|
181
|
+
case "extract": {
|
|
182
182
|
emitter.emit(events.log.log, generator.jsonToManual(object));
|
|
183
|
-
let value = await commands["
|
|
183
|
+
let value = await commands["extract"](object.description);
|
|
184
184
|
emitter.emit(events.log.log, value);
|
|
185
185
|
outputsInstance.set(object.output, value);
|
|
186
186
|
break;
|
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
|
}
|
|
@@ -1271,11 +1276,11 @@ const createCommands = (
|
|
|
1271
1276
|
return "The application was focused.";
|
|
1272
1277
|
},
|
|
1273
1278
|
/**
|
|
1274
|
-
* Extract
|
|
1279
|
+
* Extract information from the screen using AI
|
|
1275
1280
|
* @param {Object|string} options - Options object or description (for backward compatibility)
|
|
1276
|
-
* @param {string} options.description - What to
|
|
1281
|
+
* @param {string} options.description - What to extract
|
|
1277
1282
|
*/
|
|
1278
|
-
"
|
|
1283
|
+
"extract": async (...args) => {
|
|
1279
1284
|
const rememberStartTime = Date.now();
|
|
1280
1285
|
let description;
|
|
1281
1286
|
|
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
|
}
|
|
@@ -313,64 +306,16 @@
|
|
|
313
306
|
},
|
|
314
307
|
"redirects": [
|
|
315
308
|
{
|
|
316
|
-
"source": "/
|
|
317
|
-
"destination": "/
|
|
318
|
-
},
|
|
319
|
-
{
|
|
320
|
-
"source": "/features/:slug*",
|
|
321
|
-
"destination": "/v6/features/:slug*"
|
|
322
|
-
},
|
|
323
|
-
{
|
|
324
|
-
"source": "/account/:slug*",
|
|
325
|
-
"destination": "/v6/account/:slug*"
|
|
326
|
-
},
|
|
327
|
-
{
|
|
328
|
-
"source": "/cli/:slug*",
|
|
329
|
-
"destination": "/v6/cli/:slug*"
|
|
330
|
-
},
|
|
331
|
-
{
|
|
332
|
-
"source": "/interactive/:slug*",
|
|
333
|
-
"destination": "/v6/interactive/:slug*"
|
|
334
|
-
},
|
|
335
|
-
{
|
|
336
|
-
"source": "/getting-started/:slug*",
|
|
337
|
-
"destination": "/v6/getting-started/:slug*"
|
|
338
|
-
},
|
|
339
|
-
{
|
|
340
|
-
"source": "/apps/:slug*",
|
|
341
|
-
"destination": "/v6/apps/:slug*"
|
|
342
|
-
},
|
|
343
|
-
{
|
|
344
|
-
"source": "/scenarios/:slug*",
|
|
345
|
-
"destination": "/v6/scenarios/:slug*"
|
|
346
|
-
},
|
|
347
|
-
{
|
|
348
|
-
"source": "/integrations/:slug*",
|
|
349
|
-
"destination": "/v6/integrations/:slug*"
|
|
350
|
-
},
|
|
351
|
-
{
|
|
352
|
-
"source": "/guide/:slug*",
|
|
353
|
-
"destination": "/v6/guide/:slug*"
|
|
354
|
-
},
|
|
355
|
-
{
|
|
356
|
-
"source": "/action/:slug*",
|
|
357
|
-
"destination": "/v6/action/:slug*"
|
|
358
|
-
},
|
|
359
|
-
{
|
|
360
|
-
"source": "/importing/:slug*",
|
|
361
|
-
"destination": "/v6/importing/:slug*"
|
|
362
|
-
},
|
|
363
|
-
{
|
|
364
|
-
"source": "/exporting/:slug*",
|
|
365
|
-
"destination": "/v6/exporting/:slug*"
|
|
309
|
+
"source": "/guides/github-actions",
|
|
310
|
+
"destination": "/action/setup"
|
|
366
311
|
},
|
|
367
312
|
{
|
|
368
|
-
"source": "/
|
|
369
|
-
"destination": "/
|
|
313
|
+
"source": "/reference/test-steps",
|
|
314
|
+
"destination": "/features/selectorless"
|
|
370
315
|
},
|
|
371
316
|
{
|
|
372
|
-
"source": "/
|
|
373
|
-
"destination": "/
|
|
317
|
+
"source": "/guides/debugging-test-runs",
|
|
318
|
+
"destination": "/getting-started/editing"
|
|
374
319
|
}
|
|
375
320
|
],
|
|
376
321
|
"integrations": {
|
|
@@ -207,16 +207,16 @@ await testdriver.focusApplication('Google Chrome');
|
|
|
207
207
|
```
|
|
208
208
|
</CodeGroup>
|
|
209
209
|
|
|
210
|
-
###
|
|
210
|
+
### Extract
|
|
211
211
|
|
|
212
212
|
<CodeGroup>
|
|
213
213
|
```yaml YAML
|
|
214
|
-
- command:
|
|
214
|
+
- command: extract
|
|
215
215
|
description: the order number
|
|
216
216
|
```
|
|
217
217
|
|
|
218
218
|
```javascript SDK
|
|
219
|
-
const orderNumber = await testdriver.
|
|
219
|
+
const orderNumber = await testdriver.extract('the order number');
|
|
220
220
|
```
|
|
221
221
|
</CodeGroup>
|
|
222
222
|
|
package/docs/v7/api/act.mdx
CHANGED
|
@@ -202,4 +202,4 @@ describe('E-commerce Flow with AI', () => {
|
|
|
202
202
|
|
|
203
203
|
- [`find()`](/v7/api/find) - Locate specific elements
|
|
204
204
|
- [`assert()`](/v7/api/assert) - Make assertions
|
|
205
|
-
- [`
|
|
205
|
+
- [`extract()`](/v7/api/extract) - Extract information
|
package/docs/v7/api/assert.mdx
CHANGED
|
@@ -280,6 +280,6 @@ describe('Assertions', () => {
|
|
|
280
280
|
|
|
281
281
|
## Related Methods
|
|
282
282
|
|
|
283
|
-
- [`
|
|
283
|
+
- [`extract()`](/v7/api/extract) - Extract information for detailed assertions
|
|
284
284
|
- [`find()`](/v7/api/find) - Locate elements to verify
|
|
285
285
|
- [`ai()`](/v7/api/ai) - Complex AI-driven tasks
|
|
@@ -77,12 +77,12 @@ await waitForAssertion(testdriver, 'results are displayed', 10000);
|
|
|
77
77
|
|
|
78
78
|
## Extracting Information
|
|
79
79
|
|
|
80
|
-
###
|
|
80
|
+
### extract()
|
|
81
81
|
|
|
82
|
-
Extract
|
|
82
|
+
Extract information from the screen using AI.
|
|
83
83
|
|
|
84
84
|
```javascript
|
|
85
|
-
await testdriver.
|
|
85
|
+
await testdriver.extract(description)
|
|
86
86
|
```
|
|
87
87
|
|
|
88
88
|
**Parameters:**
|
|
@@ -94,17 +94,17 @@ await testdriver.remember(description)
|
|
|
94
94
|
|
|
95
95
|
```javascript
|
|
96
96
|
// Extract text from screen
|
|
97
|
-
const password = await testdriver.
|
|
98
|
-
const total = await testdriver.
|
|
99
|
-
const errorMessage = await testdriver.
|
|
97
|
+
const password = await testdriver.extract('the password displayed on screen');
|
|
98
|
+
const total = await testdriver.extract('the order total amount');
|
|
99
|
+
const errorMessage = await testdriver.extract('the error message text');
|
|
100
100
|
|
|
101
101
|
// Extract structured data
|
|
102
|
-
const email = await testdriver.
|
|
103
|
-
const orderId = await testdriver.
|
|
104
|
-
const phoneNumber = await testdriver.
|
|
102
|
+
const email = await testdriver.extract('the email address in the confirmation');
|
|
103
|
+
const orderId = await testdriver.extract('the order ID number');
|
|
104
|
+
const phoneNumber = await testdriver.extract('the phone number');
|
|
105
105
|
|
|
106
106
|
// Use extracted data
|
|
107
|
-
const password = await testdriver.
|
|
107
|
+
const password = await testdriver.extract('the password for standard_user');
|
|
108
108
|
const passwordField = await testdriver.find('password input');
|
|
109
109
|
await passwordField.click();
|
|
110
110
|
await testdriver.type(password);
|
|
@@ -114,8 +114,8 @@ await testdriver.type(password);
|
|
|
114
114
|
|
|
115
115
|
**Dynamic Content:**
|
|
116
116
|
```javascript
|
|
117
|
-
//
|
|
118
|
-
const confirmationCode = await testdriver.
|
|
117
|
+
// Extract generated values
|
|
118
|
+
const confirmationCode = await testdriver.extract('the 6-digit confirmation code');
|
|
119
119
|
console.log('Code:', confirmationCode);
|
|
120
120
|
|
|
121
121
|
// Use it later in the test
|
|
@@ -125,7 +125,7 @@ await testdriver.type(confirmationCode);
|
|
|
125
125
|
**Verification:**
|
|
126
126
|
```javascript
|
|
127
127
|
// Extract and verify
|
|
128
|
-
const displayedTotal = await testdriver.
|
|
128
|
+
const displayedTotal = await testdriver.extract('the cart total');
|
|
129
129
|
const expectedTotal = '$99.99';
|
|
130
130
|
|
|
131
131
|
expect(displayedTotal).toBe(expectedTotal);
|
|
@@ -134,7 +134,7 @@ expect(displayedTotal).toBe(expectedTotal);
|
|
|
134
134
|
**Conditional Logic:**
|
|
135
135
|
```javascript
|
|
136
136
|
// Extract state and make decisions
|
|
137
|
-
const status = await testdriver.
|
|
137
|
+
const status = await testdriver.extract('the order status');
|
|
138
138
|
|
|
139
139
|
if (status.includes('Pending')) {
|
|
140
140
|
// Wait for processing
|
|
@@ -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
|
|
@@ -75,7 +75,7 @@ v7/
|
|
|
75
75
|
- Basic assertions
|
|
76
76
|
- Negative assertions (invert parameter)
|
|
77
77
|
- Async assertions
|
|
78
|
-
- `
|
|
78
|
+
- `extract()` - Extract information from screen
|
|
79
79
|
- Testing patterns:
|
|
80
80
|
- Polling assertions
|
|
81
81
|
- Multi-step validation
|