@testdriverai/agent 7.11.240-test → 7.11.241-test

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,249 +1,145 @@
1
1
  ---
2
2
  name: testdriver:reusable-code
3
- description: Build maintainable test suites with reusable code patterns
3
+ description: Share login steps and other common flows between tests with helpers and page objects.
4
4
  ---
5
5
  <!-- Generated from reusable-code.mdx. DO NOT EDIT. -->
6
6
 
7
- When your test suite becomes larger, put the common patterns into reusable code. This keeps the tests short, easy to read, and easy to keep.
8
-
9
- ## Helper Functions
10
-
11
- The most simple method is to put the common actions into helper functions. Make a `helpers/` directory for the shared utilities:
12
-
13
- ```javascript test/helpers/auth.js
14
- export async function login(testdriver, { email, password }) {
15
- const emailInput = await testdriver.find('email input');
16
- await emailInput.click();
17
- await testdriver.type(email);
18
-
19
- const passwordInput = await testdriver.find('password input');
20
- await passwordInput.click();
21
- await testdriver.type(password);
22
-
23
- const loginButton = await testdriver.find('login button');
24
- await loginButton.click();
25
-
26
- const result = await testdriver.assert('user is logged in');
27
- return result;
28
- }
7
+ When several tests repeat the same steps, move those steps into shared code.
29
8
 
30
- export async function logout(testdriver) {
31
- const userMenu = await testdriver.find('user menu');
32
- await userMenu.click();
33
-
34
- const logoutButton = await testdriver.find('logout button');
35
- await logoutButton.click();
36
- }
37
- ```
9
+ - **Helper functions** wrap one flow, such as signing in.
10
+ - **Page objects** group every action for one screen in a class.
11
+
12
+ Both are plain JavaScript modules. They take the `testdriver` client as an argument, so they work in any test.
38
13
 
39
- <Warning>
40
- **Do not put dynamic values in element descriptions.** An element selector must describe the *type* of the element. It must not describe specific content that can change.
14
+ ## Write a helper function
41
15
 
42
- **❌ Bad:** `await testdriver.find('profile name TestDriver in the top right')`
43
- **✅ Good:** `await testdriver.find('user profile name in the top right')`
16
+ Put the shared steps in a function that takes the client. This helper signs in to the TestDriver demo store:
44
17
 
45
- Hardcoded values like usernames, product names, or prices will cause tests to fail when the data changes. Use generic descriptions that work regardless of the specific content displayed.
46
- </Warning>
18
+ ```javascript tests/helpers/auth.js
19
+ export async function signIn(testdriver, username = 'standard_user') {
20
+ const usernameField = await testdriver.find('Username input field');
21
+ await usernameField.click();
22
+ await testdriver.type(username);
47
23
 
48
- Now import and use these helpers in any test:
24
+ // The demo store shows its password on the login page
25
+ const password = await testdriver.extract('the password shown on the login page');
49
26
 
50
- ```javascript test/checkout.test.mjs
51
- import { describe, expect, it } from "vitest";
52
- import { TestDriver } from "testdriverai/vitest/hooks";
53
- import { login } from './helpers/auth.js';
27
+ const passwordField = await testdriver.find('Password input field');
28
+ await passwordField.click();
29
+ await testdriver.type(password, { secret: true });
30
+
31
+ const signInButton = await testdriver.find('Sign in button below the password field');
32
+ await signInButton.click();
33
+ }
34
+ ```
54
35
 
55
- describe("Checkout", () => {
56
- it("should complete checkout as logged in user", async (context) => {
57
- const testdriver = TestDriver(context);
58
-
59
- await testdriver.provision.chrome({
60
- url: 'https://shop.example.com',
61
- });
36
+ Import it and call it with your test's client:
62
37
 
63
- // Use the helper
64
- await login(testdriver, {
65
- email: 'user@example.com',
66
- password: 'password123'
67
- });
38
+ ```javascript tests/cart.test.mjs
39
+ import { expect, it } from 'vitest';
40
+ import { TestDriver } from 'testdriverai/vitest/hooks';
41
+ import { signIn } from './helpers/auth.js';
68
42
 
