@testdriverai/agent 7.9.32-test → 7.9.34-canary

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.
Files changed (77) hide show
  1. package/ai/skills/testdriver:ai/SKILL.md +204 -0
  2. package/ai/skills/testdriver:assert/SKILL.md +315 -0
  3. package/ai/skills/testdriver:aws-setup/SKILL.md +448 -0
  4. package/ai/skills/testdriver:cache/SKILL.md +221 -0
  5. package/ai/skills/testdriver:caching/SKILL.md +124 -0
  6. package/ai/skills/testdriver:captcha/SKILL.md +158 -0
  7. package/ai/skills/testdriver:ci-cd/SKILL.md +602 -0
  8. package/ai/skills/testdriver:click/SKILL.md +286 -0
  9. package/ai/skills/testdriver:client/SKILL.md +477 -0
  10. package/ai/skills/testdriver:customizing-devices/SKILL.md +319 -0
  11. package/ai/skills/testdriver:dashcam/SKILL.md +451 -0
  12. package/ai/skills/testdriver:debugging-with-screenshots/SKILL.md +415 -0
  13. package/ai/skills/testdriver:device-config/SKILL.md +317 -0
  14. package/ai/skills/testdriver:double-click/SKILL.md +102 -0
  15. package/ai/skills/testdriver:elements/SKILL.md +605 -0
  16. package/ai/skills/testdriver:enterprise/SKILL.md +7 -0
  17. package/ai/skills/testdriver:errors/SKILL.md +246 -0
  18. package/ai/skills/testdriver:events/SKILL.md +356 -0
  19. package/ai/skills/testdriver:exec/SKILL.md +317 -0
  20. package/ai/skills/testdriver:find/SKILL.md +860 -0
  21. package/ai/skills/testdriver:focus-application/SKILL.md +293 -0
  22. package/ai/skills/testdriver:generating-tests/SKILL.md +36 -0
  23. package/ai/skills/testdriver:hosted/SKILL.md +156 -0
  24. package/ai/skills/testdriver:hover/SKILL.md +278 -0
  25. package/ai/skills/testdriver:locating-elements/SKILL.md +71 -0
  26. package/ai/skills/testdriver:making-assertions/SKILL.md +32 -0
  27. package/ai/skills/testdriver:mcp/SKILL.md +7 -0
  28. package/ai/skills/testdriver:mouse-down/SKILL.md +161 -0
  29. package/ai/skills/testdriver:mouse-up/SKILL.md +164 -0
  30. package/ai/skills/testdriver:parse/SKILL.md +236 -0
  31. package/ai/skills/testdriver:performing-actions/SKILL.md +53 -0
  32. package/ai/skills/testdriver:press-keys/SKILL.md +348 -0
  33. package/ai/skills/testdriver:provision/SKILL.md +331 -0
  34. package/ai/skills/testdriver:quickstart/SKILL.md +172 -0
  35. package/ai/skills/testdriver:redraw/SKILL.md +214 -0
  36. package/ai/skills/testdriver:reusable-code/SKILL.md +249 -0
  37. package/ai/skills/testdriver:right-click/SKILL.md +123 -0
  38. package/ai/skills/testdriver:running-tests/SKILL.md +185 -0
  39. package/ai/skills/testdriver:screenshot/SKILL.md +248 -0
  40. package/ai/skills/testdriver:screenshots/SKILL.md +184 -0
  41. package/ai/skills/testdriver:scroll/SKILL.md +205 -0
  42. package/ai/skills/testdriver:secrets/SKILL.md +115 -0
  43. package/ai/skills/testdriver:self-hosted/SKILL.md +147 -0
  44. package/ai/skills/testdriver:test-results-json/SKILL.md +257 -0
  45. package/ai/skills/testdriver:testdriver/SKILL.md +624 -0
  46. package/ai/skills/testdriver:type/SKILL.md +357 -0
  47. package/ai/skills/testdriver:variables/SKILL.md +111 -0
  48. package/ai/skills/testdriver:wait/SKILL.md +50 -0
  49. package/ai/skills/testdriver:waiting-for-elements/SKILL.md +90 -0
  50. package/ai/skills/testdriver:what-is-testdriver/SKILL.md +54 -0
  51. package/docs/_data/examples-manifest.json +42 -42
  52. package/docs/v7/debugging-with-screenshots.mdx +14 -0
  53. package/docs/v7/examples/ai.mdx +1 -1
  54. package/docs/v7/examples/assert.mdx +1 -1
  55. package/docs/v7/examples/chrome-extension.mdx +2 -2
  56. package/docs/v7/examples/element-not-found.mdx +1 -1
  57. package/docs/v7/examples/exec-output.mdx +1 -1
  58. package/docs/v7/examples/exec-pwsh.mdx +1 -1
  59. package/docs/v7/examples/findall-coffee-icons.mdx +1 -1
  60. package/docs/v7/examples/focus-window.mdx +1 -1
  61. package/docs/v7/examples/hover-image.mdx +1 -1
  62. package/docs/v7/examples/hover-text-with-description.mdx +1 -1
  63. package/docs/v7/examples/hover-text.mdx +1 -1
  64. package/docs/v7/examples/installer.mdx +1 -1
  65. package/docs/v7/examples/launch-vscode-linux.mdx +1 -1
  66. package/docs/v7/examples/parse.mdx +1 -1
  67. package/docs/v7/examples/press-keys.mdx +1 -1
  68. package/docs/v7/examples/prompt.mdx +1 -1
  69. package/docs/v7/examples/scroll-keyboard.mdx +1 -1
  70. package/docs/v7/examples/scroll-until-image.mdx +1 -1
  71. package/docs/v7/examples/scroll.mdx +1 -1
  72. package/docs/v7/examples/type.mdx +1 -1
  73. package/docs/v7/examples/windows-installer.mdx +1 -1
  74. package/docs/v7/find.mdx +33 -0
  75. package/examples/chrome-extension.test.mjs +1 -1
  76. package/package.json +1 -1
  77. package/setup/aws/spawn-runner.sh +24 -3
