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,562 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Migration Guide"
|
|
3
|
+
sidebarTitle: "YAML to SDK"
|
|
4
|
+
description: "Migrate from YAML tests to the JavaScript SDK"
|
|
5
|
+
icon: "right-left"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
TestDriver v7 introduces a JavaScript SDK that provides programmatic access to all TestDriver capabilities. This guide helps you migrate from YAML-based tests to the SDK.
|
|
11
|
+
|
|
12
|
+
## Why Migrate?
|
|
13
|
+
|
|
14
|
+
The SDK offers several advantages over YAML:
|
|
15
|
+
|
|
16
|
+
- **Type Safety**: Full TypeScript support with autocomplete
|
|
17
|
+
- **Programmatic Control**: Use variables, loops, functions, and conditional logic
|
|
18
|
+
- **Better Debugging**: Stack traces point to your actual code
|
|
19
|
+
- **IDE Integration**: Better editor support and refactoring
|
|
20
|
+
- **Test Framework Integration**: Works with Vitest, Jest, Mocha, and more
|
|
21
|
+
- **Flexibility**: Combine with other testing libraries and tools
|
|
22
|
+
|
|
23
|
+
## Basic Structure Comparison
|
|
24
|
+
|
|
25
|
+
### YAML Test
|
|
26
|
+
|
|
27
|
+
```yaml
|
|
28
|
+
version: 6.0.0
|
|
29
|
+
steps:
|
|
30
|
+
- prompt: focus chrome
|
|
31
|
+
commands:
|
|
32
|
+
- command: focus-application
|
|
33
|
+
name: Google Chrome
|
|
34
|
+
|
|
35
|
+
- prompt: enter username
|
|
36
|
+
commands:
|
|
37
|
+
- command: hover-text
|
|
38
|
+
text: Username
|
|
39
|
+
description: username input field
|
|
40
|
+
action: click
|
|
41
|
+
- command: type
|
|
42
|
+
text: standard_user
|
|
43
|
+
|
|
44
|
+
- prompt: verify login page
|
|
45
|
+
commands:
|
|
46
|
+
- command: assert
|
|
47
|
+
assertion: the login page is displayed
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### SDK Equivalent
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
import { beforeAll, afterAll, describe, it } from 'vitest';
|
|
54
|
+
import TestDriver from 'testdriverai';
|
|
55
|
+
|
|
56
|
+
describe('Login Test', () => {
|
|
57
|
+
let testdriver;
|
|
58
|
+
|
|
59
|
+
beforeAll(async () => {
|
|
60
|
+
client = new TestDriver(process.env.TD_API_KEY, {
|
|
61
|
+
os: 'windows'
|
|
62
|
+
});
|
|
63
|
+
await testdriver.auth();
|
|
64
|
+
await testdriver.connect({ newSandbox: true });
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
afterAll(async () => {
|
|
68
|
+
await testdriver.disconnect();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should display login page and accept credentials', async () => {
|
|
72
|
+
// Focus chrome
|
|
73
|
+
await testdriver.focusApplication('Google Chrome');
|
|
74
|
+
|
|
75
|
+
// Enter username
|
|
76
|
+
const usernameField = await testdriver.find('username input field');
|
|
77
|
+
await usernameField.click();
|
|
78
|
+
await testdriver.type('standard_user');
|
|
79
|
+
|
|
80
|
+
// Verify login page
|
|
81
|
+
await testdriver.assert('the login page is displayed');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Command Mapping
|
|
87
|
+
|
|
88
|
+
### Element Location
|
|
89
|
+
|
|
90
|
+
<CodeGroup>
|
|
91
|
+
```yaml YAML
|
|
92
|
+
- command: hover-text
|
|
93
|
+
text: Submit
|
|
94
|
+
description: submit button
|
|
95
|
+
action: click
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
```javascript SDK
|
|
99
|
+
const button = await testdriver.find('submit button');
|
|
100
|
+
await button.click();
|
|
101
|
+
```
|
|
102
|
+
</CodeGroup>
|
|
103
|
+
|
|
104
|
+
### Typing
|
|
105
|
+
|
|
106
|
+
<CodeGroup>
|
|
107
|
+
```yaml YAML
|
|
108
|
+
- command: type
|
|
109
|
+
text: hello world
|
|
110
|
+
delay: 250
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
```javascript SDK
|
|
114
|
+
await testdriver.type('hello world', 250);
|
|
115
|
+
```
|
|
116
|
+
</CodeGroup>
|
|
117
|
+
|
|
118
|
+
### Keyboard Keys
|
|
119
|
+
|
|
120
|
+
<CodeGroup>
|
|
121
|
+
```yaml YAML
|
|
122
|
+
- command: press-keys
|
|
123
|
+
keys:
|
|
124
|
+
- ctrl
|
|
125
|
+
- a
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
```javascript SDK
|
|
129
|
+
await testdriver.pressKeys(['ctrl', 'a']);
|
|
130
|
+
```
|
|
131
|
+
</CodeGroup>
|
|
132
|
+
|
|
133
|
+
### Scrolling
|
|
134
|
+
|
|
135
|
+
<CodeGroup>
|
|
136
|
+
```yaml YAML
|
|
137
|
+
- command: scroll
|
|
138
|
+
direction: down
|
|
139
|
+
amount: 300
|
|
140
|
+
method: mouse
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
```javascript SDK
|
|
144
|
+
await testdriver.scroll('down', 300, 'mouse');
|
|
145
|
+
```
|
|
146
|
+
</CodeGroup>
|
|
147
|
+
|
|
148
|
+
### Assertions
|
|
149
|
+
|
|
150
|
+
<CodeGroup>
|
|
151
|
+
```yaml YAML
|
|
152
|
+
- command: assert
|
|
153
|
+
assertion: the form is valid
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
```javascript SDK
|
|
157
|
+
await testdriver.assert('the form is valid');
|
|
158
|
+
```
|
|
159
|
+
</CodeGroup>
|
|
160
|
+
|
|
161
|
+
### Wait for Element
|
|
162
|
+
|
|
163
|
+
<CodeGroup>
|
|
164
|
+
```yaml YAML
|
|
165
|
+
- command: wait-for-text
|
|
166
|
+
text: Success
|
|
167
|
+
timeout: 10000
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
```javascript SDK
|
|
171
|
+
// Use polling pattern
|
|
172
|
+
let element;
|
|
173
|
+
for (let i = 0; i < 10; i++) {
|
|
174
|
+
element = await testdriver.find('Success');
|
|
175
|
+
if (element.found()) break;
|
|
176
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
</CodeGroup>
|
|
180
|
+
|
|
181
|
+
### Code Execution
|
|
182
|
+
|
|
183
|
+
<CodeGroup>
|
|
184
|
+
```yaml YAML
|
|
185
|
+
- command: exec
|
|
186
|
+
language: pwsh
|
|
187
|
+
code: |
|
|
188
|
+
npm install -g package
|
|
189
|
+
timeout: 30000
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
```javascript SDK
|
|
193
|
+
await testdriver.exec('pwsh', 'npm install -g package', 30000);
|
|
194
|
+
```
|
|
195
|
+
</CodeGroup>
|
|
196
|
+
|
|
197
|
+
### Focus Application
|
|
198
|
+
|
|
199
|
+
<CodeGroup>
|
|
200
|
+
```yaml YAML
|
|
201
|
+
- command: focus-application
|
|
202
|
+
name: Google Chrome
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
```javascript SDK
|
|
206
|
+
await testdriver.focusApplication('Google Chrome');
|
|
207
|
+
```
|
|
208
|
+
</CodeGroup>
|
|
209
|
+
|
|
210
|
+
### Remember
|
|
211
|
+
|
|
212
|
+
<CodeGroup>
|
|
213
|
+
```yaml YAML
|
|
214
|
+
- command: remember
|
|
215
|
+
description: the order number
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
```javascript SDK
|
|
219
|
+
const orderNumber = await testdriver.remember('the order number');
|
|
220
|
+
```
|
|
221
|
+
</CodeGroup>
|
|
222
|
+
|
|
223
|
+
## Advanced Patterns
|
|
224
|
+
|
|
225
|
+
### Variables & Data Reuse
|
|
226
|
+
|
|
227
|
+
**YAML** uses template variables:
|
|
228
|
+
```yaml
|
|
229
|
+
variables:
|
|
230
|
+
username: john.doe
|
|
231
|
+
password: secret123
|
|
232
|
+
|
|
233
|
+
steps:
|
|
234
|
+
- command: type
|
|
235
|
+
text: ${username}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**SDK** uses JavaScript variables:
|
|
239
|
+
```javascript
|
|
240
|
+
const username = 'john.doe';
|
|
241
|
+
const password = 'secret123';
|
|
242
|
+
|
|
243
|
+
await testdriver.type(username);
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Conditional Logic
|
|
247
|
+
|
|
248
|
+
**YAML** uses if command:
|
|
249
|
+
```yaml
|
|
250
|
+
- command: if
|
|
251
|
+
condition: error message is visible
|
|
252
|
+
then:
|
|
253
|
+
- command: assert
|
|
254
|
+
assertion: error message is correct
|
|
255
|
+
else:
|
|
256
|
+
- command: assert
|
|
257
|
+
assertion: form submitted successfully
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**SDK** uses native JavaScript:
|
|
261
|
+
```javascript
|
|
262
|
+
const errorElement = await testdriver.find('error message');
|
|
263
|
+
|
|
264
|
+
if (errorElement.found()) {
|
|
265
|
+
await testdriver.assert('error message is correct');
|
|
266
|
+
} else {
|
|
267
|
+
await testdriver.assert('form submitted successfully');
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Loops
|
|
272
|
+
|
|
273
|
+
**YAML** requires workarounds or snippets for repetition.
|
|
274
|
+
|
|
275
|
+
**SDK** uses native JavaScript loops:
|
|
276
|
+
```javascript
|
|
277
|
+
// Fill multiple similar fields
|
|
278
|
+
const fields = ['First Name', 'Last Name', 'Email'];
|
|
279
|
+
const values = ['John', 'Doe', 'john@example.com'];
|
|
280
|
+
|
|
281
|
+
for (let i = 0; i < fields.length; i++) {
|
|
282
|
+
const field = await testdriver.find(`${fields[i]} input field`);
|
|
283
|
+
await field.click();
|
|
284
|
+
await testdriver.type(values[i]);
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Data-Driven Tests
|
|
289
|
+
|
|
290
|
+
**YAML** requires external tools or CSV imports.
|
|
291
|
+
|
|
292
|
+
**SDK** uses test framework features:
|
|
293
|
+
```javascript
|
|
294
|
+
const testCases = [
|
|
295
|
+
{ username: 'user1', password: 'pass1', expected: true },
|
|
296
|
+
{ username: 'user2', password: 'wrong', expected: false },
|
|
297
|
+
{ username: '', password: '', expected: false },
|
|
298
|
+
];
|
|
299
|
+
|
|
300
|
+
testCases.forEach(({ username, password, expected }) => {
|
|
301
|
+
it(`should handle login for ${username}`, async () => {
|
|
302
|
+
const usernameField = await testdriver.find('username field');
|
|
303
|
+
await usernameField.click();
|
|
304
|
+
await testdriver.type(username);
|
|
305
|
+
|
|
306
|
+
const passwordField = await testdriver.find('password field');
|
|
307
|
+
await passwordField.click();
|
|
308
|
+
await testdriver.type(password);
|
|
309
|
+
|
|
310
|
+
const submitButton = await testdriver.find('submit button');
|
|
311
|
+
await submitButton.click();
|
|
312
|
+
|
|
313
|
+
if (expected) {
|
|
314
|
+
await testdriver.assert('login successful');
|
|
315
|
+
} else {
|
|
316
|
+
await testdriver.assert('error message is shown');
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## Lifecycle Hooks
|
|
323
|
+
|
|
324
|
+
### YAML Lifecycle
|
|
325
|
+
|
|
326
|
+
```yaml
|
|
327
|
+
prerun: lifecycle/prerun.yaml
|
|
328
|
+
postrun: lifecycle/postrun.yaml
|
|
329
|
+
|
|
330
|
+
steps:
|
|
331
|
+
# test steps
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### SDK Lifecycle
|
|
335
|
+
|
|
336
|
+
```javascript
|
|
337
|
+
describe('My Tests', () => {
|
|
338
|
+
let testdriver;
|
|
339
|
+
|
|
340
|
+
beforeAll(async () => {
|
|
341
|
+
client = new TestDriver(process.env.TD_API_KEY);
|
|
342
|
+
await testdriver.auth();
|
|
343
|
+
await testdriver.connect();
|
|
344
|
+
|
|
345
|
+
// Prerun logic
|
|
346
|
+
await testdriver.exec('pwsh', 'npm ls dashcam -g', 30000);
|
|
347
|
+
await testdriver.exec('pwsh', 'dashcam start', 5000);
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
afterAll(async () => {
|
|
351
|
+
// Postrun logic
|
|
352
|
+
const dashcamUrl = await testdriver.exec('pwsh', 'dashcam -p', 10000);
|
|
353
|
+
console.log('Recording:', dashcamUrl);
|
|
354
|
+
|
|
355
|
+
await testdriver.disconnect();
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// Tests here
|
|
359
|
+
});
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
## Migration Checklist
|
|
363
|
+
|
|
364
|
+
<Steps>
|
|
365
|
+
<Step title="Set up project">
|
|
366
|
+
```bash
|
|
367
|
+
npm install testdriverai vitest
|
|
368
|
+
```
|
|
369
|
+
</Step>
|
|
370
|
+
|
|
371
|
+
<Step title="Create test file">
|
|
372
|
+
Create a new `.test.mjs` or `.test.js` file for each YAML test file.
|
|
373
|
+
</Step>
|
|
374
|
+
|
|
375
|
+
<Step title="Initialize client">
|
|
376
|
+
Add `beforeAll` and `afterAll` hooks to set up the TestDriver testdriver.
|
|
377
|
+
</Step>
|
|
378
|
+
|
|
379
|
+
<Step title="Convert commands">
|
|
380
|
+
Use the command mapping above to convert each YAML command to SDK calls.
|
|
381
|
+
</Step>
|
|
382
|
+
|
|
383
|
+
<Step title="Add assertions">
|
|
384
|
+
Use your test framework's assertions (`expect()`) along with TestDriver's AI assertions.
|
|
385
|
+
</Step>
|
|
386
|
+
|
|
387
|
+
<Step title="Test incrementally">
|
|
388
|
+
Run tests frequently during migration to catch issues early.
|
|
389
|
+
</Step>
|
|
390
|
+
</Steps>
|
|
391
|
+
|
|
392
|
+
## Common Pitfalls
|
|
393
|
+
|
|
394
|
+
<Warning>
|
|
395
|
+
**Element must be found before interaction**
|
|
396
|
+
|
|
397
|
+
The `find()` method automatically locates elements, but you should check if it was found:
|
|
398
|
+
|
|
399
|
+
```javascript
|
|
400
|
+
const element = await testdriver.find('button');
|
|
401
|
+
if (!element.found()) {
|
|
402
|
+
throw new Error('Element not found');
|
|
403
|
+
}
|
|
404
|
+
await element.click();
|
|
405
|
+
```
|
|
406
|
+
</Warning>
|
|
407
|
+
|
|
408
|
+
<Warning>
|
|
409
|
+
**Always call disconnect()**
|
|
410
|
+
|
|
411
|
+
Use `afterAll` to ensure sandboxes are cleaned up:
|
|
412
|
+
|
|
413
|
+
```javascript
|
|
414
|
+
afterAll(async () => {
|
|
415
|
+
await testdriver.disconnect();
|
|
416
|
+
});
|
|
417
|
+
```
|
|
418
|
+
</Warning>
|
|
419
|
+
|
|
420
|
+
<Warning>
|
|
421
|
+
**Async/await is required**
|
|
422
|
+
|
|
423
|
+
All SDK methods return Promises and must be awaited:
|
|
424
|
+
|
|
425
|
+
```javascript
|
|
426
|
+
// ❌ Wrong
|
|
427
|
+
testdriver.type('hello');
|
|
428
|
+
|
|
429
|
+
// ✅ Correct
|
|
430
|
+
await testdriver.type('hello');
|
|
431
|
+
```
|
|
432
|
+
</Warning>
|
|
433
|
+
|
|
434
|
+
## Example: Complete Migration
|
|
435
|
+
|
|
436
|
+
### Before (YAML)
|
|
437
|
+
|
|
438
|
+
```yaml
|
|
439
|
+
version: 6.0.0
|
|
440
|
+
|
|
441
|
+
variables:
|
|
442
|
+
username: standard_user
|
|
443
|
+
|
|
444
|
+
prerun: lifecycle/prerun.yaml
|
|
445
|
+
postrun: lifecycle/postrun.yaml
|
|
446
|
+
|
|
447
|
+
steps:
|
|
448
|
+
- prompt: focus chrome
|
|
449
|
+
commands:
|
|
450
|
+
- command: focus-application
|
|
451
|
+
name: Google Chrome
|
|
452
|
+
|
|
453
|
+
- prompt: fill login form
|
|
454
|
+
commands:
|
|
455
|
+
- command: hover-text
|
|
456
|
+
text: Username
|
|
457
|
+
action: click
|
|
458
|
+
- command: type
|
|
459
|
+
text: ${username}
|
|
460
|
+
- command: press-keys
|
|
461
|
+
keys: [tab]
|
|
462
|
+
- command: type
|
|
463
|
+
text: secret_sauce
|
|
464
|
+
|
|
465
|
+
- prompt: submit form
|
|
466
|
+
commands:
|
|
467
|
+
- command: press-keys
|
|
468
|
+
keys: [enter]
|
|
469
|
+
|
|
470
|
+
- prompt: verify success
|
|
471
|
+
commands:
|
|
472
|
+
- command: assert
|
|
473
|
+
assertion: products page is displayed
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### After (SDK)
|
|
477
|
+
|
|
478
|
+
```javascript
|
|
479
|
+
import { beforeAll, afterAll, describe, it, expect } from 'vitest';
|
|
480
|
+
import TestDriver from 'testdriverai';
|
|
481
|
+
|
|
482
|
+
describe('Login Flow', () => {
|
|
483
|
+
let testdriver;
|
|
484
|
+
const username = 'standard_user';
|
|
485
|
+
|
|
486
|
+
beforeAll(async () => {
|
|
487
|
+
client = new TestDriver(process.env.TD_API_KEY, {
|
|
488
|
+
os: 'windows'
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
await testdriver.auth();
|
|
492
|
+
await testdriver.connect({ newSandbox: true });
|
|
493
|
+
|
|
494
|
+
// Prerun
|
|
495
|
+
await testdriver.exec('pwsh', 'dashcam start', 5000, true);
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
afterAll(async () => {
|
|
499
|
+
// Postrun
|
|
500
|
+
const url = await testdriver.exec('pwsh', 'dashcam -p', 10000);
|
|
501
|
+
console.log('Recording:', url);
|
|
502
|
+
|
|
503
|
+
await testdriver.disconnect();
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
it('should login successfully', async () => {
|
|
507
|
+
// Focus chrome
|
|
508
|
+
await testdriver.focusApplication('Google Chrome');
|
|
509
|
+
|
|
510
|
+
// Fill login form
|
|
511
|
+
const usernameField = await testdriver.find('Username input field');
|
|
512
|
+
await usernameField.click();
|
|
513
|
+
await testdriver.type(username);
|
|
514
|
+
|
|
515
|
+
await testdriver.pressKeys(['tab']);
|
|
516
|
+
await testdriver.type('secret_sauce');
|
|
517
|
+
|
|
518
|
+
// Submit form
|
|
519
|
+
await testdriver.pressKeys(['enter']);
|
|
520
|
+
|
|
521
|
+
// Verify success
|
|
522
|
+
const result = await testdriver.assert('products page is displayed');
|
|
523
|
+
expect(result).toBeTruthy();
|
|
524
|
+
});
|
|
525
|
+
});
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
## Next Steps
|
|
529
|
+
|
|
530
|
+
<CardGroup cols={2}>
|
|
531
|
+
<Card
|
|
532
|
+
title="API Reference"
|
|
533
|
+
icon="book"
|
|
534
|
+
href="/v7/api/client"
|
|
535
|
+
>
|
|
536
|
+
Explore all available SDK methods
|
|
537
|
+
</Card>
|
|
538
|
+
|
|
539
|
+
<Card
|
|
540
|
+
title="Examples"
|
|
541
|
+
icon="code"
|
|
542
|
+
href="/v7/guides/examples"
|
|
543
|
+
>
|
|
544
|
+
See complete test examples
|
|
545
|
+
</Card>
|
|
546
|
+
|
|
547
|
+
<Card
|
|
548
|
+
title="Best Practices"
|
|
549
|
+
icon="star"
|
|
550
|
+
href="/v7/guides/best-practices"
|
|
551
|
+
>
|
|
552
|
+
Learn SDK best practices
|
|
553
|
+
</Card>
|
|
554
|
+
|
|
555
|
+
<Card
|
|
556
|
+
title="Quickstart"
|
|
557
|
+
icon="rocket"
|
|
558
|
+
href="/v7/getting-started/quickstart"
|
|
559
|
+
>
|
|
560
|
+
Get started with the SDK
|
|
561
|
+
</Card>
|
|
562
|
+
</CardGroup>
|
|
@@ -43,9 +43,10 @@ The setup process involves three main steps:
|
|
|
43
43
|
- AWS account with permissions to run CloudFormation.
|
|
44
44
|
- [AWS CLI](https://aws.amazon.com/cli/) installed locally.
|
|
45
45
|
|
|
46
|
-
<Tip>
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
<Tip>
|
|
47
|
+
Be sure to run `aws configure` with your credentials
|
|
48
|
+
</Tip>
|
|
49
|
+
- Access to the TestDriver AMI (Golden Image is `ami-055cd47506a2f39bb`)\
|
|
49
50
|
[Contact us with your preferred AWS Region for access](https://form.typeform.com/to/UECf9rDx?typeform-source=testdriver.ai).
|
|
50
51
|
- A GitHub repository for committing your tests & workflow.
|
|
51
52
|
|
|
@@ -76,8 +77,7 @@ aws cloudformation deploy \
|
|
|
76
77
|
```
|
|
77
78
|
|
|
78
79
|
<Danger>
|
|
79
|
-
**Security**: Replace `AllowedIngressCidr=0.0.0.0/0` with your specific IP
|
|
80
|
-
ranges to lock down access to your VPC.
|
|
80
|
+
**Security**: Replace `AllowedIngressCidr=0.0.0.0/0` with your specific IP ranges to lock down access to your VPC.
|
|
81
81
|
</Danger>
|
|
82
82
|
|
|
83
83
|
### Get Launch Template ID
|
|
@@ -91,7 +91,9 @@ aws cloudformation describe-stacks \
|
|
|
91
91
|
--output text
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
-
<Tip
|
|
94
|
+
<Tip>
|
|
95
|
+
**Save this ID** – you'll need it for the next step.
|
|
96
|
+
</Tip>
|
|
95
97
|
|
|
96
98
|
## Step 2: Spawn a New TestDriver Runner
|
|
97
99
|
|
|
@@ -127,15 +129,12 @@ AWS_REGION=us-east-2
|
|
|
127
129
|
```
|
|
128
130
|
|
|
129
131
|
<Note>
|
|
130
|
-
**Instance Lifecycle**: Instances spawned by this script will continue running
|
|
131
|
-
until you manually terminate them. They are automatically tagged with
|
|
132
|
-
`Name=TestDriverRunner` and `Project=[your ProjectTag value]` for easy
|
|
133
|
-
identification in the AWS console.
|
|
132
|
+
**Instance Lifecycle**: Instances spawned by this script will continue running until you manually terminate them. They are automatically tagged with `Name=TestDriverRunner` and `Project=[your ProjectTag value]` for easy identification in the AWS console.
|
|
134
133
|
</Note>
|
|
135
134
|
|
|
136
135
|
#### Changing Resolution in Lifecycle Files
|
|
137
136
|
|
|
138
|
-
You can also change the resolution before running tests by adding an `exec` command in your `lifecycle/provision.yaml` file:
|
|
137
|
+
You can also change the resolution before running tests by adding an [`exec`](/commands/exec) command in your `lifecycle/provision.yaml` file:
|
|
139
138
|
|
|
140
139
|
```yaml lifecycle/provision.yaml
|
|
141
140
|
version: 6.0.0
|
|
@@ -367,4 +366,4 @@ For enterprise customers:
|
|
|
367
366
|
|
|
368
367
|
- Contact your account manager for AMI access issues
|
|
369
368
|
- Use support channels for infrastructure questions
|
|
370
|
-
- Check the TestDriver documentation for CLI usage
|
|
369
|
+
- Check the TestDriver documentation for CLI usage
|