@testdriverai/agent 7.11.240-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,205 +1,122 @@
1
1
  ---
2
2
  name: testdriver:scroll
3
- description: Scroll pages and elements
3
+ description: Scroll the page up or down with the mouse wheel.
4
4
  ---
5
5
  <!-- Generated from scroll.mdx. DO NOT EDIT. -->
6
6
 
7
- ## Overview
7
+ Scroll the page up or down with the mouse wheel:
8
8
 
9
- Scroll the page or the active element in any direction with the mouse wheel or the keyboard.
9
+ ```javascript
10
+ await testdriver.scroll('down', { amount: 1000 });
11
+ ```
10
12
 
11
- <Warning>
12
- **Focus Requirements**
13
-
14
- A scroll needs focus on the page or on a frame. If an input field or another interactive element has focus, scroll commands can fail. Before you scroll, put the focus on the page:
15
- - Click a non-interactive area (for example, the page background)
16
- - Push the Escape key to remove the focus from interactive elements
17
- - Click outside of input fields or text areas
18
-
19
- **If the scroll still does not work**, use the Page Down or Page Up keys directly:
20
- ```javascript
21
- await testdriver.pressKeys(['pagedown']); // Scroll down
22
- await testdriver.pressKeys(['pageup']); // Scroll up
23
- ```
24
- </Warning>
13
+ If the page doesn't move, click somewhere on it first to give it focus.
25
14
 
26
- ## Syntax
15
+ ## Signature
27
16
 
28
- ```javascript
29
- await testdriver.scroll(direction, options)
17
+ ```typescript
18
+ testdriver.scroll(direction?: 'up' | 'down', options?: { amount?: number }): Promise<void>
30
19
  ```
31
20
 
32
21
  ## Parameters
33
22
 
34
- <ParamField path="direction" type="string" default="down">
35
- Direction to scroll: `'up'`, `'down'`
23
+ <ParamField path="direction" type="'up' | 'down'" default="down">
24
+ Which way to scroll. `'left'` and `'right'` aren't supported: TestDriver logs an error and doesn't scroll.
36
25
  </ParamField>
37
26
 
38
27
  <ParamField path="options" type="object">
39
28
  <Expandable title="properties">
40
29
  <ParamField path="amount" type="number" default="300">
41
- Amount to scroll in pixels
30
+ How far to scroll. Larger values scroll further.
42
31
  </ParamField>
43
32
  </Expandable>
44
33
  </ParamField>
45
34
 
46
- ## Returns
35
+ ## Errors
47
36
 
48
- `Promise<void>`
37
+ Throws an error if `direction` isn't `'up'`, `'down'`, `'left'` or `'right'`.
49
38
 
50
- ## Examples
39
+ If the screen doesn't change after the scroll, TestDriver logs a warning instead of throwing. This usually means the page didn't have focus.
40
+
41
+ ## Scroll until text appears
51
42
 
52
- ### Basic Scrolling
43
+ `testdriver.scrollUntilText()` scrolls in steps until it finds some text on screen:
53
44
 
54
45
  ```javascript
55
- // Scroll down (default)
56
- await testdriver.scroll();
46
+ await testdriver.scrollUntilText({ text: 'Privacy policy' });
47
+ await testdriver.find('Privacy policy link in the footer').click();
48
+ ```
57
49
 
58
- // Scroll down 5 clicks
59
- await testdriver.scroll('down', { amount: 5 });
50
+ <ParamField path="options" type="object" required>
51
+ <Expandable title="properties">
52
+ <ParamField path="text" type="string" required>
53
+ The text to look for.
54
+ </ParamField>
55
+ <ParamField path="direction" type="'up' | 'down'" default="down">
56
+ Which way to scroll.
57
+ </ParamField>
58
+ <ParamField path="maxDistance" type="number" default="10000">
59
+ How far to scroll in total before giving up. Each step scrolls 500.
60
+ </ParamField>
61
+ <ParamField path="invert" type="boolean" default="false">
62
+ Scroll until the text is no longer on screen.
63
+ </ParamField>
64
+ </Expandable>
65
+ </ParamField>
60
66
 
61
- // Scroll up
62
- await testdriver.scroll('up');
67
+ It throws an error if the text doesn't appear within `maxDistance`. `testdriver.scrollUntilImage({ description })` works the same way for an image you describe.
63
68
 
64
- // Scroll up 2 clicks
65
- await testdriver.scroll('up', { amount: 2 });
66
- ```
69
+ ## Examples
67
70
 
