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.
- package/.github/skills/testdriver:ai/SKILL.md +204 -0
- package/.github/skills/testdriver:assert/SKILL.md +284 -0
- package/.github/skills/testdriver:aws-setup/SKILL.md +515 -0
- package/.github/skills/testdriver:caching/SKILL.md +124 -0
- package/.github/skills/testdriver:captcha/SKILL.md +159 -0
- package/.github/skills/testdriver:ci-cd/SKILL.md +602 -0
- package/.github/skills/testdriver:click/SKILL.md +286 -0
- package/.github/skills/testdriver:client/SKILL.md +339 -0
- package/.github/skills/testdriver:cloud/SKILL.md +119 -0
- package/.github/skills/testdriver:customizing-devices/SKILL.md +153 -0
- package/.github/skills/testdriver:dashcam/SKILL.md +418 -0
- package/.github/skills/testdriver:debugging-with-screenshots/SKILL.md +271 -0
- package/.github/skills/testdriver:device-config/SKILL.md +317 -0
- package/.github/skills/testdriver:double-click/SKILL.md +102 -0
- package/.github/skills/testdriver:elements/SKILL.md +605 -0
- package/.github/skills/testdriver:enterprise/SKILL.md +114 -0
- package/.github/skills/testdriver:examples/SKILL.md +7 -0
- package/.github/skills/testdriver:exec/SKILL.md +345 -0
- package/.github/skills/testdriver:find/SKILL.md +721 -0
- package/.github/skills/testdriver:focus-application/SKILL.md +293 -0
- package/.github/skills/testdriver:generating-tests/SKILL.md +36 -0
- package/.github/skills/testdriver:hover/SKILL.md +278 -0
- package/.github/skills/testdriver:locating-elements/SKILL.md +71 -0
- package/.github/skills/testdriver:making-assertions/SKILL.md +32 -0
- package/.github/skills/testdriver:mcp-workflow/SKILL.md +410 -0
- package/.github/skills/testdriver:mouse-down/SKILL.md +161 -0
- package/.github/skills/testdriver:mouse-up/SKILL.md +164 -0
- package/.github/skills/testdriver:performing-actions/SKILL.md +51 -0
- package/.github/skills/testdriver:press-keys/SKILL.md +348 -0
- package/.github/skills/testdriver:quickstart/SKILL.md +161 -0
- package/.github/skills/testdriver:reusable-code/SKILL.md +240 -0
- package/.github/skills/testdriver:right-click/SKILL.md +123 -0
- package/.github/skills/testdriver:running-tests/SKILL.md +181 -0
- package/.github/skills/testdriver:screenshot/SKILL.md +167 -0
- package/.github/skills/testdriver:scroll/SKILL.md +299 -0
- package/.github/skills/testdriver:secrets/SKILL.md +115 -0
- package/.github/skills/testdriver:self-hosted/SKILL.md +65 -0
- package/.github/skills/testdriver:test-writer/SKILL.md +451 -0
- package/.github/skills/testdriver:testdriver/SKILL.md +523 -0
- package/.github/skills/testdriver:testdriver-mechanic/SKILL.md +165 -0
- package/.github/skills/testdriver:type/SKILL.md +357 -0
- package/.github/skills/testdriver:variables/SKILL.md +111 -0
- package/.github/skills/testdriver:waiting-for-elements/SKILL.md +66 -0
- package/.github/skills/testdriver:what-is-testdriver/SKILL.md +54 -0
- package/.github/workflows/acceptance-windows-scheduled.yaml +6 -1
- package/.github/workflows/acceptance.yaml +0 -36
- package/.github/workflows/update-examples.yaml +53 -0
- package/CHANGELOG.md +8 -0
- package/agent/events.js +1 -0
- package/agent/index.js +8 -0
- package/agent/lib/commands.js +48 -29
- package/agent/lib/redraw.js +3 -1
- package/agent/lib/sandbox.js +166 -14
- package/agent/lib/sdk.js +142 -3
- package/agent/lib/system.js +4 -6
- package/ai/skills/testdriver:ai/SKILL.md +204 -0
- package/ai/skills/testdriver:assert/SKILL.md +315 -0
- package/ai/skills/testdriver:aws-setup/SKILL.md +448 -0
- package/ai/skills/testdriver:caching/SKILL.md +124 -0
- package/ai/skills/testdriver:captcha/SKILL.md +159 -0
- package/ai/skills/testdriver:ci-cd/SKILL.md +602 -0
- package/ai/skills/testdriver:click/SKILL.md +286 -0
- package/ai/skills/testdriver:client/SKILL.md +372 -0
- package/ai/skills/testdriver:cloud/SKILL.md +119 -0
- package/ai/skills/testdriver:customizing-devices/SKILL.md +153 -0
- package/ai/skills/testdriver:dashcam/SKILL.md +418 -0
- package/ai/skills/testdriver:debugging-with-screenshots/SKILL.md +401 -0
- package/ai/skills/testdriver:device-config/SKILL.md +317 -0
- package/ai/skills/testdriver:double-click/SKILL.md +102 -0
- package/ai/skills/testdriver:elements/SKILL.md +605 -0
- package/ai/skills/testdriver:enterprise/SKILL.md +114 -0
- package/ai/skills/testdriver:examples/SKILL.md +7 -0
- package/ai/skills/testdriver:exec/SKILL.md +345 -0
- package/ai/skills/testdriver:find/SKILL.md +745 -0
- package/ai/skills/testdriver:focus-application/SKILL.md +293 -0
- package/ai/skills/testdriver:generating-tests/SKILL.md +36 -0
- package/ai/skills/testdriver:hover/SKILL.md +278 -0
- package/ai/skills/testdriver:locating-elements/SKILL.md +71 -0
- package/ai/skills/testdriver:making-assertions/SKILL.md +32 -0
- package/ai/skills/testdriver:mcp-workflow/SKILL.md +410 -0
- package/ai/skills/testdriver:mouse-down/SKILL.md +161 -0
- package/ai/skills/testdriver:mouse-up/SKILL.md +164 -0
- package/ai/skills/testdriver:ocr/SKILL.md +235 -0
- package/ai/skills/testdriver:performing-actions/SKILL.md +51 -0
- package/ai/skills/testdriver:press-keys/SKILL.md +348 -0
- package/ai/skills/testdriver:quickstart/SKILL.md +146 -0
- package/ai/skills/testdriver:reusable-code/SKILL.md +240 -0
- package/ai/skills/testdriver:right-click/SKILL.md +123 -0
- package/ai/skills/testdriver:running-tests/SKILL.md +185 -0
- package/ai/skills/testdriver:screenshot/SKILL.md +248 -0
- package/ai/skills/testdriver:scroll/SKILL.md +335 -0
- package/ai/skills/testdriver:secrets/SKILL.md +115 -0
- package/ai/skills/testdriver:self-hosted/SKILL.md +65 -0
- package/ai/skills/testdriver:test-writer/SKILL.md +451 -0
- package/ai/skills/testdriver:testdriver/SKILL.md +631 -0
- package/ai/skills/testdriver:testdriver-mechanic/SKILL.md +165 -0
- package/ai/skills/testdriver:type/SKILL.md +357 -0
- package/ai/skills/testdriver:variables/SKILL.md +111 -0
- package/ai/skills/testdriver:waiting-for-elements/SKILL.md +66 -0
- package/ai/skills/testdriver:what-is-testdriver/SKILL.md +54 -0
- package/debugger/index.html +12 -2
- package/docs/v7/examples/scroll-keyboard.mdx +1 -1
- package/docs/v7/find.mdx +1 -0
- package/examples/config.mjs +1 -1
- package/examples/findall-coffee-icons.test.mjs +42 -0
- package/examples/flake-diffthreshold-001.test.mjs +9 -0
- package/examples/flake-diffthreshold-01.test.mjs +9 -0
- package/examples/flake-diffthreshold-05.test.mjs +9 -0
- package/examples/{z_flake-noredraw-cache.test.mjs → flake-noredraw-cache.test.mjs} +2 -2
- package/examples/{z_flake-noredraw-nocache.test.mjs → flake-noredraw-nocache.test.mjs} +2 -2
- package/examples/{z_flake-redraw-cache.test.mjs → flake-redraw-cache.test.mjs} +2 -2
- package/examples/{z_flake-redraw-nocache.test.mjs → flake-redraw-nocache.test.mjs} +2 -2
- package/examples/flake-rocket-match.test.mjs +30 -0
- package/examples/{z_flake-shared.mjs → flake-shared.mjs} +2 -2
- package/examples/parse.test.mjs +19 -0
- package/examples/scroll-keyboard.test.mjs +1 -1
- package/interfaces/cli/lib/base.js +6 -0
- package/interfaces/logger.js +51 -13
- package/interfaces/vitest-plugin.mjs +137 -0
- package/lib/core/index.d.ts +22 -0
- package/lib/init-project.js +105 -6
- package/lib/vitest/hooks.mjs +2 -5
- package/lib/vitest/setup-disable-defender.mjs +52 -0
- package/package.json +2 -1
- package/sdk-log-formatter.js +90 -0
- package/sdk.d.ts +88 -51
- package/sdk.js +128 -21
- package/setup/aws/disable-defender.sh +42 -0
- package/vitest.config.mjs +1 -3
- package/examples/z_flake-diffthreshold-001.test.mjs +0 -9
- package/examples/z_flake-diffthreshold-01.test.mjs +0 -9
- package/examples/z_flake-diffthreshold-05.test.mjs +0 -9
- /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,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
|
+
```
|
|
@@ -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<string>" 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
|