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,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testdriver:cloud
|
|
3
|
+
description: The fastest way to get started with TestDriver. Just set your API key and start testing.
|
|
4
|
+
---
|
|
5
|
+
<!-- Generated from cloud.mdx. DO NOT EDIT. -->
|
|
6
|
+
|
|
7
|
+
Cloud pricing is based on **device-seconds**: the amount of time your tests run on **our infrastructure**.
|
|
8
|
+
|
|
9
|
+
- **Zero Setup** — Start testing immediately. No DevOps required.
|
|
10
|
+
- **Free Tier** — Get started with a limited preview at no cost.
|
|
11
|
+
- **Pay As You Go** — Only pay for the device-seconds you use.
|
|
12
|
+
|
|
13
|
+
## Get Started
|
|
14
|
+
Cloud is the default when you follow the Quickstart guide.
|
|
15
|
+
<Card
|
|
16
|
+
title="Try the Quickstart"
|
|
17
|
+
icon="play"
|
|
18
|
+
href="/v7/quickstart"
|
|
19
|
+
>
|
|
20
|
+
Set your API key and start testing in minutes.
|
|
21
|
+
</Card>
|
|
22
|
+
|
|
23
|
+
## Parallel Testing Limits
|
|
24
|
+
|
|
25
|
+
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).
|
|
26
|
+
|
|
27
|
+
<Info>
|
|
28
|
+
**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.
|
|
29
|
+
</Info>
|
|
30
|
+
|
|
31
|
+
## Avoiding Slot Conflicts
|
|
32
|
+
|
|
33
|
+
To prevent tests from failing due to exceeding your license slot limit, we recommend two key configurations:
|
|
34
|
+
|
|
35
|
+
<AccordionGroup>
|
|
36
|
+
<Accordion title="Set Maximum Concurrency in Vitest">
|
|
37
|
+
Limit concurrent tests to match your available license slots:
|
|
38
|
+
|
|
39
|
+
```javascript vitest.config.mjs
|
|
40
|
+
import { defineConfig } from 'vitest/config';
|
|
41
|
+
import { TestDriver } from 'testdriverai/vitest';
|
|
42
|
+
|
|
43
|
+
export default defineConfig({
|
|
44
|
+
test: {
|
|
45
|
+
testTimeout: 900000,
|
|
46
|
+
hookTimeout: 900000,
|
|
47
|
+
maxConcurrency: 5, // Set to your license slot limit
|
|
48
|
+
reporters: ['default', TestDriver()],
|
|
49
|
+
setupFiles: ['testdriverai/vitest/setup'],
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
<Tip>
|
|
55
|
+
Check your slot count at [console.testdriver.ai](https://console.testdriver.ai) and set `maxConcurrency` to that number or lower.
|
|
56
|
+
</Tip>
|
|
57
|
+
</Accordion>
|
|
58
|
+
|
|
59
|
+
<Accordion title="Use GitHub Concurrency Keys">
|
|
60
|
+
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):
|
|
61
|
+
|
|
62
|
+
```yaml .github/workflows/test.yml
|
|
63
|
+
name: Tests
|
|
64
|
+
|
|
65
|
+
on:
|
|
66
|
+
push:
|
|
67
|
+
branches: [main]
|
|
68
|
+
pull_request:
|
|
69
|
+
|
|
70
|
+
# Prevent concurrent runs from competing for license slots
|
|
71
|
+
concurrency:
|
|
72
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
73
|
+
cancel-in-progress: true
|
|
74
|
+
|
|
75
|
+
jobs:
|
|
76
|
+
test:
|
|
77
|
+
runs-on: ubuntu-latest
|
|
78
|
+
steps:
|
|
79
|
+
- uses: actions/checkout@v4
|
|
80
|
+
|
|
81
|
+
- name: Setup Node.js
|
|
82
|
+
uses: actions/setup-node@v4
|
|
83
|
+
with:
|
|
84
|
+
node-version: '20'
|
|
85
|
+
|
|
86
|
+
- name: Install dependencies
|
|
87
|
+
run: npm install
|
|
88
|
+
|
|
89
|
+
- name: Run tests
|
|
90
|
+
run: vitest run
|
|
91
|
+
env:
|
|
92
|
+
TD_API_KEY: ${{ secrets.TD_API_KEY }}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The `concurrency` block ensures:
|
|
96
|
+
- Only one workflow run per branch runs at a time
|
|
97
|
+
- New pushes cancel in-progress runs on the same branch
|
|
98
|
+
- Different branches/PRs can run in parallel (up to your slot limit)
|
|
99
|
+
</Accordion>
|
|
100
|
+
</AccordionGroup>
|
|
101
|
+
|
|
102
|
+
## When to Consider Self-Hosted
|
|
103
|
+
|
|
104
|
+
Cloud is perfect for getting started and for teams that want zero infrastructure management. However, you might consider [Self-Hosted](/v7/self-hosted) if you:
|
|
105
|
+
|
|
106
|
+
- Want to escape per-second billing with a flat license fee
|
|
107
|
+
- Require greater concurrency than offered in Cloud plans
|
|
108
|
+
- Need full control over your infrastructure and privacy
|
|
109
|
+
- Want to use your own AI API keys
|
|
110
|
+
- Require custom hardware configurations
|
|
111
|
+
- Have high test volumes that make self-hosting more economical
|
|
112
|
+
|
|
113
|
+
<Card
|
|
114
|
+
title="Explore Self-Hosted"
|
|
115
|
+
icon="server"
|
|
116
|
+
href="/v7/self-hosted"
|
|
117
|
+
>
|
|
118
|
+
Learn about self-hosting for unlimited test execution at a flat rate.
|
|
119
|
+
</Card>
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testdriver:customizing-devices
|
|
3
|
+
description: Configure TestDriver sandbox options and environment settings
|
|
4
|
+
---
|
|
5
|
+
<!-- Generated from customizing-devices.mdx. DO NOT EDIT. -->
|
|
6
|
+
|
|
7
|
+
## TestDriver Options
|
|
8
|
+
|
|
9
|
+
Configure TestDriver behavior with options passed to the `TestDriver()` function:
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
const testdriver = TestDriver(context, {
|
|
13
|
+
reconnect: false,
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Preview Mode
|
|
18
|
+
|
|
19
|
+
Control how test execution is visualized. The `preview` option determines where the live debugger view opens:
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
const testdriver = TestDriver(context, {
|
|
23
|
+
preview: "browser", // Opens in default browser (default)
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
| Value | Description |
|
|
28
|
+
|-------|-------------|
|
|
29
|
+
| `"browser"` | Opens debugger in default browser (default) |
|
|
30
|
+
| `"ide"` | Opens preview in IDE panel (VSCode, Cursor - requires TestDriver extension) |
|
|
31
|
+
| `"none"` | Headless mode, no visual preview |
|
|
32
|
+
|
|
33
|
+
**IDE Preview**
|
|
34
|
+
|
|
35
|
+
For the best development experience, use `preview: "ide"` with the TestDriver extension for VSCode or Cursor:
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
const testdriver = TestDriver(context, {
|
|
39
|
+
preview: "ide", // Opens preview in IDE panel
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Headless Mode**
|
|
44
|
+
|
|
45
|
+
Run tests without any visual preview. Useful for CI/CD pipelines:
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
const testdriver = TestDriver(context, {
|
|
49
|
+
preview: "none", // No visual preview (headless)
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
<Note>
|
|
54
|
+
The legacy `headless: true` option still works for backward compatibility and maps to `preview: "none"`.
|
|
55
|
+
</Note>
|
|
56
|
+
|
|
57
|
+
### IP Target
|
|
58
|
+
|
|
59
|
+
If self-hosting TestDriver, use `ip` to specify the device IP. See [Self-Hosting TestDriver](../self-hosting.md) for details.
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
const testdriver = TestDriver(context, {
|
|
63
|
+
ip: "203.0.113.42", // Your allowlisted IP
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Operating System
|
|
68
|
+
|
|
69
|
+
Set the `os` property to run tests on a specific operating system. Available options are `linux` (default) and `windows`.
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
const testdriver = TestDriver(context, {
|
|
73
|
+
os: "windows", // Run on Windows sandbox
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
#### Using Environment Variables
|
|
78
|
+
|
|
79
|
+
You can make the operating system configurable via environment variables. This requires adding code to read from `process.env` in your test:
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
const testdriver = TestDriver(context, {
|
|
83
|
+
os: process.env.TD_OS || "linux", // Read from env, default to Linux
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Then pass the variable when running tests:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Run tests on Windows
|
|
91
|
+
TD_OS=windows vitest run
|
|
92
|
+
|
|
93
|
+
# Run tests on Linux (default)
|
|
94
|
+
TD_OS=linux vitest run
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
This pattern is useful for running the same test suite across multiple operating systems in CI/CD:
|
|
98
|
+
|
|
99
|
+
```yaml
|
|
100
|
+
# Example GitHub Actions matrix
|
|
101
|
+
strategy:
|
|
102
|
+
matrix:
|
|
103
|
+
os: [linux, windows]
|
|
104
|
+
steps:
|
|
105
|
+
- run: TD_OS=${{ matrix.os }} vitest run
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Keepalive
|
|
109
|
+
|
|
110
|
+
By default, sandboxes terminate immediately when the test finishes. Set this value to keep the sandbox alive for reconnection.
|
|
111
|
+
|
|
112
|
+
The `keepAlive` param enables you to keep the sandbox running after the test completes for debugging or reconnection. This will allow you to use the debugger to inspect the state of the device after the test has finished.
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
const testdriver = TestDriver(context, {
|
|
116
|
+
keepAlive: 300000, // Keep sandbox alive for 5 minutes after test
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Reconnecting to Existing Sandbox
|
|
121
|
+
|
|
122
|
+
Speed up test development by reconnecting to an existing sandbox instead of starting fresh each time. This lets you iterate quickly on failing steps without re-running the entire test from the beginning.
|
|
123
|
+
|
|
124
|
+
Split your test into two files: one for known-good steps that set up the desired state, and another for work-in-progress steps you want to debug.
|
|
125
|
+
|
|
126
|
+
```javascript known-good.test.mjs
|
|
127
|
+
const testdriver = TestDriver(context, {
|
|
128
|
+
keepAlive: 60000, // Keep sandbox alive for 60 seconds after test
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
```javascript work-in-progress.test.mjs
|
|
133
|
+
// Second test file: experiment.test.mjs (run within keepAlive window)
|
|
134
|
+
const testdriver = TestDriver(context, {
|
|
135
|
+
reconnect: true, // Reconnect to existing sandbox
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Then, you can run both tests in sequence:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
vitest run -t known-good.test.mjs -t work-in-progress.test.mjs
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
And as you make changes to `work-in-progress.test.mjs`, you can re-run just that file to quickly iterate on the failing steps.
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
vitest run work-in-progress.test.mjs
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
<Warning>
|
|
152
|
+
Reconnect only works if run within the `keepAlive` window of the previous test.
|
|
153
|
+
</Warning>
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testdriver:dashcam
|
|
3
|
+
description: Record test execution with video and logs
|
|
4
|
+
---
|
|
5
|
+
<!-- Generated from dashcam.mdx. DO NOT EDIT. -->
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
Dashcam provides automatic video recording and log aggregation for your tests. It captures screen recordings, application logs, and test execution details that can be reviewed later.
|
|
10
|
+
|
|
11
|
+
## Basic Usage
|
|
12
|
+
|
|
13
|
+
### With Presets
|
|
14
|
+
|
|
15
|
+
Most presets automatically include Dashcam:
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
import { test } from 'vitest';
|
|
19
|
+
import { chrome } from 'testdriverai/presets';
|
|
20
|
+
|
|
21
|
+
test('my test', async (context) => {
|
|
22
|
+
const { testdriver, dashcam } = await chrome(context, {
|
|
23
|
+
url: 'https://example.com'
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Test executes with recording automatically
|
|
27
|
+
await testdriver.find('login button').then(el => el.click());
|
|
28
|
+
|
|
29
|
+
// Dashcam URL available after test
|
|
30
|
+
console.log('Replay:', dashcam.url);
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Manual Setup
|
|
35
|
+
|
|
36
|
+
For more control, create a Dashcam instance directly:
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
import TestDriver from 'testdriverai';
|
|
40
|
+
import Dashcam from 'testdriverai/lib/core/Dashcam.js';
|
|
41
|
+
|
|
42
|
+
const client = await TestDriver.create({ os: 'linux' });
|
|
43
|
+
const dashcam = new Dashcam(client, {
|
|
44
|
+
apiKey: process.env.DASHCAM_API_KEY
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
await dashcam.auth();
|
|
48
|
+
await dashcam.start();
|
|
49
|
+
|
|
50
|
+
// Run your tests
|
|
51
|
+
|
|
52
|
+
const url = await dashcam.stop();
|
|
53
|
+
console.log('Replay URL:', url);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Constructor
|
|
57
|
+
|
|
58
|
+
Create a new Dashcam instance:
|
|
59
|
+
|
|
60
|
+
```javascript
|
|
61
|
+
new Dashcam(client, options)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Parameters
|
|
65
|
+
|
|
66
|
+
<ParamField path="client" type="TestDriver" required>
|
|
67
|
+
TestDriver client instance
|
|
68
|
+
</ParamField>
|
|
69
|
+
|
|
70
|
+
<ParamField path="options" type="object">
|
|
71
|
+
Configuration options
|
|
72
|
+
|
|
73
|
+
<Expandable title="options properties">
|
|
74
|
+
<ParamField path="apiKey" type="string" default="4e93d8bf-3886-4d26-a144-116c4063522d">
|
|
75
|
+
Dashcam API key for authentication
|
|
76
|
+
</ParamField>
|
|
77
|
+
|
|
78
|
+
<ParamField path="autoStart" type="boolean" default={false}>
|
|
79
|
+
Automatically start recording after authentication
|
|
80
|
+
</ParamField>
|
|
81
|
+
|
|
82
|
+
<ParamField path="logs" type="array" default={[]}>
|
|
83
|
+
Log configurations to add automatically
|
|
84
|
+
</ParamField>
|
|
85
|
+
</Expandable>
|
|
86
|
+
</ParamField>
|
|
87
|
+
|
|
88
|
+
## Methods
|
|
89
|
+
|
|
90
|
+
### auth()
|
|
91
|
+
|
|
92
|
+
Authenticate with Dashcam service:
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
await dashcam.auth(apiKey)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
<ParamField path="apiKey" type="string" optional>
|
|
99
|
+
Override the API key set in constructor
|
|
100
|
+
</ParamField>
|
|
101
|
+
|
|
102
|
+
**Returns:** `Promise<void>`
|
|
103
|
+
|
|
104
|
+
**Example:**
|
|
105
|
+
```javascript
|
|
106
|
+
await dashcam.auth('your-api-key');
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### start()
|
|
110
|
+
|
|
111
|
+
Start recording:
|
|
112
|
+
|
|
113
|
+
```javascript
|
|
114
|
+
await dashcam.start()
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Returns:** `Promise<void>`
|
|
118
|
+
|
|
119
|
+
**Example:**
|
|
120
|
+
```javascript
|
|
121
|
+
await dashcam.start();
|
|
122
|
+
console.log('Recording started');
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### stop()
|
|
126
|
+
|
|
127
|
+
Stop recording and retrieve replay URL:
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
await dashcam.stop()
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Returns:** `Promise<string|null>` - Replay URL if available
|
|
134
|
+
|
|
135
|
+
**Example:**
|
|
136
|
+
```javascript
|
|
137
|
+
const url = await dashcam.stop();
|
|
138
|
+
if (url) {
|
|
139
|
+
console.log('Watch replay:', url);
|
|
140
|
+
} else {
|
|
141
|
+
console.log('No replay URL available');
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### addFileLog()
|
|
146
|
+
|
|
147
|
+
Track a log file in the recording:
|
|
148
|
+
|
|
149
|
+
```javascript
|
|
150
|
+
await dashcam.addFileLog(path, name)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
<ParamField path="path" type="string" required>
|
|
154
|
+
Path to the log file
|
|
155
|
+
</ParamField>
|
|
156
|
+
|
|
157
|
+
<ParamField path="name" type="string" required>
|
|
158
|
+
Display name for the log in Dashcam
|
|
159
|
+
</ParamField>
|
|
160
|
+
|
|
161
|
+
**Returns:** `Promise<void>`
|
|
162
|
+
|
|
163
|
+
**Example:**
|
|
164
|
+
```javascript
|
|
165
|
+
// Linux/Mac
|
|
166
|
+
await dashcam.addFileLog('/tmp/app.log', 'Application Log');
|
|
167
|
+
|
|
168
|
+
// Windows
|
|
169
|
+
await dashcam.addFileLog('C:\\logs\\app.log', 'Application Log');
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### addApplicationLog()
|
|
173
|
+
|
|
174
|
+
Track application-specific logs:
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
await dashcam.addApplicationLog(application, name)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
<ParamField path="application" type="string" required>
|
|
181
|
+
Application name to track
|
|
182
|
+
</ParamField>
|
|
183
|
+
|
|
184
|
+
<ParamField path="name" type="string" required>
|
|
185
|
+
Display name for the log
|
|
186
|
+
</ParamField>
|
|
187
|
+
|
|
188
|
+
**Returns:** `Promise<void>`
|
|
189
|
+
|
|
190
|
+
**Example:**
|
|
191
|
+
```javascript
|
|
192
|
+
await dashcam.addApplicationLog('Google Chrome', 'Browser Logs');
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### addLog()
|
|
196
|
+
|
|
197
|
+
Generic method to add any type of log:
|
|
198
|
+
|
|
199
|
+
```javascript
|
|
200
|
+
await dashcam.addLog(config)
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
<ParamField path="config" type="object" required>
|
|
204
|
+
Log configuration
|
|
205
|
+
|
|
206
|
+
<Expandable title="config properties">
|
|
207
|
+
<ParamField path="name" type="string" required>
|
|
208
|
+
Display name for the log
|
|
209
|
+
</ParamField>
|
|
210
|
+
|
|
211
|
+
<ParamField path="type" type="string" required>
|
|
212
|
+
Log type: `'file'`, `'stdout'`, or `'application'`
|
|
213
|
+
</ParamField>
|
|
214
|
+
|
|
215
|
+
<ParamField path="path" type="string">
|
|
216
|
+
File path (required for type='file')
|
|
217
|
+
</ParamField>
|
|
218
|
+
|
|
219
|
+
<ParamField path="application" type="string">
|
|
220
|
+
Application name (required for type='application')
|
|
221
|
+
</ParamField>
|
|
222
|
+
</Expandable>
|
|
223
|
+
</ParamField>
|
|
224
|
+
|
|
225
|
+
**Returns:** `Promise<void>`
|
|
226
|
+
|
|
227
|
+
**Example:**
|
|
228
|
+
```javascript
|
|
229
|
+
await dashcam.addLog({
|
|
230
|
+
name: 'Test Output',
|
|
231
|
+
type: 'file',
|
|
232
|
+
path: '/tmp/test.log'
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
await dashcam.addLog({
|
|
236
|
+
name: 'Chrome Logs',
|
|
237
|
+
type: 'application',
|
|
238
|
+
application: 'Google Chrome'
|
|
239
|
+
});
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### isRecording()
|
|
243
|
+
|
|
244
|
+
Check if currently recording:
|
|
245
|
+
|
|
246
|
+
```javascript
|
|
247
|
+
await dashcam.isRecording()
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**Returns:** `Promise<boolean>` - True if recording is active
|
|
251
|
+
|
|
252
|
+
**Example:**
|
|
253
|
+
```javascript
|
|
254
|
+
if (await dashcam.isRecording()) {
|
|
255
|
+
console.log('Recording in progress');
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Properties
|
|
260
|
+
|
|
261
|
+
### recording
|
|
262
|
+
|
|
263
|
+
Current recording state:
|
|
264
|
+
|
|
265
|
+
```javascript
|
|
266
|
+
dashcam.recording // boolean
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### apiKey
|
|
270
|
+
|
|
271
|
+
Configured API key:
|
|
272
|
+
|
|
273
|
+
```javascript
|
|
274
|
+
dashcam.apiKey // string
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### client
|
|
278
|
+
|
|
279
|
+
Associated TestDriver client:
|
|
280
|
+
|
|
281
|
+
```javascript
|
|
282
|
+
dashcam.client // TestDriver instance
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Complete Examples
|
|
286
|
+
|
|
287
|
+
### Basic Recording
|
|
288
|
+
|
|
289
|
+
```javascript
|
|
290
|
+
import { test } from 'vitest';
|
|
291
|
+
import TestDriver from 'testdriverai';
|
|
292
|
+
import Dashcam from 'testdriverai/lib/core/Dashcam.js';
|
|
293
|
+
|
|
294
|
+
test('record test execution', async () => {
|
|
295
|
+
const client = await TestDriver.create({ os: 'linux' });
|
|
296
|
+
const dashcam = new Dashcam(client);
|
|
297
|
+
|
|
298
|
+
await dashcam.auth();
|
|
299
|
+
await dashcam.start();
|
|
300
|
+
|
|
301
|
+
// Run your test
|
|
302
|
+
await client.find('button').then(el => el.click());
|
|
303
|
+
|
|
304
|
+
const url = await dashcam.stop();
|
|
305
|
+
console.log('Replay:', url);
|
|
306
|
+
|
|
307
|
+
await client.cleanup();
|
|
308
|
+
});
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### With Log Tracking
|
|
312
|
+
|
|
313
|
+
```javascript
|
|
314
|
+
test('record with logs', async () => {
|
|
315
|
+
const client = await TestDriver.create({ os: 'linux' });
|
|
316
|
+
const dashcam = new Dashcam(client);
|
|
317
|
+
|
|
318
|
+
await dashcam.auth();
|
|
319
|
+
|
|
320
|
+
// Add log files before starting
|
|
321
|
+
await dashcam.addFileLog('/tmp/testdriver.log', 'TestDriver Log');
|
|
322
|
+
await dashcam.addFileLog('/tmp/app.log', 'Application Log');
|
|
323
|
+
|
|
324
|
+
await dashcam.start();
|
|
325
|
+
|
|
326
|
+
// Test execution
|
|
327
|
+
await client.find('login button').then(el => el.click());
|
|
328
|
+
|
|
329
|
+
const url = await dashcam.stop();
|
|
330
|
+
console.log('Replay with logs:', url);
|
|
331
|
+
|
|
332
|
+
await client.cleanup();
|
|
333
|
+
});
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Auto-start Configuration
|
|
337
|
+
|
|
338
|
+
```javascript
|
|
339
|
+
test('auto-start recording', async () => {
|
|
340
|
+
const client = await TestDriver.create({ os: 'linux' });
|
|
341
|
+
const dashcam = new Dashcam(client, {
|
|
342
|
+
autoStart: true,
|
|
343
|
+
logs: [
|
|
344
|
+
{
|
|
345
|
+
name: 'App Log',
|
|
346
|
+
type: 'file',
|
|
347
|
+
path: '/tmp/app.log'
|
|
348
|
+
}
|
|
349
|
+
]
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
await dashcam.auth(); // Automatically starts recording
|
|
353
|
+
|
|
354
|
+
// Test execution
|
|
355
|
+
await client.find('submit button').then(el => el.click());
|
|
356
|
+
|
|
357
|
+
const url = await dashcam.stop();
|
|
358
|
+
console.log('Replay:', url);
|
|
359
|
+
|
|
360
|
+
await client.cleanup();
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Using with Presets
|
|
365
|
+
|
|
366
|
+
```javascript
|
|
367
|
+
import { chrome } from 'testdriverai/presets';
|
|
368
|
+
|
|
369
|
+
test('preset with dashcam', async (context) => {
|
|
370
|
+
const { testdriver, dashcam } = await chrome(context, {
|
|
371
|
+
url: 'https://example.com',
|
|
372
|
+
dashcam: true // Enabled by default
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
// Test runs with automatic recording
|
|
376
|
+
await testdriver.find('button').then(el => el.click());
|
|
377
|
+
|
|
378
|
+
// URL automatically available
|
|
379
|
+
console.log('Replay:', dashcam.url);
|
|
380
|
+
});
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### Disabling Dashcam in Presets
|
|
384
|
+
|
|
385
|
+
```javascript
|
|
386
|
+
test('without dashcam', async (context) => {
|
|
387
|
+
const { testdriver } = await chrome(context, {
|
|
388
|
+
url: 'https://example.com',
|
|
389
|
+
dashcam: false // Disable recording
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// Test runs without recording (faster)
|
|
393
|
+
await testdriver.find('button').then(el => el.click());
|
|
394
|
+
});
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
## Platform Differences
|
|
398
|
+
|
|
399
|
+
### Windows
|
|
400
|
+
|
|
401
|
+
On Windows, Dashcam uses PowerShell commands and installs via npm:
|
|
402
|
+
|
|
403
|
+
```javascript
|
|
404
|
+
// Windows-specific paths
|
|
405
|
+
await dashcam.addFileLog(
|
|
406
|
+
'C:\\Users\\testdriver\\Documents\\testdriver.log',
|
|
407
|
+
'TestDriver Log'
|
|
408
|
+
);
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Linux/Mac
|
|
412
|
+
|
|
413
|
+
On Linux/Mac, Dashcam uses shell commands:
|
|
414
|
+
|
|
415
|
+
```javascript
|
|
416
|
+
// Unix-specific paths
|
|
417
|
+
await dashcam.addFileLog('/tmp/testdriver.log', 'TestDriver Log');
|
|
418
|
+
```
|