@testdriverai/agent 7.11.239-test → 7.11.241-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 (52) hide show
  1. package/ai/skills/testdriver-agent/SKILL.md +174 -91
  2. package/ai/skills/testdriver-assert/SKILL.md +73 -269
  3. package/ai/skills/testdriver-aws-setup/SKILL.md +194 -312
  4. package/ai/skills/testdriver-bring-your-own-machine/SKILL.md +137 -204
  5. package/ai/skills/testdriver-cache/SKILL.md +142 -149
  6. package/ai/skills/testdriver-caching/SKILL.md +97 -87
  7. package/ai/skills/testdriver-captcha/SKILL.md +126 -111
  8. package/ai/skills/testdriver-ci-cd/SKILL.md +153 -542
  9. package/ai/skills/testdriver-click/SKILL.md +74 -229
  10. package/ai/skills/testdriver-client/SKILL.md +175 -229
  11. package/ai/skills/testdriver-customizing-devices/SKILL.md +72 -250
  12. package/ai/skills/testdriver-dashcam/SKILL.md +71 -404
  13. package/ai/skills/testdriver-debugging-with-screenshots/SKILL.md +103 -369
  14. package/ai/skills/testdriver-double-click/SKILL.md +46 -67
  15. package/ai/skills/testdriver-errors/SKILL.md +102 -176
  16. package/ai/skills/testdriver-events/SKILL.md +170 -327
  17. package/ai/skills/testdriver-exec/SKILL.md +92 -256
  18. package/ai/skills/testdriver-extract/SKILL.md +69 -170
  19. package/ai/skills/testdriver-find/SKILL.md +140 -736
  20. package/ai/skills/testdriver-focus-application/SKILL.md +69 -246
  21. package/ai/skills/testdriver-generating-tests/SKILL.md +102 -136
  22. package/ai/skills/testdriver-hosted/SKILL.md +79 -143
  23. package/ai/skills/testdriver-hover/SKILL.md +62 -235
  24. package/ai/skills/testdriver-locating-elements/SKILL.md +71 -366
  25. package/ai/skills/testdriver-making-assertions/SKILL.md +114 -72
  26. package/ai/skills/testdriver-mcp-setup/SKILL.md +79 -62
  27. package/ai/skills/testdriver-mouse-down/SKILL.md +46 -124
  28. package/ai/skills/testdriver-mouse-up/SKILL.md +45 -128
  29. package/ai/skills/testdriver-options/SKILL.md +73 -46
  30. package/ai/skills/testdriver-parse/SKILL.md +95 -184
  31. package/ai/skills/testdriver-performing-actions/SKILL.md +101 -91
  32. package/ai/skills/testdriver-press-keys/SKILL.md +59 -299
  33. package/ai/skills/testdriver-provision/SKILL.md +135 -179
  34. package/ai/skills/testdriver-quickstart/SKILL.md +24 -8
  35. package/ai/skills/testdriver-quickstart-claude/SKILL.md +84 -0
  36. package/ai/skills/testdriver-quickstart-github/SKILL.md +62 -32
  37. package/ai/skills/testdriver-quickstart-manual/SKILL.md +59 -32
  38. package/ai/skills/testdriver-quickstart-vscode/SKILL.md +96 -0
  39. package/ai/skills/testdriver-redraw/SKILL.md +100 -164
  40. package/ai/skills/testdriver-reusable-code/SKILL.md +95 -199
  41. package/ai/skills/testdriver-right-click/SKILL.md +45 -88
  42. package/ai/skills/testdriver-screenshot/SKILL.md +47 -201
  43. package/ai/skills/testdriver-screenshots/SKILL.md +86 -136
  44. package/ai/skills/testdriver-scroll/SKILL.md +71 -154
  45. package/ai/skills/testdriver-secrets/SKILL.md +94 -90
  46. package/ai/skills/testdriver-self-hosted/SKILL.md +82 -140
  47. package/ai/skills/testdriver-test-results-json/SKILL.md +165 -202
  48. package/ai/skills/testdriver-type/SKILL.md +56 -304
  49. package/ai/skills/testdriver-variables/SKILL.md +119 -80
  50. package/ai/skills/testdriver-wait/SKILL.md +31 -29
  51. package/ai/skills/testdriver-what-is-testdriver/SKILL.md +80 -32
  52. package/package.json +1 -1
