testdriverai 7.3.11 → 7.3.13

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 (133) hide show
  1. package/.github/skills/testdriver:ai/SKILL.md +204 -0
  2. package/.github/skills/testdriver:assert/SKILL.md +284 -0
  3. package/.github/skills/testdriver:aws-setup/SKILL.md +515 -0
  4. package/.github/skills/testdriver:caching/SKILL.md +124 -0
  5. package/.github/skills/testdriver:captcha/SKILL.md +159 -0
  6. package/.github/skills/testdriver:ci-cd/SKILL.md +602 -0
  7. package/.github/skills/testdriver:click/SKILL.md +286 -0
  8. package/.github/skills/testdriver:client/SKILL.md +339 -0
  9. package/.github/skills/testdriver:cloud/SKILL.md +119 -0
  10. package/.github/skills/testdriver:customizing-devices/SKILL.md +153 -0
  11. package/.github/skills/testdriver:dashcam/SKILL.md +418 -0
  12. package/.github/skills/testdriver:debugging-with-screenshots/SKILL.md +271 -0
  13. package/.github/skills/testdriver:device-config/SKILL.md +317 -0
  14. package/.github/skills/testdriver:double-click/SKILL.md +102 -0
  15. package/.github/skills/testdriver:elements/SKILL.md +605 -0
  16. package/.github/skills/testdriver:enterprise/SKILL.md +114 -0
  17. package/.github/skills/testdriver:examples/SKILL.md +7 -0
  18. package/.github/skills/testdriver:exec/SKILL.md +345 -0
  19. package/.github/skills/testdriver:find/SKILL.md +721 -0
  20. package/.github/skills/testdriver:focus-application/SKILL.md +293 -0
  21. package/.github/skills/testdriver:generating-tests/SKILL.md +36 -0
  22. package/.github/skills/testdriver:hover/SKILL.md +278 -0
  23. package/.github/skills/testdriver:locating-elements/SKILL.md +71 -0
  24. package/.github/skills/testdriver:making-assertions/SKILL.md +32 -0
  25. package/.github/skills/testdriver:mcp-workflow/SKILL.md +410 -0
  26. package/.github/skills/testdriver:mouse-down/SKILL.md +161 -0
  27. package/.github/skills/testdriver:mouse-up/SKILL.md +164 -0
  28. package/.github/skills/testdriver:performing-actions/SKILL.md +51 -0
  29. package/.github/skills/testdriver:press-keys/SKILL.md +348 -0
  30. package/.github/skills/testdriver:quickstart/SKILL.md +161 -0
  31. package/.github/skills/testdriver:reusable-code/SKILL.md +240 -0
  32. package/.github/skills/testdriver:right-click/SKILL.md +123 -0
  33. package/.github/skills/testdriver:running-tests/SKILL.md +181 -0
  34. package/.github/skills/testdriver:screenshot/SKILL.md +167 -0
  35. package/.github/skills/testdriver:scroll/SKILL.md +299 -0
  36. package/.github/skills/testdriver:secrets/SKILL.md +115 -0
  37. package/.github/skills/testdriver:self-hosted/SKILL.md +65 -0
  38. package/.github/skills/testdriver:test-writer/SKILL.md +451 -0
  39. package/.github/skills/testdriver:testdriver/SKILL.md +523 -0
  40. package/.github/skills/testdriver:testdriver-mechanic/SKILL.md +165 -0
  41. package/.github/skills/testdriver:type/SKILL.md +357 -0
  42. package/.github/skills/testdriver:variables/SKILL.md +111 -0
  43. package/.github/skills/testdriver:waiting-for-elements/SKILL.md +66 -0
  44. package/.github/skills/testdriver:what-is-testdriver/SKILL.md +54 -0
  45. package/.github/workflows/acceptance-windows-scheduled.yaml +6 -1
  46. package/.github/workflows/acceptance.yaml +0 -36
  47. package/.github/workflows/update-examples.yaml +53 -0
  48. package/CHANGELOG.md +8 -0
  49. package/agent/events.js +1 -0
  50. package/agent/index.js +8 -0
  51. package/agent/lib/commands.js +48 -29
  52. package/agent/lib/redraw.js +3 -1
  53. package/agent/lib/sandbox.js +166 -14
  54. package/agent/lib/sdk.js +142 -3
  55. package/agent/lib/system.js +4 -6
  56. package/ai/skills/testdriver:ai/SKILL.md +204 -0
  57. package/ai/skills/testdriver:assert/SKILL.md +315 -0
  58. package/ai/skills/testdriver:aws-setup/SKILL.md +448 -0
  59. package/ai/skills/testdriver:caching/SKILL.md +124 -0
  60. package/ai/skills/testdriver:captcha/SKILL.md +159 -0
  61. package/ai/skills/testdriver:ci-cd/SKILL.md +602 -0
  62. package/ai/skills/testdriver:click/SKILL.md +286 -0
  63. package/ai/skills/testdriver:client/SKILL.md +372 -0
  64. package/ai/skills/testdriver:cloud/SKILL.md +119 -0
  65. package/ai/skills/testdriver:customizing-devices/SKILL.md +153 -0
  66. package/ai/skills/testdriver:dashcam/SKILL.md +418 -0
  67. package/ai/skills/testdriver:debugging-with-screenshots/SKILL.md +401 -0
  68. package/ai/skills/testdriver:device-config/SKILL.md +317 -0
  69. package/ai/skills/testdriver:double-click/SKILL.md +102 -0
  70. package/ai/skills/testdriver:elements/SKILL.md +605 -0
  71. package/ai/skills/testdriver:enterprise/SKILL.md +114 -0
  72. package/ai/skills/testdriver:examples/SKILL.md +7 -0
  73. package/ai/skills/testdriver:exec/SKILL.md +345 -0
  74. package/ai/skills/testdriver:find/SKILL.md +745 -0
  75. package/ai/skills/testdriver:focus-application/SKILL.md +293 -0
  76. package/ai/skills/testdriver:generating-tests/SKILL.md +36 -0
  77. package/ai/skills/testdriver:hover/SKILL.md +278 -0
  78. package/ai/skills/testdriver:locating-elements/SKILL.md +71 -0
  79. package/ai/skills/testdriver:making-assertions/SKILL.md +32 -0
  80. package/ai/skills/testdriver:mcp-workflow/SKILL.md +410 -0
  81. package/ai/skills/testdriver:mouse-down/SKILL.md +161 -0
  82. package/ai/skills/testdriver:mouse-up/SKILL.md +164 -0
  83. package/ai/skills/testdriver:ocr/SKILL.md +235 -0
  84. package/ai/skills/testdriver:performing-actions/SKILL.md +51 -0
  85. package/ai/skills/testdriver:press-keys/SKILL.md +348 -0
  86. package/ai/skills/testdriver:quickstart/SKILL.md +146 -0
  87. package/ai/skills/testdriver:reusable-code/SKILL.md +240 -0
  88. package/ai/skills/testdriver:right-click/SKILL.md +123 -0
  89. package/ai/skills/testdriver:running-tests/SKILL.md +185 -0
  90. package/ai/skills/testdriver:screenshot/SKILL.md +248 -0
  91. package/ai/skills/testdriver:scroll/SKILL.md +335 -0
  92. package/ai/skills/testdriver:secrets/SKILL.md +115 -0
  93. package/ai/skills/testdriver:self-hosted/SKILL.md +65 -0
  94. package/ai/skills/testdriver:test-writer/SKILL.md +451 -0
  95. package/ai/skills/testdriver:testdriver/SKILL.md +631 -0
  96. package/ai/skills/testdriver:testdriver-mechanic/SKILL.md +165 -0
  97. package/ai/skills/testdriver:type/SKILL.md +357 -0
  98. package/ai/skills/testdriver:variables/SKILL.md +111 -0
  99. package/ai/skills/testdriver:waiting-for-elements/SKILL.md +66 -0
  100. package/ai/skills/testdriver:what-is-testdriver/SKILL.md +54 -0
  101. package/debugger/index.html +12 -2
  102. package/docs/v7/examples/scroll-keyboard.mdx +1 -1
  103. package/docs/v7/find.mdx +1 -0
  104. package/examples/config.mjs +1 -1
  105. package/examples/findall-coffee-icons.test.mjs +42 -0
  106. package/examples/flake-diffthreshold-001.test.mjs +9 -0
  107. package/examples/flake-diffthreshold-01.test.mjs +9 -0
  108. package/examples/flake-diffthreshold-05.test.mjs +9 -0
  109. package/examples/{z_flake-noredraw-cache.test.mjs → flake-noredraw-cache.test.mjs} +2 -2
  110. package/examples/{z_flake-noredraw-nocache.test.mjs → flake-noredraw-nocache.test.mjs} +2 -2
  111. package/examples/{z_flake-redraw-cache.test.mjs → flake-redraw-cache.test.mjs} +2 -2
  112. package/examples/{z_flake-redraw-nocache.test.mjs → flake-redraw-nocache.test.mjs} +2 -2
  113. package/examples/flake-rocket-match.test.mjs +30 -0
  114. package/examples/{z_flake-shared.mjs → flake-shared.mjs} +2 -2
  115. package/examples/parse.test.mjs +19 -0
  116. package/examples/scroll-keyboard.test.mjs +1 -1
  117. package/interfaces/cli/lib/base.js +6 -0
  118. package/interfaces/logger.js +51 -13
  119. package/interfaces/vitest-plugin.mjs +137 -0
  120. package/lib/core/index.d.ts +22 -0
  121. package/lib/init-project.js +105 -6
  122. package/lib/vitest/hooks.mjs +2 -5
  123. package/lib/vitest/setup-disable-defender.mjs +52 -0
  124. package/package.json +2 -1
  125. package/sdk-log-formatter.js +90 -0
  126. package/sdk.d.ts +88 -51
  127. package/sdk.js +128 -21
  128. package/setup/aws/disable-defender.sh +42 -0
  129. package/vitest.config.mjs +1 -3
  130. package/examples/z_flake-diffthreshold-001.test.mjs +0 -9
  131. package/examples/z_flake-diffthreshold-01.test.mjs +0 -9
  132. package/examples/z_flake-diffthreshold-05.test.mjs +0 -9
  133. /package/{examples → manual}/captcha-api.test.mjs +0 -0