69
- // Continue with checkout steps...
70
- const cartButton = await testdriver.find('cart button');
71
- await cartButton.click();
72
- });
43
+ it('shows an empty cart after signing in', async (context) => {
44
+ const testdriver = TestDriver(context);
45
+ await testdriver.provision.chrome({ url: 'https://testdriver-sandbox.vercel.app/login' });
46
+
47
+ await signIn(testdriver);
48
+
49
+ const cartIcon = await testdriver.find('Shopping cart icon in the top right corner');
50
+ await cartIcon.click();
51
+
52
+ const result = await testdriver.assert('the cart is empty');
53
+ expect(result).toBe(true);
73
54
  });
74
55
  ```
75
56
 
76
- ## Page Objects
57
+ Pass values that change between tests, like the username, as arguments. Keep them out of the descriptions you pass to [`find()`](/find), so the [cache](/caching) can match them on every run.
77
58
 
78
- For larger test suites, the Page Object pattern encapsulates all interactions with a specific page or component:
59
+ ## Group actions with a page object
79
60
 
80
- ```javascript test/pages/LoginPage.js
61
+ A page object is a class with one method per action on a screen. Use one when many tests work with the same screen.
62
+
63
+ ```javascript tests/pages/login-page.js
81
64
  export class LoginPage {
82
65
  constructor(testdriver) {
83
- this.td = testdriver;
66
+ this.testdriver = testdriver;
84
67
  }
85
68
 
86
- async enterEmail(email) {
87
- const input = await this.td.find('email input');
88
- await input.click();
89
- await this.td.type(email);
69
+ async enterUsername(username) {
70
+ const usernameField = await this.testdriver.find('Username input field');
71
+ await usernameField.click();
72
+ await this.testdriver.type(username);
90
73
  }
91
74
 
92
75
  async enterPassword(password) {
93
- const input = await this.td.find('password input');
94
- await input.click();
95
- await this.td.type(password);
76
+ const passwordField = await this.testdriver.find('Password input field');
77
+ await passwordField.click();
78
+ await this.testdriver.type(password, { secret: true });
96
79
  }
97
80
 
98
81
  async submit() {
99
- const button = await this.td.find('submit button');
100
- await button.click();
82
+ const signInButton = await this.testdriver.find('Sign in button below the password field');
83
+ await signInButton.click();
101
84
  }
85
+ }
86
+ ```
102
87
 
103
- async login(email, password) {
104
- await this.enterEmail(email);
105
- await this.enterPassword(password);
106
- await this.submit();
107
- }
88
+ ```javascript tests/login.test.mjs
89
+ import { expect, it } from 'vitest';
90
+ import { TestDriver } from 'testdriverai/vitest/hooks';
91
+ import { LoginPage } from './pages/login-page.js';
108
92
 
109
- async assertError(message) {
110
- return await this.td.assert(`error message shows "${message}"`);
111
- }
93
+ it('asks for a password when it is missing', async (context) => {
94
+ const testdriver = TestDriver(context);
95
+ await testdriver.provision.chrome({ url: 'https://testdriver-sandbox.vercel.app/login' });
112
96
 
113
- async assertLoggedIn() {
114
- return await this.td.assert('user dashboard is visible');
115
- }
116
- }
117
- ```
97
+ const loginPage = new LoginPage(testdriver);
98
+ await loginPage.enterUsername('standard_user');
99
+ await loginPage.submit();
118
100
 