@@ -1,102 +1,81 @@
1
1
  ---
2
2
  name: testdriver:double-click
3
- description: Perform a double-click action on an element or at specific coordinates
3
+ description: Double-click an element you found, for example to open a file or select a word.
4
4
  ---
5
5
  <!-- Generated from double-click.mdx. DO NOT EDIT. -->
6
6
 
7
- ## Overview
8
-
9
- The `doubleClick()` method does a double-click action on an element. You can call it on an [`Element`](/core-concepts/elements) instance. Or you can use it with a selector.
10
-
11
- ## Syntax
7
+ Double-click an element you've located with [`find()`](/find):
12
8
 
13
9
  ```javascript
14
- // Double-click on an element
15
- await element.doubleClick();
16
-
17
- // Double-click using a selector
18
- await ai.doubleClick('selector');
10
+ await testdriver.find('report.pdf in the file list').doubleClick();
19
11
  ```
20
12
 
21
- ## Parameters
13
+ ## element.doubleClick()
22
14
 
23
- When called on an `Element`, no parameters are required.
15
+ Double-clicks the element at the point where `find()` located it. It's the same as `element.click('double-click')`.
24
16
 
25
- When called directly on the AI client:
17
+ ```typescript
18
+ element.doubleClick(): Promise<void>
19
+ ```
26
20
 
27
- | Parameter | Type | Description |
28
- |-----------|------|-------------|
29
- | `selector` | `string` | The selector describing the element to double-click |
21
+ It takes no parameters.
30
22
 
31
- ## Returns
23
+ ### Errors
32
24
 
33
- It returns a `Promise<void>`. The promise resolves when the double-click action completes.
25
+ Throws an `ElementNotFoundError` if `find()` didn't locate the element. See [click()](/click#errors) for how to check `found()` first.
34
26
 
35
- ## Examples
27
+ ## Double-click at coordinates
36
28
 