@@ -0,0 +1,164 @@
1
+ ---
2
+ name: testdriver:mouse-up
3
+ description: Release the mouse button
4
+ ---
5
+ <!-- Generated from mouse-up.mdx. DO NOT EDIT. -->
6
+
7
+ ## Overview
8
+
9
+ The `mouseUp()` method releases the mouse button, completing a drag operation or custom mouse gesture that was started with [`mouseDown()`](/v7/mouse-down). You can call it without parameters to release at the current mouse position.
10
+
11
+ ## Syntax
12
+
13
+ ```javascript
14
+ // Release mouse button at current position
15
+ await ai.mouseUp();
16
+ ```
17
+
18
+ ## Parameters
19
+
20
+ None. The mouse button is released at the current cursor position.
21
+
22
+ ## Returns
23
+
24
+ Returns a `Promise<void>` that resolves when the mouse button is released.
25
+
26
+ ## Examples
27
+
28
+ ### Complete Drag and Drop
29
+
30
+ ```javascript
31
+ // Start dragging
32
+ await ai.mouseDown('file to drag');
33
+
34
+ // Move to drop location
35
+ await ai.hover('target folder');
36
+
37
+ // Complete the drop
38
+ await ai.mouseUp();
39
+ ```
40
+
41
+ ### Selecting Multiple Files
42
+
43
+ ```javascript
44
+ import { test } from 'vitest';
45
+ import { vscode } from '@testdriver/sdk';
46
+
47
+ test('selects range of files', async () => {
48
+ const { ai } = await vscode();
49
+
50
+ // Click first file
51
+ await ai.click('first-file.js in explorer');
52
+
53
+ // Hold shift and click last file
54
+ await ai.pressKeys('Shift');
55
+ await ai.mouseDown('last-file.js in explorer');
56
+ await ai.mouseUp();
57
+
58
+ // Verify multiple files selected
59
+ const selectedCount = await ai.find('status bar showing file count');
60
+ expect(selectedCount.text).toContain('5 files');
61
+ });
62
+ ```
63
+
64
+ ### Drawing Application
65
+
66
+ ```javascript
67
+ test('draws a shape', async () => {
68
+ const { ai } = await chrome('https://drawing-app.example.com');
69
+
70
+ // Select pencil tool
71
+ await ai.click('pencil tool');
72
+
73
+ // Draw a line
74
+ await ai.mouseDown('canvas near top-left');
75
+ await ai.hover('canvas center');
76
+ await ai.hover('canvas bottom-right');
77
+ await ai.mouseUp();
78
+
79
+ // Verify drawing exists
80
+ const strokes = await ai.exec('canvas.getContext("2d").getImageData(0,0,100,100)');
81
+ expect(strokes).toBeTruthy();
82
+ });
83
+ ```
84
+
85
+ ### Resizing Window Panels
86
+
87
+ ```javascript
88
+ test('resizes editor panel', async () => {
89
+ const { ai } = await vscode();
90
+
91
+ // Grab the divider
92
+ await ai.mouseDown('panel resize divider');
93
+
94
+ // Drag to new position
95
+ await ai.hover('position 400 pixels from left');
96
+
97
+ // Release to complete resize
98
+ await ai.mouseUp();
99
+
100
+ // Verify new panel size
101
+ const panel = await ai.find('editor panel');
102
+ expect(panel.width).toBeGreaterThan(350);
103
+ });
104
+ ```
105
+
106
+ ### Drag to Reorder List Items
107
+
108
+ ```javascript
109
+ import { test } from 'vitest';
110
+ import { chrome } from '@testdriver/sdk';
111
+
112
+ test('reorders tasks in list', async () => {
113
+ const { ai } = await chrome('https://todo-app.example.com');
114
+
115
+ // Start dragging first task
116
+ await ai.mouseDown('drag handle on first task');
117
+
118
+ // Move down to third position
119
+ await ai.hover('third task position');
120
+
121
+ // Drop the task
122
+ await ai.mouseUp();
123
+
124
+ // Verify new order
125
+ const thirdTask = await ai.find('third task in list');
126
+ expect(thirdTask.text).toContain('Original first task');
127
+ });
128
+ ```
129
+
130
+ ### Text Selection with Mouse
131
+
132
+ ```javascript
133
+ test('selects text with mouse drag', async () => {
134
+ const { ai } = await chrome('https://document.example.com');
135
+
136
+ // Start selection at beginning of word
137
+ await ai.mouseDown('start of "TestDriver" word');
138
+
139
+ // Drag to end of word
140
+ await ai.hover('end of "TestDriver" word');
141
+
142
+ // Complete selection
143
+ await ai.mouseUp();
144
+
145
+ // Verify selection
146
+ const selection = await ai.exec('window.getSelection().toString()');
147
+ expect(selection).toBe('TestDriver');
148
+ });
149
+ ```
150
+
151
+ ## Important Notes
152
+
153
+ - `mouseUp()` must be preceded by [`mouseDown()`](/v7/mouse-down) to have an effect
154
+ - Releases the button at the current cursor position
155
+ - Completes any drag or selection operation that was in progress
156
+ - For simple clicks, use [`click()`](/v7/click) instead of mouseDown/mouseUp pair
157
+
158
+ ## Related Methods
159
+
160
+ - [`mouseDown()`](/v7/mouse-down) - Press mouse button without releasing
161
+ - [`hover()`](/v7/hover) - Move mouse to element
162
+ - [`click()`](/v7/click) - Complete click (mouseDown + mouseUp)
163
+ - [`doubleClick()`](/v7/double-click) - Double-click on element
164
+ - [`rightClick()`](/v7/right-click) - Right-click for context menu
@@ -0,0 +1,235 @@
1
+ ---
2
+ name: testdriver:ocr
3
+ description: Extract all visible text from the screen using OCR
4
+ ---
5
+ <!-- Generated from ocr.mdx. DO NOT EDIT. -->
6
+
7
+ ## Overview
8
+
9
+ Extract all visible text from the current screen using Tesseract OCR. Returns structured data including each word's text content, bounding box coordinates, and confidence scores.
10
+
11
+ This method runs OCR on-demand and returns the results immediately. It's useful for:
12
+ - Verifying text content on screen
13
+ - Finding elements by their text when visual matching alone isn't enough
14
+ - Debugging what text TestDriver can "see"
15
+ - Building custom text-based assertions
16
+
17
+ <Note>
18
+ **Performance**: OCR runs server-side using Tesseract.js with a worker pool for fast extraction. A typical screenshot processes in 200-500ms.
19
+ </Note>
20
+
21
+ ## Syntax
22
+
23
+ ```javascript
24
+ const result = await testdriver.ocr()
25
+ ```
26
+
27
+ ## Parameters
28
+
29
+ None.
30
+
31
+ ## Returns
32
+
33
+ `Promise<OCRResult>` - Object containing extracted text data
34
+
35
+ ### OCRResult
36
+
37
+ | Property | Type | Description |
38
+ |----------|------|-------------|
39
+ | `words` | `OCRWord[]` | Array of extracted words with positions |
40
+ | `fullText` | `string` | All text concatenated with spaces |
41
+ | `confidence` | `number` | Overall OCR confidence (0-100) |
42
+ | `imageWidth` | `number` | Width of the analyzed screenshot |
43
+ | `imageHeight` | `number` | Height of the analyzed screenshot |
44
+
45
+ ### OCRWord
46
+
47
+ | Property | Type | Description |
48
+ |----------|------|-------------|
49
+ | `content` | `string` | The word's text content |
50
+ | `confidence` | `number` | Confidence score for this word (0-100) |
51
+ | `bbox.x0` | `number` | Left edge X coordinate |
52
+ | `bbox.y0` | `number` | Top edge Y coordinate |
53
+ | `bbox.x1` | `number` | Right edge X coordinate |
54
+ | `bbox.y1` | `number` | Bottom edge Y coordinate |
55
+
56
+ ## Examples
57
+
58
+ ### Get All Text on Screen
59
+
60
+ ```javascript
61
+ const result = await testdriver.ocr();
62
+ console.log(result.fullText);
63
+ // "Welcome to TestDriver Sign In Email Password Submit"
64
+
65
+ console.log(`Found ${result.words.length} words with ${result.confidence}% confidence`);
66
+ ```
67
+
68
+ ### Check if Text Exists
69
+
70
+ ```javascript
71
+ const result = await testdriver.ocr();
72
+
73
+ // Check for error message
74
+ const hasError = result.words.some(w =>
75
+ w.content.toLowerCase().includes('error')
76
+ );
77
+
78
+ if (hasError) {
79
+ console.log('Error message detected on screen');
80
+ }
81
+ ```
82
+
83
+ ### Find and Click Text
84
+
85
+ ```javascript
86
+ const result = await testdriver.ocr();
87
+
88
+ // Find the "Submit" button text
89
+ const submitWord = result.words.find(w => w.content === 'Submit');
90
+
91
+ if (submitWord) {
92
+ // Calculate center of the word's bounding box
93
+ const x = Math.round((submitWord.bbox.x0 + submitWord.bbox.x1) / 2);
94
+ const y = Math.round((submitWord.bbox.y0 + submitWord.bbox.y1) / 2);
95
+
96
+ // Click at those coordinates
97
+ await testdriver.click({ x, y });
98
+ }
99
+ ```
100
+
101
+ ### Filter Words by Confidence
102
+
103
+ ```javascript
104
+ const result = await testdriver.ocr();
105
+
106
+ // Only use high-confidence words (90%+)
107
+ const reliableWords = result.words.filter(w => w.confidence >= 90);
108
+
109
+ console.log('High confidence words:', reliableWords.map(w => w.content));
110
+ ```
111
+
112
+ ### Build Custom Assertions
113
+
114
+ ```javascript
115
+ import { describe, expect, it } from "vitest";
116
+ import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
117
+
118
+ describe("Login Page", () => {
119
+ it("should show form labels", async (context) => {
120
+ const testdriver = TestDriver(context);
121
+
122
+ await testdriver.provision.chrome({
123
+ url: 'https://myapp.com/login',
124
+ });
125
+
126
+ const result = await testdriver.ocr();
127
+
128
+ // Assert expected labels are present
129
+ expect(result.fullText).toContain('Email');
130
+ expect(result.fullText).toContain('Password');
131
+ expect(result.fullText).toContain('Sign In');
132
+ });
133
+ });
134
+ ```
135
+
136
+ ### Debug Screen Content
137
+
138
+ ```javascript
139
+ // Useful for debugging what TestDriver can see
140
+ const result = await testdriver.ocr();
141
+
142
+ console.log('=== Screen Text ===');
143
+ console.log(result.fullText);
144
+ console.log('');
145
+
146
+ console.log('=== Word Details ===');
147
+ result.words.forEach((word, i) => {
148
+ console.log(`${i + 1}. "${word.content}" at (${word.bbox.x0}, ${word.bbox.y0}) - ${word.confidence}% confidence`);
149
+ });
150
+ ```
151
+
152
+ ### Find Multiple Instances
153
+
154
+ ```javascript
155
+ const result = await testdriver.ocr();
156
+
157
+ // Find all instances of "Button" text
158
+ const buttons = result.words.filter(w =>
159
+ w.content.toLowerCase() === 'button'
160
+ );
161
+
162
+ console.log(`Found ${buttons.length} buttons on screen`);
163
+
164
+ buttons.forEach((btn, i) => {
165
+ console.log(`Button ${i + 1} at position (${btn.bbox.x0}, ${btn.bbox.y0})`);
166
+ });
167
+ ```
168
+
169
+ ## How It Works
170
+
171
+ 1. TestDriver captures a screenshot of the current screen
172
+ 2. The image is sent to the TestDriver API
173
+ 3. Tesseract.js processes the image server-side with multiple workers
174
+ 4. The API returns structured data with text and positions
175
+ 5. Bounding box coordinates are scaled to match the original screen resolution
176
+
177
+ <Note>
178
+ OCR works best with clear, readable text. Very small text, unusual fonts, or low-contrast text may have lower confidence scores or be missed entirely.
179
+ </Note>
180
+
181
+ ## Best Practices
182
+
183
+ <AccordionGroup>
184
+ <Accordion title="Use find() for element location">
185
+ For locating elements, prefer `find()` which uses AI vision. Use `ocr()` when you need raw text data or want to build custom text-based logic.
186
+
187
+ ```javascript
188
+ // Prefer this for clicking elements
189
+ await testdriver.find("Submit button").click();
190
+
191
+ // Use ocr() for text verification or custom logic
192
+ const result = await testdriver.ocr();
193
+ expect(result.fullText).toContain('Success');
194
+ ```
195
+ </Accordion>
196
+
197
+ <Accordion title="Filter by confidence">
198
+ OCR can sometimes misread characters. Filter by confidence score when accuracy is critical.
199
+
200
+ ```javascript
201
+ const result = await testdriver.ocr();
202
+ const reliable = result.words.filter(w => w.confidence >= 85);
203
+ ```
204
+ </Accordion>
205
+
206
+ <Accordion title="Handle case sensitivity">
207
+ Text matching should usually be case-insensitive since OCR capitalization can vary.
208
+
209
+ ```javascript
210
+ const result = await testdriver.ocr();
211
+ const hasLogin = result.words.some(w =>
212
+ w.content.toLowerCase() === 'login'
213
+ );
214
+ ```
215
+ </Accordion>
216
+
217
+ <Accordion title="Wait for content to load">
218
+ If text isn't being found, the page may not be fully loaded. Add a wait or use `waitForText()`.
219
+
220
+ ```javascript
221
+ // Wait for specific text to appear
222
+ await testdriver.waitForText("Welcome");
223
+
224
+ // Then run OCR
225
+ const result = await testdriver.ocr();
226
+ ```
227
+ </Accordion>
228
+ </AccordionGroup>
229
+
230
+ ## Related
231
+
232
+ - [find()](/v7/find) - AI-powered element location
233
+ - [assert()](/v7/assert) - Make AI-powered assertions about screen state
234
+ - [waitForText()](/v7/waiting-for-elements) - Wait for text to appear on screen
235
+ - [screenshot()](/v7/screenshot) - Capture screenshots
@@ -0,0 +1,51 @@
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
+ await testdriver.scrollUntilText('Footer content');
31
+
32
+ // Extracting information from screen
33
+ const price = await testdriver.extract('the total price');
34
+ const orderNumber = await testdriver.extract('the order confirmation number');
35
+ ```
36
+
37
+ ## Chaining Actions
38
+
39
+ TestDriver supports method chaining for cleaner code:
40
+
41
+ ```javascript
42
+ // Chain find() with actions
43
+ const button = await testdriver.find('submit button').click();
44
+ ```
45
+
46
+ Or save element reference for later use:
47
+
48
+ ```javascript
49
+ const button = await testdriver.find('submit button');
50
+ await button.click();
51
+ ```