119
- Use the page object in your tests:
120
-
121
- ```javascript test/auth.test.mjs
122
- import { describe, expect, it } from "vitest";
123
- import { TestDriver } from "testdriverai/vitest/hooks";
124
- import { LoginPage } from './pages/LoginPage.js';
125
-
126
- describe("Authentication", () => {
127
- it("should show error for invalid credentials", async (context) => {
128
- const testdriver = TestDriver(context);
129
-
130
- await testdriver.provision.chrome({
131
- url: 'https://app.example.com/login',
132
- });
133
-
134
- const loginPage = new LoginPage(testdriver);
135
-
136
- await loginPage.login('invalid@test.com', 'wrongpassword');
137
-
138
- const hasError = await loginPage.assertError('Invalid credentials');
139
- expect(hasError).toBeTruthy();
140
- });
141
-
142
- it("should redirect to dashboard on success", async (context) => {
143
- const testdriver = TestDriver(context);
144
-
145
- await testdriver.provision.chrome({
146
- url: 'https://app.example.com/login',
147
- });
148
-
149
- const loginPage = new LoginPage(testdriver);
150
-
151
- await loginPage.login('valid@test.com', 'correctpassword');
152
-
153
- const isLoggedIn = await loginPage.assertLoggedIn();
154
- expect(isLoggedIn).toBeTruthy();
155
- });
101
+ const result = await testdriver.assert('a "Please fill out this field" message is visible near the password field');
102
+ expect(result).toBe(true);
156
103
  });
157
104
  ```
158
105
 
159
- ## Shared Test Fixtures
160
-
161
- Create reusable fixtures for common test setup scenarios:
162
-
163
- ```javascript test/fixtures/index.js
164
- export const testUsers = {
165
- admin: { email: 'admin@example.com', password: 'admin123' },
166
- regular: { email: 'user@example.com', password: 'user123' },
167
- guest: { email: 'guest@example.com', password: 'guest123' },
168
- };
169
-
170
- export const testUrls = {
171
- staging: 'https://staging.example.com',
172
- production: 'https://example.com',
173
- };
174
-
175
- export async function setupAuthenticatedSession(testdriver, user = testUsers.regular) {
176
- const emailInput = await testdriver.find('email input');
177
- await emailInput.click();
178
- await testdriver.type(user.email);
179
-
180
- const passwordInput = await testdriver.find('password input');
181
- await passwordInput.click();
182
- await testdriver.type(user.password);
183
-
184
- const loginButton = await testdriver.find('login button');
185
- await loginButton.click();
186
-
187
- await testdriver.assert('user is logged in');
188
- }
189
- ```
106
+ Start with helper functions. Move to page objects when several tests repeat the same actions on one screen.
190
107
 
191
- ```javascript test/admin.test.mjs
192
- import { describe, expect, it } from "vitest";
193
- import { TestDriver } from "testdriverai/vitest/hooks";
194
- import { testUsers, testUrls, setupAuthenticatedSession } from './fixtures/index.js';
195
-
196
- describe("Admin Panel", () => {
197
- it("should access admin settings", async (context) => {
198
- const testdriver = TestDriver(context);
199
-
200
- await testdriver.provision.chrome({
201
- url: `${testUrls.staging}/login`,
202
- });
203
-
204
- await setupAuthenticatedSession(testdriver, testUsers.admin);
205
-
206
- const settingsLink = await testdriver.find('admin settings link');
207
- await settingsLink.click();
208
-
209
- const result = await testdriver.assert('admin settings panel is visible');
210
- expect(result).toBeTruthy();
211
- });
212
- });
213
- ```
108
+ ## Organize your files
214
109
 
215
- ## Suggested Project Structure
110
+ A layout that keeps shared code apart from tests:
216
111
 
217
112
  <FileTree>
218
- <Folder name="test" defaultOpen>
219
- <Folder name="fixtures" defaultOpen>
220
- <File name="index.js" />
221
- </Folder>
113
+ <Folder name="tests" defaultOpen>
222
114
  <Folder name="helpers" defaultOpen>
223
115
  <File name="auth.js" />
224
- <File name="navigation.js" />
225
- <File name="forms.js" />
226
116
  </Folder>
227
117
  <Folder name="pages" defaultOpen>
228
- <File name="LoginPage.js" />
229
- <File name="DashboardPage.js" />
230
- <File name="CheckoutPage.js" />
118
+ <File name="login-page.js" />
231
119
  </Folder>
232
- <Folder name="specs" defaultOpen>
233
- <File name="auth.test.mjs" />
234
- <File name="checkout.test.mjs" />
235
- <File name="search.test.mjs" />
120
+ <Folder name="fixtures" defaultOpen>
121
+ <File name="usernames.js" />
236
122
  </Folder>