37
- ### Double-Click on Found Element
29
+ The client has no `doubleClick()` method. To double-click a point on the screen, pass `action: 'double-click'` to [`testdriver.click()`](/click#testdriver-click-options):
38
30
 
39
31
  ```javascript
40
- const fileItem = await ai.find('README.md file');
41
- await fileItem.doubleClick();
32
+ await testdriver.click({ x: 640, y: 360, action: 'double-click' });
42
33
  ```
43
34
 
44
- ### Direct Double-Click with Selector
35
+ Prefer `element.doubleClick()`, which keeps working when the layout or screen size changes.
45
36
 
46
- ```javascript
47
- await ai.doubleClick('README.md in the file list');
48
- ```
37
+ ## Examples
49
38
 
50
- ### Opening Files in VS Code
39
+ ### Open a file in VS Code
51
40
 
52
41
  ```javascript
53
- import { test } from 'vitest';
54
- import { vscode } from '@testdriver/sdk';
55
-
56
- test('opens a file by double-clicking', async () => {
57
- const { ai } = await vscode();
58
-
59
- // Double-click to open a file in the explorer
60
- await ai.doubleClick('package.json in the file explorer');
61
-
62
- // Verify the file opened
63
- const editor = await ai.find('text editor showing package.json');
64
- expect(editor).toBeTruthy();
65
- });
42
+ await testdriver.find('package.json in the Explorer sidebar').doubleClick();
43
+ await testdriver.assert('package.json is open in the editor');
66
44
  ```
67
45
 
68
- ### Opening Folders in File Manager
46
+ ### Select a word
69
47
 
70
48
  ```javascript
71
- import { test } from 'vitest';
72
- import { chrome } from '@testdriver/sdk';
73
-
74
- test('navigates folders in Google Drive', async () => {
75
- const { ai } = await chrome('https://drive.google.com');
76
-
77
- // Double-click to open a folder
78
- await ai.doubleClick('Documents folder');
79
-
80
- // Wait for folder to open
81
- await ai.find('breadcrumb showing Documents');
82
- });
49
+ await testdriver.find('the word "Checkout" in the page heading').doubleClick();
50
+ await testdriver.pressKeys(['ctrl', 'c']);
83
51
  ```
84
52
 
85
- ### Selecting Text with Double-Click
53
+ ## Complete example
86
54
 
87
- ```javascript
88
- // Double-click to select a word
89
- await ai.doubleClick('word "TestDriver" in the paragraph');
55
+ ```javascript tests/open-file.test.mjs
56
+ import { describe, expect, it } from 'vitest';
57
+ import { TestDriver } from 'testdriverai/vitest/hooks';
90
58
 
91
- // Verify selection
92
- const selectedText = await ai.exec('window.getSelection().toString()');
93
- expect(selectedText).toBe('TestDriver');
59
+ describe('VS Code', () => {
60
+ it('opens a file from the Explorer', async (context) => {
61
+ const testdriver = TestDriver(context);
62
+ await testdriver.exec({
63
+ language: 'sh',
64
+ code: 'mkdir -p /tmp/my-project && echo "{}" > /tmp/my-project/package.json',
65
+ });
66
+ await testdriver.provision.vscode({ workspace: '/tmp/my-project' });
67
+
68
+ await testdriver.find('package.json in the Explorer sidebar').doubleClick();
69
+
70
+ const result = await testdriver.assert('package.json is open in the editor');
71
+ expect(result).toBe(true);
72
+ });
73
+ });
94
74
  ```
95
75
 
96
- ## Related Methods
76
+ ## Related
97
77
 
98
- - [`click()`](/click) - Single click on an element
99
- - [`rightClick()`](/right-click) - Right-click to open context menu
100
- - [`mouseDown()`](/mouse-down) - Press mouse button without releasing
101
- - [`mouseUp()`](/mouse-up) - Release mouse button
102
- - [`hover()`](/hover) - Move mouse over element without clicking
78
+ - [click()](/click): single clicks, and clicks at coordinates
79
+ - [rightClick()](/right-click): open a context menu
80
+ - [find()](/find): locate the element to double-click
81
+ - [Perform actions](/performing-actions): every kind of action in one guide
@@ -1,246 +1,172 @@
1
1
  ---
2
2
  name: testdriver:errors
3
- description: Custom error classes and error handling
3
+ description: The errors TestDriver throws, what they contain, and how to catch them.
4
4
  ---
5
5
  <!-- Generated from errors.mdx. DO NOT EDIT. -->
6
6
 
7
- ## Overview
8
-
9
- TestDriver gives custom error classes with full debug information. The SDK exports them. You can use them for `instanceof` checks in your tests.
7
+ TestDriver exports two error classes you can check with `instanceof`:
10
8
 
11
9
  ```javascript
12
- import TestDriver, { ElementNotFoundError, AIError } from 'testdriverai';
10
+ import { ElementNotFoundError, AIError } from 'testdriverai';
13
11
  ```
14
12
 
13
+ - [`ElementNotFoundError`](#elementnotfounderror): you acted on an element that `find()` didn't locate.
14
+ - [`AIError`](#aierror): an `ai()` task failed.
15
+
16
+ Other failures, such as a failed assertion, throw a plain `Error` with a recognizable message. See [Other errors](#other-errors).
17
+
15
18
  ## ElementNotFoundError
16
19
 
17
- TestDriver throws this when `find()` cannot find an element on the screen. It also throws this when you call `click()` or `hover()` on an element that TestDriver did not find.
20
+ Thrown when you call an action on an element that [`find()`](/find) didn't locate:
21
+
22
+ - `click()`, `doubleClick()`, `rightClick()`
23
+ - `hover()`
24
+ - `mouseDown()`, `mouseUp()`
25
+
26
+ `find()` itself doesn't throw when nothing matches. It returns an element whose `found()` is `false`. Check `found()` when the element might not be there:
18
27
 
19
28
  ```javascript
20
- try {
21
- await testdriver.find('nonexistent button').click();
22
- } catch (error) {
23
- if (error instanceof ElementNotFoundError) {
24
- console.log(error.description); // "nonexistent button"
25
- console.log(error.screenshotPath); // path to debug screenshot
26
- console.log(error.pixelDiffPath); // path to pixel diff image
27
- }
29
+ const cookieBanner = await testdriver.find('Cookie consent banner', { timeout: 0 });
30
+ if (cookieBanner.found()) {
31
+ await testdriver.find('Accept all cookies button').click();
28
32
  }
29
33
  ```
30
34
 
31
35
  ### Properties
32
36
 
33
- <ParamField path="name" type="string">
37
+ <ResponseField name="name" type="string">
34
38
  Always `"ElementNotFoundError"`.
35
- </ParamField>
39
+ </ResponseField>
36
40
 
37
- <ParamField path="message" type="string">
38
- A message with a debug block. The block has the element description, the cache status, the similarity scores, and the AI response details.
39
- </ParamField>
41
+ <ResponseField name="description" type="string">
42
+ The description you passed to `find()`.
43
+ </ResponseField>
40
44
 
41
- <ParamField path="description" type="string">
42
- The original element description passed to `find()`.
43
- </ParamField>
45
+ <ResponseField name="message" type="string">
46
+ Says which element wasn't found, followed by a debug block. See below.
47
+ </ResponseField>
44
48
 
45
- <ParamField path="screenshotPath" type="string | null">
46
- Absolute path to a debug screenshot saved at the time of failure. Written to `<os.tmpdir>/testdriver-debug/screenshot-<timestamp>.png`.
47
- </ParamField>
49
+ <ResponseField name="aiResponse" type="object | null">
50
+ The response from the `find()` call, with screenshots and other large images removed. Includes fields such as `cacheHit`, `similarity`, and `reasoning` when the API returned them.
51
+ </ResponseField>
48
52
 
49
- <ParamField path="pixelDiffPath" type="string | null">
50
- Absolute path to a pixel diff image showing the comparison between the cached and current screenshots. Written to `<os.tmpdir>/testdriver-debug/pixel-diff-error-<timestamp>.png`. Only present when cache was involved.
51
- </ParamField>
53
+ <ResponseField name="timestamp" type="string">
54
+ When the error was created, as an ISO 8601 string.
55
+ </ResponseField>
52
56
 
53
- <ParamField path="cachedImagePath" type="string | null">
54
- URL to the cached image that was compared against.
55
- </ParamField>
57
+ ### Message
56
58
 
57
- <ParamField path="aiResponse" type="object | null">
58
- Sanitized AI response object. Large binary fields (`croppedImage`, `screenshot`, `pixelDiffImage`) are removed. Contains cache metadata like `similarity`, `cacheHit`, `cacheStrategy`, `cacheDiffPercent`, and `threshold`.
59
- </ParamField>
59
+ The message starts with the element's description, then adds what TestDriver knows about the failed `find()`:
60
60
 
61
- <ParamField path="timestamp" type="string">
62
- ISO 8601 timestamp of when the error was created.
63
- </ParamField>
61
+ ```text
62
+ Element "Sign in button" not found.
64
63
 
65
- ### Enhanced Message
64
+ === Debug Information ===
65
+ Element searched for: "Sign in button"
66
+ Cache: MISS
66
67
 
67
- The error message is automatically enhanced with debugging information:
68
-
69
- ```
70
- Element not found: "submit button"
71
-
72
- === Element Debug Info ===
73
- Element: submit button
74
- Cache Hit: false
75
- Similarity: 0.23
76
- Cache Strategy: pixel-diff
77
- Threshold: 0.05
78
- AI Response Element: null
68
+ AI Response:
69
+ The page shows a loading spinner. There is no sign in button yet.
79
70
  ```
80
71
 
81
- ### Stack Trace Cleaning
72
+ Depending on the `find()` call, the debug block can also include:
82
73
 
83
- Stack traces are automatically cleaned to remove internal SDK frames (`Element.*`, `sdk.js` internals), showing only your test code for easier debugging.
74
+ - The cache threshold and the required similarity.
75
+ - When the cache was hit: the cache strategy, the entry's age, and the pixel difference.
76
+ - The similarity score, marked `(below threshold)` when it's too low.
77
+
78
+ The stack trace starts at your test code, not inside the SDK.
84
79
 
85
80
  ## AIError
86
81
 
87
- Thrown when `act()` exhausts all retry attempts.
82
+ Thrown when a task you give to `ai()` fails:
88
83
 
89
84
  ```javascript
85
+ import { AIError } from 'testdriverai';
86
+
90
87
  try {
91
- await testdriver.act('perform complex workflow', { tries: 3 });
88
+ await testdriver.ai('Add the blue T-shirt to the cart', { tries: 3 });
92
89
  } catch (error) {
93
90
  if (error instanceof AIError) {
94
- console.log(error.task); // "perform complex workflow"
95
- console.log(error.tries); // 3
96
- console.log(error.duration); // 15234 (ms)
97
- console.log(error.cause); // underlying Error
91
+ console.log(`Stopped after ${error.tries} of ${error.maxTries} tries`);
92
+ console.log(error.cause?.message); // the error that stopped the task
98
93
  }
94
+ throw error;
99
95
  }
100
96
  ```
101
97
 
98
+ `act()` is the same method under another name and throws the same error.
99
+
102
100
  ### Properties
103
101
 
104
- <ParamField path="name" type="string">
102
+ <ResponseField name="name" type="string">
105
103
  Always `"AIError"`.
106
- </ParamField>
104
+ </ResponseField>
107
105
 
108
- <ParamField path="message" type="string">
109
- Enhanced message with execution details block.
110
- </ParamField>
106
+ <ResponseField name="task" type="string">
107
+ The task you passed to `ai()`.
108
+ </ResponseField>
111
109
 
112
- <ParamField path="task" type="string">
113
- The task description passed to `act()`.
114
- </ParamField>
110
+ <ResponseField name="tries" type="number">
111
+ How many check attempts were made.
112
+ </ResponseField>
115
113
 
116
- <ParamField path="tries" type="number">
117
- Number of attempts that were made.
118
- </ParamField>
114
+ <ResponseField name="maxTries" type="number">
115
+ The `tries` limit for the call. Defaults to `7`.
116
+ </ResponseField>
119
117
 
120
- <ParamField path="maxTries" type="number">
121
- Maximum number of attempts configured.
122
- </ParamField>
118
+ <ResponseField name="duration" type="number">
119
+ How long the task ran, in milliseconds.
120
+ </ResponseField>
123
121
 
124
- <ParamField path="duration" type="number">
125
- Total execution time in milliseconds.
126
- </ParamField>
122
+ <ResponseField name="cause" type="Error">
123
+ The error that stopped the task.
124
+ </ResponseField>
127
125
 
128
- <ParamField path="cause" type="Error | undefined">
129
- The underlying error that caused the final failure.
130
- </ParamField>
126
+ <ResponseField name="timestamp" type="string">
127
+ When the error was created, as an ISO 8601 string.
128
+ </ResponseField>
131
129
 
132
- <ParamField path="timestamp" type="string">
133
- ISO 8601 timestamp of when the error was created.
134
- </ParamField>
130
+ ### Message
135
131
 
136
- ### Enhanced Message
137
-
138
- ```
139
- AI failed: Element not found after 3 attempts
132
+ ```text
133
+ AI failed: <the cause's message>
140
134
 
141
135
  === AI Execution Details ===
142
- Task: perform complex workflow
143
- Tries: 3 / 3
144
- Duration: 15234ms
145
- Cause: ElementNotFoundError: Element not found: "submit button"
136
+ Task: "Add the blue T-shirt to the cart"
137
+ Tries: 3/3
138
+ Duration: 41250ms
139
+ Timestamp: 2026-10-21T14:30:00.000Z
140
+ Underlying error: <the cause's message>
146
141
  ```
147
142
 
148
- ## Internal Error Classes
149
-
150
- These errors are used internally by the agent and are not exported, but may appear as the `cause` of an `AIError`:
151
-
152
- ### MatchError
153
-
154
- Thrown when element matching fails (text, image, or assertion).
155
-
156
- | Property | Type | Description |
157
- |---|---|---|
158
- | `fatal` | `boolean` | If `true`, cannot be healed. Default: `false` |
159
- | `attachScreenshot` | `boolean` | Always `true` — a screenshot is attached to the error |
160
-
161
- ### CommandError
143
+ ## Other errors
162
144
 
163
- Thrown for invalid arguments or unsupported operations.
145
+ These failures throw an error whose class isn't exported. Check the message instead.
164
146
 
165
- | Property | Type | Description |
166
- |---|---|---|
167
- | `fatal` | `boolean` | Always `true` |
168
- | `attachScreenshot` | `boolean` | Always `false` |
169
-
170
- ## Soft Assert Mode
171
-
172
- Inside `act()`, assertions run in **soft assert mode**. When an assertion fails, it returns the failure result instead of throwing, allowing the AI to process the failure and adjust its approach.
173
-
174
- ```javascript
175
- // Inside act(), assertion failures don't throw
176
- await testdriver.act('verify the dashboard shows correct data', {
177
- tries: 3,
178
- });
179
- // The AI can see assertion results and self-correct
180
- ```
181
-
182
- This is automatic — you don't need to configure it. Regular `assert()` calls outside of `act()` will throw normally on failure.
183
-
184
- ## Error Handling Patterns
185
-
186
- ### Catching Specific Errors
147
+ | What failed | Message starts with |
148
+ | --- | --- |
149
+ | [`assert()`](/assert) | `AI Assertion failed:` followed by the assertion and the AI's explanation |
150
+ | [`exec()`](/exec) with `sh` or `pwsh`, when the command exits non-zero | `Command failed with exit code <code>:` followed by stderr |
187
151
 
188
152
  ```javascript
189
- import TestDriver, { ElementNotFoundError, AIError } from 'testdriverai';
190
-
191
153
  try {
192
- await testdriver.find('submit button').click();
154
+ await testdriver.assert('the cart shows 2 items');
193
155
  } catch (error) {
194
- if (error instanceof ElementNotFoundError) {
195
- // Element wasn't found — check screenshot for debugging
196
- console.log('Debug screenshot:', error.screenshotPath);
197
- } else if (error instanceof AIError) {
198
- // AI exhausted retries
199
- console.log(`Failed after ${error.tries} tries in ${error.duration}ms`);
200
- } else {
201
- throw error; // Unexpected error
156
+ if (error.message.startsWith('AI Assertion failed:')) {
157
+ // The assertion didn't hold
202
158
  }
159
+ throw error;
203
160
  }
204
161
  ```
205
162
 
206
- ### Using Debug Screenshots
163
+ <Note>
164
+ Inside `ai()`, a failed `assert()` resolves to `false` instead of throwing, so the AI can see the result and try another approach.
165
+ </Note>
207
166
 
208
- ```javascript
209
- try {
210
- const el = await testdriver.find('checkout button');
211
- await el.click();
212
- } catch (error) {
213
- if (error instanceof ElementNotFoundError) {
214
- // Screenshot of what the screen looked like
215
- console.log('Screen:', error.screenshotPath);
216
- // Pixel diff showing cache comparison
217
- console.log('Diff:', error.pixelDiffPath);
218
- // Full AI response metadata
219
- console.log('AI:', JSON.stringify(error.aiResponse, null, 2));
220
- }
221
- }
222
- ```
167
+ ## Related
223
168
 
224
- ## Types
225
-
226
- ```typescript
227
- class ElementNotFoundError extends Error {
228
- name: 'ElementNotFoundError';
229
- description: string;
230
- screenshotPath: string | null;
231
- pixelDiffPath: string | null;
232
- cachedImagePath: string | null;
233
- aiResponse: Record<string, any> | null;
234
- timestamp: string;
235
- }
236
-
237
- class AIError extends Error {
238
- name: 'AIError';
239
- task: string;
240
- tries: number;
241
- maxTries: number;
242
- duration: number;
243
- cause?: Error;
244
- timestamp: string;
245
- }
246
- ```
169
+ - [find()](/find): returns an element whose `found()` tells you whether it was located
170
+ - [assert()](/assert): check what's on screen
171
+ - [Debug a failing test](/debugging-with-screenshots): find out why a test failed
172
+ - [Events](/events): listen for errors as they happen