@@ -0,0 +1,236 @@
1
+ ---
2
+ name: testdriver:parse
3
+ description: Detect all UI elements on screen using OmniParser
4
+ ---
5
+ <!-- Generated from parse.mdx. DO NOT EDIT. -->
6
+
7
+ ## Overview
8
+
9
+ Parse the current screen using OmniParser v2 to detect all visible UI elements. Returns structured data including element types, text content, interactivity levels, and bounding box coordinates.
10
+
11
+ This method analyzes the entire screen and returns every detected element. It's useful for:
12
+ - Understanding the full UI layout of a screen
13
+ - Finding all clickable or interactive elements
14
+ - Building custom element-based logic
15
+ - Debugging what elements TestDriver can detect
16
+ - Accessibility auditing
17
+
18
+ <Note>
19
+ **Availability**: `parse()` requires an enterprise or self-hosted plan. It uses OmniParser v2 server-side for element detection.
20
+ </Note>
21
+
22
+ ## Syntax
23
+
24
+ ```javascript
25
+ const result = await testdriver.parse()
26
+ ```
27
+
28
+ ## Parameters
29
+
30
+ None.
31
+
32
+ ## Returns
33
+
34
+ `Promise<ParseResult>` - Object containing detected UI elements
35
+
36
+ ### ParseResult
37
+
38
+ | Property | Type | Description |
39
+ |----------|------|-------------|
40
+ | `elements` | `ParsedElement[]` | Array of detected UI elements |
41
+ | `annotatedImageUrl` | `string` | URL of the annotated screenshot with bounding boxes |
42
+ | `imageWidth` | `number` | Width of the analyzed screenshot |
43
+ | `imageHeight` | `number` | Height of the analyzed screenshot |
44
+
45
+ ### ParsedElement
46
+
47
+ | Property | Type | Description |
48
+ |----------|------|-------------|
49
+ | `index` | `number` | Element index |
50
+ | `type` | `string` | Element type (e.g. `"text"`, `"icon"`, `"button"`) |
51
+ | `content` | `string` | Text content or description of the element |
52
+ | `interactivity` | `string` | Interactivity level (e.g. `"clickable"`, `"non-interactive"`) |
53
+ | `bbox` | `object` | Bounding box in pixel coordinates `{x0, y0, x1, y1}` |
54
+ | `boundingBox` | `object` | Bounding box as `{left, top, width, height}` |
55
+
56
+ ## Examples
57
+
58
+ ### Get All Elements on Screen
59
+
60
+ ```javascript
61
+ const result = await testdriver.parse();
62
+ console.log(`Found ${result.elements.length} elements`);
63
+
64
+ result.elements.forEach((el, i) => {
65
+ console.log(`${i + 1}. [${el.type}] "${el.content}" (${el.interactivity})`);
66
+ });
67
+ ```
68
+
69
+ ### Find Clickable Elements
70
+
71
+ ```javascript
72
+ const result = await testdriver.parse();
73
+
74
+ const clickable = result.elements.filter(e => e.interactivity === 'clickable');
75
+ console.log(`Found ${clickable.length} clickable elements`);
76
+
77
+ clickable.forEach(el => {
78
+ console.log(`- "${el.content}" at (${el.bbox.x0}, ${el.bbox.y0})`);
79
+ });
80
+ ```
81
+
82
+ ### Find and Click an Element by Content
83
+
84
+ ```javascript
85
+ const result = await testdriver.parse();
86
+
87
+ // Find a "Submit" button
88
+ const submitBtn = result.elements.find(e =>
89
+ e.content.toLowerCase().includes('submit') && e.interactivity === 'clickable'
90
+ );
91
+
92
+ if (submitBtn) {
93
+ // Calculate center of the bounding box
94
+ const x = Math.round((submitBtn.bbox.x0 + submitBtn.bbox.x1) / 2);
95
+ const y = Math.round((submitBtn.bbox.y0 + submitBtn.bbox.y1) / 2);
96
+
97
+ await testdriver.click({ x, y });
98
+ }
99
+ ```
100
+
101
+ ### Filter by Element Type
102
+
103
+ ```javascript
104
+ const result = await testdriver.parse();
105
+
106
+ // Get all text elements
107
+ const textElements = result.elements.filter(e => e.type === 'text');
108
+ textElements.forEach(e => console.log(`Text: "${e.content}"`));
109
+
110
+ // Get all icons
111
+ const icons = result.elements.filter(e => e.type === 'icon');
112
+ console.log(`Found ${icons.length} icons`);
113
+
114
+ // Get all buttons
115
+ const buttons = result.elements.filter(e => e.type === 'button');
116
+ console.log(`Found ${buttons.length} buttons`);
117
+ ```
118
+
119
+ ### Build Custom Assertions
120
+
121
+ ```javascript
122
+ import { describe, expect, it } from "vitest";
123
+ import { TestDriver } from "testdriverai/vitest/hooks";
124
+
125
+ describe("Login Page", () => {
126
+ it("should have expected form elements", async (context) => {
127
+ const testdriver = TestDriver(context);
128
+
129
+ await testdriver.provision.chrome({
130
+ url: 'https://myapp.com/login',
131
+ });
132
+
133
+ const result = await testdriver.parse();
134
+
135
+ // Assert expected elements exist
136
+ const textContent = result.elements.map(e => e.content.toLowerCase());
137
+ expect(textContent).toContain('email');
138
+ expect(textContent).toContain('password');
139
+
140
+ // Assert there are clickable elements
141
+ const clickable = result.elements.filter(e => e.interactivity === 'clickable');
142
+ expect(clickable.length).toBeGreaterThan(0);
143
+ });
144
+ });
145
+ ```
146
+
147
+ ### Use Bounding Box Coordinates
148
+
149
+ ```javascript
150
+ const result = await testdriver.parse();
151
+
152
+ result.elements.forEach(el => {
153
+ // Pixel coordinates
154
+ console.log(`Element "${el.content}":`);
155
+ console.log(` bbox: (${el.bbox.x0}, ${el.bbox.y0}) to (${el.bbox.x1}, ${el.bbox.y1})`);
156
+ console.log(` size: ${el.boundingBox.width}x${el.boundingBox.height}`);
157
+ console.log(` position: left=${el.boundingBox.left}, top=${el.boundingBox.top}`);
158
+ });
159
+ ```
160
+
161
+ ### View Annotated Screenshot
162
+
163
+ ```javascript
164
+ const result = await testdriver.parse();
165
+
166
+ // The annotated image shows all detected elements with bounding boxes
167
+ console.log('Annotated screenshot:', result.annotatedImageUrl);
168
+ console.log(`Image dimensions: ${result.imageWidth}x${result.imageHeight}`);
169
+ ```
170
+
171
+ ## How It Works
172
+
173
+ 1. TestDriver captures a screenshot of the current screen
174
+ 2. The image is sent to the TestDriver API
175
+ 3. OmniParser v2 analyzes the image to detect all UI elements
176
+ 4. Each element is classified by type (text, icon, button, etc.) and interactivity
177
+ 5. Bounding box coordinates are returned in pixel coordinates matching the screen resolution
178
+
179
+ <Note>
180
+ OmniParser detects elements visually — it works with any UI framework, native apps, and even non-standard interfaces. It does not rely on DOM or accessibility trees.
181
+ </Note>
182
+
183
+ ## Best Practices
184
+
185
+ <AccordionGroup>
186
+ <Accordion title="Use find() for targeting specific elements">
187
+ For locating and interacting with a specific element, prefer `find()` which uses AI vision. Use `parse()` when you need a complete inventory of all elements on screen.
188
+
189
+ ```javascript
190
+ // Prefer this for clicking a specific element
191
+ await testdriver.find("Submit button").click();
192
+
193
+ // Use parse() for full UI analysis
194
+ const result = await testdriver.parse();
195
+ const allButtons = result.elements.filter(e => e.type === 'button');
196
+ ```
197
+ </Accordion>
198
+
199
+ <Accordion title="Filter by interactivity">
200
+ Use the `interactivity` field to distinguish between clickable and non-interactive elements.
201
+
202
+ ```javascript
203
+ const result = await testdriver.parse();
204
+ const interactive = result.elements.filter(e => e.interactivity === 'clickable');
205
+ const static_ = result.elements.filter(e => e.interactivity === 'non-interactive');
206
+ ```
207
+ </Accordion>
208
+
209
+ <Accordion title="Wait for content to load">
210
+ If elements aren't being detected, the page may not be fully loaded. Add a wait first.
211
+
212
+ ```javascript
213
+ // Wait for page to stabilize
214
+ await testdriver.wait(2000);
215
+
216
+ // Then parse
217
+ const result = await testdriver.parse();
218
+ ```
219
+ </Accordion>
220
+
221
+ <Accordion title="Use the annotated image for debugging">
222
+ The `annotatedImageUrl` provides a visual overlay showing all detected elements with their bounding boxes — great for debugging.
223
+
224
+ ```javascript
225
+ const result = await testdriver.parse();
226
+ console.log('View annotated screenshot:', result.annotatedImageUrl);
227
+ ```
228
+ </Accordion>
229
+ </AccordionGroup>
230
+
231
+ ## Related
232
+
233
+ - [find()](/v7/find) - AI-powered element location
234
+ - [assert()](/v7/assert) - Make AI-powered assertions about screen state
235
+ - [screenshot()](/v7/screenshot) - Capture screenshots
236
+ - [Elements Reference](/v7/elements) - Complete Element API
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: testdriver:performing-actions
3
+ description: Click, type, hover, scroll and more with TestDriver
4
+ ---
5
+ <!-- Generated from performing-actions.mdx. DO NOT EDIT. -->
6
+
7
+ ## Performing Actions
8
+
9
+ TestDriver provides a variety of actions you can perform, like [clicking](/v7/click), [typing](/v7/type), [hovering](/v7/hover), and [scrolling](/v7/scroll). For a full list, see the [API Reference](/v7/click).
10
+
11
+ ```javascript
12
+ // Clicking
13
+ await testdriver.find('submit button').click();
14
+ await testdriver.find('file item').doubleClick();
15
+ await testdriver.find('text area').rightClick();
16
+
17
+ // Typing
18
+ await testdriver.find('email input').type('user@example.com');
19
+ await testdriver.find('password input').type('secret', { secret: true });
20
+
21
+ // Keyboard shortcuts
22
+ await testdriver.pressKeys(['enter']);
23
+ await testdriver.pressKeys(['ctrl', 'c']);
24
+
25
+ // Hovering
26
+ await testdriver.find('dropdown menu').hover();
27
+
28
+ // Scrolling
29
+ await testdriver.scroll('down', 500);
30
+
31
+ // Waiting
32
+ await testdriver.wait(2000); // Wait 2 seconds for animation/state change
33
+
34
+ // Extracting information from screen
35
+ const price = await testdriver.extract('the total price');
36
+ const orderNumber = await testdriver.extract('the order confirmation number');
37
+ ```
38
+
39
+ ## Chaining Actions
40
+
41
+ TestDriver supports method chaining for cleaner code:
42
+
43
+ ```javascript
44
+ // Chain find() with actions
45
+ const button = await testdriver.find('submit button').click();
46
+ ```
47
+
48
+ Or save element reference for later use:
49
+
50
+ ```javascript
51
+ const button = await testdriver.find('submit button');
52
+ await button.click();
53
+ ```
@@ -0,0 +1,348 @@
1
+ ---
2
+ name: testdriver:press-keys
3
+ description: Press keyboard keys and shortcuts
4
+ ---
5
+ <!-- Generated from press-keys.mdx. DO NOT EDIT. -->
6
+
7
+ ## Overview
8
+
9
+ Press one or more keyboard keys simultaneously, useful for keyboard shortcuts, navigation, and special keys.
10
+
11
+ ## Syntax
12
+
13
+ ```javascript
14
+ await testdriver.pressKeys(keys)
15
+ ```
16
+
17
+ ## Parameters
18
+
19
+ <ParamField path="keys" type="Array&lt;string&gt;" required>
20
+ Array of keys to press simultaneously
21
+ </ParamField>
22
+
23
+ ## Returns
24
+
25
+ `Promise<void>`
26
+
27
+ ## Common Keys
28
+
29
+ ### Special Keys
30
+ - `'enter'`, `'tab'`, `'escape'`, `'backspace'`, `'delete'`
31
+ - `'space'`, `'up'`, `'down'`, `'left'`, `'right'`
32
+ - `'home'`, `'end'`, `'pageup'`, `'pagedown'`
33
+
34
+ ### Modifier Keys
35
+ - `'ctrl'`, `'alt'`, `'shift'`
36
+ - `'command'` (macOS), `'win'` (Windows)
37
+ - `'ctrlleft'`, `'ctrlright'`, `'shiftleft'`, `'shiftright'`
38
+
39
+ ### Function Keys
40
+ - `'f1'` through `'f24'`
41
+
42
+ ## Examples
43
+
44
+ ### Navigation
45
+
46
+ ```javascript
47
+ // Tab to next field
48
+ await testdriver.pressKeys(['tab']);
49
+
50
+ // Shift+Tab to previous field
51
+ await testdriver.pressKeys(['shift', 'tab']);
52
+
53
+ // Arrow keys
54
+ await testdriver.pressKeys(['down']);
55
+ await testdriver.pressKeys(['up']);
56
+ await testdriver.pressKeys(['left']);
57
+ await testdriver.pressKeys(['right']);
58
+
59
+ // Home/End
60
+ await testdriver.pressKeys(['home']); // Start of line
61
+ await testdriver.pressKeys(['end']); // End of line
62
+
63
+ // Page navigation
64
+ await testdriver.pressKeys(['pagedown']);
65
+ await testdriver.pressKeys(['pageup']);
66
+ ```
67
+
68
+ ### Keyboard Shortcuts
69
+
70
+ ```javascript
71
+ // Copy (Ctrl+C / Cmd+C)
72
+ await testdriver.pressKeys(['ctrl', 'c']);
73
+
74
+ // Paste (Ctrl+V / Cmd+V)
75
+ await testdriver.pressKeys(['ctrl', 'v']);
76
+
77
+ // Save (Ctrl+S)
78
+ await testdriver.pressKeys(['ctrl', 's']);
79
+
80
+ // Select All (Ctrl+A)
81
+ await testdriver.pressKeys(['ctrl', 'a']);
82
+
83
+ // Undo (Ctrl+Z)
84
+ await testdriver.pressKeys(['ctrl', 'z']);
85
+
86
+ // Redo (Ctrl+Y)
87
+ await testdriver.pressKeys(['ctrl', 'y']);
88
+
89
+ // Find (Ctrl+F)
90
+ await testdriver.pressKeys(['ctrl', 'f']);
91
+
92
+ // New tab (Ctrl+T)
93
+ await testdriver.pressKeys(['ctrl', 't']);
94
+
95
+ // Close tab (Ctrl+W)
96
+ await testdriver.pressKeys(['ctrl', 'w']);
97
+
98
+ // Refresh (F5 or Ctrl+R)
99
+ await testdriver.pressKeys(['f5']);
100
+ await testdriver.pressKeys(['ctrl', 'r']);
101
+ ```
102
+
103
+ ### System Shortcuts
104
+
105
+ ```javascript
106
+ // Alt+Tab (Windows - switch apps)
107
+ await testdriver.pressKeys(['alt', 'tab']);
108
+
109
+ // Alt+F4 (Windows - close window)
110
+ await testdriver.pressKeys(['alt', 'f4']);
111
+
112
+ // Win+D (Windows - show desktop)
113
+ await testdriver.pressKeys(['winleft', 'd']);
114
+
115
+ // Win+L (Windows - lock screen)
116
+ await testdriver.pressKeys(['winleft', 'l']);
117
+
118
+ // Cmd+Tab (macOS - switch apps)
119
+ await testdriver.pressKeys(['command', 'tab']);
120
+
121
+ // Cmd+Q (macOS - quit app)
122
+ await testdriver.pressKeys(['command', 'q']);
123
+ ```
124
+
125
+ ### Form Submission
126
+
127
+ ```javascript
128
+ // Submit form
129
+ await testdriver.pressKeys(['enter']);
130
+
131
+ // Cancel/Close
132
+ await testdriver.pressKeys(['escape']);
133
+
134
+ // Check checkbox
135
+ await testdriver.pressKeys(['space']);
136
+ ```
137
+
138
+ ### Text Editing
139
+
140
+ ```javascript
141
+ // Delete selected text
142
+ await testdriver.pressKeys(['delete']);
143
+
144
+ // Backspace
145
+ await testdriver.pressKeys(['backspace']);
146
+
147
+ // Select all and delete
148
+ await testdriver.pressKeys(['ctrl', 'a']);
149
+ await testdriver.pressKeys(['delete']);
150
+
151
+ // Cut text
152
+ await testdriver.pressKeys(['ctrl', 'x']);
153
+ ```
154
+
155
+ ## Best Practices
156
+
157
+ <Check>
158
+ **Wait after shortcuts**
159
+
160
+ Some keyboard shortcuts trigger animations or navigation:
161
+
162
+ ```javascript
163
+ await testdriver.pressKeys(['ctrl', 't']); // New tab
164
+ await new Promise(r => setTimeout(r, 500)); // Wait for tab
165
+ await testdriver.pressKeys(['ctrl', 'l']); // Focus URL bar
166
+ ```
167
+ </Check>
168
+
169
+ <Check>
170
+ **Use Tab for form navigation**
171
+
172
+ Tab is more reliable than clicking multiple fields:
173
+
174
+ ```javascript
175
+ const firstField = await testdriver.find('email input');
176
+ await firstField.click();
177
+ await testdriver.type('user@example.com');
178
+
179
+ await testdriver.pressKeys(['tab']);
180
+ await testdriver.type('password123');
181
+
182
+ await testdriver.pressKeys(['tab']);
183
+ await testdriver.pressKeys(['enter']); // Submit
184
+ ```
185
+ </Check>
186
+
187
+ <Warning>
188
+ **Platform-specific keys**
189
+
190
+ Use the appropriate modifier key for the platform:
191
+ - Windows/Linux: `'ctrl'`
192
+ - macOS: `'command'`
193
+
194
+ ```javascript
195
+ // For cross-platform, you might need to detect OS
196
+ const modKey = process.platform === 'darwin' ? 'command' : 'ctrl';
197
+ await testdriver.pressKeys([modKey, 'c']); // Copy
198
+ ```
199
+ </Warning>
200
+
201
+ ## Use Cases
202
+
203
+ <AccordionGroup>
204
+ <Accordion title="Form Navigation">
205
+ ```javascript
206
+ // Fill form using Tab
207
+ const firstField = await testdriver.find('name field');
208
+ await firstField.click();
209
+ await testdriver.type('John Doe');
210
+
211
+ await testdriver.pressKeys(['tab']);
212
+ await testdriver.type('john@example.com');
213
+
214
+ await testdriver.pressKeys(['tab']);
215
+ await testdriver.type('555-0123');
216
+
217
+ await testdriver.pressKeys(['tab']);
218
+ await testdriver.pressKeys(['enter']); // Submit
219
+ ```
220
+ </Accordion>
221
+
222
+ <Accordion title="Text Manipulation">
223
+ ```javascript
224
+ const textArea = await testdriver.find('comment textarea');
225
+ await textArea.click();
226
+
227
+ // Select all existing text
228
+ await testdriver.pressKeys(['ctrl', 'a']);
229
+
230
+ // Copy it
231
+ await testdriver.pressKeys(['ctrl', 'c']);
232
+
233
+ // Type new text
234
+ await testdriver.type('New comment');
235
+
236
+ // Undo if needed
237
+ await testdriver.pressKeys(['ctrl', 'z']);
238
+ ```
239
+ </Accordion>
240
+
241
+ <Accordion title="Browser Navigation">
242
+ ```javascript
243
+ // Open new tab
244
+ await testdriver.pressKeys(['ctrl', 't']);
245
+ await new Promise(r => setTimeout(r, 500));
246
+
247
+ // Focus address bar
248
+ await testdriver.pressKeys(['ctrl', 'l']);
249
+ await testdriver.type('https://example.com');
250
+ await testdriver.pressKeys(['enter']);
251
+
252
+ // Refresh page
253
+ await testdriver.pressKeys(['f5']);
254
+
255
+ // Close tab
256
+ await testdriver.pressKeys(['ctrl', 'w']);
257
+ ```
258
+ </Accordion>
259
+
260
+ <Accordion title="Application Shortcuts">
261
+ ```javascript
262
+ // Save document
263
+ await testdriver.pressKeys(['ctrl', 's']);
264
+
265
+ // Print
266
+ await testdriver.pressKeys(['ctrl', 'p']);
267
+
268
+ // Find in page
269
+ await testdriver.pressKeys(['ctrl', 'f']);
270
+ await testdriver.type('search term');
271
+ await testdriver.pressKeys(['escape']); // Close find
272
+ ```
273
+ </Accordion>
274
+ </AccordionGroup>
275
+
276
+ ## Complete Example
277
+
278
+ ```javascript
279
+ import { beforeAll, afterAll, describe, it } from 'vitest';
280
+ import TestDriver from 'testdriverai';
281
+
282
+ describe('Keyboard Navigation', () => {
283
+ let testdriver;
284
+
285
+ beforeAll(async () => {
286
+ client = new TestDriver(process.env.TD_API_KEY);
287
+ await testdriver.auth();
288
+ await testdriver.connect();
289
+ });
290
+
291
+ afterAll(async () => {
292
+ await testdriver.disconnect();
293
+ });
294
+
295
+ it('should navigate form with keyboard', async () => {
296
+ await testdriver.focusApplication('Google Chrome');
297
+
298
+ // Find first field
299
+ const emailField = await testdriver.find('email input');
300
+ await emailField.click();
301
+ await testdriver.type('user@example.com');
302
+
303
+ // Tab through fields
304
+ await testdriver.pressKeys(['tab']);
305
+ await testdriver.type('John');
306
+
307
+ await testdriver.pressKeys(['tab']);
308
+ await testdriver.type('Doe');
309
+
310
+ await testdriver.pressKeys(['tab']);
311
+ await testdriver.type('password123');
312
+
313
+ // Submit with Enter
314
+ await testdriver.pressKeys(['tab']);
315
+ await testdriver.pressKeys(['enter']);
316
+
317
+ await testdriver.assert('form submitted successfully');
318
+ });
319
+
320
+ it('should use keyboard shortcuts', async () => {
321
+ // Open new browser tab
322
+ await testdriver.pressKeys(['ctrl', 't']);
323
+ await new Promise(r => setTimeout(r, 500));
324
+
325
+ // Focus address bar
326
+ await testdriver.pressKeys(['ctrl', 'l']);
327
+ await testdriver.type('https://example.com');
328
+ await testdriver.pressKeys(['enter']);
329
+
330
+ await new Promise(r => setTimeout(r, 2000));
331
+
332
+ // Select all page content
333
+ await testdriver.pressKeys(['ctrl', 'a']);
334
+
335
+ // Copy
336
+ await testdriver.pressKeys(['ctrl', 'c']);
337
+
338
+ // Refresh page
339
+ await testdriver.pressKeys(['f5']);
340
+ });
341
+ });
342
+ ```
343
+
344
+ ## Related Methods
345
+
346
+ - [`type()`](/v7/type) - Type text
347
+ - [`click()`](/v7/click) - Click elements
348
+ - [`scroll()`](/v7/scroll) - Scroll pages