123
+ <File name="cart.test.mjs" />
124
+ <File name="login.test.mjs" />
237
125
  </Folder>
238
126
  </FileTree>
239
127
 
240
- | Folder | Purpose |
241
- |--------|---------|
242
- | `fixtures/` | Test data and setup utilities |
243
- | `helpers/` | Reusable helper functions |
244
- | `pages/` | Page object classes |
245
- | `specs/` | Test files |
246
-
247
- <Tip>
248
- Start simple with helper functions. Only introduce page objects when you find yourself duplicating the same element interactions across multiple tests.
249
- </Tip>
128
+ By default, Vitest runs only files named `*.test.*` or `*.spec.*`, so helpers, page objects, and [fixtures](/variables#reuse-test-data-with-fixtures) aren't run as tests.
129
+
130
+ ## Next steps
131
+
132
+ <CardGroup cols={2}>
133
+ <Card title="Use variables and test data" icon="square-root-variable" href="/variables">
134
+ Feed helpers with environment variables and fixtures.
135
+ </Card>
136
+ <Card title="Use secrets" icon="key" href="/secrets">
137
+ Keep the credentials your helpers type out of logs.
138
+ </Card>
139
+ <Card title="Locate elements" icon="crosshairs" href="/locating-elements">
140
+ Write descriptions that find the right element.
141
+ </Card>
142
+ <Card title="Click an icon example" icon="mouse-pointer" href="/examples/click-icon">
143
+ A complete test that uses a login helper.
144
+ </Card>
145
+ </CardGroup>
@@ -1,123 +1,80 @@
1
1
  ---
2
2
  name: testdriver:right-click
3
- description: Perform a right-click action to open context menus
3
+ description: Right-click an element you found, usually to open a context menu.
4
4
  ---
5
5
  <!-- Generated from right-click.mdx. DO NOT EDIT. -->
6
6
 
7
- ## Overview
8
-
9
- The `rightClick()` method does a right-click action on an element. It usually opens context menus. You can call it on an [`Element`](/core-concepts/elements) instance. Or you can use it with a selector.
10
-
11
- ## Syntax
7
+ Right-click an element you've located with [`find()`](/find), then pick an item from the menu that opens:
12
8
 
13
9
  ```javascript
14
- // Right-click on an element
15
- await element.rightClick();
16
-
17
- // Right-click using a selector
18
- await ai.rightClick('selector');
10
+ await testdriver.find('report.pdf in the file list').rightClick();
11
+ await testdriver.find('Rename in the context menu').click();
19
12
  ```
20
13
 
21
- ## Parameters
14
+ ## element.rightClick()
22
15
 
23
- When called on an `Element`, no parameters are required.
16
+ Right-clicks the element at the point where `find()` located it. It's the same as `element.click('right-click')`.
24
17
 
25
- When called directly on the AI client:
18
+ ```typescript
19
+ element.rightClick(): Promise<void>
20
+ ```
26
21
 
27
- | Parameter | Type | Description |
28
- |-----------|------|-------------|
29
- | `selector` | `string` | The selector describing the element to right-click |
22
+ It takes no parameters.
30
23
 
31
- ## Returns
24
+ ### Errors
32
25
 
33
- It returns a `Promise<void>`. The promise resolves when the right-click action completes.
26
+ Throws an `ElementNotFoundError` if `find()` didn't locate the element. See [click()](/click#errors) for how to check `found()` first.
34
27
 
35
- ## Examples
28
+ ## Right-click at coordinates
36
29
 
37
- ### Right-Click to Open Context Menu
30
+ The client has no `rightClick()` method. To right-click a point on the screen, pass `action: 'right-click'` to [`testdriver.click()`](/click#testdriver-click-options):
38
31
 
39
32
  ```javascript
40
- const fileItem = await ai.find('README.md file');
41
- await fileItem.rightClick();
42
-
43
- // Select menu option
44
- await ai.click('Delete from context menu');
33
+ await testdriver.click({ x: 640, y: 360, action: 'right-click' });
45
34
  ```
46
35
 
47
- ### Direct Right-Click with Selector
36
+ Prefer `element.rightClick()`, which keeps working when the layout or screen size changes.
48
37
 
49
- ```javascript
50
- await ai.rightClick('image in the gallery');
51
- await ai.click('Save image as');
52
- ```
38
+ ## Examples
53
39
 
54
- ### VS Code Context Menu
40
+ ### Open a link in a new tab
55
41
 
56
42
  ```javascript
57
- import { test } from 'vitest';
58
- import { vscode } from '@testdriver/sdk';
59
-
60
- test('renames a file via context menu', async () => {
61
- const { ai } = await vscode();
62
-
63
- // Right-click on a file
64
- await ai.rightClick('test.js in the file explorer');
65
-
66
- // Click rename option
67
- await ai.click('Rename');
68
-
69
- // Type new name
70
- await ai.type('test.spec.js');
71
- await ai.pressKeys('Enter');
72
-
73
- // Verify rename
74
- const renamedFile = await ai.find('test.spec.js in the file explorer');
75
- expect(renamedFile).toBeTruthy();
76
- });
43
+ await testdriver.find('Documentation link in the page footer').rightClick();
44
+ await testdriver.find('Open link in new tab in the context menu').click();
77
45
  ```
78
46
 
79
- ### Browser Context Menu
47
+ ### Rename a file in VS Code
80
48
 
81
49
  ```javascript
82
- import { test } from 'vitest';
83
- import { chrome } from '@testdriver/sdk';
84
-
85
- test('opens link in new tab', async () => {
86
- const { ai } = await chrome('https://example.com');
87
-
88
- // Right-click on a link
89
- await ai.rightClick('Documentation link');
90
-
91
- // Select "Open in new tab"
92
- await ai.click('Open link in new tab');
93
- });
50
+ await testdriver.find('index.js in the Explorer sidebar').rightClick();
51
+ await testdriver.find('Rename in the context menu').click();
52
+ await testdriver.type('main.js');
53
+ await testdriver.pressKeys(['enter']);
94
54
  ```
95
55
 
96
- ### Custom Context Menu in Web App
56
+ ## Complete example
97
57
 
98
- ```javascript
99
- test('uses custom context menu', async () => {
100
- const { ai } = await chrome('https://app.example.com');
101
-
102
- // Right-click on custom element
103
- await ai.rightClick('project item in the list');
104
-
105
- // Wait for custom menu to appear
106
- await ai.find('custom context menu');
107
-
108
- // Click menu option
109
- await ai.click('Duplicate project');
110
-
111
- // Verify duplication
112
- const duplicatedProject = await ai.find('project item (copy)');
113
- expect(duplicatedProject).toBeTruthy();
58
+ ```javascript tests/context-menu.test.mjs
59
+ import { describe, expect, it } from 'vitest';
60
+ import { TestDriver } from 'testdriverai/vitest/hooks';
61
+
62
+ describe('Context menu', () => {
63
+ it('opens the browser context menu on the page', async (context) => {
64
+ const testdriver = TestDriver(context);
65
+ await testdriver.provision.chrome({ url: 'https://testdriver-sandbox.vercel.app/login' });
66
+
67
+ await testdriver.find('the page heading').rightClick();
68
+
69
+ const result = await testdriver.assert('a context menu with a "Back" item is open');
70
+ expect(result).toBe(true);
71
+ });
114
72
  });
115
73
  ```
116
74
 
117
- ## Related Methods
75
+ ## Related
118
76
 
119
- - [`click()`](/click) - Single click on an element
120
- - [`doubleClick()`](/double-click) - Double-click on an element
121
- - [`mouseDown()`](/mouse-down) - Press mouse button without releasing
122
- - [`mouseUp()`](/mouse-up) - Release mouse button
123
- - [`hover()`](/hover) - Move mouse over element without clicking
77
+ - [click()](/click): single clicks, and clicks at coordinates
78
+ - [doubleClick()](/double-click): open files and select words
79
+ - [find()](/find): locate the element to right-click
80
+ - [Perform actions](/performing-actions): every kind of action in one guide