68
- ### Horizontal Scrolling
71
+ ### Focus the page, then scroll
69
72
 
70
73
  ```javascript
71
- // Scroll right
72
- await testdriver.scroll('right', { amount: 3 });
73
-
74
- // Scroll left
75
- await testdriver.scroll('left', { amount: 3 });
74
+ await testdriver.find('the page heading').click();
75
+ await testdriver.scroll('down', { amount: 1000 });
76
76
  ```
77
77
 
78
- ### Scroll Methods
78
+ ### Load more results in an infinite list
79
79
 
80
80
  ```javascript
81
- // Mouse wheel scroll (default)
82
- await testdriver.scroll('down', { amount: 3 });
83
-
84
- // For keyboard-based scrolling, use pressKeys instead
85
- await testdriver.pressKeys(['pagedown']);
81
+ for (let i = 0; i < 3; i++) {
82
+ await testdriver.scroll('down', { amount: 1000 });
83
+ }
84
+ await testdriver.assert('more than 20 results are listed');
86
85
  ```
87
86
 
88
- ## Best Practices
89
-
90
- <Check>
91
- **Make sure that the page has focus before you scroll**
92
-
93
- ```javascript
94
- // After typing in an input, unfocus it first
95
- await testdriver.find('email input').click();
96
- await testdriver.type('user@example.com');
97
-
98
- // Click elsewhere or press Escape before scrolling
99
- await testdriver.pressKeys(['escape']);
100
- // Or click a non-interactive area
101
- // await testdriver.find('page background').click();
102
-
103
- // Now scroll will work properly
104
- await testdriver.scroll('down');
105
-
106
- // If scroll still doesn't work, use Page Down directly
107
- // await testdriver.pressKeys(['pagedown']);
108
- ```
109
- </Check>
110
-
111
- <Check>
112
- **Control the scroll distance with the options object**
113
-
114
- ```javascript
115
- // For web pages, mouse scroll works well
116
- await testdriver.scroll('down', { amount: 3 });
117
-
118
- // For desktop apps or when mouse doesn't work, use keyboard
119
- await testdriver.pressKeys(['pagedown']);
120
- ```
121
- </Check>
122
-
123
- <Warning>
124
- **The keyboard scroll uses Page Down and Page Up**
125
-
126
- A keyboard scroll usually moves one "page" each time. This can be more than the click amount that you set. It is more compatible than a mouse scroll, but it is less precise.
127
- </Warning>
128
-
129
- ## Use Cases
130
-
131
- <AccordionGroup>
132
- <Accordion title="Infinite Scroll">
133
- ```javascript
134
- // Scroll multiple times for infinite scroll
135
- for (let i = 0; i < 5; i++) {
136
- await testdriver.scroll('down', { amount: 5 });
137
- await new Promise(r => setTimeout(r, 1000)); // Wait for load
138
- }
139
- ```
140
- </Accordion>
141
-
142
- <Accordion title="Horizontal Gallery">
143
- ```javascript
144
- // Navigate horizontal carousel
145
- await testdriver.scroll('right', { amount: 3 });
146
- await new Promise(r => setTimeout(r, 500));
147
-
148
- const nextImage = await testdriver.find('next image in carousel');
149
- await nextImage.click();
150
- ```
151
- </Accordion>
152
- </AccordionGroup>
153
-
154
- ## Complete Example
87
+ ### Use the keyboard instead
88
+
89
+ Some apps don't respond to the mouse wheel. Press Page Down with [`pressKeys()`](/press-keys):
155
90
 
