testdriverai 7.2.3 → 7.2.10
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/publish.yaml +15 -7
- package/.github/workflows/testdriver.yml +163 -0
- package/.testdriver/last-sandbox +7 -0
- package/agent/events.js +1 -0
- package/agent/index.js +99 -163
- package/agent/lib/sandbox.js +11 -1
- package/agents.md +393 -0
- package/bin/testdriverai.js +8 -0
- package/debug/01-table-initial.png +0 -0
- package/debug/02-after-ai-explore.png +0 -0
- package/debug/02-after-scroll.png +0 -0
- package/debugger/index.html +37 -0
- package/docs/docs.json +93 -125
- package/docs/v7/_drafts/architecture.mdx +1 -26
- package/docs/v7/_drafts/caching.mdx +2 -2
- package/docs/v7/{getting-started → _drafts}/installation.mdx +0 -66
- package/docs/v7/{features/coverage.mdx → _drafts/powerful.mdx} +1 -90
- package/docs/v7/_drafts/quick-start-test-recording.mdx +0 -1
- package/docs/v7/{features → _drafts}/scalable.mdx +126 -4
- package/docs/v7/_drafts/screenshot.mdx +155 -0
- package/docs/v7/_drafts/test-recording.mdx +0 -6
- package/docs/v7/_drafts/writing-tests.mdx +25 -0
- package/docs/v7/{api/act.mdx → ai.mdx} +28 -27
- package/docs/v7/{api/assert.mdx → assert.mdx} +3 -3
- package/docs/v7/aws-setup.mdx +338 -0
- package/docs/v7/caching.mdx +128 -0
- package/docs/v7/ci-cd.mdx +605 -0
- package/docs/v7/{api/click.mdx → click.mdx} +4 -4
- package/docs/v7/cloud.mdx +120 -0
- package/docs/v7/customizing-devices.mdx +129 -0
- package/docs/v7/{api/doubleClick.mdx → double-click.mdx} +5 -5
- package/docs/v7/enterprise.mdx +135 -0
- package/docs/v7/examples.mdx +5 -0
- package/docs/v7/{api/exec.mdx → exec.mdx} +3 -3
- package/docs/v7/{api/find.mdx → find.mdx} +17 -21
- package/docs/v7/{api/focusApplication.mdx → focus-application.mdx} +3 -3
- package/docs/v7/generating-tests.mdx +32 -0
- package/docs/v7/{api/hover.mdx → hover.mdx} +3 -3
- package/docs/v7/locating-elements.mdx +71 -0
- package/docs/v7/making-assertions.mdx +32 -0
- package/docs/v7/{api/mouseDown.mdx → mouse-down.mdx} +7 -7
- package/docs/v7/{api/mouseUp.mdx → mouse-up.mdx} +8 -8
- package/docs/v7/performing-actions.mdx +51 -0
- package/docs/v7/{api/pressKeys.mdx → press-keys.mdx} +3 -3
- package/docs/v7/quickstart.mdx +162 -0
- package/docs/v7/reusable-code.mdx +240 -0
- package/docs/v7/{api/rightClick.mdx → right-click.mdx} +5 -5
- package/docs/v7/running-tests.mdx +181 -0
- package/docs/v7/{api/scroll.mdx → scroll.mdx} +3 -3
- package/docs/v7/secrets.mdx +115 -0
- package/docs/v7/self-hosted.mdx +66 -0
- package/docs/v7/{api/type.mdx → type.mdx} +3 -3
- package/docs/v7/variables.mdx +111 -0
- package/docs/v7/waiting-for-elements.mdx +66 -0
- package/docs/v7/what-is-testdriver.mdx +54 -0
- package/interfaces/cli/commands/init.js +33 -19
- package/interfaces/cli/lib/base.js +24 -0
- package/interfaces/cli.js +8 -1
- package/interfaces/logger.js +8 -3
- package/interfaces/vitest-plugin.mjs +16 -71
- package/lib/sentry.js +343 -0
- package/lib/vitest/hooks.mjs +81 -81
- package/package.json +4 -3
- package/sdk-log-formatter.js +41 -0
- package/sdk.d.ts +22 -9
- package/sdk.js +344 -100
- package/test/manual/reconnect-provision.test.mjs +49 -0
- package/test/manual/reconnect-signin.test.mjs +41 -0
- package/test/testdriver/act.test.mjs +30 -0
- package/test/testdriver/ai.test.mjs +30 -0
- package/test/testdriver/assert.test.mjs +1 -1
- package/test/testdriver/hover-text.test.mjs +1 -1
- package/test/testdriver/setup/testHelpers.mjs +8 -119
- package/test/testdriver/windows-installer.test.mjs +61 -0
- package/tests/example.test.js +33 -0
- package/tests/login.js +28 -0
- package/tests/table-sort-enrollments.test.mjs +72 -0
- package/tests/table-sort-experiment.test.mjs +42 -0
- package/tests/table-sort-setup.test.mjs +59 -0
- package/vitest.config.mjs +3 -1
- package/agent/lib/cache.js +0 -142
- package/docs/v7/api/assertions.mdx +0 -403
- package/docs/v7/features/ai-native.mdx +0 -413
- package/docs/v7/features/application-logs.mdx +0 -353
- package/docs/v7/features/browser-logs.mdx +0 -414
- package/docs/v7/features/cache-management.mdx +0 -402
- package/docs/v7/features/continuous-testing.mdx +0 -346
- package/docs/v7/features/data-driven-testing.mdx +0 -441
- package/docs/v7/features/easy-to-write.mdx +0 -280
- package/docs/v7/features/enterprise.mdx +0 -656
- package/docs/v7/features/fast.mdx +0 -406
- package/docs/v7/features/managed-sandboxes.mdx +0 -384
- package/docs/v7/features/network-monitoring.mdx +0 -568
- package/docs/v7/features/parallel-execution.mdx +0 -381
- package/docs/v7/features/powerful.mdx +0 -531
- package/docs/v7/features/sandbox-customization.mdx +0 -229
- package/docs/v7/features/stable.mdx +0 -473
- package/docs/v7/features/system-performance.mdx +0 -616
- package/docs/v7/features/test-analytics.mdx +0 -373
- package/docs/v7/features/test-cases.mdx +0 -393
- package/docs/v7/features/test-replays.mdx +0 -408
- package/docs/v7/features/test-reports.mdx +0 -308
- package/docs/v7/getting-started/debugging-tests.mdx +0 -382
- package/docs/v7/getting-started/quickstart.mdx +0 -90
- package/docs/v7/getting-started/running-tests.mdx +0 -173
- package/docs/v7/getting-started/setting-up-in-ci.mdx +0 -612
- package/docs/v7/getting-started/writing-tests.mdx +0 -534
- package/docs/v7/overview/what-is-testdriver.mdx +0 -386
- package/docs/v7/presets/chrome-extension.mdx +0 -248
- package/docs/v7/presets/chrome.mdx +0 -300
- package/docs/v7/presets/electron.mdx +0 -460
- package/docs/v7/presets/vscode.mdx +0 -417
- package/docs/v7/presets/webapp.mdx +0 -393
- /package/docs/v7/{commands → _drafts/commands}/assert.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/exec.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/focus-application.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/hover-image.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/hover-text.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/if.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/match-image.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/press-keys.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/remember.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/run.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/scroll-until-image.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/scroll-until-text.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/scroll.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/type.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/wait-for-image.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/wait-for-text.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/wait.mdx +0 -0
- /package/docs/v7/{getting-started → _drafts}/configuration.mdx +0 -0
- /package/docs/v7/{features → _drafts}/observable.mdx +0 -0
- /package/docs/v7/{platforms → _drafts/platforms}/linux.mdx +0 -0
- /package/docs/v7/{platforms → _drafts/platforms}/macos.mdx +0 -0
- /package/docs/v7/{platforms → _drafts/platforms}/windows.mdx +0 -0
- /package/docs/v7/{playwright.mdx → _drafts/playwright.mdx} +0 -0
- /package/docs/v7/{overview → _drafts}/readme.mdx +0 -0
- /package/docs/v7/{features → _drafts}/reports.mdx +0 -0
- /package/docs/v7/{api/client.mdx → client.mdx} +0 -0
- /package/docs/v7/{api/dashcam.mdx → dashcam.mdx} +0 -0
- /package/docs/v7/{api/elements.mdx → elements.mdx} +0 -0
- /package/docs/v7/{api/sandbox.mdx → sandbox.mdx} +0 -0
|
@@ -1,534 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Writing Tests"
|
|
3
|
-
description: "Learn how to write effective TestDriver tests with natural language"
|
|
4
|
-
icon: "pencil"
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
TestDriver makes writing tests intuitive by using natural language to describe interactions. This guide covers everything you need to know to write effective, maintainable tests.
|
|
8
|
-
|
|
9
|
-
## Basic Test Structure
|
|
10
|
-
|
|
11
|
-
Every TestDriver test follows this simple pattern:
|
|
12
|
-
|
|
13
|
-
```javascript
|
|
14
|
-
import { test } from 'vitest';
|
|
15
|
-
import { TestDriver } from 'testdriverai/vitest/hooks';
|
|
16
|
-
|
|
17
|
-
test('descriptive test name', async (context) => {
|
|
18
|
-
// 1. Setup: Launch and navigate
|
|
19
|
-
const testdriver = TestDriver(context, { headless: true });
|
|
20
|
-
await testdriver.provision.chrome({ url: 'https://myapp.com' });
|
|
21
|
-
|
|
22
|
-
// 2. Act: Interact with your application
|
|
23
|
-
await testdriver.find('email input').type('user@example.com');
|
|
24
|
-
await testdriver.find('submit button').click();
|
|
25
|
-
|
|
26
|
-
// 3. Assert: Verify expected state
|
|
27
|
-
await testdriver.assert('Welcome message is visible');
|
|
28
|
-
});
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
<Tip>
|
|
32
|
-
The TestDriver hook handles all setup and cleanup automatically - no need for manual browser management!
|
|
33
|
-
</Tip>
|
|
34
|
-
|
|
35
|
-
## Finding Elements
|
|
36
|
-
|
|
37
|
-
Use natural language to describe elements:
|
|
38
|
-
|
|
39
|
-
<Tabs>
|
|
40
|
-
<Tab title="Good Descriptions">
|
|
41
|
-
```javascript
|
|
42
|
-
// ✅ Specific and contextual
|
|
43
|
-
await testdriver.find('submit button in the login form');
|
|
44
|
-
await testdriver.find('email input field');
|
|
45
|
-
await testdriver.find('delete button in the top right corner');
|
|
46
|
-
await testdriver.find('first product card in the grid');
|
|
47
|
-
await testdriver.find('dropdown menu labeled "Country"');
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
These descriptions are:
|
|
51
|
-
- Specific enough to locate the element
|
|
52
|
-
- Include context (location, parent container)
|
|
53
|
-
- Use natural human language
|
|
54
|
-
</Tab>
|
|
55
|
-
|
|
56
|
-
<Tab title="Avoid Vague">
|
|
57
|
-
```javascript
|
|
58
|
-
// ❌ Too vague
|
|
59
|
-
await testdriver.find('button');
|
|
60
|
-
await testdriver.find('input');
|
|
61
|
-
await testdriver.find('link');
|
|
62
|
-
await testdriver.find('text');
|
|
63
|
-
|
|
64
|
-
// ✅ Better
|
|
65
|
-
await testdriver.find('submit button');
|
|
66
|
-
await testdriver.find('email input');
|
|
67
|
-
await testdriver.find('contact us link');
|
|
68
|
-
await testdriver.find('welcome message text');
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Add specificity to help AI locate the exact element.
|
|
72
|
-
</Tab>
|
|
73
|
-
</Tabs>
|
|
74
|
-
|
|
75
|
-
## Chaining Actions
|
|
76
|
-
|
|
77
|
-
TestDriver supports method chaining for cleaner code:
|
|
78
|
-
|
|
79
|
-
```javascript
|
|
80
|
-
// Chain find() with actions
|
|
81
|
-
await testdriver.find('Login button').click();
|
|
82
|
-
await testdriver.find('email input').type('user@example.com');
|
|
83
|
-
await testdriver.find('dropdown menu').hover();
|
|
84
|
-
await testdriver.find('menu item').doubleClick();
|
|
85
|
-
await testdriver.find('context option').rightClick();
|
|
86
|
-
|
|
87
|
-
// Or save element reference
|
|
88
|
-
const button = await testdriver.find('submit button');
|
|
89
|
-
await button.click();
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
## Common Interactions
|
|
93
|
-
|
|
94
|
-
<AccordionGroup>
|
|
95
|
-
<Accordion title="Clicking Elements">
|
|
96
|
-
```javascript
|
|
97
|
-
// Regular click
|
|
98
|
-
await testdriver.find('button').click();
|
|
99
|
-
|
|
100
|
-
// Double-click
|
|
101
|
-
await testdriver.find('file item').doubleClick();
|
|
102
|
-
|
|
103
|
-
// Right-click (context menu)
|
|
104
|
-
await testdriver.find('text area').rightClick();
|
|
105
|
-
|
|
106
|
-
// Click at specific coordinates
|
|
107
|
-
await testdriver.click(500, 300);
|
|
108
|
-
```
|
|
109
|
-
</Accordion>
|
|
110
|
-
|
|
111
|
-
<Accordion title="Typing Text">
|
|
112
|
-
```javascript
|
|
113
|
-
// Basic typing
|
|
114
|
-
await testdriver.find('search input').type('query text');
|
|
115
|
-
|
|
116
|
-
// Type sensitive data (won't be logged)
|
|
117
|
-
await testdriver.find('password input').type('secret', { secret: true });
|
|
118
|
-
|
|
119
|
-
// Type with delay between keystrokes
|
|
120
|
-
await testdriver.find('input').type('slow typing', { delay: 500 });
|
|
121
|
-
|
|
122
|
-
// Type numbers
|
|
123
|
-
await testdriver.find('age input').type(25);
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
<Warning>
|
|
127
|
-
Always use `{ secret: true }` for passwords and sensitive data to prevent logging!
|
|
128
|
-
</Warning>
|
|
129
|
-
</Accordion>
|
|
130
|
-
|
|
131
|
-
<Accordion title="Keyboard Shortcuts">
|
|
132
|
-
```javascript
|
|
133
|
-
// Single keys
|
|
134
|
-
await testdriver.pressKeys(['enter']);
|
|
135
|
-
await testdriver.pressKeys(['tab']);
|
|
136
|
-
await testdriver.pressKeys(['escape']);
|
|
137
|
-
|
|
138
|
-
// Combinations
|
|
139
|
-
await testdriver.pressKeys(['ctrl', 'c']); // Copy
|
|
140
|
-
await testdriver.pressKeys(['ctrl', 'v']); // Paste
|
|
141
|
-
await testdriver.pressKeys(['ctrl', 's']); // Save
|
|
142
|
-
|
|
143
|
-
// macOS modifiers
|
|
144
|
-
await testdriver.pressKeys(['cmd', 'c']); // macOS copy
|
|
145
|
-
await testdriver.pressKeys(['cmd', 'shift', 'p']); // Command palette
|
|
146
|
-
```
|
|
147
|
-
</Accordion>
|
|
148
|
-
|
|
149
|
-
<Accordion title="Hovering">
|
|
150
|
-
```javascript
|
|
151
|
-
// Hover over element to reveal dropdown
|
|
152
|
-
await testdriver.find('Products menu').hover();
|
|
153
|
-
await testdriver.find('Laptops submenu').click();
|
|
154
|
-
|
|
155
|
-
// Hover at coordinates
|
|
156
|
-
await testdriver.hover(400, 200);
|
|
157
|
-
```
|
|
158
|
-
</Accordion>
|
|
159
|
-
|
|
160
|
-
<Accordion title="Scrolling">
|
|
161
|
-
```javascript
|
|
162
|
-
// Scroll down
|
|
163
|
-
await testdriver.scroll('down', 500);
|
|
164
|
-
|
|
165
|
-
// Scroll up
|
|
166
|
-
await testdriver.scroll('up', 300);
|
|
167
|
-
|
|
168
|
-
// Scroll until text appears
|
|
169
|
-
await testdriver.scrollUntilText('Footer content');
|
|
170
|
-
|
|
171
|
-
// Scroll until element is visible
|
|
172
|
-
await testdriver.scroll('down', 1000);
|
|
173
|
-
await testdriver.find('load more button').click();
|
|
174
|
-
```
|
|
175
|
-
</Accordion>
|
|
176
|
-
</AccordionGroup>
|
|
177
|
-
|
|
178
|
-
## Making Assertions
|
|
179
|
-
|
|
180
|
-
Use AI-powered assertions to verify application state:
|
|
181
|
-
|
|
182
|
-
```javascript
|
|
183
|
-
// Verify visibility
|
|
184
|
-
await testdriver.assert('login page is displayed');
|
|
185
|
-
await testdriver.assert('submit button is visible');
|
|
186
|
-
await testdriver.assert('loading spinner is not visible');
|
|
187
|
-
|
|
188
|
-
// Verify content
|
|
189
|
-
await testdriver.assert('page title is "Welcome"');
|
|
190
|
-
await testdriver.assert('success message says "Account created"');
|
|
191
|
-
await testdriver.assert('error message contains "Invalid email"');
|
|
192
|
-
|
|
193
|
-
// Verify state
|
|
194
|
-
await testdriver.assert('checkbox is checked');
|
|
195
|
-
await testdriver.assert('dropdown shows "United States"');
|
|
196
|
-
await testdriver.assert('button is disabled');
|
|
197
|
-
|
|
198
|
-
// Verify visual appearance
|
|
199
|
-
await testdriver.assert('submit button is blue');
|
|
200
|
-
await testdriver.assert('form has red border');
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
<Tip>
|
|
204
|
-
Assertions automatically wait for the condition to be true, making tests more stable.
|
|
205
|
-
</Tip>
|
|
206
|
-
|
|
207
|
-
## Working with Multiple Elements
|
|
208
|
-
|
|
209
|
-
Find and interact with multiple elements:
|
|
210
|
-
|
|
211
|
-
```javascript
|
|
212
|
-
// Find all matching elements
|
|
213
|
-
const products = await testdriver.findAll('product card');
|
|
214
|
-
console.log(`Found ${products.length} products`);
|
|
215
|
-
|
|
216
|
-
// Interact with each
|
|
217
|
-
for (const product of products) {
|
|
218
|
-
const title = await product.find('title text');
|
|
219
|
-
console.log('Product:', title.text);
|
|
220
|
-
|
|
221
|
-
await product.find('add to cart button').click();
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Or find specific element
|
|
225
|
-
const firstProduct = products[0];
|
|
226
|
-
await firstProduct.click();
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
## Handling Forms
|
|
230
|
-
|
|
231
|
-
Complete form example:
|
|
232
|
-
|
|
233
|
-
```javascript
|
|
234
|
-
test('fill out contact form', async (context) => {
|
|
235
|
-
const { testdriver } = await chrome(context, {
|
|
236
|
-
url: 'https://example.com/contact'
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
// Fill text inputs
|
|
240
|
-
await testdriver.find('name input').type('John Doe');
|
|
241
|
-
await testdriver.find('email input').type('john@example.com');
|
|
242
|
-
await testdriver.find('phone input').type('555-1234');
|
|
243
|
-
|
|
244
|
-
// Select from dropdown
|
|
245
|
-
await testdriver.find('country dropdown').click();
|
|
246
|
-
await testdriver.find('United States option').click();
|
|
247
|
-
|
|
248
|
-
// Check checkbox
|
|
249
|
-
await testdriver.find('newsletter checkbox').click();
|
|
250
|
-
|
|
251
|
-
// Select radio button
|
|
252
|
-
await testdriver.find('urgent priority radio button').click();
|
|
253
|
-
|
|
254
|
-
// Fill textarea
|
|
255
|
-
await testdriver.find('message textarea').type('This is my message.');
|
|
256
|
-
|
|
257
|
-
// Submit
|
|
258
|
-
await testdriver.find('send message button').click();
|
|
259
|
-
|
|
260
|
-
// Verify success
|
|
261
|
-
await testdriver.assert('thank you message is displayed');
|
|
262
|
-
});
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
## Navigation Patterns
|
|
266
|
-
|
|
267
|
-
<Tabs>
|
|
268
|
-
<Tab title="Multi-Page Flow">
|
|
269
|
-
```javascript
|
|
270
|
-
test('checkout flow', async (context) => {
|
|
271
|
-
const { testdriver } = await chrome(context, {
|
|
272
|
-
url: 'https://shop.example.com'
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
// Page 1: Browse products
|
|
276
|
-
await testdriver.find('first product').click();
|
|
277
|
-
await testdriver.find('add to cart button').click();
|
|
278
|
-
|
|
279
|
-
// Page 2: Cart
|
|
280
|
-
await testdriver.find('cart icon').click();
|
|
281
|
-
await testdriver.find('checkout button').click();
|
|
282
|
-
|
|
283
|
-
// Page 3: Shipping info
|
|
284
|
-
await testdriver.find('address input').type('123 Main St');
|
|
285
|
-
await testdriver.find('continue button').click();
|
|
286
|
-
|
|
287
|
-
// Page 4: Payment
|
|
288
|
-
await testdriver.find('card number').type('4242424242424242');
|
|
289
|
-
await testdriver.find('place order').click();
|
|
290
|
-
|
|
291
|
-
// Page 5: Confirmation
|
|
292
|
-
await testdriver.assert('order confirmation is shown');
|
|
293
|
-
});
|
|
294
|
-
```
|
|
295
|
-
</Tab>
|
|
296
|
-
|
|
297
|
-
<Tab title="Back Navigation">
|
|
298
|
-
```javascript
|
|
299
|
-
// Navigate forward
|
|
300
|
-
await testdriver.find('next page link').click();
|
|
301
|
-
await testdriver.assert('page 2 is displayed');
|
|
302
|
-
|
|
303
|
-
// Go back
|
|
304
|
-
await testdriver.pressKeys(['alt', 'left']); // Browser back
|
|
305
|
-
await testdriver.assert('page 1 is displayed');
|
|
306
|
-
```
|
|
307
|
-
</Tab>
|
|
308
|
-
|
|
309
|
-
<Tab title="Opening Links in New Tab">
|
|
310
|
-
```javascript
|
|
311
|
-
// Open link in new tab (cmd+click / ctrl+click)
|
|
312
|
-
const link = await testdriver.find('external link');
|
|
313
|
-
await testdriver.pressKeys(['cmd']); // Hold cmd
|
|
314
|
-
await link.click();
|
|
315
|
-
// New tab opens
|
|
316
|
-
|
|
317
|
-
// Switch between windows
|
|
318
|
-
await testdriver.focusWindow(1); // Switch to second window
|
|
319
|
-
```
|
|
320
|
-
</Tab>
|
|
321
|
-
</Tabs>
|
|
322
|
-
|
|
323
|
-
## Best Practices
|
|
324
|
-
|
|
325
|
-
<CardGroup cols={2}>
|
|
326
|
-
<Card title="Write Descriptive Selectors" icon="text">
|
|
327
|
-
```javascript
|
|
328
|
-
// ✅ Good
|
|
329
|
-
await testdriver.find('blue submit button in the bottom right');
|
|
330
|
-
|
|
331
|
-
// ❌ Too vague
|
|
332
|
-
await testdriver.find('button');
|
|
333
|
-
```
|
|
334
|
-
</Card>
|
|
335
|
-
|
|
336
|
-
<Card title="Use secret: true for Passwords" icon="lock">
|
|
337
|
-
```javascript
|
|
338
|
-
// ✅ Secure
|
|
339
|
-
await testdriver.type('password', { secret: true });
|
|
340
|
-
|
|
341
|
-
// ❌ Logged in dashcam
|
|
342
|
-
await testdriver.type('password');
|
|
343
|
-
```
|
|
344
|
-
</Card>
|
|
345
|
-
|
|
346
|
-
<Card title="Test User Flows, Not Implementation" icon="route">
|
|
347
|
-
```javascript
|
|
348
|
-
// ✅ User-focused
|
|
349
|
-
test('user can purchase item', async (context) => {
|
|
350
|
-
// Test the complete flow
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
// ❌ Implementation-focused
|
|
354
|
-
test('click button #12345', async (context) => {
|
|
355
|
-
// Too specific to implementation
|
|
356
|
-
});
|
|
357
|
-
```
|
|
358
|
-
</Card>
|
|
359
|
-
|
|
360
|
-
<Card title="Use Meaningful Test Names" icon="tag">
|
|
361
|
-
```javascript
|
|
362
|
-
// ✅ Clear intent
|
|
363
|
-
test('user can reset password via email');
|
|
364
|
-
|
|
365
|
-
// ❌ Vague
|
|
366
|
-
test('test login');
|
|
367
|
-
```
|
|
368
|
-
</Card>
|
|
369
|
-
</CardGroup>
|
|
370
|
-
|
|
371
|
-
## Advanced Patterns
|
|
372
|
-
|
|
373
|
-
<AccordionGroup>
|
|
374
|
-
<Accordion title="Conditional Logic">
|
|
375
|
-
```javascript
|
|
376
|
-
// Check if element exists
|
|
377
|
-
try {
|
|
378
|
-
await testdriver.find('cookie banner', { timeout: 5000 });
|
|
379
|
-
// Banner found, dismiss it
|
|
380
|
-
await testdriver.find('accept cookies button').click();
|
|
381
|
-
} catch (error) {
|
|
382
|
-
// Banner not found, continue
|
|
383
|
-
console.log('No cookie banner');
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// Conditional actions
|
|
387
|
-
const loginButton = await testdriver.find('login button');
|
|
388
|
-
if (loginButton) {
|
|
389
|
-
await loginButton.click();
|
|
390
|
-
}
|
|
391
|
-
```
|
|
392
|
-
</Accordion>
|
|
393
|
-
|
|
394
|
-
<Accordion title="Data-Driven Tests">
|
|
395
|
-
```javascript
|
|
396
|
-
const testCases = [
|
|
397
|
-
{ email: 'valid@example.com', password: 'pass123', shouldPass: true },
|
|
398
|
-
{ email: 'invalid', password: 'pass123', shouldPass: false },
|
|
399
|
-
{ email: 'user@example.com', password: 'wrong', shouldPass: false },
|
|
400
|
-
];
|
|
401
|
-
|
|
402
|
-
testCases.forEach(({ email, password, shouldPass }) => {
|
|
403
|
-
test(`login with ${email}`, async (context) => {
|
|
404
|
-
const { testdriver } = await chrome(context, { url });
|
|
405
|
-
|
|
406
|
-
await testdriver.find('email').type(email);
|
|
407
|
-
await testdriver.find('password').type(password, { secret: true });
|
|
408
|
-
await testdriver.find('submit').click();
|
|
409
|
-
|
|
410
|
-
if (shouldPass) {
|
|
411
|
-
await testdriver.assert('dashboard is visible');
|
|
412
|
-
} else {
|
|
413
|
-
await testdriver.assert('error message is shown');
|
|
414
|
-
}
|
|
415
|
-
});
|
|
416
|
-
});
|
|
417
|
-
```
|
|
418
|
-
</Accordion>
|
|
419
|
-
|
|
420
|
-
<Accordion title="Reusable Helpers">
|
|
421
|
-
```javascript
|
|
422
|
-
// helpers.js
|
|
423
|
-
export async function login(testdriver, email, password) {
|
|
424
|
-
await testdriver.find('email input').type(email);
|
|
425
|
-
await testdriver.find('password input').type(password, { secret: true });
|
|
426
|
-
await testdriver.find('login button').click();
|
|
427
|
-
await testdriver.assert('dashboard is visible');
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
// test.test.js
|
|
431
|
-
import { login } from './helpers';
|
|
432
|
-
|
|
433
|
-
test('user can view profile', async (context) => {
|
|
434
|
-
const { testdriver } = await chrome(context, { url });
|
|
435
|
-
|
|
436
|
-
await login(testdriver, 'user@example.com', 'password');
|
|
437
|
-
|
|
438
|
-
await testdriver.find('profile link').click();
|
|
439
|
-
await testdriver.assert('profile page is displayed');
|
|
440
|
-
});
|
|
441
|
-
```
|
|
442
|
-
</Accordion>
|
|
443
|
-
</AccordionGroup>
|
|
444
|
-
|
|
445
|
-
## Common Patterns
|
|
446
|
-
|
|
447
|
-
<Tabs>
|
|
448
|
-
<Tab title="Login Flow">
|
|
449
|
-
```javascript
|
|
450
|
-
test('user login', async (context) => {
|
|
451
|
-
const { testdriver } = await chrome(context, {
|
|
452
|
-
url: 'https://myapp.com/login'
|
|
453
|
-
});
|
|
454
|
-
|
|
455
|
-
await testdriver.find('email input').type('user@example.com');
|
|
456
|
-
await testdriver.find('password input').type('secret', { secret: true });
|
|
457
|
-
await testdriver.find('Login button').click();
|
|
458
|
-
|
|
459
|
-
await testdriver.assert('Dashboard is visible');
|
|
460
|
-
await testdriver.assert('Welcome message shows user name');
|
|
461
|
-
});
|
|
462
|
-
```
|
|
463
|
-
</Tab>
|
|
464
|
-
|
|
465
|
-
<Tab title="Search">
|
|
466
|
-
```javascript
|
|
467
|
-
test('search functionality', async (context) => {
|
|
468
|
-
const { testdriver } = await chrome(context, { url });
|
|
469
|
-
|
|
470
|
-
await testdriver.find('search input').type('laptop');
|
|
471
|
-
await testdriver.pressKeys(['enter']);
|
|
472
|
-
|
|
473
|
-
await testdriver.assert('search results are displayed');
|
|
474
|
-
await testdriver.assert('results contain "laptop"');
|
|
475
|
-
|
|
476
|
-
const results = await testdriver.findAll('result item');
|
|
477
|
-
console.log(`Found ${results.length} results`);
|
|
478
|
-
});
|
|
479
|
-
```
|
|
480
|
-
</Tab>
|
|
481
|
-
|
|
482
|
-
<Tab title="Shopping Cart">
|
|
483
|
-
```javascript
|
|
484
|
-
test('add to cart', async (context) => {
|
|
485
|
-
const { testdriver } = await chrome(context, { url });
|
|
486
|
-
|
|
487
|
-
await testdriver.find('first product').click();
|
|
488
|
-
await testdriver.find('add to cart button').click();
|
|
489
|
-
|
|
490
|
-
await testdriver.assert('cart badge shows 1');
|
|
491
|
-
|
|
492
|
-
await testdriver.find('cart icon').click();
|
|
493
|
-
await testdriver.assert('product is in cart');
|
|
494
|
-
await testdriver.assert('subtotal is correct');
|
|
495
|
-
});
|
|
496
|
-
```
|
|
497
|
-
</Tab>
|
|
498
|
-
</Tabs>
|
|
499
|
-
|
|
500
|
-
## Next Steps
|
|
501
|
-
|
|
502
|
-
<CardGroup cols={2}>
|
|
503
|
-
<Card
|
|
504
|
-
title="Generate Tests with AI"
|
|
505
|
-
icon="wand-magic-sparkles"
|
|
506
|
-
href="/v7/getting-started/generating-tests"
|
|
507
|
-
>
|
|
508
|
-
Use Claude to write tests automatically
|
|
509
|
-
</Card>
|
|
510
|
-
|
|
511
|
-
<Card
|
|
512
|
-
title="Running & Debugging"
|
|
513
|
-
icon="bug"
|
|
514
|
-
href="/v7/getting-started/running-and-debugging"
|
|
515
|
-
>
|
|
516
|
-
Run tests and debug failures
|
|
517
|
-
</Card>
|
|
518
|
-
|
|
519
|
-
<Card
|
|
520
|
-
title="API Reference"
|
|
521
|
-
icon="book"
|
|
522
|
-
href="/v7/api/client"
|
|
523
|
-
>
|
|
524
|
-
Complete API documentation
|
|
525
|
-
</Card>
|
|
526
|
-
|
|
527
|
-
<Card
|
|
528
|
-
title="Examples"
|
|
529
|
-
icon="code"
|
|
530
|
-
href="/v7/presets/chrome"
|
|
531
|
-
>
|
|
532
|
-
View more examples
|
|
533
|
-
</Card>
|
|
534
|
-
</CardGroup>
|