testdriverai 7.2.47 → 7.2.48
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/workflows/acceptance-linux-scheduled.yaml +1 -1
- package/.github/workflows/acceptance.yaml +2 -2
- package/.github/workflows/windows-self-hosted.yaml +1 -1
- package/README.md +2 -2
- package/docs/TEST-GITHUB-COMMENTS.md +2 -2
- package/docs/v7/_drafts/plugin-migration.mdx +1 -1
- package/docs/v7/aws-setup.mdx +1 -1
- package/docs/v7/examples.mdx +1 -1
- package/{test/testdriver → examples}/chrome-extension.test.mjs +1 -1
- package/package.json +1 -1
- package/test/manual/reconnect-provision.test.mjs +2 -2
- package/testdriver-plugin/skills/actions/SKILL.md +93 -0
- package/testdriver-plugin/skills/assertions/SKILL.md +77 -0
- package/testdriver-plugin/skills/caching/SKILL.md +66 -0
- package/testdriver-plugin/skills/creating-tests/SKILL.md +104 -0
- package/testdriver-plugin/skills/finding-elements/SKILL.md +77 -0
- package/testdriver-plugin/skills/github-actions/SKILL.md +100 -0
- package/testdriver-plugin/skills/running-tests/SKILL.md +77 -0
- package/testdriver-plugin/skills/secrets/SKILL.md +87 -0
- package/testdriver-plugin/skills/self-hosting/SKILL.md +89 -0
- package/testdriver-plugin/skills/setup/SKILL.md +76 -0
- package/testdriver-plugin/skills/variables/SKILL.md +88 -0
- package/testdriver-plugin/skills/waiting/SKILL.md +72 -0
- package/debug/01-table-initial.png +0 -0
- package/debug/02-after-ai-explore.png +0 -0
- package/debug/02-after-scroll.png +0 -0
- package/examples/github-actions.yml +0 -68
- package/examples/run-tests-with-recording.sh +0 -70
- package/examples/screenshot-example.js +0 -63
- package/examples/sdk-awesome-logs-demo.js +0 -177
- package/examples/sdk-cache-thresholds.js +0 -96
- package/examples/sdk-element-properties.js +0 -155
- package/examples/sdk-simple-example.js +0 -65
- package/examples/test-recording-example.test.js +0 -166
- /package/{test/testdriver → examples}/ai.test.mjs +0 -0
- /package/{test/testdriver → examples}/assert.test.mjs +0 -0
- /package/{test/testdriver → examples}/drag-and-drop.test.mjs +0 -0
- /package/{test/testdriver → examples}/element-not-found.test.mjs +0 -0
- /package/{test/testdriver → examples}/exec-output.test.mjs +0 -0
- /package/{test/testdriver → examples}/exec-pwsh.test.mjs +0 -0
- /package/{test/testdriver → examples}/focus-window.test.mjs +0 -0
- /package/{test/testdriver → examples}/formatted-logging.test.mjs +0 -0
- /package/{test/testdriver → examples}/hover-image.test.mjs +0 -0
- /package/{test/testdriver → examples}/hover-text-with-description.test.mjs +0 -0
- /package/{test/testdriver → examples}/hover-text.test.mjs +0 -0
- /package/{test/testdriver → examples}/installer.test.mjs +0 -0
- /package/{test/testdriver → examples}/launch-vscode-linux.test.mjs +0 -0
- /package/{test/testdriver → examples}/match-image.test.mjs +0 -0
- /package/{test/testdriver → examples}/press-keys.test.mjs +0 -0
- /package/{test/testdriver → examples}/prompt.test.mjs +0 -0
- /package/{test/testdriver → examples}/scroll-keyboard.test.mjs +0 -0
- /package/{test/testdriver → examples}/scroll-until-image.test.mjs +0 -0
- /package/{test/testdriver → examples}/scroll-until-text.test.mjs +0 -0
- /package/{test/testdriver → examples}/scroll.test.mjs +0 -0
- /package/{test/testdriver → examples}/type.test.mjs +0 -0
- /package/{test/testdriver → examples}/windows-installer.test.mjs +0 -0
|
@@ -31,7 +31,7 @@ jobs:
|
|
|
31
31
|
|
|
32
32
|
- name: Run Linux tests with Sentry Cron monitoring
|
|
33
33
|
run: |
|
|
34
|
-
sentry-cli monitors run testdriver-linux-acceptance -- npx vitest run
|
|
34
|
+
sentry-cli monitors run testdriver-linux-acceptance -- npx vitest run examples/*.test.mjs
|
|
35
35
|
env:
|
|
36
36
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
|
37
37
|
TD_API_KEY: ${{ secrets.TD_API_KEY }}
|
|
@@ -29,7 +29,7 @@ jobs:
|
|
|
29
29
|
run: npm ci
|
|
30
30
|
|
|
31
31
|
- name: Run Linux tests
|
|
32
|
-
run: npx vitest run
|
|
32
|
+
run: npx vitest run examples/*.test.mjs
|
|
33
33
|
env:
|
|
34
34
|
TD_API_KEY: ${{ secrets.TD_API_KEY }}
|
|
35
35
|
TD_OS: linux
|
|
@@ -52,7 +52,7 @@ jobs:
|
|
|
52
52
|
if: contains(github.event.pull_request.labels.*.name, 'test-windows')
|
|
53
53
|
uses: ./.github/workflows/windows-self-hosted.yaml
|
|
54
54
|
with:
|
|
55
|
-
test_pattern: '
|
|
55
|
+
test_pattern: 'examples/assert.test.mjs'
|
|
56
56
|
secrets:
|
|
57
57
|
TD_API_KEY: ${{ secrets.TD_API_KEY }}
|
|
58
58
|
TD_WEBSITE: ${{ secrets.TD_WEBSITE }}
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<br />
|
|
12
12
|
<br />
|
|
13
13
|
|
|
14
|
-
[🚀 **Quick Start**](#-quick-start) • [📖 **Documentation**](https://docs.testdriver.ai) • [💻 **Examples**](https://github.com/testdriverai/testdriverai/tree/main/
|
|
14
|
+
[🚀 **Quick Start**](#-quick-start) • [📖 **Documentation**](https://docs.testdriver.ai) • [💻 **Examples**](https://github.com/testdriverai/testdriverai/tree/main/examples) • [📖 **Pricing**](https://docs.testdriver.ai) • [💬 **Discord**](https://discord.com/invite/cWDFW8DzPm) • [🌐 **Website**](https://testdriver.ai)
|
|
15
15
|
|
|
16
16
|
</div>
|
|
17
17
|
|
|
@@ -41,7 +41,7 @@ const result = await testdriver.assert(
|
|
|
41
41
|
expect(result).toBeTruthy();
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
[See Full Example](https://github.com/testdriverai/testdriverai/blob/main/
|
|
44
|
+
[See Full Example](https://github.com/testdriverai/testdriverai/blob/main/examples/drag-and-drop.test.mjs) • [Browse All Examples](https://github.com/testdriverai/testdriverai/tree/main/examples)
|
|
45
45
|
|
|
46
46
|
---
|
|
47
47
|
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
## What the Test Does
|
|
40
40
|
|
|
41
|
-
The workflow runs `
|
|
41
|
+
The workflow runs `examples/assert.test.mjs` which:
|
|
42
42
|
- Provisions a Chrome browser
|
|
43
43
|
- Navigates to https://saucedemo.com
|
|
44
44
|
- Performs login actions
|
|
@@ -72,7 +72,7 @@ Skipped: 0 ⏭️
|
|
|
72
72
|
|
|
73
73
|
| Status | Test | File | Duration | Replay |
|
|
74
74
|
|--------|------|------|----------|--------|
|
|
75
|
-
| ✅ | Assert Test | `
|
|
75
|
+
| ✅ | Assert Test | `examples/assert.test.mjs` | 25.3s | [🎥 View](https://console.testdriver.ai/replay/...) |
|
|
76
76
|
|
|
77
77
|
## 🎥 Dashcam Replays
|
|
78
78
|
|
|
@@ -142,7 +142,7 @@ export default defineConfig({
|
|
|
142
142
|
|
|
143
143
|
### Test Helpers
|
|
144
144
|
|
|
145
|
-
- ✅ **Removed**: `
|
|
145
|
+
- ✅ **Removed**: `examples/setup/` folder (legacy helpers)
|
|
146
146
|
- Code moved to `lib/vitest/hooks.mjs` framework
|
|
147
147
|
- Tests now use `TestDriver(context, options)` pattern directly
|
|
148
148
|
|
package/docs/v7/aws-setup.mdx
CHANGED
package/docs/v7/examples.mdx
CHANGED
|
@@ -55,7 +55,7 @@ describe("Chrome Extension Test", () => {
|
|
|
55
55
|
// When clicked, it shows a popup with "Hello Extensions"
|
|
56
56
|
|
|
57
57
|
// Click on the extensions button (puzzle piece icon) in Chrome toolbar
|
|
58
|
-
const extensionsButton = await testdriver.find("The extensions button in the Chrome toolbar");
|
|
58
|
+
const extensionsButton = await testdriver.find("The extensions button in the Chrome toolbar", {zoom: true});
|
|
59
59
|
await extensionsButton.click();
|
|
60
60
|
|
|
61
61
|
// Look for the hello world extension in the extensions menu
|
package/package.json
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* Run reconnect-signin.test.mjs within 2 minutes of this test completing.
|
|
9
9
|
*
|
|
10
10
|
* Usage:
|
|
11
|
-
* 1. npm test --
|
|
12
|
-
* 2. (within 2 minutes)
|
|
11
|
+
* 1. npm test -- examples/reconnect-provision.test.mjs
|
|
12
|
+
* 2. (within 2 minutes) examples/reconnect-signin.test.mjs
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { afterAll, describe, expect, it } from "vitest";
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: actions
|
|
3
|
+
description: Perform actions in TestDriver tests. Use when clicking, typing, pressing keys, scrolling, hovering, dragging, or interacting with UI elements.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Performing Actions
|
|
7
|
+
|
|
8
|
+
Read these docs:
|
|
9
|
+
- `node_modules/testdriverai/docs/v7/click.mdx`
|
|
10
|
+
- `node_modules/testdriverai/docs/v7/type.mdx`
|
|
11
|
+
- `node_modules/testdriverai/docs/v7/press-keys.mdx`
|
|
12
|
+
- `node_modules/testdriverai/docs/v7/scroll.mdx`
|
|
13
|
+
- `node_modules/testdriverai/docs/v7/hover.mdx`
|
|
14
|
+
- `node_modules/testdriverai/docs/v7/double-click.mdx`
|
|
15
|
+
- `node_modules/testdriverai/docs/v7/right-click.mdx`
|
|
16
|
+
- `node_modules/testdriverai/docs/v7/mouse-down.mdx`
|
|
17
|
+
- `node_modules/testdriverai/docs/v7/mouse-up.mdx`
|
|
18
|
+
|
|
19
|
+
## Click Actions
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
const element = await testdriver.find("button");
|
|
23
|
+
await element.click();
|
|
24
|
+
await element.doubleClick();
|
|
25
|
+
await element.rightClick();
|
|
26
|
+
await element.hover();
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Typing
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
await testdriver.find("Email input").click();
|
|
33
|
+
await testdriver.type("user@example.com");
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Clear before typing
|
|
37
|
+
```javascript
|
|
38
|
+
await testdriver.find("Search input").click();
|
|
39
|
+
await testdriver.pressKeys(["ctrl", "a"]);
|
|
40
|
+
await testdriver.type("new search term");
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Keyboard Input
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
await testdriver.pressKeys(["enter"]);
|
|
47
|
+
await testdriver.pressKeys(["tab"]);
|
|
48
|
+
await testdriver.pressKeys(["escape"]);
|
|
49
|
+
await testdriver.pressKeys(["ctrl", "a"]); // Select all
|
|
50
|
+
await testdriver.pressKeys(["ctrl", "c"]); // Copy
|
|
51
|
+
await testdriver.pressKeys(["ctrl", "v"]); // Paste
|
|
52
|
+
await testdriver.pressKeys(["alt", "f4"]); // Close (Windows)
|
|
53
|
+
await testdriver.pressKeys(["cmd", "q"]); // Quit (macOS)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Scrolling
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
await testdriver.scroll("down");
|
|
60
|
+
await testdriver.scroll("up");
|
|
61
|
+
await testdriver.scrollUntilText("Footer content");
|
|
62
|
+
await testdriver.scrollUntilImage("Product image at bottom");
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Drag and Drop
|
|
66
|
+
|
|
67
|
+
```javascript
|
|
68
|
+
const source = await testdriver.find("Draggable item");
|
|
69
|
+
const target = await testdriver.find("Drop zone");
|
|
70
|
+
await source.mouseDown();
|
|
71
|
+
await target.hover();
|
|
72
|
+
await target.mouseUp();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Execute Code in Sandbox
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
// JavaScript (browser)
|
|
79
|
+
const title = await testdriver.exec("js", "return document.title", 5000);
|
|
80
|
+
|
|
81
|
+
// Shell (Linux)
|
|
82
|
+
await testdriver.exec("sh", "ls -la", 5000);
|
|
83
|
+
|
|
84
|
+
// PowerShell (Windows)
|
|
85
|
+
await testdriver.exec("pwsh", "Get-Date", 5000);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Examples
|
|
89
|
+
|
|
90
|
+
- `node_modules/testdriverai/examples/type.test.mjs`
|
|
91
|
+
- `node_modules/testdriverai/examples/press-keys.test.mjs`
|
|
92
|
+
- `node_modules/testdriverai/examples/scroll.test.mjs`
|
|
93
|
+
- `node_modules/testdriverai/examples/drag-and-drop.test.mjs`
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: assertions
|
|
3
|
+
description: Make assertions in TestDriver tests. Use when verifying UI state, checking visual conditions, or validating test outcomes with natural language.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Making Assertions
|
|
7
|
+
|
|
8
|
+
Read: `node_modules/testdriverai/docs/v7/assert.mdx`
|
|
9
|
+
Read: `node_modules/testdriverai/docs/v7/making-assertions.mdx`
|
|
10
|
+
|
|
11
|
+
## Basic Usage
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
const result = await testdriver.assert("the dashboard is visible");
|
|
15
|
+
expect(result).toBeTruthy();
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Writing Good Assertions
|
|
19
|
+
|
|
20
|
+
**Be specific:**
|
|
21
|
+
```javascript
|
|
22
|
+
// ✅ Good
|
|
23
|
+
await testdriver.assert("the login button is visible in the header");
|
|
24
|
+
await testdriver.assert("user's name 'John' appears in the profile section");
|
|
25
|
+
await testdriver.assert("error message 'Invalid email' is displayed");
|
|
26
|
+
|
|
27
|
+
// ❌ Vague
|
|
28
|
+
await testdriver.assert("button visible");
|
|
29
|
+
await testdriver.assert("it worked");
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Describe what you see:**
|
|
33
|
+
```javascript
|
|
34
|
+
await testdriver.assert("the settings panel is open on the right side");
|
|
35
|
+
await testdriver.assert("a green success checkmark appears next to the form");
|
|
36
|
+
await testdriver.assert("the page shows 'Welcome back, John'");
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Include context:**
|
|
40
|
+
```javascript
|
|
41
|
+
await testdriver.assert("the shopping cart shows 3 items");
|
|
42
|
+
await testdriver.assert("the price total is $99.99");
|
|
43
|
+
await testdriver.assert("the submit button is disabled");
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Common Patterns
|
|
47
|
+
|
|
48
|
+
### After navigation
|
|
49
|
+
```javascript
|
|
50
|
+
await testdriver.find("Settings link").click();
|
|
51
|
+
const result = await testdriver.assert("Settings page is displayed");
|
|
52
|
+
expect(result).toBeTruthy();
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Form validation
|
|
56
|
+
```javascript
|
|
57
|
+
await testdriver.find("Submit button").click();
|
|
58
|
+
const hasError = await testdriver.assert("email validation error is shown");
|
|
59
|
+
expect(hasError).toBeTruthy();
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### State changes
|
|
63
|
+
```javascript
|
|
64
|
+
await testdriver.find("Toggle switch").click();
|
|
65
|
+
const isOn = await testdriver.assert("the toggle is now in the ON position");
|
|
66
|
+
expect(isOn).toBeTruthy();
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Negative assertions
|
|
70
|
+
```javascript
|
|
71
|
+
const noError = await testdriver.assert("no error messages are visible");
|
|
72
|
+
expect(noError).toBeTruthy();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Examples
|
|
76
|
+
|
|
77
|
+
See `node_modules/testdriverai/examples/assert.test.mjs`
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: caching
|
|
3
|
+
description: Understand TestDriver element caching. Use when optimizing test speed, managing cache keys, or troubleshooting cached element issues.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Element Caching
|
|
7
|
+
|
|
8
|
+
Read: `node_modules/testdriverai/docs/v7/caching.mdx`
|
|
9
|
+
|
|
10
|
+
## How Caching Works
|
|
11
|
+
|
|
12
|
+
TestDriver caches element locations to speed up subsequent test runs. When you `find()` an element, the result is stored and reused in future runs.
|
|
13
|
+
|
|
14
|
+
## Cache Options
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
const testdriver = TestDriver(context, {
|
|
18
|
+
cache: true, // Enable caching (default: true)
|
|
19
|
+
cacheKey: 'my-test', // Custom cache key
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## When to Use Custom Cache Keys
|
|
24
|
+
|
|
25
|
+
Use different cache keys when:
|
|
26
|
+
- Testing different pages/states with similar elements
|
|
27
|
+
- Running tests in different environments
|
|
28
|
+
- Elements have different positions in different contexts
|
|
29
|
+
|
|
30
|
+
```javascript
|
|
31
|
+
// Login page test
|
|
32
|
+
const testdriver = TestDriver(context, { cacheKey: 'login-page' });
|
|
33
|
+
|
|
34
|
+
// Dashboard test
|
|
35
|
+
const testdriver = TestDriver(context, { cacheKey: 'dashboard' });
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Disabling Cache
|
|
39
|
+
|
|
40
|
+
Disable caching when:
|
|
41
|
+
- Elements frequently change position
|
|
42
|
+
- Debugging element detection issues
|
|
43
|
+
- Dynamic content that varies between runs
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
const testdriver = TestDriver(context, { cache: false });
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Cache Invalidation
|
|
50
|
+
|
|
51
|
+
The cache is automatically invalidated when:
|
|
52
|
+
- Element is not found at cached location
|
|
53
|
+
- Test fails due to element mismatch
|
|
54
|
+
- Cache key changes
|
|
55
|
+
|
|
56
|
+
## Troubleshooting
|
|
57
|
+
|
|
58
|
+
**Element found at wrong position?**
|
|
59
|
+
- Try disabling cache: `cache: false`
|
|
60
|
+
- Use a different cache key
|
|
61
|
+
- The UI may have changed since last run
|
|
62
|
+
|
|
63
|
+
**Tests slower than expected?**
|
|
64
|
+
- Ensure caching is enabled
|
|
65
|
+
- Use consistent cache keys
|
|
66
|
+
- Cache builds up over successful runs
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: creating-tests
|
|
3
|
+
description: Create TestDriver tests. Use when writing new test files, structuring test suites, using the two-file workflow pattern, or setting up provision for browser/desktop testing.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Creating Tests
|
|
7
|
+
|
|
8
|
+
Read: `node_modules/testdriverai/docs/v7/quickstart.mdx`
|
|
9
|
+
|
|
10
|
+
## Basic Test Structure
|
|
11
|
+
|
|
12
|
+
```javascript
|
|
13
|
+
import { describe, expect, it } from "vitest";
|
|
14
|
+
import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
|
|
15
|
+
|
|
16
|
+
describe("My Test Suite", () => {
|
|
17
|
+
it("should do something", async (context) => {
|
|
18
|
+
const testdriver = TestDriver(context);
|
|
19
|
+
|
|
20
|
+
await testdriver.provision.chrome({ url: 'https://example.com' });
|
|
21
|
+
|
|
22
|
+
const button = await testdriver.find("Sign In button");
|
|
23
|
+
await button.click();
|
|
24
|
+
|
|
25
|
+
const result = await testdriver.assert("dashboard is visible");
|
|
26
|
+
expect(result).toBeTruthy();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Provisioning
|
|
32
|
+
|
|
33
|
+
### Web Testing
|
|
34
|
+
```javascript
|
|
35
|
+
await testdriver.provision.chrome({ url: 'https://your-app.com' });
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Desktop App Testing
|
|
39
|
+
```javascript
|
|
40
|
+
await testdriver.provision.installer({
|
|
41
|
+
url: 'https://example.com/app.deb', // or .msi, .exe
|
|
42
|
+
launch: true,
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Two-File Workflow (Recommended for Development)
|
|
47
|
+
|
|
48
|
+
Use two files to iterate efficiently without restarting from scratch.
|
|
49
|
+
|
|
50
|
+
### setup.test.mjs
|
|
51
|
+
```javascript
|
|
52
|
+
import { afterAll, describe, expect, it } from "vitest";
|
|
53
|
+
import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
|
|
54
|
+
|
|
55
|
+
describe("Setup", () => {
|
|
56
|
+
afterAll(async () => {
|
|
57
|
+
console.log("Sandbox staying alive for reconnect");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should set up state", async (context) => {
|
|
61
|
+
const testdriver = TestDriver(context);
|
|
62
|
+
await testdriver.provision.chrome({ url: 'https://your-app.com' });
|
|
63
|
+
const result = await testdriver.assert("page loaded");
|
|
64
|
+
expect(result).toBeTruthy();
|
|
65
|
+
console.log("✅ Run experiment.test.mjs now");
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### experiment.test.mjs
|
|
71
|
+
```javascript
|
|
72
|
+
import { describe, expect, it } from "vitest";
|
|
73
|
+
import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
|
|
74
|
+
|
|
75
|
+
describe("Experiment", () => {
|
|
76
|
+
it("should continue", async (context) => {
|
|
77
|
+
const testdriver = TestDriver(context, { reconnect: true });
|
|
78
|
+
// NO provision - sandbox already running
|
|
79
|
+
// Add new steps here...
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Run setup first, then experiment within 2 minutes.
|
|
85
|
+
|
|
86
|
+
⚠️ **NEVER remove `reconnect: true`** unless combining into a final test.
|
|
87
|
+
|
|
88
|
+
## TestDriver Options
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
TestDriver(context, {
|
|
92
|
+
newSandbox: true, // Create new sandbox
|
|
93
|
+
reconnect: false, // Reconnect to last sandbox
|
|
94
|
+
keepAlive: 30000, // Keep alive after test (ms)
|
|
95
|
+
os: 'linux', // 'linux' | 'windows'
|
|
96
|
+
resolution: '1366x768', // Sandbox resolution
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
See `node_modules/testdriverai/docs/v7/device-config.mdx` for all options.
|
|
101
|
+
|
|
102
|
+
## Examples
|
|
103
|
+
|
|
104
|
+
See `node_modules/testdriverai/examples/` for working test patterns.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: finding-elements
|
|
3
|
+
description: Find elements in TestDriver tests. Use when locating UI elements by natural language description, understanding element properties, or debugging element detection.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Finding Elements
|
|
7
|
+
|
|
8
|
+
Read: `node_modules/testdriverai/docs/v7/find.mdx`
|
|
9
|
+
Read: `node_modules/testdriverai/docs/v7/elements.mdx`
|
|
10
|
+
Read: `node_modules/testdriverai/docs/v7/locating-elements.mdx`
|
|
11
|
+
|
|
12
|
+
## Basic Usage
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
const button = await testdriver.find("Sign In button");
|
|
16
|
+
const input = await testdriver.find("Email input field");
|
|
17
|
+
const link = await testdriver.find("Forgot password link");
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Find All Matching Elements
|
|
21
|
+
|
|
22
|
+
```javascript
|
|
23
|
+
const items = await testdriver.findAll("Product cards in the grid");
|
|
24
|
+
console.log(`Found ${items.length} products`);
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Element Properties
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
const element = await testdriver.find("Submit button");
|
|
31
|
+
|
|
32
|
+
// Check if found
|
|
33
|
+
console.log(element.found()); // boolean
|
|
34
|
+
|
|
35
|
+
// Coordinates
|
|
36
|
+
console.log(element.x, element.y); // top-left
|
|
37
|
+
console.log(element.centerX, element.centerY); // center
|
|
38
|
+
|
|
39
|
+
// Dimensions
|
|
40
|
+
console.log(element.width, element.height);
|
|
41
|
+
|
|
42
|
+
// AI detection info
|
|
43
|
+
console.log(element.confidence); // 0-1
|
|
44
|
+
console.log(element.text); // detected text
|
|
45
|
+
console.log(element.boundingBox); // full box
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Tips for Good Element Descriptions
|
|
49
|
+
|
|
50
|
+
**Be specific:**
|
|
51
|
+
- ✅ "Sign In button in the header"
|
|
52
|
+
- ❌ "button"
|
|
53
|
+
|
|
54
|
+
**Include context:**
|
|
55
|
+
- ✅ "Email input field in the login form"
|
|
56
|
+
- ❌ "input"
|
|
57
|
+
|
|
58
|
+
**Describe visual appearance:**
|
|
59
|
+
- ✅ "Blue Submit button at bottom of form"
|
|
60
|
+
- ✅ "User avatar in top right corner"
|
|
61
|
+
|
|
62
|
+
## Debugging
|
|
63
|
+
|
|
64
|
+
Log element info to understand what AI sees:
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
const element = await testdriver.find("Some element");
|
|
68
|
+
console.log("Found:", element.found());
|
|
69
|
+
console.log("Position:", element.x, element.y);
|
|
70
|
+
console.log("Size:", element.width, element.height);
|
|
71
|
+
console.log("Confidence:", element.confidence);
|
|
72
|
+
console.log("Text:", element.text);
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Examples
|
|
76
|
+
|
|
77
|
+
See `node_modules/testdriverai/examples/hover-text.test.mjs`
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: github-actions
|
|
3
|
+
description: Integrate TestDriver with GitHub Actions. Use when setting up CI/CD pipelines, configuring workflows, or automating test runs on pull requests.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GitHub Actions Integration
|
|
7
|
+
|
|
8
|
+
Read: `node_modules/testdriverai/docs/v7/ci-cd.mdx`
|
|
9
|
+
|
|
10
|
+
## Basic Workflow
|
|
11
|
+
|
|
12
|
+
Create `.github/workflows/testdriver.yml`:
|
|
13
|
+
|
|
14
|
+
```yaml
|
|
15
|
+
name: TestDriver Tests
|
|
16
|
+
|
|
17
|
+
on:
|
|
18
|
+
push:
|
|
19
|
+
branches: [main]
|
|
20
|
+
pull_request:
|
|
21
|
+
branches: [main]
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
test:
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v4
|
|
29
|
+
|
|
30
|
+
- name: Setup Node.js
|
|
31
|
+
uses: actions/setup-node@v4
|
|
32
|
+
with:
|
|
33
|
+
node-version: '20'
|
|
34
|
+
|
|
35
|
+
- name: Install dependencies
|
|
36
|
+
run: npm ci
|
|
37
|
+
|
|
38
|
+
- name: Run TestDriver tests
|
|
39
|
+
env:
|
|
40
|
+
TD_API_KEY: ${{ secrets.TD_API_KEY }}
|
|
41
|
+
run: npx vitest run
|
|
42
|
+
|
|
43
|
+
- name: Upload test results
|
|
44
|
+
uses: actions/upload-artifact@v4
|
|
45
|
+
if: always()
|
|
46
|
+
with:
|
|
47
|
+
name: test-results
|
|
48
|
+
path: test-report.junit.xml
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Required Secrets
|
|
52
|
+
|
|
53
|
+
Add to your repository secrets (Settings → Secrets → Actions):
|
|
54
|
+
- `TD_API_KEY` - Your TestDriver API key
|
|
55
|
+
|
|
56
|
+
## Windows Testing
|
|
57
|
+
|
|
58
|
+
For Windows sandbox testing, add AWS credentials:
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
- name: Run TestDriver tests (Windows)
|
|
62
|
+
env:
|
|
63
|
+
TD_API_KEY: ${{ secrets.TD_API_KEY }}
|
|
64
|
+
TD_OS: windows
|
|
65
|
+
AWS_REGION: ${{ secrets.AWS_REGION }}
|
|
66
|
+
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
67
|
+
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
68
|
+
AMI_ID: ${{ secrets.AMI_ID }}
|
|
69
|
+
AWS_LAUNCH_TEMPLATE_ID: ${{ secrets.AWS_LAUNCH_TEMPLATE_ID }}
|
|
70
|
+
run: npx vitest run
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## JUnit Test Reports
|
|
74
|
+
|
|
75
|
+
TestDriver outputs JUnit XML for CI integration:
|
|
76
|
+
|
|
77
|
+
```yaml
|
|
78
|
+
- name: Publish Test Results
|
|
79
|
+
uses: dorny/test-reporter@v1
|
|
80
|
+
if: always()
|
|
81
|
+
with:
|
|
82
|
+
name: TestDriver Results
|
|
83
|
+
path: test-report.junit.xml
|
|
84
|
+
reporter: java-junit
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Parallel Testing
|
|
88
|
+
|
|
89
|
+
```yaml
|
|
90
|
+
jobs:
|
|
91
|
+
test:
|
|
92
|
+
runs-on: ubuntu-latest
|
|
93
|
+
strategy:
|
|
94
|
+
matrix:
|
|
95
|
+
test-file: [login, checkout, settings]
|
|
96
|
+
steps:
|
|
97
|
+
# ...
|
|
98
|
+
- name: Run tests
|
|
99
|
+
run: npx vitest run tests/${{ matrix.test-file }}.test.mjs
|
|
100
|
+
```
|