156
91
  ```javascript
157
- import { beforeAll, afterAll, describe, it } from 'vitest';
158
- import TestDriver from 'testdriverai';
92
+ await testdriver.pressKeys(['pagedown']);
93
+ ```
159
94
 
160
- describe('Scrolling', () => {
161
- let testdriver;
95
+ ## Complete example
162
96
 
163
- beforeAll(async () => {
164
- client = new TestDriver(process.env.TD_API_KEY);
165
- await testdriver.auth();
166
- await testdriver.connect();
167
- });
97
+ ```javascript tests/scroll.test.mjs
98
+ import { describe, expect, it } from 'vitest';
99
+ import { TestDriver } from 'testdriverai/vitest/hooks';
168
100
 
169
- afterAll(async () => {
170
- await testdriver.disconnect();
171
- });
101
+ describe('Scroll', () => {
102
+ it('scrolls the heading out of view', async (context) => {
103
+ const testdriver = TestDriver(context);
104
+ await testdriver.provision.chrome({ url: 'https://www.webhamster.com/' });
172
105
 
173
- it('should scroll to find elements', async () => {
174
- await testdriver.focusApplication('Google Chrome');
175
-
176
- // Scroll down the page
177
- await testdriver.scroll('down', { amount: 5 });
178
-
179
- // Click footer link
180
- const privacyLink = await testdriver.find('Privacy Policy link');
181
- await privacyLink.click();
182
-
183
- await testdriver.assert('privacy policy page is displayed');
184
- });
106
+ // Click the page so it has focus before scrolling
107
+ await testdriver.find('The Hamster Dance, large heading at the top of the page').click();
108
+ await testdriver.scroll('down', { amount: 1000 });
185
109
 
186
- it('should handle infinite scroll', async () => {
187
- await testdriver.focusApplication('Google Chrome');
188
-
189
- // Scroll multiple times to load content
190
- for (let i = 0; i < 3; i++) {
191
- await testdriver.scroll('down', { amount: 5 });
192
- await new Promise(r => setTimeout(r, 1500)); // Wait for load
193
- }
194
-
195
- // Verify content loaded
196
- await testdriver.assert('more than 10 items are visible');
110
+ const result = await testdriver.assert(
111
+ "the text 'The Hamster Dance' isn't visible in the page content",
112
+ );
113
+ expect(result).toBe(true);
197
114
  });
198
115
  });
199
116
  ```
200
117
 
201
- ## Related Methods
118
+ ## Related
202
119
 
203
- - [`find()`](/find) - Find elements after a scroll
204
- - [`pressKeys()`](/press-keys) - Use the Page Down and Page Up keys
205
- - [`wait()`](/wait) - Wait after a scroll
120
+ - [pressKeys()](/press-keys): scroll with Page Down, Home and End
121
+ - [find()](/find): locate an element after scrolling to it
122
+ - [Perform actions](/performing-actions): every kind of action in one guide
@@ -1,115 +1,119 @@
1
1
  ---
2
2
  name: testdriver:secrets
3
- description: Securely manage passwords and sensitive data in your tests
3
+ description: Keep passwords and tokens out of your test code and TestDriver's logs.
4
4
  ---
5
5
  <!-- Generated from secrets.mdx. DO NOT EDIT. -->
6
6
 
7
- Protect sensitive information such as passwords, API keys, and tokens in your TestDriver tests.
7
+ Store credentials outside your code, and mark them as secret when you type them.
8
8
 
9
- ## Typing Secrets Securely
9
+ - Read passwords and tokens from environment variables, never from the test file.
10
+ - Type them with `secret: true` so TestDriver doesn't log or store them.
10
11
 
11
- When you type sensitive information such as passwords, use the `secret: true` option. This stops TestDriver from a log or a store of the value:
12
+ ## Type a secret
12
13
 
13
- ```javascript
14
- import { test } from 'vitest';
15
- import { chrome } from 'testdriverai/presets';
14
+ Pass `{ secret: true }` to [`type()`](/type) for any sensitive value. Click the field first, then type:
16
15
 
17
- test('login with secure password', async (context) => {
18
- const { testdriver } = await chrome(context, {
19
- url: 'https://myapp.com/login'
20
- });
16
+ ```javascript tests/login.test.mjs
17
+ import { expect, it } from 'vitest';
18
+ import { TestDriver } from 'testdriverai/vitest/hooks';
21
19
 
22
- await testdriver.find('email input').click();
23
- await testdriver.type(process.env.TD_USERNAME);
24
-
25
- await testdriver.find('password input').click();
26
- // Password is masked in logs and recordings
27
- await testdriver.type(process.env.TD_PASSWORD, { secret: true });
28
-
29
- await testdriver.find('login button').click();
30
- await testdriver.assert('dashboard is visible');
20
+ it('signs in', async (context) => {
21
+ const testdriver = TestDriver(context);
22
+ await testdriver.provision.chrome({ url: `${process.env.APP_URL}/login` });
23
+
24
+ const usernameField = await testdriver.find('Username input field');
25
+ await usernameField.click();
26
+ await testdriver.type(process.env.TEST_USERNAME);
27
+
28
+ const passwordField = await testdriver.find('Password input field');
29
+ await passwordField.click();
30
+ await testdriver.type(process.env.TEST_PASSWORD, { secret: true });
31
+
32
+ const signInButton = await testdriver.find('Sign in button below the password field');
33
+ await signInButton.click();
34
+
35
+ const result = await testdriver.assert('the dashboard is visible');
36
+ expect(result).toBe(true);
31
37
  });
32
38
  ```
33
39
 
34
- <Note>
35
- When you set `secret: true`, the typed text shows as `****` in all logs, recordings, and dashcam output.
36
- </Note>
40
+ ## What `secret: true` hides
37
41
 
38
- ## Storing Secrets in GitHub
42
+ With `secret: true`, TestDriver replaces the text with `****`:
39
43
 
40
- Store sensitive credentials as GitHub repository secrets. Then they are never in your code:
44
+ - In the SDK's console output.
45
+ - In the record of the action that TestDriver stores for the test run.
41
46
 
42
- <Steps>
43
- <Step title="Navigate to Repository Settings">
44
- Go to your GitHub repository → **Settings** → **Secrets and variables** → **Actions**
45
- </Step>
46
- <Step title="Add Repository Secrets">
47
- Click **New repository secret** and add your secrets:
48
- - `TD_API_KEY` - Your TestDriver API key
49
- - `TD_USERNAME` - Test account username
50
- - `TD_PASSWORD` - Test account password
51
- </Step>
52
- <Step title="Use in GitHub Actions">
53
- Reference secrets in your workflow file:
54
- ```yaml .github/workflows/test.yml
55
- - name: Run TestDriver tests
56
- env:
57
- TD_API_KEY: ${{ secrets.TD_API_KEY }}
58
- TD_USERNAME: ${{ secrets.TD_USERNAME }}
59
- TD_PASSWORD: ${{ secrets.TD_PASSWORD }}
60
- run: vitest run
61
- ```
62
- </Step>
63
- </Steps>
47
+ The text is still typed into the sandbox, so `secret: true` can't hide what the screen shows. If the field displays its contents, the value appears in the [Dashcam](/dashcam) recording and in screenshots. Password fields usually mask what you type, but plain text fields don't.
48
+
49
+ <Warning>
50
+ With [`autoScreenshots`](/options#param-auto-screenshots) on, screenshot file names include the first characters of the typed text, even when `secret` is `true`. Leave `autoScreenshots` off in tests that type secrets.
51
+ </Warning>
64
52
 
65
- ## Local Development
53
+ ## Store secrets locally
66
54
 
67
- For local development, store secrets in a `.env` file:
55
+ TestDriver loads a `.env` file in your project root automatically. Put your local credentials there:
68
56
 
69
57
  ```bash .env
70
- TD_API_KEY=your_api_key_here
71
- TD_USERNAME=testuser@example.com
72
- TD_PASSWORD=your_secure_password
58
+ TD_API_KEY=your_api_key
59
+ APP_URL=https://staging.example.com
60
+ TEST_USERNAME=qa@example.com
61
+ TEST_PASSWORD=your_test_password
73
62
  ```
74
63
 
75
- <Warning>
76
- Never commit `.env` files to version control. Add `.env` to your `.gitignore` file.
77
- </Warning>
64
+ Add `.env` to `.gitignore` so it's never committed:
78
65
 
79
- ## Complete Example
80
-
81
- Here's a full login test with proper secrets handling:
82
-
83
- ```javascript tests/login.test.js
84
- import { test, expect } from 'vitest';
85
- import { chrome } from 'testdriverai/presets';
86
-
87
- test('secure login flow', async (context) => {
88
- const { testdriver } = await chrome(context, {
89
- url: process.env.TD_WEBSITE || 'https://staging.myapp.com'
90
- });
91
-
92
- // Enter username (not sensitive)
93
- await testdriver.find('email input').click();
94
- await testdriver.type(process.env.TD_USERNAME);
95
-
96
- // Enter password securely
97
- await testdriver.find('password input').click();
98
- await testdriver.type(process.env.TD_PASSWORD, { secret: true });
99
-
100
- // Submit login
101
- await testdriver.find('login button').click();
102
-
103
- // Verify successful login
104
- const loggedIn = await testdriver.assert('user is logged in');
105
- expect(loggedIn).toBeTruthy();
106
- });
66
+ ```bash .gitignore
67
+ .env
107
68
  ```
108
69
 
109
- <Card title="Secrets Best Practices" icon="shield-check">
110
- - **Always use `secret: true`** when typing passwords, tokens, or sensitive data
111
- - **Use environment variables** to keep secrets out of code
112
- - **Store secrets in your CI provider** (GitHub Actions, GitLab CI, etc.)
113
- - **Never commit secrets** to version control
114
- - **Rotate secrets regularly** to maintain security
115
- </Card>
70
+ ## Store secrets in CI
71
+
72
+ In GitHub Actions, store each credential as a repository secret:
73
+
74
+ <Steps>
75
+ <Step title="Open your repository's secrets">
76
+ In GitHub, go to **Settings** > **Secrets and variables** > **Actions**.
77
+ </Step>
78
+ <Step title="Add each secret">
79
+ Click **New repository secret** and add `TEST_USERNAME` and `TEST_PASSWORD`.
80
+ </Step>
81
+ <Step title="Pass them to the test step">
82
+ Map the secrets to environment variables in your workflow:
83
+
84
+ ```yaml .github/workflows/testdriver.yml
85
+ - name: Run TestDriver tests
86
+ run: npx vitest run
87
+ env:
88
+ APP_URL: https://staging.example.com
89
+ TEST_USERNAME: ${{ secrets.TEST_USERNAME }}
90
+ TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}
91
+ ```
92
+ </Step>
93
+ </Steps>
94
+
95
+ You don't need to store your TestDriver API key this way. The `testdriverai/action` step authenticates with GitHub OIDC. See [Run in CI/CD](/ci-cd) for the full workflow.
96
+
97
+ ## Checklist
98
+
99
+ - Type passwords, tokens, and other sensitive values with `secret: true`.
100
+ - Read credentials from environment variables, not from the test file.
101
+ - Keep `.env` out of version control.
102
+ - Use test accounts with only the access your tests need.
103
+
104
+ ## Next steps
105
+
106
+ <CardGroup cols={2}>
107
+ <Card title="Use variables and test data" icon="square-root-variable" href="/variables">
108
+ Drive tests with environment variables and fixtures.
109
+ </Card>
110
+ <Card title="type()" icon="keyboard" href="/type">
111
+ Every option for typing text.
112
+ </Card>
113
+ <Card title="Run in CI/CD" icon="code-branch" href="/ci-cd">
114
+ Authenticate and run tests in your pipeline.
115
+ </Card>
116
+ <Card title="Reuse code" icon="recycle" href="/reusable-code">
117
+ Put your login steps in a shared helper.
118
+ </Card>
119
+ </CardGroup>