@testdriverai/agent 7.9.0 → 7.9.1-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.
- package/agent/lib/sandbox.js +55 -6
- package/agent/lib/sdk.js +4 -4
- package/ai/skills/testdriver-enterprise/SKILL.md +2 -109
- package/ai/skills/testdriver-hosted/SKILL.md +156 -0
- package/ai/skills/testdriver-mcp/SKILL.md +2 -2
- package/ai/skills/testdriver-quickstart/SKILL.md +30 -2
- package/ai/skills/testdriver-self-hosted/SKILL.md +125 -43
- package/ai/skills/testdriver-test-results-json/SKILL.md +257 -0
- package/docs/_scripts/generate-examples.js +127 -60
- package/docs/docs.json +27 -28
- package/docs/v7/examples/ai.mdx +4 -3
- package/docs/v7/examples/assert.mdx +19 -4
- package/docs/v7/examples/chrome-extension.mdx +36 -29
- package/docs/v7/examples/element-not-found.mdx +2 -1
- package/docs/v7/examples/exec-output.mdx +3 -4
- package/docs/v7/examples/exec-pwsh.mdx +3 -4
- package/docs/v7/examples/findall-coffee-icons.mdx +88 -0
- package/docs/v7/examples/focus-window.mdx +3 -4
- package/docs/v7/examples/hover-image.mdx +4 -3
- package/docs/v7/examples/hover-text-with-description.mdx +104 -0
- package/docs/v7/examples/hover-text.mdx +4 -3
- package/docs/v7/examples/installer.mdx +5 -4
- package/docs/v7/examples/launch-vscode-linux.mdx +3 -7
- package/docs/v7/examples/match-image.mdx +3 -2
- package/docs/v7/examples/parse.mdx +66 -0
- package/docs/v7/examples/press-keys.mdx +8 -14
- package/docs/v7/examples/scroll-keyboard.mdx +4 -3
- package/docs/v7/examples/scroll-until-image.mdx +3 -2
- package/docs/v7/examples/scroll.mdx +6 -14
- package/docs/v7/examples/type.mdx +1 -5
- package/docs/v7/examples/windows-installer.mdx +10 -4
- package/interfaces/vitest-plugin.mjs +2 -2
- package/lib/core/Dashcam.js +4 -1
- package/lib/sentry.js +5 -1
- package/package.json +1 -1
- package/setup/aws/install-dev-runner.sh +7 -2
- package/setup/aws/spawn-runner.sh +12 -0
- package/vitest.config.mjs +1 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "FindAll Coffee Icons"
|
|
3
|
+
sidebarTitle: "Findall Coffee Icons"
|
|
4
|
+
description: "TestDriver SDK - FindAll Coffee Icons Test Loads a random icon grid and uses findAll() to locate and click all 4 coffee cup icons."
|
|
5
|
+
icon: "play"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
TestDriver SDK - FindAll Coffee Icons Test Loads a random icon grid and uses findAll() to locate and click all 4 coffee cup icons
|
|
11
|
+
|
|
12
|
+
Review the source code below to understand the implementation details and patterns used.
|
|
13
|
+
|
|
14
|
+
## Live Test Run
|
|
15
|
+
|
|
16
|
+
Watch this test execute in a real sandbox environment:
|
|
17
|
+
|
|
18
|
+
{/* findall-coffee-icons.test.mjs output */}
|
|
19
|
+
<iframe
|
|
20
|
+
src="https://api.testdriver.ai/api/v1/testdriver/testcase/69c5d03ae8a04db4b705cbf0/replay"
|
|
21
|
+
width="100%"
|
|
22
|
+
height="600"
|
|
23
|
+
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
24
|
+
allow="fullscreen"
|
|
25
|
+
/>
|
|
26
|
+
|
|
27
|
+
## Source Code
|
|
28
|
+
|
|
29
|
+
```javascript title="findall-coffee-icons.test.mjs"
|
|
30
|
+
/**
|
|
31
|
+
* TestDriver SDK - FindAll Coffee Icons Test
|
|
32
|
+
* Loads a random icon grid and uses findAll() to locate and click all 4 coffee cup icons
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import { describe, expect, it } from "vitest";
|
|
36
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
37
|
+
|
|
38
|
+
describe("FindAll Coffee Icons", () => {
|
|
39
|
+
it("should find and click all 4 coffee cup icons", async (context) => {
|
|
40
|
+
const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP,
|
|
41
|
+
headless: true,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
await testdriver.provision.chrome({
|
|
45
|
+
url: "https://v0-random-icon-grid.vercel.app/",
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Use findAll to locate all coffee cup icons on the page
|
|
49
|
+
const coffeeIcons = await testdriver.findAll("coffee cup icon, there are exactly 4 on the page");
|
|
50
|
+
|
|
51
|
+
// Log each icon's coordinates
|
|
52
|
+
console.log(`Found ${coffeeIcons.length} coffee icons:`);
|
|
53
|
+
coffeeIcons.forEach((icon, i) => {
|
|
54
|
+
console.log(` Icon ${i + 1}: (${icon.x}, ${icon.y}) center=(${icon.centerX}, ${icon.centerY})`);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Verify we found 3 or 4 coffee icons
|
|
58
|
+
expect(coffeeIcons.length).toBeGreaterThanOrEqual(3);
|
|
59
|
+
expect(coffeeIcons.length).toBeLessThanOrEqual(4);
|
|
60
|
+
|
|
61
|
+
// Click each coffee cup icon
|
|
62
|
+
for (const icon of coffeeIcons) {
|
|
63
|
+
await icon.click();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Verify the selection count is displayed
|
|
67
|
+
await testdriver.assert("the page says 'Selected: 3 / 4' or 'Matched 4 of a kind!'");
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Running This Example
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# Clone the TestDriver repository
|
|
76
|
+
git clone https://github.com/testdriverai/testdriverai
|
|
77
|
+
|
|
78
|
+
# Install dependencies
|
|
79
|
+
cd testdriverai
|
|
80
|
+
npm install
|
|
81
|
+
|
|
82
|
+
# Run this specific example
|
|
83
|
+
npx vitest run examples/findall-coffee-icons.test.mjs
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
<Note>
|
|
87
|
+
Make sure you have `TD_API_KEY` set in your environment. Get one at [testdriver.ai](https://testdriver.ai).
|
|
88
|
+
</Note>
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* focus-window.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://api
|
|
15
|
+
src="https://api.testdriver.ai/api/v1/testdriver/testcase/69c5d042e8a04db4b705cbf2/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -28,14 +28,13 @@ Watch this test execute in a real sandbox environment:
|
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
30
|
import { describe, expect, it } from "vitest";
|
|
31
|
-
import { TestDriver } from "
|
|
32
|
-
import { getDefaults } from "./config.mjs";
|
|
31
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
33
32
|
|
|
34
33
|
describe("Focus Window Test", () => {
|
|
35
34
|
it.skip(
|
|
36
35
|
"should click Microsoft Edge icon and focus Google Chrome",
|
|
37
36
|
async (context) => {
|
|
38
|
-
const testdriver = TestDriver(context, {
|
|
37
|
+
const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP, headless: true });
|
|
39
38
|
await testdriver.provision.chrome({ url: 'http://testdriver-sandbox.vercel.app/login' });
|
|
40
39
|
|
|
41
40
|
//
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* hover-image.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://api
|
|
15
|
+
src="https://api.testdriver.ai/api/v1/testdriver/testcase/69c5d0300201196437256cd3/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -23,7 +23,8 @@ Watch this test execute in a real sandbox environment:
|
|
|
23
23
|
|
|
24
24
|
```javascript title="hover-image.test.mjs" {40-42,47}
|
|
25
25
|
/**
|
|
26
|
-
* TestDriver SDK - Hover Image Test
|
|
26
|
+
* TestDriver SDK - Hover Image Test (Vitest)
|
|
27
|
+
* Converted from: testdriver/acceptance/hover-image.yaml
|
|
27
28
|
*/
|
|
28
29
|
|
|
29
30
|
import { describe, expect, it } from "vitest";
|
|
@@ -50,7 +51,7 @@ async function performLogin(client, username = "standard_user") {
|
|
|
50
51
|
|
|
51
52
|
describe("Hover Image Test", () => {
|
|
52
53
|
it("should click on shopping cart icon and verify empty cart", async (context) => {
|
|
53
|
-
const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP
|
|
54
|
+
const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP});
|
|
54
55
|
|
|
55
56
|
// provision.chrome() automatically calls ready() and starts dashcam
|
|
56
57
|
await testdriver.provision.chrome({
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Hover Text With Description Test"
|
|
3
|
+
sidebarTitle: "Hover Text With Description"
|
|
4
|
+
description: "TestDriver SDK - Hover Text With Description Test (Vitest) Converted from: testdriver/acceptance/hover-text-with-description.yaml."
|
|
5
|
+
icon: "hand-pointer"
|
|
6
|
+
mode: "wide"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
TestDriver SDK - Hover Text With Description Test (Vitest) Converted from: testdriver/acceptance/hover-text-with-description.yaml
|
|
12
|
+
|
|
13
|
+
Review the source code below to understand the implementation details and patterns used.
|
|
14
|
+
|
|
15
|
+
## Live Test Run
|
|
16
|
+
|
|
17
|
+
Watch this test execute in a real sandbox environment:
|
|
18
|
+
|
|
19
|
+
{/* hover-text-with-description.test.mjs output */}
|
|
20
|
+
<iframe
|
|
21
|
+
src="https://api.testdriver.ai/api/v1/testdriver/testcase/69c5d029c2e6e94933886764/replay"
|
|
22
|
+
width="100%"
|
|
23
|
+
height="600"
|
|
24
|
+
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
25
|
+
allow="fullscreen"
|
|
26
|
+
/>
|
|
27
|
+
|
|
28
|
+
## Source Code
|
|
29
|
+
|
|
30
|
+
```javascript title="hover-text-with-description.test.mjs"
|
|
31
|
+
/**
|
|
32
|
+
* TestDriver SDK - Hover Text With Description Test (Vitest)
|
|
33
|
+
* Converted from: testdriver/acceptance/hover-text-with-description.yaml
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import { describe, expect, it } from "vitest";
|
|
37
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Perform login flow for SauceLabs demo app
|
|
41
|
+
* @param {TestDriver} client - TestDriver client
|
|
42
|
+
* @param {string} username - Username (default: 'standard_user')
|
|
43
|
+
*/
|
|
44
|
+
async function performLogin(client, username = "standard_user") {
|
|
45
|
+
await client.focusApplication("Google Chrome");
|
|
46
|
+
const password = await client.extract("the password");
|
|
47
|
+
const usernameField = await client.find("username input");
|
|
48
|
+
await usernameField.click();
|
|
49
|
+
await client.type(username);
|
|
50
|
+
await client.pressKeys(["tab"]);
|
|
51
|
+
await client.type(password, { secret: true });
|
|
52
|
+
await client.pressKeys(["tab"]);
|
|
53
|
+
await client.pressKeys(["enter"]);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
describe("Hover Text With Description Test", () => {
|
|
57
|
+
it("should add TestDriver Hat to cart and verify", async (context) => {
|
|
58
|
+
const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP,
|
|
59
|
+
headless: true,
|
|
60
|
+
});
|
|
61
|
+
await testdriver.provision.chrome({
|
|
62
|
+
url: "http://testdriver-sandbox.vercel.app/login",
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
//
|
|
66
|
+
// Perform login first
|
|
67
|
+
await performLogin(testdriver);
|
|
68
|
+
|
|
69
|
+
// Click on "Add to Cart" under TestDriver Hat
|
|
70
|
+
const addToCartButton = await testdriver.find(
|
|
71
|
+
"Add to Cart, add to cart button under TestDriver Hat",
|
|
72
|
+
);
|
|
73
|
+
await addToCartButton.click();
|
|
74
|
+
|
|
75
|
+
// Click on the cart
|
|
76
|
+
const cartButton = await testdriver.find(
|
|
77
|
+
"Cart, cart button in the top right corner",
|
|
78
|
+
);
|
|
79
|
+
await cartButton.click();
|
|
80
|
+
|
|
81
|
+
// Assert the TestDriver Hat is in the cart
|
|
82
|
+
const result = await testdriver.assert("There is an item in the cart");
|
|
83
|
+
expect(result).toBeTruthy();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Running This Example
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Clone the TestDriver repository
|
|
92
|
+
git clone https://github.com/testdriverai/testdriverai
|
|
93
|
+
|
|
94
|
+
# Install dependencies
|
|
95
|
+
cd testdriverai
|
|
96
|
+
npm install
|
|
97
|
+
|
|
98
|
+
# Run this specific example
|
|
99
|
+
npx vitest run examples/hover-text-with-description.test.mjs
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
<Note>
|
|
103
|
+
Make sure you have `TD_API_KEY` set in your environment. Get one at [testdriver.ai](https://testdriver.ai).
|
|
104
|
+
</Note>
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* hover-text.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://api
|
|
15
|
+
src="https://api.testdriver.ai/api/v1/testdriver/testcase/69c5d04b0201196437256ce6/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -23,7 +23,8 @@ Watch this test execute in a real sandbox environment:
|
|
|
23
23
|
|
|
24
24
|
```javascript title="hover-text.test.mjs" {13-15,18-20}
|
|
25
25
|
/**
|
|
26
|
-
* TestDriver SDK - Hover Text Test
|
|
26
|
+
* TestDriver SDK - Hover Text Test (Vitest)
|
|
27
|
+
* Converted from: testdriver/acceptance/hover-text.yaml
|
|
27
28
|
*/
|
|
28
29
|
|
|
29
30
|
import { describe, expect, it } from "vitest";
|
|
@@ -31,7 +32,7 @@ import { TestDriver } from "testdriverai/vitest/hooks";
|
|
|
31
32
|
|
|
32
33
|
describe("Hover Text Test", () => {
|
|
33
34
|
it("should click Sign In and verify error message", async (context) => {
|
|
34
|
-
const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP
|
|
35
|
+
const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP});
|
|
35
36
|
await testdriver.provision.chrome({ url: 'http://testdriver-sandbox.vercel.app/login' });
|
|
36
37
|
|
|
37
38
|
// Click on Sign In button using new find() API
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* installer.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://api
|
|
15
|
+
src="https://api.testdriver.ai/api/v1/testdriver/testcase/69c5d032c2e6e94933886769/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -23,7 +23,8 @@ Watch this test execute in a real sandbox environment:
|
|
|
23
23
|
|
|
24
24
|
```javascript title="installer.test.mjs" {16-18}
|
|
25
25
|
/**
|
|
26
|
-
* TestDriver SDK - Installer Test
|
|
26
|
+
* TestDriver SDK - Installer Test (Vitest)
|
|
27
|
+
* Tests the provision.installer() method for downloading and installing apps
|
|
27
28
|
*/
|
|
28
29
|
|
|
29
30
|
import { describe, expect, it } from "vitest";
|
|
@@ -35,7 +36,7 @@ describe("Provision Installer", () => {
|
|
|
35
36
|
it.skipIf(!isLinux)(
|
|
36
37
|
"should download and install a .deb package on Linux",
|
|
37
38
|
async (context) => {
|
|
38
|
-
const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP
|
|
39
|
+
const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP});
|
|
39
40
|
|
|
40
41
|
// Install bat (a cat clone with syntax highlighting) using provision.installer
|
|
41
42
|
const filePath = await testdriver.provision.installer({
|
|
@@ -53,7 +54,7 @@ describe("Provision Installer", () => {
|
|
|
53
54
|
it.skipIf(!isLinux)(
|
|
54
55
|
"should download a shell script and verify it exists",
|
|
55
56
|
async (context) => {
|
|
56
|
-
const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP
|
|
57
|
+
const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP});
|
|
57
58
|
|
|
58
59
|
// Download a shell script (nvm installer)
|
|
59
60
|
const filePath = await testdriver.provision.installer({
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* launch-vscode-linux.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://api
|
|
15
|
+
src="https://api.testdriver.ai/api/v1/testdriver/testcase/69c5d02be8a04db4b705cbe5/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -22,10 +22,6 @@ Watch this test execute in a real sandbox environment:
|
|
|
22
22
|
## Source Code
|
|
23
23
|
|
|
24
24
|
```javascript title="launch-vscode-linux.test.mjs" {13,27-29}
|
|
25
|
-
/**
|
|
26
|
-
* TestDriver SDK - Launch VS Code Test
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
25
|
import { describe, expect, it } from "vitest";
|
|
30
26
|
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
31
27
|
|
|
@@ -35,7 +31,7 @@ describe("Launch VS Code on Linux", () => {
|
|
|
35
31
|
it.skipIf(!isLinux)(
|
|
36
32
|
"should launch VS Code on Debian/Ubuntu",
|
|
37
33
|
async (context) => {
|
|
38
|
-
const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP
|
|
34
|
+
const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP});
|
|
39
35
|
|
|
40
36
|
// provision.vscode() automatically calls ready() and starts dashcam
|
|
41
37
|
await testdriver.provision.vscode();
|
|
@@ -52,7 +48,7 @@ describe("Launch VS Code on Linux", () => {
|
|
|
52
48
|
it.skipIf(!isLinux)(
|
|
53
49
|
"should install and use a VS Code extension",
|
|
54
50
|
async (context) => {
|
|
55
|
-
const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP
|
|
51
|
+
const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP});
|
|
56
52
|
|
|
57
53
|
// Launch VS Code with the Prettier extension installed
|
|
58
54
|
await testdriver.provision.vscode({
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* match-image.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://api
|
|
15
|
+
src="https://api.testdriver.ai/api/v1/testdriver/testcase/69c5d0270201196437256ccf/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -23,7 +23,8 @@ Watch this test execute in a real sandbox environment:
|
|
|
23
23
|
|
|
24
24
|
```javascript title="match-image.test.mjs" {42}
|
|
25
25
|
/**
|
|
26
|
-
* TestDriver SDK - Match Image Test
|
|
26
|
+
* TestDriver SDK - Match Image Test (Vitest)
|
|
27
|
+
* Converted from: testdriver/acceptance/match-image.yaml
|
|
27
28
|
*/
|
|
28
29
|
|
|
29
30
|
import path, { dirname } from "path";
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Parse Test"
|
|
3
|
+
sidebarTitle: "Parse"
|
|
4
|
+
description: "TestDriver SDK - Parse Test (Vitest) Opens Airbnb and runs the .parse() SDK command to analyze the screen."
|
|
5
|
+
icon: "play"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
TestDriver SDK - Parse Test (Vitest) Opens Airbnb and runs the .parse() SDK command to analyze the screen.
|
|
11
|
+
|
|
12
|
+
Review the source code below to understand the implementation details and patterns used.
|
|
13
|
+
|
|
14
|
+
## Live Test Run
|
|
15
|
+
|
|
16
|
+
Watch this test execute in a real sandbox environment:
|
|
17
|
+
|
|
18
|
+
{/* parse.test.mjs output */}
|
|
19
|
+
<iframe
|
|
20
|
+
src="https://api.testdriver.ai/api/v1/testdriver/testcase/69c5d04d0201196437256ce7/replay"
|
|
21
|
+
width="100%"
|
|
22
|
+
height="600"
|
|
23
|
+
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
24
|
+
allow="fullscreen"
|
|
25
|
+
/>
|
|
26
|
+
|
|
27
|
+
## Source Code
|
|
28
|
+
|
|
29
|
+
```javascript title="parse.test.mjs"
|
|
30
|
+
/**
|
|
31
|
+
* TestDriver SDK - Parse Test (Vitest)
|
|
32
|
+
* Opens Airbnb and runs the .parse() SDK command to analyze the screen.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import { describe, it } from "vitest";
|
|
36
|
+
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
37
|
+
|
|
38
|
+
describe("Parse Test", () => {
|
|
39
|
+
it("should open Airbnb and parse the screen", async (context) => {
|
|
40
|
+
const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP});
|
|
41
|
+
await testdriver.provision.chrome({ url: "https://www.airbnb.com" });
|
|
42
|
+
|
|
43
|
+
// The SDK automatically outputs elements as a formatted table
|
|
44
|
+
const result = await testdriver.parse();
|
|
45
|
+
console.log(`Found ${result.elements?.length || 0} elements`);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Running This Example
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Clone the TestDriver repository
|
|
54
|
+
git clone https://github.com/testdriverai/testdriverai
|
|
55
|
+
|
|
56
|
+
# Install dependencies
|
|
57
|
+
cd testdriverai
|
|
58
|
+
npm install
|
|
59
|
+
|
|
60
|
+
# Run this specific example
|
|
61
|
+
npx vitest run examples/parse.test.mjs
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
<Note>
|
|
65
|
+
Make sure you have `TD_API_KEY` set in your environment. Get one at [testdriver.ai](https://testdriver.ai).
|
|
66
|
+
</Note>
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* press-keys.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://api
|
|
15
|
+
src="https://api.testdriver.ai/api/v1/testdriver/testcase/69c5d036058ffe89003c6ada/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -23,7 +23,8 @@ Watch this test execute in a real sandbox environment:
|
|
|
23
23
|
|
|
24
24
|
```javascript title="press-keys.test.mjs" {17,24,36}
|
|
25
25
|
/**
|
|
26
|
-
* TestDriver SDK - Press Keys Test
|
|
26
|
+
* TestDriver SDK - Press Keys Test (Vitest)
|
|
27
|
+
* Converted from: testdriver/acceptance/press-keys.yaml
|
|
27
28
|
*/
|
|
28
29
|
|
|
29
30
|
import { describe, expect, it } from "vitest";
|
|
@@ -43,23 +44,16 @@ describe("Press Keys Test", () => {
|
|
|
43
44
|
await testdriver.pressKeys(["ctrl", "t"]);
|
|
44
45
|
|
|
45
46
|
// Poll for "Learn more" to appear
|
|
46
|
-
let
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (learnMore.found()) break;
|
|
50
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
51
|
-
}
|
|
47
|
+
let imagesLink = await testdriver.find("Images", {timeout: 5000});
|
|
48
|
+
|
|
49
|
+
expect(imagesLink.found()).toBeTruthy();
|
|
52
50
|
|
|
53
51
|
// Open DevTools
|
|
54
52
|
await testdriver.pressKeys(["ctrl", "shift", "i"]);
|
|
55
53
|
|
|
56
54
|
// Poll for "Elements" to appear
|
|
57
|
-
let elements = await testdriver.find("Elements");
|
|
58
|
-
|
|
59
|
-
elements = await elements.find();
|
|
60
|
-
if (elements.found()) break;
|
|
61
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
62
|
-
}
|
|
55
|
+
let elements = await testdriver.find("Elements", {timeout: 5000});
|
|
56
|
+
expect(elements.found()).toBeTruthy();
|
|
63
57
|
|
|
64
58
|
// Open another tab and navigate
|
|
65
59
|
await testdriver.pressKeys(["ctrl", "t"]);
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* scroll-keyboard.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://api
|
|
15
|
+
src="https://api.testdriver.ai/api/v1/testdriver/testcase/69c5d03da0a3ef8239de474f/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -23,7 +23,8 @@ Watch this test execute in a real sandbox environment:
|
|
|
23
23
|
|
|
24
24
|
```javascript title="scroll-keyboard.test.mjs" {26}
|
|
25
25
|
/**
|
|
26
|
-
* TestDriver SDK - Scroll Keyboard Test
|
|
26
|
+
* TestDriver SDK - Scroll Keyboard Test (Vitest)
|
|
27
|
+
* Converted from: testdriver/acceptance/scroll-keyboard.yaml
|
|
27
28
|
*/
|
|
28
29
|
|
|
29
30
|
import { describe, expect, it } from "vitest";
|
|
@@ -38,7 +39,7 @@ describe("Scroll Keyboard Test", () => {
|
|
|
38
39
|
// Navigate to https://www.webhamster.com/
|
|
39
40
|
await testdriver.focusApplication("Google Chrome");
|
|
40
41
|
const urlBar = await testdriver.find(
|
|
41
|
-
"
|
|
42
|
+
"the URL in the omnibox", {zoom: true}
|
|
42
43
|
);
|
|
43
44
|
await urlBar.click();
|
|
44
45
|
await testdriver.pressKeys(["ctrl", "a"]);
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* scroll-until-image.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://api
|
|
15
|
+
src="https://api.testdriver.ai/api/v1/testdriver/testcase/69c5d03f0201196437256cda/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -23,7 +23,8 @@ Watch this test execute in a real sandbox environment:
|
|
|
23
23
|
|
|
24
24
|
```javascript title="scroll-until-image.test.mjs" {26}
|
|
25
25
|
/**
|
|
26
|
-
* TestDriver SDK - Scroll Until Image Test
|
|
26
|
+
* TestDriver SDK - Scroll Until Image Test (Vitest)
|
|
27
|
+
* Converted from: testdriver/acceptance/scroll-until-image.yaml
|
|
27
28
|
*/
|
|
28
29
|
|
|
29
30
|
import { describe, expect, it } from "vitest";
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* scroll.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://api
|
|
15
|
+
src="https://api.testdriver.ai/api/v1/testdriver/testcase/69c5d043058ffe89003c6ae0/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -23,7 +23,10 @@ Watch this test execute in a real sandbox environment:
|
|
|
23
23
|
|
|
24
24
|
```javascript title="scroll.test.mjs" {29}
|
|
25
25
|
/**
|
|
26
|
-
* TestDriver SDK - Scroll Test
|
|
26
|
+
* TestDriver SDK - Scroll Test (Vitest)
|
|
27
|
+
* Converted from: testdriver/acceptance/scroll.yaml
|
|
28
|
+
*
|
|
29
|
+
* UPDATED: Now using chrome preset for automatic setup
|
|
27
30
|
*/
|
|
28
31
|
|
|
29
32
|
import { describe, expect, it } from "vitest";
|
|
@@ -32,19 +35,8 @@ import { TestDriver } from "testdriverai/vitest/hooks";
|
|
|
32
35
|
describe("Scroll Test", () => {
|
|
33
36
|
it("should navigate and scroll down the page", async (context) => {
|
|
34
37
|
const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP, headless: true });
|
|
35
|
-
await testdriver.provision.chrome({ url: '
|
|
38
|
+
await testdriver.provision.chrome({ url: 'https://www.webhamster.com/' });
|
|
36
39
|
|
|
37
|
-
// Give Chrome a moment to fully render the UI
|
|
38
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
39
|
-
|
|
40
|
-
// Navigate to webhamster.com - just look for the domain, not the full path
|
|
41
|
-
const urlBar = await testdriver.find(
|
|
42
|
-
"testdriver-sandbox.vercel.app, the URL in the address bar",
|
|
43
|
-
);
|
|
44
|
-
await urlBar.click();
|
|
45
|
-
await testdriver.pressKeys(["ctrl", "a"]);
|
|
46
|
-
await testdriver.type("https://www.webhamster.com/");
|
|
47
|
-
await testdriver.pressKeys(["enter"]);
|
|
48
40
|
|
|
49
41
|
// Wait for page to load and click heading
|
|
50
42
|
const heading = await testdriver.find(
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* type.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://api
|
|
15
|
+
src="https://api.testdriver.ai/api/v1/testdriver/testcase/69c5d034c2e6e9493388676c/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -22,10 +22,6 @@ Watch this test execute in a real sandbox environment:
|
|
|
22
22
|
## Source Code
|
|
23
23
|
|
|
24
24
|
```javascript title="type.test.mjs" {13}
|
|
25
|
-
/**
|
|
26
|
-
* TestDriver SDK - Type Test
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
25
|
import { describe, expect, it } from "vitest";
|
|
30
26
|
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
31
27
|
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* windows-installer.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://api
|
|
15
|
+
src="https://api.testdriver.ai/api/v1/testdriver/testcase/69c5d02ce8a04db4b705cbe9/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -23,7 +23,14 @@ Watch this test execute in a real sandbox environment:
|
|
|
23
23
|
|
|
24
24
|
```javascript title="windows-installer.test.mjs" {22-25}
|
|
25
25
|
/**
|
|
26
|
-
* TestDriver SDK - Windows Installer Example
|
|
26
|
+
* TestDriver SDK - Windows Installer Example (Vitest)
|
|
27
|
+
*
|
|
28
|
+
* This example demonstrates how to download and install a Windows application
|
|
29
|
+
* using PowerShell commands, then launch and interact with it.
|
|
30
|
+
*
|
|
31
|
+
* Based on the v6 GitButler provisioning workflow.
|
|
32
|
+
*
|
|
33
|
+
* Run: TD_OS=windows vitest run examples/windows-installer.test.mjs
|
|
27
34
|
*/
|
|
28
35
|
|
|
29
36
|
import { describe, it } from "vitest";
|
|
@@ -35,8 +42,7 @@ describe("Windows App Installation", () => {
|
|
|
35
42
|
|
|
36
43
|
it.skipIf(isLinux)("should download, install, and launch GitButler on Windows", async (context) => {
|
|
37
44
|
// Alternative approach using provision.installer helper
|
|
38
|
-
const testdriver = TestDriver(context, {
|
|
39
|
-
ip: context.ip || process.env.TD_IP,
|
|
45
|
+
const testdriver = TestDriver(context, { ip: context.ip || process.env.TD_IP,
|
|
40
46
|
os: 'windows'
|
|
41
47
|
});
|
|
42
48
|
|
|
@@ -412,9 +412,9 @@ export async function authenticateWithApiKey(apiKey, apiRoot) {
|
|
|
412
412
|
if (response.status >= 500) {
|
|
413
413
|
const serverError = new Error(
|
|
414
414
|
data.message ||
|
|
415
|
-
`
|
|
415
|
+
`An error occurred on the TestDriver server (HTTP ${response.status}). Please try again later.`,
|
|
416
416
|
);
|
|
417
|
-
serverError.code = data.error || "
|
|
417
|
+
serverError.code = data.error || "SERVER_ERROR";
|
|
418
418
|
serverError.isServerError = true;
|
|
419
419
|
throw serverError;
|
|
420
420
|
}
|
package/lib/core/Dashcam.js
CHANGED
|
@@ -369,6 +369,7 @@ class Dashcam {
|
|
|
369
369
|
} else {
|
|
370
370
|
// Linux/Mac with TD_API_ROOT
|
|
371
371
|
this._log("debug", "Starting dashcam recording on Linux/Mac...");
|
|
372
|
+
const dashcamPath = await this._getDashcamPath();
|
|
372
373
|
const titleArg = this.title
|
|
373
374
|
? ` --title="${this.title.replace(/"/g, '"')}"`
|
|
374
375
|
: "";
|
|
@@ -376,10 +377,12 @@ class Dashcam {
|
|
|
376
377
|
this.startTime = Date.now();
|
|
377
378
|
await this.client.exec(
|
|
378
379
|
shell,
|
|
379
|
-
`TD_API_ROOT="${apiRoot}"
|
|
380
|
+
`TD_API_ROOT="${apiRoot}" "${dashcamPath}" record${titleArg} >/dev/null 2>&1 &`,
|
|
380
381
|
10000,
|
|
381
382
|
process.env.TD_DEBUG == "true" ? false : true,
|
|
382
383
|
);
|
|
384
|
+
// Give dashcam time to initialize and create its status file before marking as recording
|
|
385
|
+
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
383
386
|
this._log("debug", "Dashcam recording started");
|
|
384
387
|
}
|
|
385
388
|
|