testdriverai 6.2.1 → 7.0.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/MIGRATION.md +389 -0
- package/PLUGIN_MIGRATION.md +222 -0
- package/PROMPT_CACHE.md +200 -0
- package/SDK_LOGGING.md +222 -0
- package/SDK_MIGRATION.md +474 -0
- package/SDK_README.md +1122 -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 +258 -68
- 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 +143 -188
- package/agent/lib/redraw.js +6 -3
- package/agent/lib/sandbox.js +19 -5
- package/agent/lib/sdk.js +1 -0
- package/agent/lib/system.js +0 -3
- package/agent/lib/validation.js +1 -7
- package/debug-locate-response.js +82 -0
- package/debug-screenshot-1763401388589.png +0 -0
- package/debugger/index.html +16 -5
- package/docs/ARCHITECTURE.md +424 -0
- package/docs/AWESOME_LOGS_QUICK_REF.md +100 -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 +232 -152
- 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/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/pressKeys.mdx +349 -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/quickstart.mdx +199 -0
- package/docs/v7/guides/migration.mdx +562 -0
- package/docs/{getting-started → v7/guides}/self-hosting.mdx +11 -12
- package/docs/v7/playwright.mdx +342 -0
- package/eslint.config.js +19 -1
- package/examples/run-tests-with-recording.sh +70 -0
- package/examples/screenshot-example.js +63 -0
- package/examples/sdk-awesome-logs-demo.js +177 -0
- package/examples/sdk-cache-thresholds.js +96 -0
- package/examples/sdk-element-properties.js +155 -0
- package/examples/sdk-simple-example.js +65 -0
- package/examples/test-recording-example.test.js +166 -0
- 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 +744 -0
- package/mcp-server/AI_GUIDELINES.md +57 -0
- package/package.json +18 -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 +735 -0
- package/sdk.js +1906 -0
- package/{.github/workflows/self-hosted.yml → self-hosted.yml} +13 -4
- package/setup/aws/cloudformation.yaml +9 -2
- package/test/mcp-example-test.yaml +27 -0
- package/test-find-api.js +73 -0
- package/test-prompt-cache.js +96 -0
- package/test-sandbox-render.js +28 -0
- package/test-sdk-methods.js +15 -0
- package/test-sdk-refactor.js +53 -0
- package/test-stack-trace.mjs +57 -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 +44 -0
- package/testdriver/acceptance-sdk/drag-and-drop.test.mjs +70 -0
- package/testdriver/acceptance-sdk/element-not-found.test.mjs +38 -0
- package/testdriver/acceptance-sdk/exec-js.test.mjs +55 -0
- package/testdriver/acceptance-sdk/exec-output.test.mjs +71 -0
- package/testdriver/acceptance-sdk/exec-pwsh.test.mjs +69 -0
- package/testdriver/acceptance-sdk/focus-window.test.mjs +48 -0
- package/testdriver/acceptance-sdk/formatted-logging.test.mjs +41 -0
- package/testdriver/acceptance-sdk/hover-image.test.mjs +43 -0
- package/testdriver/acceptance-sdk/hover-text-with-description.test.mjs +50 -0
- package/testdriver/acceptance-sdk/hover-text.test.mjs +41 -0
- package/testdriver/acceptance-sdk/match-image.test.mjs +48 -0
- package/testdriver/acceptance-sdk/press-keys.test.mjs +64 -0
- package/testdriver/acceptance-sdk/prompt.test.mjs +45 -0
- package/testdriver/acceptance-sdk/scroll-keyboard.test.mjs +52 -0
- package/testdriver/acceptance-sdk/scroll-until-image.test.mjs +51 -0
- package/testdriver/acceptance-sdk/scroll-until-text.test.mjs +42 -0
- package/testdriver/acceptance-sdk/scroll.test.mjs +50 -0
- package/testdriver/acceptance-sdk/setup/globalTeardown.mjs +11 -0
- package/testdriver/acceptance-sdk/setup/lifecycleHelpers.mjs +239 -0
- package/testdriver/acceptance-sdk/setup/testHelpers.mjs +648 -0
- package/testdriver/acceptance-sdk/setup/vitestSetup.mjs +40 -0
- package/testdriver/acceptance-sdk/type-checking-demo.js +49 -0
- package/testdriver/acceptance-sdk/type.test.mjs +84 -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 +65 -0
- package/vitest.config.mjs.bak +44 -0
- package/.github/workflows/acceptance-v6.yml +0 -169
- 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
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
name: v6 Linux
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
paths-ignore:
|
|
9
|
+
- "docs/**"
|
|
10
|
+
pull_request:
|
|
11
|
+
branches:
|
|
12
|
+
- main
|
|
13
|
+
|
|
14
|
+
schedule:
|
|
15
|
+
- cron: "0 0 * * *"
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
# Job to gather all test files
|
|
19
|
+
test-setup:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v3
|
|
23
|
+
- uses: actions/setup-node@v3
|
|
24
|
+
with:
|
|
25
|
+
node-version: 22
|
|
26
|
+
cache: npm
|
|
27
|
+
- run: npm ci
|
|
28
|
+
|
|
29
|
+
gather:
|
|
30
|
+
name: Gather Test Files
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
outputs:
|
|
33
|
+
test_files: ${{ steps.test_list.outputs.files }}
|
|
34
|
+
steps:
|
|
35
|
+
- name: Check out repository
|
|
36
|
+
uses: actions/checkout@v2
|
|
37
|
+
|
|
38
|
+
- name: Find all test files
|
|
39
|
+
id: test_list
|
|
40
|
+
run: |
|
|
41
|
+
FILES=$(ls ./testdriver/acceptance/*.yaml)
|
|
42
|
+
FILENAMES=$(basename -a $FILES)
|
|
43
|
+
FILES_JSON=$(echo "$FILENAMES" | jq -R -s -c 'split("\n")[:-1]')
|
|
44
|
+
echo "files=$FILES_JSON" >> $GITHUB_OUTPUT
|
|
45
|
+
test:
|
|
46
|
+
needs:
|
|
47
|
+
- gather
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
strategy:
|
|
50
|
+
matrix:
|
|
51
|
+
test: ${{ fromJson(needs.gather.outputs.test_files) }}
|
|
52
|
+
max-parallel: 8
|
|
53
|
+
fail-fast: false
|
|
54
|
+
steps:
|
|
55
|
+
- name: Checkout repository
|
|
56
|
+
uses: actions/checkout@v4
|
|
57
|
+
with:
|
|
58
|
+
fetch-depth: 0
|
|
59
|
+
|
|
60
|
+
- name: Set up Node.js
|
|
61
|
+
uses: actions/setup-node@v4
|
|
62
|
+
with:
|
|
63
|
+
node-version: "20"
|
|
64
|
+
cache: "npm"
|
|
65
|
+
|
|
66
|
+
- name: Install dependencies
|
|
67
|
+
run: NODE_ENV=production npm ci
|
|
68
|
+
- name: Run test in headless mode
|
|
69
|
+
run: node bin/testdriverai.js run testdriver/acceptance/${{ matrix.test }} --junit=out.xml
|
|
70
|
+
env:
|
|
71
|
+
FORCE_COLOR: 3
|
|
72
|
+
TD_API_KEY: 49c2996c-0687-40bf-9f2c-5d2e55b2a2c6
|
|
73
|
+
TD_WEBSITE: https://testdriver-sandbox.vercel.app
|
|
74
|
+
TD_THIS_FILE: ${{ matrix.test }}
|
|
75
|
+
TD_API_ROOT: "https://replayable-dev-ian-mac-m1-16.ngrok.io"
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
name: Acceptance SDK Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
push:
|
|
8
|
+
branches: [main]
|
|
9
|
+
paths-ignore:
|
|
10
|
+
- "docs/**"
|
|
11
|
+
# So that we can manually trigger tests when there's flake
|
|
12
|
+
workflow_dispatch:
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
test-workflow:
|
|
16
|
+
name: Run SDK Tests - ${{ matrix.platform }}
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
timeout-minutes: 30
|
|
19
|
+
strategy:
|
|
20
|
+
fail-fast: false
|
|
21
|
+
matrix:
|
|
22
|
+
platform: [linux, windows]
|
|
23
|
+
steps:
|
|
24
|
+
- name: Checkout repository
|
|
25
|
+
uses: actions/checkout@v4
|
|
26
|
+
with:
|
|
27
|
+
fetch-depth: 0
|
|
28
|
+
|
|
29
|
+
- name: Set up Node.js
|
|
30
|
+
uses: actions/setup-node@v4
|
|
31
|
+
with:
|
|
32
|
+
node-version: "20"
|
|
33
|
+
cache: "npm"
|
|
34
|
+
|
|
35
|
+
- name: Install dependencies
|
|
36
|
+
run: npm ci
|
|
37
|
+
|
|
38
|
+
- name: Run ESLint
|
|
39
|
+
run: npx eslint . --max-warnings 0
|
|
40
|
+
|
|
41
|
+
- name: Run Prettier
|
|
42
|
+
run: npx prettier --check .
|
|
43
|
+
|
|
44
|
+
- name: Run SDK tests with Vitest - ${{ matrix.platform }}
|
|
45
|
+
run: npx vitest run testdriver/acceptance-sdk/*.test.mjs
|
|
46
|
+
env:
|
|
47
|
+
FORCE_COLOR: 3
|
|
48
|
+
TD_API_KEY: ${{ secrets.TESTDRIVER_API_KEY }}
|
|
49
|
+
TEST_PLATFORM: ${{ matrix.platform }}
|
|
50
|
+
VERBOSE: true
|
|
51
|
+
LOGGING: true
|
|
52
|
+
continue-on-error: true
|
|
53
|
+
|
|
54
|
+
- name: Generate GitHub Summary
|
|
55
|
+
if: always()
|
|
56
|
+
run: |
|
|
57
|
+
echo "# 🧪 TestDriver SDK Test Results" >> $GITHUB_STEP_SUMMARY
|
|
58
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
59
|
+
|
|
60
|
+
if [ -f test-results/results.json ]; then
|
|
61
|
+
node -e "
|
|
62
|
+
const fs = require('fs');
|
|
63
|
+
const results = JSON.parse(fs.readFileSync('test-results/results.json', 'utf8'));
|
|
64
|
+
|
|
65
|
+
const total = results.numTotalTests || 0;
|
|
66
|
+
const passed = results.numPassedTests || 0;
|
|
67
|
+
const failed = results.numFailedTests || 0;
|
|
68
|
+
const skipped = results.numPendingTests || 0;
|
|
69
|
+
const duration = ((results.testResults?.[0]?.endTime - results.testResults?.[0]?.startTime) / 1000 || 0).toFixed(2);
|
|
70
|
+
|
|
71
|
+
console.log('## 📊 Overview\n');
|
|
72
|
+
console.log('| Metric | Count |');
|
|
73
|
+
console.log('|--------|-------|');
|
|
74
|
+
console.log('| ✅ Passed | ' + passed + ' |');
|
|
75
|
+
console.log('| ❌ Failed | ' + failed + ' |');
|
|
76
|
+
console.log('| ⏭️ Skipped | ' + skipped + ' |');
|
|
77
|
+
console.log('| 📝 Total | ' + total + ' |');
|
|
78
|
+
console.log('| ⏱️ Duration | ' + duration + 's |');
|
|
79
|
+
console.log('');
|
|
80
|
+
|
|
81
|
+
if (failed > 0) {
|
|
82
|
+
console.log('## ❌ Failed Tests\n');
|
|
83
|
+
results.testResults?.forEach(file => {
|
|
84
|
+
file.assertionResults?.filter(test => test.status === 'failed').forEach(test => {
|
|
85
|
+
console.log('### ' + test.fullName);
|
|
86
|
+
console.log('**File:** \`' + file.name + '\`');
|
|
87
|
+
console.log('');
|
|
88
|
+
if (test.failureMessages?.length > 0) {
|
|
89
|
+
console.log('**Error:**');
|
|
90
|
+
console.log('\`\`\`');
|
|
91
|
+
console.log(test.failureMessages.join('\n').substring(0, 1000));
|
|
92
|
+
console.log('\`\`\`');
|
|
93
|
+
console.log('');
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (passed > 0) {
|
|
100
|
+
console.log('## ✅ Passed Tests\n');
|
|
101
|
+
results.testResults?.forEach(file => {
|
|
102
|
+
const passedTests = file.assertionResults?.filter(test => test.status === 'passed') || [];
|
|
103
|
+
if (passedTests.length > 0) {
|
|
104
|
+
console.log('### ' + file.name.split('/').pop());
|
|
105
|
+
passedTests.forEach(test => {
|
|
106
|
+
console.log('- ✅ ' + test.title);
|
|
107
|
+
});
|
|
108
|
+
console.log('');
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
" >> $GITHUB_STEP_SUMMARY
|
|
113
|
+
else
|
|
114
|
+
echo "⚠️ No test results found" >> $GITHUB_STEP_SUMMARY
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
- name: Test Summary (JUnit)
|
|
118
|
+
uses: test-summary/action@v2
|
|
119
|
+
with:
|
|
120
|
+
paths: "test-results/junit.xml"
|
|
121
|
+
if: always()
|
|
122
|
+
|
|
123
|
+
- name: Upload test results
|
|
124
|
+
if: always()
|
|
125
|
+
uses: actions/upload-artifact@v4
|
|
126
|
+
with:
|
|
127
|
+
name: test-results-${{ matrix.platform }}
|
|
128
|
+
path: |
|
|
129
|
+
test-results/junit.xml
|
|
130
|
+
test-results/results.json
|
|
131
|
+
test-results/index.html
|
|
132
|
+
retention-days: 7
|
|
133
|
+
if-no-files-found: ignore
|
package/.vscode/settings.json
CHANGED
|
@@ -6,5 +6,9 @@
|
|
|
6
6
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
7
7
|
"yaml.schemas": {
|
|
8
8
|
"https://raw.githubusercontent.com/testdriverai/testdriverai/main/schema.json": "file:///Users/kid/Desktop/td/internal/testdriverai/testdriver.yaml"
|
|
9
|
-
}
|
|
9
|
+
},
|
|
10
|
+
"vitest.enable": true,
|
|
11
|
+
"vitest.commandLine": "npx vitest --watch",
|
|
12
|
+
"vitest.include": ["**/testdriver/acceptance-sdk/*.test.mjs"],
|
|
13
|
+
"vitest.exclude": []
|
|
10
14
|
}
|
package/MIGRATION.md
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
# Migrating from CLI to SDK
|
|
2
|
+
|
|
3
|
+
This guide helps you migrate from using TestDriver as a CLI tool to using it as an SDK in your JavaScript/Node.js applications.
|
|
4
|
+
|
|
5
|
+
## Key Differences
|
|
6
|
+
|
|
7
|
+
### CLI Approach (Old)
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# YAML-based test files
|
|
11
|
+
testdriverai run testdriver/my-test.yaml
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```yaml
|
|
15
|
+
# testdriver/my-test.yaml
|
|
16
|
+
version: 6.1.10
|
|
17
|
+
steps:
|
|
18
|
+
- prompt: "Login to the application"
|
|
19
|
+
commands:
|
|
20
|
+
- command: hover-text
|
|
21
|
+
text: "Email"
|
|
22
|
+
- command: type
|
|
23
|
+
string: "user@example.com"
|
|
24
|
+
- command: hover-text
|
|
25
|
+
text: "Submit"
|
|
26
|
+
- command: wait-for-text
|
|
27
|
+
text: "Dashboard"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### SDK Approach (New)
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
// JavaScript-based tests
|
|
34
|
+
const TestDriver = require("testdriverai");
|
|
35
|
+
|
|
36
|
+
async function testLogin() {
|
|
37
|
+
const client = new TestDriver(process.env.TD_API_KEY);
|
|
38
|
+
await client.auth();
|
|
39
|
+
await client.connect();
|
|
40
|
+
|
|
41
|
+
await client.hoverText("Email");
|
|
42
|
+
await client.type("user@example.com");
|
|
43
|
+
await client.hoverText("Submit");
|
|
44
|
+
await client.waitForText("Dashboard");
|
|
45
|
+
|
|
46
|
+
await client.disconnect();
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Command Mapping
|
|
51
|
+
|
|
52
|
+
Here's how CLI commands map to SDK methods:
|
|
53
|
+
|
|
54
|
+
| YAML Command | SDK Method | Example |
|
|
55
|
+
| -------------------- | -------------------- | ----------------------------------------- |
|
|
56
|
+
| `hover-text` | `hoverText()` | `await client.hoverText('Submit')` |
|
|
57
|
+
| `hover-image` | `hoverImage()` | `await client.hoverImage('red button')` |
|
|
58
|
+
| `match-image` | `matchImage()` | `await client.matchImage('./button.png')` |
|
|
59
|
+
| `type` | `type()` | `await client.type('hello')` |
|
|
60
|
+
| `press-keys` | `pressKeys()` | `await client.pressKeys(['enter'])` |
|
|
61
|
+
| `click` | `click()` | `await client.click(100, 200)` |
|
|
62
|
+
| `scroll` | `scroll()` | `await client.scroll('down', 500)` |
|
|
63
|
+
| `wait` | `wait()` | `await client.wait(3000)` |
|
|
64
|
+
| `wait-for-text` | `waitForText()` | `await client.waitForText('Success')` |
|
|
65
|
+
| `wait-for-image` | `waitForImage()` | `await client.waitForImage('logo')` |
|
|
66
|
+
| `scroll-until-text` | `scrollUntilText()` | `await client.scrollUntilText('Footer')` |
|
|
67
|
+
| `scroll-until-image` | `scrollUntilImage()` | `await client.scrollUntilImage('banner')` |
|
|
68
|
+
| `focus-application` | `focusApplication()` | `await client.focusApplication('Chrome')` |
|
|
69
|
+
| `remember` | `remember()` | `await client.remember('user name')` |
|
|
70
|
+
| `assert` | `assert()` | `await client.assert('form is visible')` |
|
|
71
|
+
| `exec` | `exec()` | `await client.exec('js', code, 5000)` |
|
|
72
|
+
|
|
73
|
+
## Converting YAML to SDK
|
|
74
|
+
|
|
75
|
+
### Example 1: Simple Form Interaction
|
|
76
|
+
|
|
77
|
+
**YAML (CLI):**
|
|
78
|
+
|
|
79
|
+
```yaml
|
|
80
|
+
version: 6.1.10
|
|
81
|
+
steps:
|
|
82
|
+
- prompt: "Fill out contact form"
|
|
83
|
+
commands:
|
|
84
|
+
- command: hover-text
|
|
85
|
+
text: "Name"
|
|
86
|
+
- command: type
|
|
87
|
+
string: "John Doe"
|
|
88
|
+
- command: hover-text
|
|
89
|
+
text: "Email"
|
|
90
|
+
- command: type
|
|
91
|
+
string: "john@example.com"
|
|
92
|
+
- command: hover-text
|
|
93
|
+
text: "Submit"
|
|
94
|
+
- command: wait-for-text
|
|
95
|
+
text: "Thank you"
|
|
96
|
+
timeout: 5000
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**SDK (JavaScript):**
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
const TestDriver = require("testdriverai");
|
|
103
|
+
|
|
104
|
+
async function fillContactForm() {
|
|
105
|
+
const client = new TestDriver(process.env.TD_API_KEY);
|
|
106
|
+
|
|
107
|
+
await client.auth();
|
|
108
|
+
await client.connect();
|
|
109
|
+
|
|
110
|
+
await client.hoverText("Name");
|
|
111
|
+
await client.type("John Doe");
|
|
112
|
+
await client.hoverText("Email");
|
|
113
|
+
await client.type("john@example.com");
|
|
114
|
+
await client.hoverText("Submit");
|
|
115
|
+
await client.waitForText("Thank you", 5000);
|
|
116
|
+
|
|
117
|
+
await client.disconnect();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
fillContactForm();
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Example 2: Complex Navigation Flow
|
|
124
|
+
|
|
125
|
+
**YAML (CLI):**
|
|
126
|
+
|
|
127
|
+
```yaml
|
|
128
|
+
version: 6.1.10
|
|
129
|
+
steps:
|
|
130
|
+
- prompt: "Navigate to settings"
|
|
131
|
+
commands:
|
|
132
|
+
- command: focus-application
|
|
133
|
+
name: "Google Chrome"
|
|
134
|
+
- command: wait
|
|
135
|
+
timeout: 2000
|
|
136
|
+
- command: hover-text
|
|
137
|
+
text: "Menu"
|
|
138
|
+
- command: wait
|
|
139
|
+
timeout: 1000
|
|
140
|
+
- command: hover-text
|
|
141
|
+
text: "Settings"
|
|
142
|
+
- command: scroll
|
|
143
|
+
direction: "down"
|
|
144
|
+
amount: 500
|
|
145
|
+
- command: assert
|
|
146
|
+
expect: "The settings page is displayed"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**SDK (JavaScript):**
|
|
150
|
+
|
|
151
|
+
```javascript
|
|
152
|
+
const TestDriver = require("testdriverai");
|
|
153
|
+
|
|
154
|
+
async function navigateToSettings() {
|
|
155
|
+
const client = new TestDriver(process.env.TD_API_KEY);
|
|
156
|
+
|
|
157
|
+
await client.auth();
|
|
158
|
+
await client.connect();
|
|
159
|
+
|
|
160
|
+
await client.focusApplication("Google Chrome");
|
|
161
|
+
await client.wait(2000);
|
|
162
|
+
await client.hoverText("Menu");
|
|
163
|
+
await client.wait(1000);
|
|
164
|
+
await client.hoverText("Settings");
|
|
165
|
+
await client.scroll("down", 500);
|
|
166
|
+
await client.assert("The settings page is displayed");
|
|
167
|
+
|
|
168
|
+
await client.disconnect();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
navigateToSettings();
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Example 3: Using Variables and Loops
|
|
175
|
+
|
|
176
|
+
**YAML (CLI):**
|
|
177
|
+
|
|
178
|
+
```yaml
|
|
179
|
+
version: 6.1.10
|
|
180
|
+
steps:
|
|
181
|
+
- prompt: "Process multiple items"
|
|
182
|
+
commands:
|
|
183
|
+
- command: exec
|
|
184
|
+
language: "js"
|
|
185
|
+
code: |
|
|
186
|
+
const items = ['Item 1', 'Item 2', 'Item 3'];
|
|
187
|
+
result = items;
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**SDK (JavaScript):**
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
const TestDriver = require("testdriverai");
|
|
194
|
+
|
|
195
|
+
async function processMultipleItems() {
|
|
196
|
+
const client = new TestDriver(process.env.TD_API_KEY);
|
|
197
|
+
|
|
198
|
+
await client.auth();
|
|
199
|
+
await client.connect();
|
|
200
|
+
|
|
201
|
+
const items = ["Item 1", "Item 2", "Item 3"];
|
|
202
|
+
|
|
203
|
+
for (const item of items) {
|
|
204
|
+
await client.hoverText(item);
|
|
205
|
+
await client.wait(1000);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
await client.disconnect();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
processMultipleItems();
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Benefits of Using SDK
|
|
215
|
+
|
|
216
|
+
### 1. **Native JavaScript Control Flow**
|
|
217
|
+
|
|
218
|
+
```javascript
|
|
219
|
+
// Use if/else statements
|
|
220
|
+
if (await checkCondition()) {
|
|
221
|
+
await client.hoverText("Option A");
|
|
222
|
+
} else {
|
|
223
|
+
await client.hoverText("Option B");
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Use loops
|
|
227
|
+
for (let i = 0; i < 5; i++) {
|
|
228
|
+
await client.scroll("down", 100);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Use try/catch for error handling
|
|
232
|
+
try {
|
|
233
|
+
await client.waitForText("Success", 5000);
|
|
234
|
+
} catch (error) {
|
|
235
|
+
console.error("Timeout waiting for success message");
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### 2. **Integration with Testing Frameworks**
|
|
240
|
+
|
|
241
|
+
```javascript
|
|
242
|
+
// Jest
|
|
243
|
+
describe("Login Flow", () => {
|
|
244
|
+
let client;
|
|
245
|
+
|
|
246
|
+
beforeAll(async () => {
|
|
247
|
+
client = new TestDriver(process.env.TD_API_KEY);
|
|
248
|
+
await client.auth();
|
|
249
|
+
await client.connect();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
afterAll(async () => {
|
|
253
|
+
await client.disconnect();
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
test("should login successfully", async () => {
|
|
257
|
+
await client.hoverText("Email");
|
|
258
|
+
await client.type("test@example.com");
|
|
259
|
+
await client.hoverText("Submit");
|
|
260
|
+
await client.waitForText("Dashboard");
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### 3. **Dynamic Test Data**
|
|
266
|
+
|
|
267
|
+
```javascript
|
|
268
|
+
const users = [
|
|
269
|
+
{ email: "user1@test.com", password: "pass1" },
|
|
270
|
+
{ email: "user2@test.com", password: "pass2" },
|
|
271
|
+
];
|
|
272
|
+
|
|
273
|
+
for (const user of users) {
|
|
274
|
+
await client.hoverText("Email");
|
|
275
|
+
await client.type(user.email);
|
|
276
|
+
await client.hoverText("Password");
|
|
277
|
+
await client.type(user.password);
|
|
278
|
+
await client.hoverText("Login");
|
|
279
|
+
await client.waitForText("Dashboard");
|
|
280
|
+
// Logout for next iteration
|
|
281
|
+
await client.hoverText("Logout");
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### 4. **Reusable Functions**
|
|
286
|
+
|
|
287
|
+
```javascript
|
|
288
|
+
async function login(client, email, password) {
|
|
289
|
+
await client.hoverText("Email");
|
|
290
|
+
await client.type(email);
|
|
291
|
+
await client.hoverText("Password");
|
|
292
|
+
await client.type(password);
|
|
293
|
+
await client.hoverText("Login");
|
|
294
|
+
await client.waitForText("Dashboard");
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
async function logout(client) {
|
|
298
|
+
await client.hoverText("Menu");
|
|
299
|
+
await client.hoverText("Logout");
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Use anywhere
|
|
303
|
+
await login(client, "user@test.com", "password123");
|
|
304
|
+
await logout(client);
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## When to Use CLI vs SDK
|
|
308
|
+
|
|
309
|
+
### Use CLI When:
|
|
310
|
+
|
|
311
|
+
- ✅ You need exploratory testing with AI-generated tests
|
|
312
|
+
- ✅ You want to quickly prototype tests without writing code
|
|
313
|
+
- ✅ You prefer declarative YAML configuration
|
|
314
|
+
- ✅ You're using the interactive edit mode
|
|
315
|
+
|
|
316
|
+
### Use SDK When:
|
|
317
|
+
|
|
318
|
+
- ✅ You need programmatic control over test execution
|
|
319
|
+
- ✅ You want to integrate with existing test frameworks (Jest, Mocha, etc.)
|
|
320
|
+
- ✅ You need complex control flow (loops, conditionals, error handling)
|
|
321
|
+
- ✅ You want to use dynamic test data
|
|
322
|
+
- ✅ You're building automated CI/CD pipelines
|
|
323
|
+
- ✅ You need to reuse test logic across multiple tests
|
|
324
|
+
|
|
325
|
+
## Running Both CLI and SDK
|
|
326
|
+
|
|
327
|
+
You can use both approaches in the same project:
|
|
328
|
+
|
|
329
|
+
```json
|
|
330
|
+
{
|
|
331
|
+
"scripts": {
|
|
332
|
+
"test:cli": "testdriverai run testdriver/regression.yaml",
|
|
333
|
+
"test:sdk": "node tests/login.test.js",
|
|
334
|
+
"test:all": "npm run test:cli && npm run test:sdk"
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## Best Practices
|
|
340
|
+
|
|
341
|
+
1. **Use environment variables for credentials:**
|
|
342
|
+
|
|
343
|
+
```javascript
|
|
344
|
+
const client = new TestDriver(process.env.TD_API_KEY);
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
2. **Always disconnect after tests:**
|
|
348
|
+
|
|
349
|
+
```javascript
|
|
350
|
+
try {
|
|
351
|
+
// Your tests
|
|
352
|
+
} finally {
|
|
353
|
+
await client.disconnect();
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
3. **Create helper functions for common actions:**
|
|
358
|
+
|
|
359
|
+
```javascript
|
|
360
|
+
const helpers = {
|
|
361
|
+
login: async (client, email, password) => {
|
|
362
|
+
/* ... */
|
|
363
|
+
},
|
|
364
|
+
navigateTo: async (client, page) => {
|
|
365
|
+
/* ... */
|
|
366
|
+
},
|
|
367
|
+
fillForm: async (client, data) => {
|
|
368
|
+
/* ... */
|
|
369
|
+
},
|
|
370
|
+
};
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
4. **Use async/await consistently:**
|
|
374
|
+
|
|
375
|
+
```javascript
|
|
376
|
+
// ✅ Good
|
|
377
|
+
await client.hoverText("Submit");
|
|
378
|
+
await client.wait(1000);
|
|
379
|
+
|
|
380
|
+
// ❌ Bad
|
|
381
|
+
client.hoverText("Submit");
|
|
382
|
+
client.wait(1000);
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## Next Steps
|
|
386
|
+
|
|
387
|
+
- Read the [SDK Documentation](./SDK_README.md) for complete API reference
|
|
388
|
+
- Check out [examples](./examples/sdk-example.js) for more use cases
|
|
389
|
+
- Join our [Discord](https://discord.com/invite/cWDFW8DzPm) for support
|