@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.
- package/ai/skills/testdriver-agent/SKILL.md +174 -91
- package/ai/skills/testdriver-assert/SKILL.md +73 -269
- package/ai/skills/testdriver-aws-setup/SKILL.md +194 -312
- package/ai/skills/testdriver-bring-your-own-machine/SKILL.md +137 -204
- package/ai/skills/testdriver-cache/SKILL.md +142 -149
- package/ai/skills/testdriver-caching/SKILL.md +97 -87
- package/ai/skills/testdriver-captcha/SKILL.md +126 -111
- package/ai/skills/testdriver-ci-cd/SKILL.md +153 -542
- package/ai/skills/testdriver-click/SKILL.md +74 -229
- package/ai/skills/testdriver-client/SKILL.md +175 -229
- package/ai/skills/testdriver-customizing-devices/SKILL.md +72 -250
- package/ai/skills/testdriver-dashcam/SKILL.md +71 -404
- package/ai/skills/testdriver-debugging-with-screenshots/SKILL.md +103 -369
- package/ai/skills/testdriver-double-click/SKILL.md +46 -67
- package/ai/skills/testdriver-errors/SKILL.md +102 -176
- package/ai/skills/testdriver-events/SKILL.md +170 -327
- package/ai/skills/testdriver-exec/SKILL.md +92 -256
- package/ai/skills/testdriver-extract/SKILL.md +69 -170
- package/ai/skills/testdriver-find/SKILL.md +140 -736
- package/ai/skills/testdriver-focus-application/SKILL.md +69 -246
- package/ai/skills/testdriver-generating-tests/SKILL.md +102 -136
- package/ai/skills/testdriver-hosted/SKILL.md +79 -143
- package/ai/skills/testdriver-hover/SKILL.md +62 -235
- package/ai/skills/testdriver-locating-elements/SKILL.md +71 -366
- package/ai/skills/testdriver-making-assertions/SKILL.md +114 -72
- package/ai/skills/testdriver-mcp-setup/SKILL.md +79 -62
- package/ai/skills/testdriver-mouse-down/SKILL.md +46 -124
- package/ai/skills/testdriver-mouse-up/SKILL.md +45 -128
- package/ai/skills/testdriver-options/SKILL.md +73 -46
- package/ai/skills/testdriver-parse/SKILL.md +95 -184
- package/ai/skills/testdriver-performing-actions/SKILL.md +101 -91
- package/ai/skills/testdriver-press-keys/SKILL.md +59 -299
- package/ai/skills/testdriver-provision/SKILL.md +135 -179
- package/ai/skills/testdriver-quickstart/SKILL.md +24 -8
- package/ai/skills/testdriver-quickstart-claude/SKILL.md +84 -0
- package/ai/skills/testdriver-quickstart-github/SKILL.md +62 -32
- package/ai/skills/testdriver-quickstart-manual/SKILL.md +59 -32
- package/ai/skills/testdriver-quickstart-vscode/SKILL.md +96 -0
- package/ai/skills/testdriver-redraw/SKILL.md +100 -164
- package/ai/skills/testdriver-reusable-code/SKILL.md +95 -199
- package/ai/skills/testdriver-right-click/SKILL.md +45 -88
- package/ai/skills/testdriver-screenshot/SKILL.md +47 -201
- package/ai/skills/testdriver-screenshots/SKILL.md +86 -136
- package/ai/skills/testdriver-scroll/SKILL.md +71 -154
- package/ai/skills/testdriver-secrets/SKILL.md +94 -90
- package/ai/skills/testdriver-self-hosted/SKILL.md +82 -140
- package/ai/skills/testdriver-test-results-json/SKILL.md +165 -202
- package/ai/skills/testdriver-type/SKILL.md +56 -304
- package/ai/skills/testdriver-variables/SKILL.md +119 -80
- package/ai/skills/testdriver-wait/SKILL.md +31 -29
- package/ai/skills/testdriver-what-is-testdriver/SKILL.md +80 -32
- package/package.json +1 -1
|
@@ -1,155 +1,91 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: testdriver:hosted
|
|
3
|
-
description:
|
|
3
|
+
description: Run tests on TestDriver's cloud sandboxes, billed by testing minutes, with no infrastructure to manage.
|
|
4
4
|
---
|
|
5
5
|
<!-- Generated from hosted.mdx. DO NOT EDIT. -->
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
import { EnterpriseBadge, EnterpriseCta } from '/snippets/enterprise.mdx';
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- **Free Tier** — Start with a limited preview at no cost.
|
|
11
|
-
- **Pay As You Go** — Pay only for the device-seconds that you use.
|
|
9
|
+
By default, your tests run on TestDriver's cloud. Each test gets a fresh sandbox, and you don't manage any machines.
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
- Hosted is the default. When you follow the [Quickstart](/quickstart), you're using it.
|
|
12
|
+
- You're billed in **testing minutes**: the time a sandbox is running.
|
|
13
|
+
- Your plan sets how many sandboxes can run at the same time.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
## Plans
|
|
16
|
+
|
|
17
|
+
| | Free | Pro | Team |
|
|
18
|
+
| --- | --- | --- | --- |
|
|
19
|
+
| **Price** | $0 | $20 per seat per month | $600 per month |
|
|
20
|
+
| **Testing minutes included** | 30 | 120 | 10,000 |
|
|
21
|
+
| **Extra minutes** | Not available | $0.14 per minute | $0.14 per minute |
|
|
22
|
+
| **Sandboxes at once** | 2 | 4 | 8 |
|
|
23
|
+
| **Users** | Unlimited | One per seat | 5 |
|
|
24
|
+
| **Test analytics** | No | Yes | Yes |
|
|
25
|
+
| **CPU, RAM, and network profiles** | No | Yes | Yes |
|
|
26
|
+
| **Support** | Community | Community | Private |
|
|
27
|
+
|
|
28
|
+
<EnterpriseCta feature="Windows sandboxes, custom screen resolutions, and self-hosting" plural />
|
|
29
|
+
|
|
30
|
+
Pro starts with a 14-day free trial. Start a plan from the [TestDriver console](https://console.testdriver.ai/checkout/pro).
|
|
31
|
+
|
|
32
|
+
On the Free plan, new sandboxes are refused once you've used your 30 minutes. Upgrade to keep testing.
|
|
33
|
+
|
|
34
|
+
<Note>
|
|
35
|
+
If you install TestDriver from GitHub Marketplace, GitHub bills you instead. The **Open Source** plan is free with 300 testing minutes per month. The **Team** plan is $20 per seat per month with 120 testing minutes per seat.
|
|
36
|
+
</Note>
|
|
37
|
+
|
|
38
|
+
## How testing minutes are counted
|
|
39
|
+
|
|
40
|
+
Testing minutes run while a sandbox is running. That includes sandboxes started by:
|
|
41
|
+
|
|
42
|
+
- Your test runs, locally and in CI.
|
|
43
|
+
- The TestDriver agent, when it reviews a pull request or writes a test.
|
|
44
|
+
|
|
45
|
+
A sandbox kept running with [`keepAlive`](/customizing-devices#keep-a-sandbox-alive) uses minutes until it shuts down. Keep `keepAlive` as short as you need.
|
|
46
|
+
|
|
47
|
+
## Concurrency
|
|
48
|
+
|
|
49
|
+
Each running sandbox uses one of your plan's slots. A slot frees up when its sandbox shuts down.
|
|
50
|
+
|
|
51
|
+
When every slot is busy, a new test waits for a free slot instead of failing. The SDK retries every 10 seconds, for up to 60 seconds by default. Set `TD_CONCURRENCY_MAX_WAIT` to change the wait. See [Concurrency limits](/ci-cd#concurrency-limits).
|
|
52
|
+
|
|
53
|
+
To stay within your slots, limit how many test files Vitest runs at once:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npx vitest run --maxWorkers=4
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
In GitHub Actions, a `concurrency` group stops two runs on the same branch from competing for slots. A new push cancels the older run:
|
|
60
|
+
|
|
61
|
+
```yaml .github/workflows/testdriver.yml
|
|
62
|
+
concurrency:
|
|
63
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
64
|
+
cancel-in-progress: true
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## When to self-host
|
|
68
|
+
|
|
69
|
+
Consider [self-hosting](/self-hosted) when you need to:
|
|
70
|
+
|
|
71
|
+
- Run tests on your own infrastructure, without per-minute billing.
|
|
72
|
+
- Use your own AI provider keys.
|
|
73
|
+
- Run custom VM images with your software preinstalled.
|
|
74
|
+
- Run more tests in parallel than the hosted plans allow.
|
|
75
|
+
|
|
76
|
+
## Next steps
|
|
77
|
+
|
|
78
|
+
<CardGroup cols={2}>
|
|
79
|
+
<Card title="Quickstart" icon="play" href="/quickstart">
|
|
80
|
+
Run your first test on a hosted sandbox.
|
|
23
81
|
</Card>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
**$20/month per user**
|
|
27
|
-
|
|
28
|
-
- 2 Concurrent Sandboxes
|
|
29
|
-
- 120 Minutes Included
|
|
30
|
-
- Overage: $0.001/second
|
|
31
|
-
- Test Recordings
|
|
32
|
-
- Community Support
|
|
82
|
+
<Card title="Run tests in CI/CD" icon="code-branch" href="/ci-cd">
|
|
83
|
+
Run your tests on every push and pull request.
|
|
33
84
|
</Card>
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
- 10,000 Minutes Included
|
|
40
|
-
- Overage: $0.001/second
|
|
41
|
-
- 5 Team Users
|
|
42
|
-
- Test Recordings
|
|
43
|
-
- Private Support
|
|
44
|
-
- Test Analytics
|
|
45
|
-
- CPU, RAM, & Network Profiles
|
|
85
|
+
<Card title="Self-hosted" icon="server" href="/self-hosted">
|
|
86
|
+
Run sandboxes on your own infrastructure.
|
|
87
|
+
</Card>
|
|
88
|
+
<Card title="Run tests" icon="play" href="/copilot/running-tests">
|
|
89
|
+
Run tests locally and in parallel.
|
|
46
90
|
</Card>
|
|
47
91
|
</CardGroup>
|
|
48
|
-
|
|
49
|
-
## Get Started
|
|
50
|
-
Hosted is the default when you follow the Quickstart guide.
|
|
51
|
-
<Card
|
|
52
|
-
title="Try the Quickstart"
|
|
53
|
-
icon="play"
|
|
54
|
-
href="/quickstart"
|
|
55
|
-
>
|
|
56
|
-
Set your API key and start testing in minutes.
|
|
57
|
-
</Card>
|
|
58
|
-
|
|
59
|
-
## Parallel Testing Limits
|
|
60
|
-
|
|
61
|
-
Your account has a set number of **license slots** that determine how many devices can run simultaneously. You can view your available slots in the [TestDriver Dashboard](https://console.testdriver.ai).
|
|
62
|
-
|
|
63
|
-
<Info>
|
|
64
|
-
**When is a slot in use?** A license slot is occupied when a test client is connected. As soon as your device is destroyed the slot becomes available immediately.
|
|
65
|
-
</Info>
|
|
66
|
-
|
|
67
|
-
## Avoiding Slot Conflicts
|
|
68
|
-
|
|
69
|
-
To prevent tests from failing due to exceeding your license slot limit, we recommend two key configurations:
|
|
70
|
-
|
|
71
|
-
<AccordionGroup>
|
|
72
|
-
<Accordion title="Set Maximum Concurrency in Vitest">
|
|
73
|
-
Limit concurrent tests to match your available license slots:
|
|
74
|
-
|
|
75
|
-
```javascript vitest.config.mjs
|
|
76
|
-
import { defineConfig } from 'vitest/config';
|
|
77
|
-
import TestDriver from 'testdriverai/vitest';
|
|
78
|
-
|
|
79
|
-
export default defineConfig({
|
|
80
|
-
test: {
|
|
81
|
-
testTimeout: 900000,
|
|
82
|
-
hookTimeout: 900000,
|
|
83
|
-
maxConcurrency: 5, // Set to your license slot limit
|
|
84
|
-
reporters: ['default', TestDriver()],
|
|
85
|
-
setupFiles: ['testdriverai/vitest/setup'],
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
<Tip>
|
|
91
|
-
Check your slot count at [console.testdriver.ai](https://console.testdriver.ai) and set `maxConcurrency` to that number or lower.
|
|
92
|
-
</Tip>
|
|
93
|
-
</Accordion>
|
|
94
|
-
|
|
95
|
-
<Accordion title="Use GitHub Concurrency Keys">
|
|
96
|
-
Prevent multiple workflow runs from competing for the same slots by using [GitHub's concurrency controls](https://docs.github.com/actions/writing-workflows/choosing-what-your-workflow-does/control-the-concurrency-of-workflows-and-jobs):
|
|
97
|
-
|
|
98
|
-
```yaml .github/workflows/test.yml
|
|
99
|
-
name: Tests
|
|
100
|
-
|
|
101
|
-
on:
|
|
102
|
-
push:
|
|
103
|
-
branches: [main]
|
|
104
|
-
pull_request:
|
|
105
|
-
|
|
106
|
-
# Prevent concurrent runs from competing for license slots
|
|
107
|
-
concurrency:
|
|
108
|
-
group: ${{ github.workflow }}-${{ github.ref }}
|
|
109
|
-
cancel-in-progress: true
|
|
110
|
-
|
|
111
|
-
jobs:
|
|
112
|
-
test:
|
|
113
|
-
runs-on: ubuntu-latest
|
|
114
|
-
steps:
|
|
115
|
-
- uses: actions/checkout@v4
|
|
116
|
-
|
|
117
|
-
- name: Setup Node.js
|
|
118
|
-
uses: actions/setup-node@v4
|
|
119
|
-
with:
|
|
120
|
-
node-version: '20'
|
|
121
|
-
|
|
122
|
-
- name: Install dependencies
|
|
123
|
-
run: npm install
|
|
124
|
-
|
|
125
|
-
- name: Run tests
|
|
126
|
-
run: vitest run
|
|
127
|
-
env:
|
|
128
|
-
TD_API_KEY: ${{ secrets.TD_API_KEY }}
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
The `concurrency` block ensures:
|
|
132
|
-
- Only one workflow run per branch runs at a time
|
|
133
|
-
- New pushes cancel in-progress runs on the same branch
|
|
134
|
-
- Different branches/PRs can run in parallel (up to your slot limit)
|
|
135
|
-
</Accordion>
|
|
136
|
-
</AccordionGroup>
|
|
137
|
-
|
|
138
|
-
## When to Consider Self-Hosted
|
|
139
|
-
|
|
140
|
-
Hosted is perfect for getting started and for teams that want zero infrastructure management. However, you might consider [Self-Hosted](/self-hosted) if you:
|
|
141
|
-
|
|
142
|
-
- Want to escape per-second billing with a flat license fee
|
|
143
|
-
- Require greater concurrency than offered in Cloud plans
|
|
144
|
-
- Need full control over your infrastructure and privacy
|
|
145
|
-
- Want to use your own AI API keys
|
|
146
|
-
- Require custom hardware configurations
|
|
147
|
-
- Have high test volumes that make self-hosting more economical
|
|
148
|
-
|
|
149
|
-
<Card
|
|
150
|
-
title="Explore Self-Hosted"
|
|
151
|
-
icon="server"
|
|
152
|
-
href="/self-hosted"
|
|
153
|
-
>
|
|
154
|
-
Learn about self-hosting for unlimited test execution at a flat rate.
|
|
155
|
-
</Card>
|
|
@@ -1,278 +1,105 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: testdriver:hover
|
|
3
|
-
description:
|
|
3
|
+
description: Move the mouse over an element or a point without clicking, to reveal tooltips and menus.
|
|
4
4
|
---
|
|
5
5
|
<!-- Generated from hover.mdx. DO NOT EDIT. -->
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Move the mouse cursor onto elements or coordinates without a click. Use this to show tooltips, dropdowns, and hover effects.
|
|
10
|
-
|
|
11
|
-
## Element Hover
|
|
12
|
-
|
|
13
|
-
Put the cursor on a found element.
|
|
14
|
-
|
|
15
|
-
### Syntax
|
|
7
|
+
Move the mouse onto an element without clicking. Use it to reveal tooltips, dropdown menus and hover styles.
|
|
16
8
|
|
|
17
9
|
```javascript
|
|
18
|
-
await
|
|
10
|
+
await testdriver.find('Products menu in the top navigation').hover();
|
|
11
|
+
await testdriver.find('Laptops in the Products dropdown').click();
|
|
19
12
|
```
|
|
20
13
|
|
|
21
|
-
|
|
14
|
+
## element.hover()
|
|
22
15
|
|
|
23
|
-
`
|
|
24
|
-
|
|
25
|
-
### Examples
|
|
26
|
-
|
|
27
|
-
```javascript
|
|
28
|
-
// Find and hover
|
|
29
|
-
const tooltip = await testdriver.find('info icon');
|
|
30
|
-
await tooltip.hover();
|
|
16
|
+
Moves the mouse to the point where [`find()`](/find) located the element. It's the same as `element.click('hover')`.
|
|
31
17
|
|
|
32
|
-
|
|
33
|
-
|
|
18
|
+
```typescript
|
|
19
|
+
element.hover(): Promise<void>
|
|
20
|
+
```
|
|
34
21
|
|
|
35
|
-
|
|
36
|
-
const menu = await testdriver.find('Products menu');
|
|
37
|
-
await menu.hover();
|
|
22
|
+
It takes no parameters.
|
|
38
23
|
|
|
39
|
-
|
|
40
|
-
await submenu.click();
|
|
41
|
-
```
|
|
24
|
+
### Errors
|
|
42
25
|
|
|
43
|
-
|
|
26
|
+
Throws an `ElementNotFoundError` if `find()` didn't locate the element. See [click()](/click#errors) for how to check `found()` first.
|
|
44
27
|
|
|
45
|
-
|
|
28
|
+
## testdriver.hover(options)
|
|
46
29
|
|
|
47
|
-
|
|
30
|
+
Moves the mouse to a point on the screen by its coordinates. Prefer `element.hover()`, which keeps working when the layout or screen size changes.
|
|
48
31
|
|
|
49
|
-
```
|
|
50
|
-
|
|
32
|
+
```typescript
|
|
33
|
+
testdriver.hover(options: { x: number; y: number }): Promise<void>
|
|
51
34
|
```
|
|
52
35
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
<ParamField path="x" type="number" required>
|
|
56
|
-
|
|
36
|
+
<ParamField path="options" type="object" required>
|
|
37
|
+
<Expandable title="properties">
|
|
38
|
+
<ParamField path="x" type="number" required>
|
|
39
|
+
Distance from the left edge of the screen, in pixels.
|
|
40
|
+
</ParamField>
|
|
41
|
+
<ParamField path="y" type="number" required>
|
|
42
|
+
Distance from the top edge of the screen, in pixels.
|
|
43
|
+
</ParamField>
|
|
44
|
+
</Expandable>
|
|
57
45
|
</ParamField>
|
|
58
46
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
47
|
+
```javascript
|
|
48
|
+
await testdriver.hover({ x: 640, y: 360 });
|
|
49
|
+
```
|
|
62
50
|
|
|
63
|
-
|
|
51
|
+
<Note>
|
|
52
|
+
The older form `testdriver.hover(x, y)` still works. Use the options object in new tests.
|
|
53
|
+
</Note>
|
|
64
54
|
|
|
65
|
-
|
|
55
|
+
## Examples
|
|
66
56
|
|
|
67
|
-
###
|
|
57
|
+
### Read a tooltip
|
|
68
58
|
|
|
69
59
|
```javascript
|
|
70
|
-
|
|
71
|
-
await testdriver.
|
|
72
|
-
|
|
73
|
-
// Hover and wait
|
|
74
|
-
await testdriver.hover(500, 300);
|
|
75
|
-
await new Promise(r => setTimeout(r, 1000));
|
|
60
|
+
await testdriver.find('help icon next to the Password label').hover();
|
|
61
|
+
const tooltip = await testdriver.extract('the text of the tooltip');
|
|
76
62
|
```
|
|
77
63
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
<Check>
|
|
81
|
-
**Prefer element hover over coordinates**
|
|
82
|
-
|
|
83
|
-
```javascript
|
|
84
|
-
// ✅ Preferred
|
|
85
|
-
const icon = await testdriver.find('info icon');
|
|
86
|
-
await icon.hover();
|
|
87
|
-
|
|
88
|
-
// ❌ Avoid
|
|
89
|
-
await testdriver.hover(500, 300);
|
|
90
|
-
```
|
|
91
|
-
</Check>
|
|
92
|
-
|
|
93
|
-
<Check>
|
|
94
|
-
**Wait after hovering for dynamic content**
|
|
95
|
-
|
|
96
|
-
```javascript
|
|
97
|
-
const menuItem = await testdriver.find('Settings menu');
|
|
98
|
-
await menuItem.hover();
|
|
99
|
-
|
|
100
|
-
// Wait for submenu to appear
|
|
101
|
-
await new Promise(r => setTimeout(r, 500));
|
|
102
|
-
|
|
103
|
-
const subItem = await testdriver.find('Profile submenu');
|
|
104
|
-
await subItem.click();
|
|
105
|
-
```
|
|
106
|
-
</Check>
|
|
64
|
+
### Check a hover style
|
|
107
65
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const element = await testdriver.find('tooltip trigger');
|
|
113
|
-
if (!element.found()) {
|
|
114
|
-
throw new Error('Element not found');
|
|
115
|
-
}
|
|
116
|
-
await element.hover();
|
|
117
|
-
```
|
|
118
|
-
</Check>
|
|
119
|
-
|
|
120
|
-
## Use Cases
|
|
66
|
+
```javascript
|
|
67
|
+
await testdriver.find('Sign in button').hover();
|
|
68
|
+
await testdriver.assert('the Sign in button is highlighted');
|
|
69
|
+
```
|
|
121
70
|
|
|
122
|
-
|
|
123
|
-
<Accordion title="Tooltips">
|
|
124
|
-
```javascript
|
|
125
|
-
// Hover to show tooltip
|
|
126
|
-
const icon = await testdriver.find('help icon');
|
|
127
|
-
await icon.hover();
|
|
128
|
-
|
|
129
|
-
await new Promise(r => setTimeout(r, 1000));
|
|
130
|
-
|
|
131
|
-
// Read tooltip content
|
|
132
|
-
const tooltipText = await testdriver.extract('the tooltip text');
|
|
133
|
-
console.log('Tooltip:', tooltipText);
|
|
134
|
-
```
|
|
135
|
-
</Accordion>
|
|
136
|
-
|
|
137
|
-
<Accordion title="Dropdown Menus">
|
|
138
|
-
```javascript
|
|
139
|
-
// Hover to reveal dropdown
|
|
140
|
-
const menuItem = await testdriver.find('Products menu item');
|
|
141
|
-
await menuItem.hover();
|
|
142
|
-
|
|
143
|
-
// Wait for dropdown animation
|
|
144
|
-
await new Promise(r => setTimeout(r, 500));
|
|
145
|
-
|
|
146
|
-
// Click submenu option
|
|
147
|
-
const category = await testdriver.find('Electronics category');
|
|
148
|
-
await category.click();
|
|
149
|
-
```
|
|
150
|
-
</Accordion>
|
|
151
|
-
|
|
152
|
-
<Accordion title="Image Previews">
|
|
153
|
-
```javascript
|
|
154
|
-
// Hover over thumbnail to see preview
|
|
155
|
-
const thumbnail = await testdriver.find('product thumbnail');
|
|
156
|
-
await thumbnail.hover();
|
|
157
|
-
|
|
158
|
-
await new Promise(r => setTimeout(r, 800));
|
|
159
|
-
|
|
160
|
-
// Verify preview appears
|
|
161
|
-
await testdriver.assert('product preview is displayed');
|
|
162
|
-
```
|
|
163
|
-
</Accordion>
|
|
164
|
-
|
|
165
|
-
<Accordion title="Hover Effects">
|
|
166
|
-
```javascript
|
|
167
|
-
// Test hover state styling
|
|
168
|
-
const button = await testdriver.find('call to action button');
|
|
169
|
-
await button.hover();
|
|
170
|
-
|
|
171
|
-
await new Promise(r => setTimeout(r, 500));
|
|
172
|
-
|
|
173
|
-
// Verify hover effect
|
|
174
|
-
await testdriver.assert('button background changed to blue');
|
|
175
|
-
```
|
|
176
|
-
</Accordion>
|
|
177
|
-
|
|
178
|
-
<Accordion title="Drag and Drop">
|
|
179
|
-
```javascript
|
|
180
|
-
// Use hover in drag and drop
|
|
181
|
-
const item = await testdriver.find('draggable item');
|
|
182
|
-
await item.mouseDown();
|
|
183
|
-
|
|
184
|
-
// Hover over drop zone
|
|
185
|
-
const dropZone = await testdriver.find('drop area');
|
|
186
|
-
await dropZone.hover();
|
|
187
|
-
|
|
188
|
-
await new Promise(r => setTimeout(r, 300));
|
|
189
|
-
await dropZone.mouseUp();
|
|
190
|
-
```
|
|
191
|
-
</Accordion>
|
|
192
|
-
</AccordionGroup>
|
|
71
|
+
### Drag an item
|
|
193
72
|
|
|
194
|
-
|
|
73
|
+
`hover()` moves the mouse while the button is held down by [`mouseDown()`](/mouse-down):
|
|
195
74
|
|
|
196
75
|
```javascript
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
let testdriver;
|
|
76
|
+
await testdriver.find('Task card titled "Write docs"').mouseDown();
|
|
77
|
+
await testdriver.find('Done column').hover();
|
|
78
|
+
await testdriver.find('Done column').mouseUp();
|
|
79
|
+
```
|
|
202
80
|
|
|
203
|
-
|
|
204
|
-
client = new TestDriver(process.env.TD_API_KEY);
|
|
205
|
-
await testdriver.auth();
|
|
206
|
-
await testdriver.connect();
|
|
207
|
-
});
|
|
81
|
+
## Complete example
|
|
208
82
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
83
|
+
```javascript tests/hover.test.mjs
|
|
84
|
+
import { describe, expect, it } from 'vitest';
|
|
85
|
+
import { TestDriver } from 'testdriverai/vitest/hooks';
|
|
212
86
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
const infoIcon = await testdriver.find('information icon');
|
|
218
|
-
await infoIcon.hover();
|
|
219
|
-
|
|
220
|
-
// Wait for tooltip to appear
|
|
221
|
-
await new Promise(r => setTimeout(r, 1000));
|
|
222
|
-
|
|
223
|
-
// Verify tooltip is visible
|
|
224
|
-
await testdriver.assert('tooltip is displayed');
|
|
225
|
-
|
|
226
|
-
// Extract tooltip text
|
|
227
|
-
const tooltipText = await testdriver.extract('the tooltip message');
|
|
228
|
-
console.log('Tooltip says:', tooltipText);
|
|
229
|
-
});
|
|
87
|
+
describe('Hover', () => {
|
|
88
|
+
it('highlights the sign in button on hover', async (context) => {
|
|
89
|
+
const testdriver = TestDriver(context);
|
|
90
|
+
await testdriver.provision.chrome({ url: 'https://testdriver-sandbox.vercel.app/login' });
|
|
230
91
|
|
|
231
|
-
|
|
232
|
-
// Hover over main menu
|
|
233
|
-
const menu = await testdriver.find('Navigation menu');
|
|
234
|
-
await menu.hover();
|
|
235
|
-
|
|
236
|
-
// Wait for dropdown
|
|
237
|
-
await new Promise(r => setTimeout(r, 500));
|
|
238
|
-
|
|
239
|
-
// Hover over submenu item
|
|
240
|
-
const submenu = await testdriver.find('Account submenu');
|
|
241
|
-
await submenu.hover();
|
|
242
|
-
|
|
243
|
-
await new Promise(r => setTimeout(r, 300));
|
|
244
|
-
|
|
245
|
-
// Click nested menu item
|
|
246
|
-
const settings = await testdriver.find('Settings option');
|
|
247
|
-
await settings.click();
|
|
248
|
-
|
|
249
|
-
await testdriver.assert('settings page is displayed');
|
|
250
|
-
});
|
|
92
|
+
await testdriver.find('Sign in button below the password field').hover();
|
|
251
93
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
const productImg = await testdriver.find('product 1 thumbnail');
|
|
255
|
-
await productImg.hover();
|
|
256
|
-
|
|
257
|
-
// Wait for preview
|
|
258
|
-
await new Promise(r => setTimeout(r, 800));
|
|
259
|
-
|
|
260
|
-
// Verify preview appeared
|
|
261
|
-
await testdriver.assert('large product preview is shown');
|
|
262
|
-
|
|
263
|
-
// Move away
|
|
264
|
-
const otherElement = await testdriver.find('page heading');
|
|
265
|
-
await otherElement.hover();
|
|
266
|
-
|
|
267
|
-
// Verify preview disappeared
|
|
268
|
-
await new Promise(r => setTimeout(r, 500));
|
|
269
|
-
await testdriver.assert('product preview is hidden');
|
|
94
|
+
const result = await testdriver.assert('the mouse pointer is over the Sign in button');
|
|
95
|
+
expect(result).toBe(true);
|
|
270
96
|
});
|
|
271
97
|
});
|
|
272
98
|
```
|
|
273
99
|
|
|
274
|
-
## Related
|
|
100
|
+
## Related
|
|
275
101
|
|
|
276
|
-
- [
|
|
277
|
-
- [
|
|
278
|
-
- [
|
|
102
|
+
- [find()](/find): locate the element to hover over
|
|
103
|
+
- [click()](/click): click after a menu opens
|
|
104
|
+
- [mouseDown()](/mouse-down) and [mouseUp()](/mouse-up): drag and drop
|
|
105
|
+
- [Perform actions](/performing-actions): every kind of action in one guide
|