testdriverai 6.2.2 → 7.1.0
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.yml +75 -0
- package/.github/workflows/acceptance-sdk-tests.yml +133 -0
- package/.vscode/settings.json +5 -1
- package/AGENTS.md +550 -0
- package/CODEOWNERS +0 -1
- package/README.md +126 -0
- package/{testdriver → _testdriver}/acceptance/drag-and-drop.yaml +2 -2
- package/{testdriver → _testdriver}/acceptance/snippets/login.yaml +1 -1
- package/_testdriver/examples/desktop/lifecycle/prerun.yaml +0 -0
- package/{testdriver → _testdriver}/examples/web/lifecycle/prerun.yaml +6 -1
- package/{testdriver → _testdriver}/lifecycle/postrun.yaml +3 -2
- package/_testdriver/lifecycle/prerun.yaml +15 -0
- package/{testdriver → _testdriver}/lifecycle/provision.yaml +7 -2
- package/agent/index.js +300 -85
- package/agent/interface.js +15 -0
- package/agent/lib/cache.js +142 -0
- package/agent/lib/commander.js +1 -39
- package/agent/lib/commands.js +910 -296
- package/agent/lib/redraw.js +129 -41
- package/agent/lib/sandbox.js +29 -6
- package/agent/lib/sdk.js +22 -0
- package/agent/lib/system.js +0 -3
- package/agent/lib/validation.js +1 -7
- package/debug-locate-response.js +82 -0
- package/debugger/index.html +15 -4
- package/docs/ARCHITECTURE.md +424 -0
- package/docs/AWESOME_LOGS_QUICK_REF.md +100 -0
- package/docs/MIGRATION.md +425 -0
- package/docs/PRESETS.md +210 -0
- package/docs/QUICK_START_TEST_RECORDING.md +215 -0
- package/docs/SDK_AWESOME_LOGS.md +468 -0
- package/docs/TEST_RECORDING.md +388 -0
- package/docs/docs.json +286 -152
- package/docs/guide/best-practices-polling.mdx +154 -0
- package/docs/sdk-browser-rendering.md +167 -0
- package/docs/v6/getting-started/self-hosting.mdx +407 -0
- package/docs/{guide → v6/guide}/dashcam.mdx +1 -1
- package/docs/{guide → v6/guide}/environment-variables.mdx +4 -5
- package/docs/{guide → v6/guide}/lifecycle.mdx +1 -1
- package/docs/v6/overview/comparison.mdx +101 -0
- package/docs/v7/README.md +135 -0
- package/docs/v7/api/ai.mdx +205 -0
- package/docs/v7/api/assert.mdx +285 -0
- package/docs/v7/api/assertions.mdx +403 -0
- package/docs/v7/api/click.mdx +287 -0
- package/docs/v7/api/client.mdx +322 -0
- package/docs/v7/api/dashcam.mdx +497 -0
- package/docs/v7/api/doubleClick.mdx +102 -0
- package/docs/v7/api/elements.mdx +479 -0
- package/docs/v7/api/exec.mdx +346 -0
- package/docs/v7/api/find.mdx +316 -0
- package/docs/v7/api/focusApplication.mdx +294 -0
- package/docs/v7/api/hover.mdx +279 -0
- package/docs/v7/api/mouseDown.mdx +161 -0
- package/docs/v7/api/mouseUp.mdx +164 -0
- package/docs/v7/api/pressKeys.mdx +349 -0
- package/docs/v7/api/rightClick.mdx +123 -0
- package/docs/v7/api/sandbox.mdx +404 -0
- package/docs/v7/api/scroll.mdx +300 -0
- package/docs/v7/api/type.mdx +314 -0
- package/docs/v7/commands/assert.mdx +45 -0
- package/docs/v7/commands/exec.mdx +282 -0
- package/docs/v7/commands/focus-application.mdx +44 -0
- package/docs/v7/commands/hover-image.mdx +69 -0
- package/docs/v7/commands/hover-text.mdx +47 -0
- package/docs/v7/commands/if.mdx +53 -0
- package/docs/v7/commands/match-image.mdx +67 -0
- package/docs/v7/commands/press-keys.mdx +87 -0
- package/docs/v7/commands/remember.mdx +49 -0
- package/docs/v7/commands/run.mdx +44 -0
- package/docs/v7/commands/scroll-until-image.mdx +66 -0
- package/docs/v7/commands/scroll-until-text.mdx +60 -0
- package/docs/v7/commands/scroll.mdx +69 -0
- package/docs/v7/commands/type.mdx +45 -0
- package/docs/v7/commands/wait-for-image.mdx +54 -0
- package/docs/v7/commands/wait-for-text.mdx +48 -0
- package/docs/v7/commands/wait.mdx +45 -0
- package/docs/v7/getting-started/configuration.mdx +380 -0
- package/docs/v7/getting-started/quickstart.mdx +332 -0
- package/docs/v7/guides/best-practices.mdx +486 -0
- package/docs/v7/guides/caching-ai.mdx +215 -0
- package/docs/v7/guides/caching-selectors.mdx +292 -0
- package/docs/v7/guides/caching.mdx +366 -0
- package/docs/v7/guides/ci-cd/azure.mdx +587 -0
- package/docs/v7/guides/ci-cd/circleci.mdx +523 -0
- package/docs/v7/guides/ci-cd/github-actions.mdx +457 -0
- package/docs/v7/guides/ci-cd/gitlab.mdx +498 -0
- package/docs/v7/guides/ci-cd/jenkins.mdx +664 -0
- package/docs/v7/guides/ci-cd/travis.mdx +438 -0
- package/docs/v7/guides/debugging.mdx +349 -0
- package/docs/v7/guides/faq.mdx +393 -0
- package/docs/v7/guides/migration.mdx +562 -0
- package/docs/v7/guides/performance.mdx +517 -0
- package/docs/{getting-started → v7/guides}/self-hosting.mdx +11 -12
- package/docs/v7/guides/troubleshooting.mdx +526 -0
- package/docs/v7/guides/vitest-plugin.mdx +477 -0
- package/docs/v7/guides/vitest.mdx +535 -0
- package/docs/v7/platforms/linux.mdx +308 -0
- package/docs/v7/platforms/macos.mdx +433 -0
- package/docs/v7/platforms/windows.mdx +430 -0
- package/docs/v7/playwright.mdx +342 -0
- package/docs/v7/presets/chrome-extension.mdx +223 -0
- package/docs/v7/presets/chrome.mdx +287 -0
- package/docs/v7/presets/electron.mdx +435 -0
- package/docs/v7/presets/vscode.mdx +398 -0
- package/docs/v7/presets/webapp.mdx +396 -0
- package/docs/v7/progressive-apis/CORE.md +459 -0
- package/docs/v7/progressive-apis/HOOKS.md +360 -0
- package/docs/v7/progressive-apis/PROGRESSIVE_DISCLOSURE.md +230 -0
- package/docs/v7/progressive-apis/PROVISION.md +266 -0
- package/eslint.config.js +19 -1
- package/interfaces/cli/lib/base.js +10 -4
- package/interfaces/logger.js +2 -1
- package/interfaces/shared-test-state.mjs +69 -0
- package/interfaces/vitest-plugin.mjs +830 -0
- package/package.json +29 -5
- package/schema.json +8 -29
- package/scripts/view-test-results.mjs +96 -0
- package/sdk-log-formatter.js +714 -0
- package/sdk.d.ts +1028 -0
- package/sdk.js +2567 -0
- package/{.github/workflows/self-hosted.yml → self-hosted.yml} +13 -4
- package/setup/aws/cloudformation.yaml +9 -2
- package/src/core/Dashcam.js +469 -0
- package/src/core/index.d.ts +150 -0
- package/src/core/index.js +12 -0
- package/src/presets/index.mjs +331 -0
- package/src/vitest/extended.mjs +108 -0
- package/src/vitest/hooks.d.ts +119 -0
- package/src/vitest/hooks.mjs +298 -0
- package/src/vitest/index.mjs +64 -0
- package/src/vitest/lifecycle.mjs +277 -0
- package/src/vitest/utils.mjs +150 -0
- package/test/dashcam.test.js +137 -0
- package/test/mcp-example-test.yaml +27 -0
- package/testdriver/acceptance-sdk/QUICK_REFERENCE.md +61 -0
- package/testdriver/acceptance-sdk/README.md +128 -0
- package/testdriver/acceptance-sdk/TEST_REPORTING.md +245 -0
- package/testdriver/acceptance-sdk/assert.test.mjs +26 -0
- package/testdriver/acceptance-sdk/auto-cache-key-demo.test.mjs +56 -0
- package/testdriver/acceptance-sdk/chrome-extension.test.mjs +89 -0
- package/testdriver/acceptance-sdk/drag-and-drop.test.mjs +58 -0
- package/testdriver/acceptance-sdk/element-not-found.test.mjs +25 -0
- package/testdriver/acceptance-sdk/exec-js.test.mjs +43 -0
- package/testdriver/acceptance-sdk/exec-output.test.mjs +59 -0
- package/testdriver/acceptance-sdk/exec-pwsh.test.mjs +57 -0
- package/testdriver/acceptance-sdk/focus-window.test.mjs +36 -0
- package/testdriver/acceptance-sdk/formatted-logging.test.mjs +26 -0
- package/testdriver/acceptance-sdk/hooks-example.test.mjs +38 -0
- package/testdriver/acceptance-sdk/hover-image.test.mjs +34 -0
- package/testdriver/acceptance-sdk/hover-text-with-description.test.mjs +38 -0
- package/testdriver/acceptance-sdk/hover-text.test.mjs +27 -0
- package/testdriver/acceptance-sdk/match-image.test.mjs +36 -0
- package/testdriver/acceptance-sdk/presets-example.test.mjs +87 -0
- package/testdriver/acceptance-sdk/press-keys.test.mjs +50 -0
- package/testdriver/acceptance-sdk/prompt.test.mjs +33 -0
- package/testdriver/acceptance-sdk/scroll-keyboard.test.mjs +38 -0
- package/testdriver/acceptance-sdk/scroll-until-image.test.mjs +39 -0
- package/testdriver/acceptance-sdk/scroll-until-text.test.mjs +28 -0
- package/testdriver/acceptance-sdk/scroll.test.mjs +41 -0
- package/testdriver/acceptance-sdk/setup/globalTeardown.mjs +11 -0
- package/testdriver/acceptance-sdk/setup/testHelpers.mjs +420 -0
- package/testdriver/acceptance-sdk/setup/vitestSetup.mjs +40 -0
- package/testdriver/acceptance-sdk/sully-ai.test.mjs +234 -0
- package/testdriver/acceptance-sdk/test-console-logs.test.mjs +42 -0
- package/testdriver/acceptance-sdk/type-checking-demo.js +49 -0
- package/testdriver/acceptance-sdk/type.test.mjs +45 -0
- package/verify-element-api.js +89 -0
- package/verify-types.js +0 -0
- package/vitest.config.example.js +19 -0
- package/vitest.config.mjs +66 -0
- package/vitest.config.mjs.bak +44 -0
- package/.github/workflows/acceptance-v6.yml +0 -169
- package/.vscode/mcp.json +0 -9
- package/docs/overview/comparison.mdx +0 -82
- package/testdriver/lifecycle/prerun.yaml +0 -17
- /package/{testdriver/examples/desktop/lifecycle/prerun.yaml → .env.example} +0 -0
- /package/{testdriver → _testdriver}/acceptance/assert.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/dashcam.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/embed.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/exec-js.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/exec-output.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/exec-shell.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/focus-window.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/hover-image.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/hover-text-with-description.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/hover-text.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/if-else.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/match-image.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/press-keys.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/prompt.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/remember.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/screenshots/cart.png +0 -0
- /package/{testdriver → _testdriver}/acceptance/scroll-keyboard.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/scroll-until-image.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/scroll-until-text.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/scroll.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/snippets/match-cart.yaml +0 -0
- /package/{testdriver → _testdriver}/acceptance/type.yaml +0 -0
- /package/{testdriver → _testdriver}/behavior/failure.yaml +0 -0
- /package/{testdriver → _testdriver}/behavior/hover-text.yaml +0 -0
- /package/{testdriver → _testdriver}/behavior/lifecycle/postrun.yaml +0 -0
- /package/{testdriver → _testdriver}/behavior/lifecycle/prerun.yaml +0 -0
- /package/{testdriver → _testdriver}/behavior/lifecycle/provision.yaml +0 -0
- /package/{testdriver → _testdriver}/behavior/secrets.yaml +0 -0
- /package/{testdriver → _testdriver}/edge-cases/dashcam-chrome.yaml +0 -0
- /package/{testdriver → _testdriver}/edge-cases/exec-pwsh-multiline.yaml +0 -0
- /package/{testdriver → _testdriver}/edge-cases/js-exception.yaml +0 -0
- /package/{testdriver → _testdriver}/edge-cases/js-promise.yaml +0 -0
- /package/{testdriver → _testdriver}/edge-cases/lifecycle/postrun.yaml +0 -0
- /package/{testdriver → _testdriver}/edge-cases/prompt-in-middle.yaml +0 -0
- /package/{testdriver → _testdriver}/edge-cases/prompt-nested.yaml +0 -0
- /package/{testdriver → _testdriver}/edge-cases/success-test.yaml +0 -0
- /package/{testdriver → _testdriver}/examples/android/example.yaml +0 -0
- /package/{testdriver → _testdriver}/examples/android/lifecycle/postrun.yaml +0 -0
- /package/{testdriver → _testdriver}/examples/android/lifecycle/provision.yaml +0 -0
- /package/{testdriver → _testdriver}/examples/android/readme.md +0 -0
- /package/{testdriver → _testdriver}/examples/chrome-extension/lifecycle/provision.yaml +0 -0
- /package/{testdriver → _testdriver}/examples/desktop/lifecycle/provision.yaml +0 -0
- /package/{testdriver → _testdriver}/examples/vscode-extension/lifecycle/provision.yaml +0 -0
- /package/{testdriver → _testdriver}/examples/web/lifecycle/postrun.yaml +0 -0
- /package/docs/{account → v6/account}/dashboard.mdx +0 -0
- /package/docs/{account → v6/account}/enterprise.mdx +0 -0
- /package/docs/{account → v6/account}/pricing.mdx +0 -0
- /package/docs/{account → v6/account}/projects.mdx +0 -0
- /package/docs/{account → v6/account}/team.mdx +0 -0
- /package/docs/{action → v6/action}/ami.mdx +0 -0
- /package/docs/{action → v6/action}/performance.mdx +0 -0
- /package/docs/{action → v6/action}/secrets.mdx +0 -0
- /package/docs/{apps → v6/apps}/chrome-extensions.mdx +0 -0
- /package/docs/{apps → v6/apps}/desktop-apps.mdx +0 -0
- /package/docs/{apps → v6/apps}/mobile-apps.mdx +0 -0
- /package/docs/{apps → v6/apps}/static-websites.mdx +0 -0
- /package/docs/{apps → v6/apps}/tauri-apps.mdx +0 -0
- /package/docs/{bugs → v6/bugs}/jira.mdx +0 -0
- /package/docs/{cli → v6/cli}/overview.mdx +0 -0
- /package/docs/{commands → v6/commands}/assert.mdx +0 -0
- /package/docs/{commands → v6/commands}/exec.mdx +0 -0
- /package/docs/{commands → v6/commands}/focus-application.mdx +0 -0
- /package/docs/{commands → v6/commands}/hover-image.mdx +0 -0
- /package/docs/{commands → v6/commands}/hover-text.mdx +0 -0
- /package/docs/{commands → v6/commands}/if.mdx +0 -0
- /package/docs/{commands → v6/commands}/match-image.mdx +0 -0
- /package/docs/{commands → v6/commands}/press-keys.mdx +0 -0
- /package/docs/{commands → v6/commands}/remember.mdx +0 -0
- /package/docs/{commands → v6/commands}/run.mdx +0 -0
- /package/docs/{commands → v6/commands}/scroll-until-image.mdx +0 -0
- /package/docs/{commands → v6/commands}/scroll-until-text.mdx +0 -0
- /package/docs/{commands → v6/commands}/scroll.mdx +0 -0
- /package/docs/{commands → v6/commands}/type.mdx +0 -0
- /package/docs/{commands → v6/commands}/wait-for-image.mdx +0 -0
- /package/docs/{commands → v6/commands}/wait-for-text.mdx +0 -0
- /package/docs/{commands → v6/commands}/wait.mdx +0 -0
- /package/docs/{exporting → v6/exporting}/junit.mdx +0 -0
- /package/docs/{exporting → v6/exporting}/playwright.mdx +0 -0
- /package/docs/{features → v6/features}/auto-healing.mdx +0 -0
- /package/docs/{features → v6/features}/generation.mdx +0 -0
- /package/docs/{features → v6/features}/parallel-testing.mdx +0 -0
- /package/docs/{features → v6/features}/reusable-snippets.mdx +0 -0
- /package/docs/{features → v6/features}/selectorless.mdx +0 -0
- /package/docs/{features → v6/features}/visual-assertions.mdx +0 -0
- /package/docs/{getting-started → v6/getting-started}/ci.mdx +0 -0
- /package/docs/{getting-started → v6/getting-started}/cli.mdx +0 -0
- /package/docs/{getting-started → v6/getting-started}/editing.mdx +0 -0
- /package/docs/{getting-started → v6/getting-started}/playwright.mdx +0 -0
- /package/docs/{getting-started → v6/getting-started}/running.mdx +0 -0
- /package/docs/{getting-started → v6/getting-started}/vscode.mdx +0 -0
- /package/docs/{guide → v6/guide}/assertions.mdx +0 -0
- /package/docs/{guide → v6/guide}/authentication.mdx +0 -0
- /package/docs/{guide → v6/guide}/code.mdx +0 -0
- /package/docs/{guide → v6/guide}/locating.mdx +0 -0
- /package/docs/{guide → v6/guide}/protips.mdx +0 -0
- /package/docs/{guide → v6/guide}/variables.mdx +0 -0
- /package/docs/{guide → v6/guide}/waiting.mdx +0 -0
- /package/docs/{importing → v6/importing}/csv.mdx +0 -0
- /package/docs/{importing → v6/importing}/gherkin.mdx +0 -0
- /package/docs/{importing → v6/importing}/jira.mdx +0 -0
- /package/docs/{importing → v6/importing}/testrail.mdx +0 -0
- /package/docs/{integrations → v6/integrations}/electron.mdx +0 -0
- /package/docs/{integrations → v6/integrations}/netlify.mdx +0 -0
- /package/docs/{integrations → v6/integrations}/vercel.mdx +0 -0
- /package/docs/{interactive → v6/interactive}/explore.mdx +0 -0
- /package/docs/{interactive → v6/interactive}/run.mdx +0 -0
- /package/docs/{interactive → v6/interactive}/save.mdx +0 -0
- /package/docs/{overview → v6/overview}/faq.mdx +0 -0
- /package/docs/{overview → v6/overview}/performance.mdx +0 -0
- /package/docs/{overview → v6/overview}/quickstart.mdx +0 -0
- /package/docs/{overview → v6/overview}/what-is-testdriver.mdx +0 -0
- /package/docs/{scenarios → v6/scenarios}/ai-chatbot.mdx +0 -0
- /package/docs/{scenarios → v6/scenarios}/cookie-banner.mdx +0 -0
- /package/docs/{scenarios → v6/scenarios}/file-upload.mdx +0 -0
- /package/docs/{scenarios → v6/scenarios}/form-filling.mdx +0 -0
- /package/docs/{scenarios → v6/scenarios}/log-in.mdx +0 -0
- /package/docs/{scenarios → v6/scenarios}/pdf-generation.mdx +0 -0
- /package/docs/{scenarios → v6/scenarios}/spell-check.mdx +0 -0
- /package/docs/{security → v6/security}/action.mdx +0 -0
- /package/docs/{security → v6/security}/agent.mdx +0 -0
- /package/docs/{security → v6/security}/platform.mdx +0 -0
- /package/docs/{tutorials → v6/tutorials}/advanced-test.mdx +0 -0
- /package/docs/{tutorials → v6/tutorials}/basic-test.mdx +0 -0
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
name: AWS
|
|
2
|
-
|
|
3
2
|
on:
|
|
4
3
|
workflow_dispatch:
|
|
5
4
|
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
6
7
|
paths-ignore:
|
|
7
8
|
- "docs/**"
|
|
9
|
+
pull_request:
|
|
10
|
+
branches:
|
|
11
|
+
- main
|
|
12
|
+
types:
|
|
13
|
+
- ready_for_review
|
|
14
|
+
pull_request_review:
|
|
15
|
+
types:
|
|
16
|
+
- submitted
|
|
8
17
|
|
|
9
18
|
jobs:
|
|
10
19
|
gather:
|
|
@@ -54,6 +63,7 @@ jobs:
|
|
|
54
63
|
- name: Setup AWS Instance
|
|
55
64
|
id: aws-setup
|
|
56
65
|
run: |
|
|
66
|
+
chmod +x ./setup/aws/spawn-runner.sh
|
|
57
67
|
OUTPUT=$(./setup/aws/spawn-runner.sh | tee /dev/stderr) # Capture and display output
|
|
58
68
|
echo "$OUTPUT"
|
|
59
69
|
PUBLIC_IP=$(echo "$OUTPUT" | grep "PUBLIC_IP=" | cut -d'=' -f2)
|
|
@@ -68,9 +78,8 @@ jobs:
|
|
|
68
78
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
69
79
|
AWS_REGION: us-east-2
|
|
70
80
|
AWS_LAUNCH_TEMPLATE_ID: lt-00d02f31cfc602f27
|
|
71
|
-
AMI_ID: ami-
|
|
72
|
-
|
|
73
|
-
RESOLUTION_HEIGHT: 1080
|
|
81
|
+
AMI_ID: ami-055cd47506a2f39bb
|
|
82
|
+
RESOLUTION: 1920x1080
|
|
74
83
|
- name: Run TestDriver
|
|
75
84
|
run: node bin/testdriverai.js run testdriver/acceptance/${{ matrix.test }} --ip="${{ steps.aws-setup.outputs.public-ip }}" --junit=out.xml
|
|
76
85
|
env:
|
|
@@ -168,8 +168,15 @@ Resources:
|
|
|
168
168
|
IpProtocol: tcp,
|
|
169
169
|
FromPort: 8765,
|
|
170
170
|
ToPort: 8765,
|
|
171
|
-
CidrIp:
|
|
172
|
-
Description: "pyautogui-cli WebSockets",
|
|
171
|
+
CidrIp: 35.171.123.200/32,
|
|
172
|
+
Description: "pyautogui-cli WebSockets - Static IP 1",
|
|
173
|
+
}
|
|
174
|
+
- {
|
|
175
|
+
IpProtocol: tcp,
|
|
176
|
+
FromPort: 8765,
|
|
177
|
+
ToPort: 8765,
|
|
178
|
+
CidrIp: 52.201.199.222/32,
|
|
179
|
+
Description: "pyautogui-cli WebSockets - Static IP 2",
|
|
173
180
|
}
|
|
174
181
|
- {
|
|
175
182
|
IpProtocol: tcp,
|
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashcam Class
|
|
3
|
+
* Manages Dashcam CLI recording lifecycle
|
|
4
|
+
*
|
|
5
|
+
* Provides a clean interface for:
|
|
6
|
+
* - Authentication
|
|
7
|
+
* - Log tracking
|
|
8
|
+
* - Starting/stopping recordings
|
|
9
|
+
* - Retrieving replay URLs
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
class Dashcam {
|
|
13
|
+
/**
|
|
14
|
+
* Create a Dashcam instance
|
|
15
|
+
* @param {Object} client - TestDriver client instance
|
|
16
|
+
* @param {Object} options - Configuration options
|
|
17
|
+
* @param {string} [options.apiKey] - Dashcam API key
|
|
18
|
+
* @param {boolean} [options.autoStart=false] - Auto-start recording
|
|
19
|
+
* @param {Array} [options.logs=[]] - Log configurations to add
|
|
20
|
+
*/
|
|
21
|
+
constructor(client, options = {}) {
|
|
22
|
+
if (!client) {
|
|
23
|
+
throw new Error('Dashcam requires a TestDriver client instance');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
this.client = client;
|
|
27
|
+
// Use provided apiKey, or client's apiKey, or fallback to a default
|
|
28
|
+
this.apiKey = options.apiKey || client.apiKey || client.config?.TD_API_KEY || '4e93d8bf-3886-4d26-a144-116c4063522d';
|
|
29
|
+
this.autoStart = options.autoStart ?? false;
|
|
30
|
+
this.logs = options.logs || [];
|
|
31
|
+
this.recording = false;
|
|
32
|
+
this._authenticated = false;
|
|
33
|
+
this.startTime = null; // Track when dashcam recording started
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get shell type based on client OS
|
|
38
|
+
* @private
|
|
39
|
+
*/
|
|
40
|
+
_getShell() {
|
|
41
|
+
return this.client.os === 'windows' ? 'pwsh' : 'sh';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get TD_API_ROOT from client config
|
|
46
|
+
* @private
|
|
47
|
+
*/
|
|
48
|
+
_getApiRoot() {
|
|
49
|
+
return this.client.config?.TD_API_ROOT || 'http://localhost:1337';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get dashcam executable path
|
|
54
|
+
* @private
|
|
55
|
+
*/
|
|
56
|
+
async _getDashcamPath() {
|
|
57
|
+
const shell = this._getShell();
|
|
58
|
+
const npmPrefix = await this.client.exec(shell, 'npm prefix -g', 40000, true);
|
|
59
|
+
|
|
60
|
+
if (this.client.os === 'windows') {
|
|
61
|
+
return npmPrefix.trim() + '\\dashcam.cmd';
|
|
62
|
+
}
|
|
63
|
+
return npmPrefix.trim() + '/bin/dashcam';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Authenticate dashcam with API key
|
|
68
|
+
* @param {string} [apiKey] - Override API key
|
|
69
|
+
* @returns {Promise<void>}
|
|
70
|
+
*/
|
|
71
|
+
async auth(apiKey) {
|
|
72
|
+
const key = apiKey || this.apiKey;
|
|
73
|
+
const shell = this._getShell();
|
|
74
|
+
const apiRoot = this._getApiRoot();
|
|
75
|
+
|
|
76
|
+
if (this.client.os === 'windows') {
|
|
77
|
+
// Debug session info
|
|
78
|
+
const debug = await this.client.exec(shell, 'query session', 40000, true);
|
|
79
|
+
this._log('debug', 'Debug version output:', debug);
|
|
80
|
+
|
|
81
|
+
// Uninstall and clear cache for fresh install
|
|
82
|
+
await this.client.exec(shell, 'npm uninstall dashcam -g', 40000, true);
|
|
83
|
+
await this.client.exec(shell, 'npm cache clean --force', 40000, true);
|
|
84
|
+
|
|
85
|
+
// Install dashcam with TD_API_ROOT environment variable
|
|
86
|
+
const installOutput = await this.client.exec(
|
|
87
|
+
shell,
|
|
88
|
+
`$env:TD_API_ROOT="${apiRoot}"; npm install dashcam@beta -g`,
|
|
89
|
+
120000,
|
|
90
|
+
true
|
|
91
|
+
);
|
|
92
|
+
this._log('debug', 'Install dashcam output:', installOutput);
|
|
93
|
+
|
|
94
|
+
// Verify version
|
|
95
|
+
const latestVersion = await this.client.exec(
|
|
96
|
+
shell,
|
|
97
|
+
'npm view dashcam@beta version',
|
|
98
|
+
40000,
|
|
99
|
+
true
|
|
100
|
+
);
|
|
101
|
+
this._log('debug', 'Latest beta version available:', latestVersion);
|
|
102
|
+
|
|
103
|
+
const dashcamPath = await this._getDashcamPath();
|
|
104
|
+
this._log('debug', 'Dashcam executable path:', dashcamPath);
|
|
105
|
+
|
|
106
|
+
const installedVersion = await this.client.exec(
|
|
107
|
+
shell,
|
|
108
|
+
'npm ls dashcam -g',
|
|
109
|
+
40000,
|
|
110
|
+
true
|
|
111
|
+
);
|
|
112
|
+
this._log('debug', 'Installed dashcam version:', installedVersion);
|
|
113
|
+
|
|
114
|
+
// Test version command
|
|
115
|
+
const versionTest = await this.client.exec(
|
|
116
|
+
shell,
|
|
117
|
+
`& "${dashcamPath}" version`,
|
|
118
|
+
40000,
|
|
119
|
+
true
|
|
120
|
+
);
|
|
121
|
+
this._log('debug', 'Dashcam version test:', versionTest);
|
|
122
|
+
|
|
123
|
+
// Verify installation
|
|
124
|
+
if (!installedVersion) {
|
|
125
|
+
this._log('error', 'Dashcam version command returned null/empty');
|
|
126
|
+
this._log('debug', 'Install output was:', installOutput);
|
|
127
|
+
} else if (!installedVersion.includes('1.3.')) {
|
|
128
|
+
this._log('warn', 'Dashcam version may be outdated. Expected 1.3.x, got:', installedVersion);
|
|
129
|
+
} else {
|
|
130
|
+
this._log('debug', 'Dashcam version verified:', installedVersion);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Authenticate with TD_API_ROOT
|
|
134
|
+
const authOutput = await this.client.exec(
|
|
135
|
+
shell,
|
|
136
|
+
`$env:TD_API_ROOT="${apiRoot}"; & "${dashcamPath}" auth ${key}`,
|
|
137
|
+
120000,
|
|
138
|
+
true
|
|
139
|
+
);
|
|
140
|
+
this._log('debug', 'Auth output:', authOutput);
|
|
141
|
+
} else {
|
|
142
|
+
// Linux/Mac authentication with TD_API_ROOT
|
|
143
|
+
const authOutput = await this.client.exec(
|
|
144
|
+
shell,
|
|
145
|
+
`TD_API_ROOT="${apiRoot}" dashcam auth ${key}`,
|
|
146
|
+
120000,
|
|
147
|
+
true
|
|
148
|
+
);
|
|
149
|
+
this._log('debug', 'Auth output:', authOutput);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
this._authenticated = true;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Add file log tracking
|
|
157
|
+
* @param {string} path - Path to log file
|
|
158
|
+
* @param {string} name - Display name
|
|
159
|
+
* @returns {Promise<void>}
|
|
160
|
+
*/
|
|
161
|
+
async addFileLog(path, name) {
|
|
162
|
+
const shell = this._getShell();
|
|
163
|
+
const apiRoot = this._getApiRoot();
|
|
164
|
+
|
|
165
|
+
if (this.client.os === 'windows') {
|
|
166
|
+
// Create log file if it doesn't exist
|
|
167
|
+
const createFileOutput = await this.client.exec(
|
|
168
|
+
shell,
|
|
169
|
+
`New-Item -ItemType File -Path "${path}" -Force`,
|
|
170
|
+
10000,
|
|
171
|
+
true
|
|
172
|
+
);
|
|
173
|
+
this._log('debug', 'Create log file output:', createFileOutput);
|
|
174
|
+
|
|
175
|
+
const dashcamPath = await this._getDashcamPath();
|
|
176
|
+
const addLogOutput = await this.client.exec(
|
|
177
|
+
shell,
|
|
178
|
+
`$env:TD_API_ROOT="${apiRoot}"; & "${dashcamPath}" logs --add --type=file --file="${path}" --name="${name}"`,
|
|
179
|
+
120000,
|
|
180
|
+
true
|
|
181
|
+
);
|
|
182
|
+
this._log('debug', 'Add log tracking output:', addLogOutput);
|
|
183
|
+
} else {
|
|
184
|
+
// Create log file
|
|
185
|
+
await this.client.exec(shell, `touch ${path}`, 10000, true);
|
|
186
|
+
|
|
187
|
+
// Add log tracking with TD_API_ROOT
|
|
188
|
+
const addLogOutput = await this.client.exec(
|
|
189
|
+
shell,
|
|
190
|
+
`TD_API_ROOT="${apiRoot}" dashcam logs --add --type=file --file="${path}" --name="${name}"`,
|
|
191
|
+
10000,
|
|
192
|
+
true
|
|
193
|
+
);
|
|
194
|
+
this._log('debug', 'Add log tracking output:', addLogOutput);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Add application log tracking
|
|
200
|
+
* @param {string} application - Application name
|
|
201
|
+
* @param {string} name - Display name
|
|
202
|
+
* @returns {Promise<void>}
|
|
203
|
+
*/
|
|
204
|
+
async addApplicationLog(application, name) {
|
|
205
|
+
const shell = this._getShell();
|
|
206
|
+
const dashcamPath = await this._getDashcamPath();
|
|
207
|
+
const apiRoot = this._getApiRoot();
|
|
208
|
+
|
|
209
|
+
if (this.client.os === 'windows') {
|
|
210
|
+
const addLogOutput = await this.client.exec(
|
|
211
|
+
shell,
|
|
212
|
+
`$env:TD_API_ROOT="${apiRoot}"; & "${dashcamPath}" logs --add --type=application --application="${application}" --name="${name}"`,
|
|
213
|
+
120000,
|
|
214
|
+
true
|
|
215
|
+
);
|
|
216
|
+
this._log('debug', 'Add application log tracking output:', addLogOutput);
|
|
217
|
+
} else {
|
|
218
|
+
const addLogOutput = await this.client.exec(
|
|
219
|
+
shell,
|
|
220
|
+
`TD_API_ROOT="${apiRoot}" dashcam logs --add --type=application --application="${application}" --name="${name}"`,
|
|
221
|
+
10000,
|
|
222
|
+
true
|
|
223
|
+
);
|
|
224
|
+
this._log('debug', 'Add application log tracking output:', addLogOutput);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Add web log tracking
|
|
230
|
+
* @param {string} pattern - URL pattern to match (e.g., "*example.com*")
|
|
231
|
+
* @param {string} name - Display name
|
|
232
|
+
* @returns {Promise<void>}
|
|
233
|
+
*/
|
|
234
|
+
async addWebLog(pattern, name) {
|
|
235
|
+
const shell = this._getShell();
|
|
236
|
+
const dashcamPath = await this._getDashcamPath();
|
|
237
|
+
const apiRoot = this._getApiRoot();
|
|
238
|
+
|
|
239
|
+
if (this.client.os === 'windows') {
|
|
240
|
+
const addLogOutput = await this.client.exec(
|
|
241
|
+
shell,
|
|
242
|
+
`$env:TD_API_ROOT="${apiRoot}"; & "${dashcamPath}" logs --add --type=web --pattern="${pattern}" --name="${name}"`,
|
|
243
|
+
120000,
|
|
244
|
+
true
|
|
245
|
+
);
|
|
246
|
+
this._log('debug', 'Add web log tracking output:', addLogOutput);
|
|
247
|
+
} else {
|
|
248
|
+
const addLogOutput = await this.client.exec(
|
|
249
|
+
shell,
|
|
250
|
+
`TD_API_ROOT="${apiRoot}" dashcam logs --add --type=web --pattern="${pattern}" --name="${name}"`,
|
|
251
|
+
10000,
|
|
252
|
+
true
|
|
253
|
+
);
|
|
254
|
+
this._log('debug', 'Add web log tracking output:', addLogOutput);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Start dashcam recording
|
|
260
|
+
* @returns {Promise<void>}
|
|
261
|
+
*/
|
|
262
|
+
async start() {
|
|
263
|
+
if (this.recording) {
|
|
264
|
+
this._log('warn', 'Dashcam already recording');
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Auto-authenticate if not already done
|
|
269
|
+
if (!this._authenticated) {
|
|
270
|
+
this._log('info', 'Auto-authenticating dashcam...');
|
|
271
|
+
await this.auth();
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const shell = this._getShell();
|
|
275
|
+
const apiRoot = this._getApiRoot();
|
|
276
|
+
|
|
277
|
+
if (this.client.os === 'windows') {
|
|
278
|
+
this._log('info', 'Starting dashcam recording on Windows...');
|
|
279
|
+
|
|
280
|
+
const dashcamPath = await this._getDashcamPath();
|
|
281
|
+
this._log('debug', 'Dashcam path:', dashcamPath);
|
|
282
|
+
|
|
283
|
+
// Verify dashcam exists
|
|
284
|
+
const dashcamExists = await this.client.exec(
|
|
285
|
+
shell,
|
|
286
|
+
`Test-Path "${dashcamPath}"`,
|
|
287
|
+
10000,
|
|
288
|
+
true
|
|
289
|
+
);
|
|
290
|
+
this._log('debug', 'Dashcam.cmd exists:', dashcamExists);
|
|
291
|
+
|
|
292
|
+
// Start dashcam record and redirect output with TD_API_ROOT
|
|
293
|
+
const outputFile = 'C:\\Users\\testdriver\\.dashcam-cli\\dashcam-start.log';
|
|
294
|
+
const startScript = `
|
|
295
|
+
try {
|
|
296
|
+
$env:TD_API_ROOT="${apiRoot}"
|
|
297
|
+
$process = Start-Process "cmd.exe" -ArgumentList "/c", "${dashcamPath} record > ${outputFile} 2>&1" -PassThru
|
|
298
|
+
Write-Output "Process started with PID: $($process.Id)"
|
|
299
|
+
Start-Sleep -Seconds 2
|
|
300
|
+
if ($process.HasExited) {
|
|
301
|
+
Write-Output "Process has already exited with code: $($process.ExitCode)"
|
|
302
|
+
} else {
|
|
303
|
+
Write-Output "Process is still running"
|
|
304
|
+
}
|
|
305
|
+
} catch {
|
|
306
|
+
Write-Output "ERROR: $_"
|
|
307
|
+
}
|
|
308
|
+
`;
|
|
309
|
+
|
|
310
|
+
const startOutput = await this.client.exec(shell, startScript, 10000, true);
|
|
311
|
+
this._log('debug', 'Start-Process output:', startOutput);
|
|
312
|
+
|
|
313
|
+
// Wait and check output
|
|
314
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
315
|
+
const dashcamOutput = await this.client.exec(
|
|
316
|
+
shell,
|
|
317
|
+
`Get-Content "${outputFile}" -ErrorAction SilentlyContinue`,
|
|
318
|
+
10000,
|
|
319
|
+
true
|
|
320
|
+
);
|
|
321
|
+
this._log('debug', 'Dashcam record output:', dashcamOutput);
|
|
322
|
+
|
|
323
|
+
// Give process time to initialize
|
|
324
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
325
|
+
|
|
326
|
+
this._log('info', 'Dashcam recording started');
|
|
327
|
+
} else {
|
|
328
|
+
// Linux/Mac with TD_API_ROOT
|
|
329
|
+
this._log('info', 'Starting dashcam recording on Linux/Mac...');
|
|
330
|
+
await this.client.exec(shell, `TD_API_ROOT="${apiRoot}" dashcam record >/dev/null 2>&1 &`);
|
|
331
|
+
this._log('info', 'Dashcam recording started');
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
this.recording = true;
|
|
335
|
+
this.startTime = Date.now(); // Record the timestamp when dashcam started
|
|
336
|
+
|
|
337
|
+
// Update the session with dashcam start time for interaction timestamp synchronization
|
|
338
|
+
if (this.client && this.client.agent && this.client.agent.session) {
|
|
339
|
+
try {
|
|
340
|
+
const apiRoot = this.apiRoot || process.env.TD_API_ROOT || 'https://app.testdriver.ai';
|
|
341
|
+
const response = await fetch(`${apiRoot}/api/v7.0.0/testdriver/session/${this.client.agent.session}/update-dashcam-time`, {
|
|
342
|
+
method: 'POST',
|
|
343
|
+
headers: {
|
|
344
|
+
'Content-Type': 'application/json',
|
|
345
|
+
'Authorization': `Bearer ${this.apiKey}`
|
|
346
|
+
},
|
|
347
|
+
body: JSON.stringify({ dashcamStartTime: this.startTime })
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
if (response.ok) {
|
|
351
|
+
this._log('info', `Updated session ${this.client.agent.session} with dashcam start time: ${this.startTime}`);
|
|
352
|
+
} else {
|
|
353
|
+
this._log('warn', 'Failed to update session with dashcam start time:', response.statusText);
|
|
354
|
+
}
|
|
355
|
+
} catch (err) {
|
|
356
|
+
this._log('warn', 'Error updating session with dashcam start time:', err.message);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Stop dashcam recording and retrieve replay URL
|
|
363
|
+
* @returns {Promise<string|null>} Replay URL if available
|
|
364
|
+
*/
|
|
365
|
+
async stop() {
|
|
366
|
+
if (!this.recording) {
|
|
367
|
+
// Internal log only - don't spam user console
|
|
368
|
+
this._log('warn', 'Dashcam not recording');
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
this._log('info', 'Stopping dashcam and retrieving URL...');
|
|
373
|
+
const shell = this._getShell();
|
|
374
|
+
const apiRoot = this._getApiRoot();
|
|
375
|
+
let output;
|
|
376
|
+
|
|
377
|
+
if (this.client.os === 'windows') {
|
|
378
|
+
this._log('info', 'Stopping dashcam process on Windows...');
|
|
379
|
+
|
|
380
|
+
const dashcamPath = await this._getDashcamPath();
|
|
381
|
+
|
|
382
|
+
// Stop and get output with TD_API_ROOT
|
|
383
|
+
output = await this.client.exec(shell, `$env:TD_API_ROOT="${apiRoot}"; & "${dashcamPath}" stop`, 120000);
|
|
384
|
+
this._log('debug', 'Dashcam stop command output:', output);
|
|
385
|
+
} else {
|
|
386
|
+
// Linux/Mac with TD_API_ROOT
|
|
387
|
+
const dashcamPath = await this._getDashcamPath();
|
|
388
|
+
output = await this.client.exec(shell, `TD_API_ROOT="${apiRoot}" "${dashcamPath}" stop`, 60000, false);
|
|
389
|
+
this._log('debug', 'Dashcam command output:', output);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
this.recording = false;
|
|
393
|
+
|
|
394
|
+
// Extract URL from output
|
|
395
|
+
if (output) {
|
|
396
|
+
// Look for replay URL with optional query parameters (most specific)
|
|
397
|
+
// Matches: http://localhost:3001/replay/abc123?share=xyz or https://app.dashcam.io/replay/abc123
|
|
398
|
+
const replayUrlMatch = output.match(/https?:\/\/[^\s"',}]+\/replay\/[^\s"',}]+/);
|
|
399
|
+
if (replayUrlMatch) {
|
|
400
|
+
let url = replayUrlMatch[0];
|
|
401
|
+
// Remove trailing punctuation but keep query params
|
|
402
|
+
url = url.replace(/[.,;:!\)\]]+$/, '').trim();
|
|
403
|
+
this._log('info', 'Found dashcam URL:', url);
|
|
404
|
+
return url;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Fallback: any dashcam.io or testdriver.ai URL
|
|
408
|
+
const dashcamUrlMatch = output.match(/https?:\/\/(?:app\.)?(?:dashcam\.io|testdriver\.ai)[^\s"',}]+/);
|
|
409
|
+
if (dashcamUrlMatch) {
|
|
410
|
+
let url = dashcamUrlMatch[0];
|
|
411
|
+
url = url.replace(/[.,;:!\?\)\]]+$/, '').trim();
|
|
412
|
+
this._log('info', 'Found dashcam URL:', url);
|
|
413
|
+
return url;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
this._log('warn', 'No replay URL found in dashcam output');
|
|
417
|
+
} else {
|
|
418
|
+
this._log('warn', 'Dashcam command returned no output');
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Internal logging - writes to testdriver log file but not user console
|
|
426
|
+
* @private
|
|
427
|
+
*/
|
|
428
|
+
_log(level, ...args) {
|
|
429
|
+
const message = args.map(arg =>
|
|
430
|
+
typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)
|
|
431
|
+
).join(' ');
|
|
432
|
+
|
|
433
|
+
const timestamp = new Date().toISOString();
|
|
434
|
+
const logLine = `[${timestamp}] [DASHCAM:${level.toUpperCase()}] ${message}`;
|
|
435
|
+
|
|
436
|
+
// Send to sandbox log file via output command (same as console interceptor)
|
|
437
|
+
if (this.client?.sandbox?.instanceSocketConnected) {
|
|
438
|
+
try {
|
|
439
|
+
this.client.sandbox.send({
|
|
440
|
+
type: "output",
|
|
441
|
+
output: Buffer.from(logLine, "utf8").toString("base64"),
|
|
442
|
+
});
|
|
443
|
+
} catch {
|
|
444
|
+
// Silently fail
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Check if currently recording
|
|
451
|
+
* @returns {Promise<boolean>}
|
|
452
|
+
*/
|
|
453
|
+
async isRecording() {
|
|
454
|
+
return this.recording;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Get milliseconds elapsed since dashcam started recording
|
|
459
|
+
* @returns {number|null} Milliseconds since start, or null if not recording
|
|
460
|
+
*/
|
|
461
|
+
getElapsedTime() {
|
|
462
|
+
if (!this.recording || !this.startTime) {
|
|
463
|
+
return null;
|
|
464
|
+
}
|
|
465
|
+
return Date.now() - this.startTime;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
module.exports = Dashcam;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript definitions for TestDriver Core Module
|
|
3
|
+
* @module testdriverai/core
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export class Dashcam {
|
|
7
|
+
/**
|
|
8
|
+
* Create a new Dashcam instance
|
|
9
|
+
* @param client - TestDriver client instance
|
|
10
|
+
* @param options - Dashcam options
|
|
11
|
+
*/
|
|
12
|
+
constructor(client: any, options?: DashcamOptions);
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Authenticate with Dashcam CLI
|
|
16
|
+
* @param apiKey - Dashcam API key (optional, uses DASHCAM_API_KEY env var if not provided)
|
|
17
|
+
* @returns Promise that resolves when authenticated
|
|
18
|
+
*/
|
|
19
|
+
auth(apiKey?: string): Promise<void>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Add a log entry to Dashcam
|
|
23
|
+
* @param config - Log configuration
|
|
24
|
+
*/
|
|
25
|
+
addLog(config: LogConfig): Promise<void>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Add a file log to Dashcam
|
|
29
|
+
* @param path - Path to file to log
|
|
30
|
+
* @param name - Name/description for the log entry
|
|
31
|
+
*/
|
|
32
|
+
addFileLog(path: string, name: string): Promise<void>;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Add an application log to Dashcam
|
|
36
|
+
* @param application - Application name to track
|
|
37
|
+
* @param name - Name/description for the log entry
|
|
38
|
+
*/
|
|
39
|
+
addApplicationLog(application: string, name: string): Promise<void>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Start recording
|
|
43
|
+
* @returns Promise that resolves when recording starts
|
|
44
|
+
*/
|
|
45
|
+
start(): Promise<void>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Stop recording and get replay URL
|
|
49
|
+
* @returns Promise that resolves to the replay URL (or null if not recording)
|
|
50
|
+
*/
|
|
51
|
+
stop(): Promise<string | null>;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Check if currently recording
|
|
55
|
+
* @returns true if recording, false otherwise
|
|
56
|
+
*/
|
|
57
|
+
isRecording(): boolean;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface DashcamOptions {
|
|
61
|
+
/**
|
|
62
|
+
* Dashcam API key (defaults to DASHCAM_API_KEY env var)
|
|
63
|
+
*/
|
|
64
|
+
apiKey?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface LogConfig {
|
|
68
|
+
/**
|
|
69
|
+
* Type of log entry
|
|
70
|
+
*/
|
|
71
|
+
type: 'file' | 'application';
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Path to file (for file logs)
|
|
75
|
+
*/
|
|
76
|
+
path?: string;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Application name (for application logs)
|
|
80
|
+
*/
|
|
81
|
+
application?: string;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Name/description for the log entry
|
|
85
|
+
*/
|
|
86
|
+
name: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* TestDriver SDK class
|
|
91
|
+
* Re-exported from main module for convenience
|
|
92
|
+
*/
|
|
93
|
+
export class TestDriver {
|
|
94
|
+
constructor(apiKey: string, options?: TestDriverOptions);
|
|
95
|
+
|
|
96
|
+
auth(): Promise<void>;
|
|
97
|
+
connect(options?: ConnectOptions): Promise<any>;
|
|
98
|
+
disconnect(): Promise<void>;
|
|
99
|
+
|
|
100
|
+
find(query: string): Promise<any>;
|
|
101
|
+
findAll(query: string): Promise<any[]>;
|
|
102
|
+
click(target: string): Promise<void>;
|
|
103
|
+
type(target: string, text: string): Promise<void>;
|
|
104
|
+
exec(shell: string, command: string, timeout?: number, ignoreError?: boolean): Promise<string>;
|
|
105
|
+
focusApplication(appName: string): Promise<void>;
|
|
106
|
+
|
|
107
|
+
// Add other TestDriver methods as needed
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface TestDriverOptions {
|
|
111
|
+
/**
|
|
112
|
+
* API endpoint URL
|
|
113
|
+
*/
|
|
114
|
+
apiRoot?: string;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Target OS: 'linux', 'mac', or 'windows'
|
|
118
|
+
*/
|
|
119
|
+
os?: 'linux' | 'mac' | 'windows';
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Create new sandbox
|
|
123
|
+
*/
|
|
124
|
+
newSandbox?: boolean;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Screen resolution
|
|
128
|
+
*/
|
|
129
|
+
resolution?: string;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Enable analytics
|
|
133
|
+
*/
|
|
134
|
+
analytics?: boolean;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Cache thresholds for find operations
|
|
138
|
+
*/
|
|
139
|
+
cacheThresholds?: {
|
|
140
|
+
find?: number;
|
|
141
|
+
findAll?: number;
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface ConnectOptions {
|
|
146
|
+
/**
|
|
147
|
+
* Create new sandbox instance
|
|
148
|
+
*/
|
|
149
|
+
new?: boolean;
|
|
150
|
+
}
|