testdriverai 7.0.0 → 7.1.1
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/.env.example +2 -0
- package/.github/workflows/linux-tests.yml +28 -0
- package/README.md +126 -0
- package/agent/index.js +7 -9
- package/agent/interface.js +13 -2
- package/agent/lib/commands.js +795 -136
- package/agent/lib/redraw.js +124 -39
- package/agent/lib/sandbox.js +40 -3
- package/agent/lib/sdk.js +21 -0
- package/agent/lib/valid-version.js +2 -2
- package/debugger/index.html +1 -1
- package/docs/docs.json +86 -71
- package/docs/guide/best-practices-polling.mdx +154 -0
- package/docs/v6/getting-started/self-hosting.mdx +3 -2
- package/docs/v7/_drafts/agents.mdx +852 -0
- package/docs/v7/_drafts/auto-cache-key.mdx +167 -0
- package/docs/v7/_drafts/best-practices.mdx +486 -0
- package/docs/v7/_drafts/caching-ai.mdx +215 -0
- package/docs/v7/_drafts/caching-selectors.mdx +400 -0
- package/docs/v7/_drafts/caching.mdx +366 -0
- package/docs/v7/_drafts/cli-to-sdk-migration.mdx +425 -0
- package/docs/v7/_drafts/core.mdx +459 -0
- package/docs/v7/_drafts/dashcam-title-feature.mdx +89 -0
- package/docs/v7/_drafts/debugging.mdx +349 -0
- package/docs/v7/_drafts/error-handling.mdx +501 -0
- package/docs/v7/_drafts/faq.mdx +393 -0
- package/docs/v7/_drafts/hooks.mdx +360 -0
- package/docs/v7/_drafts/implementation-plan.mdx +994 -0
- package/docs/v7/_drafts/init-command.mdx +95 -0
- package/docs/v7/_drafts/optimal-sdk-design.mdx +1348 -0
- package/docs/v7/_drafts/performance.mdx +517 -0
- package/docs/v7/_drafts/presets.mdx +210 -0
- package/docs/v7/_drafts/progressive-disclosure.mdx +230 -0
- package/docs/v7/_drafts/provision.mdx +266 -0
- package/docs/{QUICK_START_TEST_RECORDING.md → v7/_drafts/quick-start-test-recording.mdx} +3 -3
- package/docs/v7/_drafts/sdk-v7-complete.mdx +345 -0
- package/docs/v7/{guides → _drafts}/self-hosting.mdx +1 -1
- package/docs/v7/_drafts/troubleshooting.mdx +526 -0
- package/docs/v7/_drafts/vitest-plugin.mdx +477 -0
- package/docs/v7/_drafts/vitest.mdx +535 -0
- package/docs/v7/api/{ai.mdx → act.mdx} +24 -24
- package/docs/v7/api/client.mdx +1 -1
- package/docs/v7/api/dashcam.mdx +497 -0
- package/docs/v7/api/doubleClick.mdx +102 -0
- package/docs/v7/api/elements.mdx +143 -41
- package/docs/v7/api/find.mdx +258 -0
- package/docs/v7/api/mouseDown.mdx +161 -0
- package/docs/v7/api/mouseUp.mdx +164 -0
- package/docs/v7/api/rightClick.mdx +123 -0
- package/docs/v7/api/type.mdx +51 -7
- package/docs/v7/features/ai-native.mdx +427 -0
- package/docs/v7/features/easy-to-write.mdx +351 -0
- package/docs/v7/features/enterprise.mdx +540 -0
- package/docs/v7/features/fast.mdx +424 -0
- package/docs/v7/features/observable.mdx +623 -0
- package/docs/v7/features/powerful.mdx +531 -0
- package/docs/v7/features/scalable.mdx +417 -0
- package/docs/v7/features/stable.mdx +514 -0
- package/docs/v7/getting-started/configuration.mdx +380 -0
- package/docs/v7/getting-started/generating-tests.mdx +525 -0
- package/docs/v7/getting-started/installation.mdx +486 -0
- package/docs/v7/getting-started/quickstart.mdx +320 -141
- package/docs/v7/getting-started/running-and-debugging.mdx +511 -0
- package/docs/v7/getting-started/setting-up-in-ci.mdx +612 -0
- package/docs/v7/getting-started/writing-tests.mdx +535 -0
- package/docs/v7/overview/what-is-testdriver.mdx +398 -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 +3 -3
- package/docs/v7/presets/chrome-extension.mdx +223 -0
- package/docs/v7/presets/chrome.mdx +303 -0
- package/docs/v7/presets/electron.mdx +453 -0
- package/docs/v7/presets/vscode.mdx +417 -0
- package/docs/v7/presets/webapp.mdx +396 -0
- package/examples/run-tests-with-recording.sh +2 -2
- package/interfaces/cli/commands/init.js +358 -0
- package/interfaces/vitest-plugin.mjs +393 -103
- package/lib/core/Dashcam.js +506 -0
- package/lib/core/index.d.ts +150 -0
- package/lib/core/index.js +12 -0
- package/lib/presets/index.mjs +331 -0
- package/lib/vitest/hooks.d.ts +119 -0
- package/lib/vitest/hooks.mjs +316 -0
- package/lib/vitest/setup.mjs +44 -0
- package/package.json +13 -3
- package/sdk.d.ts +350 -44
- package/sdk.js +818 -105
- package/{self-hosted.yml → setup/aws/self-hosted.yml} +1 -1
- package/test/manual/test-console-logs.test.mjs +42 -0
- package/test/manual/test-init.sh +54 -0
- package/test/manual/test-provision-auth.mjs +22 -0
- package/test/testdriver/assert.test.mjs +41 -0
- package/test/testdriver/auto-cache-key-demo.test.mjs +56 -0
- package/test/testdriver/chrome-extension.test.mjs +89 -0
- package/{testdriver/acceptance-sdk → test/testdriver}/drag-and-drop.test.mjs +7 -19
- package/{testdriver/acceptance-sdk → test/testdriver}/element-not-found.test.mjs +6 -19
- package/{testdriver/acceptance-sdk → test/testdriver}/exec-js.test.mjs +6 -18
- package/{testdriver/acceptance-sdk → test/testdriver}/exec-output.test.mjs +9 -21
- package/{testdriver/acceptance-sdk → test/testdriver}/exec-pwsh.test.mjs +14 -26
- package/{testdriver/acceptance-sdk → test/testdriver}/focus-window.test.mjs +8 -20
- package/{testdriver/acceptance-sdk → test/testdriver}/formatted-logging.test.mjs +5 -20
- package/{testdriver/acceptance-sdk → test/testdriver}/hover-image.test.mjs +10 -19
- package/{testdriver/acceptance-sdk → test/testdriver}/hover-text-with-description.test.mjs +7 -19
- package/{testdriver/acceptance-sdk → test/testdriver}/hover-text.test.mjs +5 -19
- package/{testdriver/acceptance-sdk → test/testdriver}/match-image.test.mjs +7 -19
- package/{testdriver/acceptance-sdk → test/testdriver}/press-keys.test.mjs +5 -19
- package/{testdriver/acceptance-sdk → test/testdriver}/prompt.test.mjs +7 -19
- package/{testdriver/acceptance-sdk → test/testdriver}/scroll-keyboard.test.mjs +6 -20
- package/{testdriver/acceptance-sdk → test/testdriver}/scroll-until-image.test.mjs +6 -18
- package/test/testdriver/scroll-until-text.test.mjs +28 -0
- package/{testdriver/acceptance-sdk → test/testdriver}/scroll.test.mjs +12 -21
- package/test/testdriver/setup/lifecycleHelpers.mjs +262 -0
- package/{testdriver/acceptance-sdk → test/testdriver}/setup/testHelpers.mjs +25 -20
- package/test/testdriver/type.test.mjs +45 -0
- package/vitest.config.mjs +11 -56
- package/.github/dependabot.yml +0 -11
- package/.github/workflows/acceptance-linux.yml +0 -75
- package/.github/workflows/acceptance-sdk-tests.yml +0 -133
- package/.github/workflows/acceptance-tests.yml +0 -130
- package/.github/workflows/lint.yml +0 -27
- package/.github/workflows/publish-canary.yml +0 -40
- package/.github/workflows/publish-latest.yml +0 -61
- package/.github/workflows/test-install.yml +0 -29
- package/.vscode/extensions.json +0 -3
- package/.vscode/launch.json +0 -22
- package/.vscode/mcp.json +0 -9
- package/.vscode/settings.json +0 -14
- package/CODEOWNERS +0 -3
- package/MIGRATION.md +0 -389
- package/SDK_README.md +0 -1122
- package/_testdriver/acceptance/assert.yaml +0 -7
- package/_testdriver/acceptance/dashcam.yaml +0 -9
- package/_testdriver/acceptance/drag-and-drop.yaml +0 -49
- package/_testdriver/acceptance/embed.yaml +0 -9
- package/_testdriver/acceptance/exec-js.yaml +0 -29
- package/_testdriver/acceptance/exec-output.yaml +0 -43
- package/_testdriver/acceptance/exec-shell.yaml +0 -40
- package/_testdriver/acceptance/focus-window.yaml +0 -16
- package/_testdriver/acceptance/hover-image.yaml +0 -18
- package/_testdriver/acceptance/hover-text-with-description.yaml +0 -29
- package/_testdriver/acceptance/hover-text.yaml +0 -14
- package/_testdriver/acceptance/if-else.yaml +0 -31
- package/_testdriver/acceptance/match-image.yaml +0 -15
- package/_testdriver/acceptance/press-keys.yaml +0 -35
- package/_testdriver/acceptance/prompt.yaml +0 -11
- package/_testdriver/acceptance/remember.yaml +0 -27
- package/_testdriver/acceptance/screenshots/cart.png +0 -0
- package/_testdriver/acceptance/scroll-keyboard.yaml +0 -34
- package/_testdriver/acceptance/scroll-until-image.yaml +0 -26
- package/_testdriver/acceptance/scroll-until-text.yaml +0 -20
- package/_testdriver/acceptance/scroll.yaml +0 -33
- package/_testdriver/acceptance/snippets/login.yaml +0 -29
- package/_testdriver/acceptance/snippets/match-cart.yaml +0 -8
- package/_testdriver/acceptance/type.yaml +0 -29
- package/_testdriver/behavior/failure.yaml +0 -7
- package/_testdriver/behavior/hover-text.yaml +0 -13
- package/_testdriver/behavior/lifecycle/postrun.yaml +0 -10
- package/_testdriver/behavior/lifecycle/prerun.yaml +0 -8
- package/_testdriver/behavior/lifecycle/provision.yaml +0 -8
- package/_testdriver/behavior/secrets.yaml +0 -7
- package/_testdriver/edge-cases/dashcam-chrome.yaml +0 -8
- package/_testdriver/edge-cases/exec-pwsh-multiline.yaml +0 -10
- package/_testdriver/edge-cases/js-exception.yaml +0 -8
- package/_testdriver/edge-cases/js-promise.yaml +0 -19
- package/_testdriver/edge-cases/lifecycle/postrun.yaml +0 -10
- package/_testdriver/edge-cases/prompt-in-middle.yaml +0 -23
- package/_testdriver/edge-cases/prompt-nested.yaml +0 -7
- package/_testdriver/edge-cases/success-test.yaml +0 -9
- package/_testdriver/examples/android/example.yaml +0 -12
- package/_testdriver/examples/android/lifecycle/postrun.yaml +0 -11
- package/_testdriver/examples/android/lifecycle/provision.yaml +0 -47
- package/_testdriver/examples/android/readme.md +0 -7
- package/_testdriver/examples/chrome-extension/lifecycle/provision.yaml +0 -74
- package/_testdriver/examples/desktop/lifecycle/prerun.yaml +0 -0
- package/_testdriver/examples/desktop/lifecycle/provision.yaml +0 -64
- package/_testdriver/examples/vscode-extension/lifecycle/provision.yaml +0 -73
- package/_testdriver/examples/web/lifecycle/postrun.yaml +0 -7
- package/_testdriver/examples/web/lifecycle/prerun.yaml +0 -22
- package/_testdriver/lifecycle/postrun.yaml +0 -8
- package/_testdriver/lifecycle/prerun.yaml +0 -15
- package/_testdriver/lifecycle/provision.yaml +0 -25
- package/debug-screenshot-1763401388589.png +0 -0
- package/mcp-server/AI_GUIDELINES.md +0 -57
- package/scripts/view-test-results.mjs +0 -96
- package/styles/.vale-config/2-MDX.ini +0 -5
- package/styles/Microsoft/AMPM.yml +0 -9
- package/styles/Microsoft/Accessibility.yml +0 -30
- package/styles/Microsoft/Acronyms.yml +0 -64
- package/styles/Microsoft/Adverbs.yml +0 -272
- package/styles/Microsoft/Auto.yml +0 -11
- package/styles/Microsoft/Avoid.yml +0 -14
- package/styles/Microsoft/Contractions.yml +0 -50
- package/styles/Microsoft/Dashes.yml +0 -13
- package/styles/Microsoft/DateFormat.yml +0 -8
- package/styles/Microsoft/DateNumbers.yml +0 -40
- package/styles/Microsoft/DateOrder.yml +0 -8
- package/styles/Microsoft/Ellipses.yml +0 -9
- package/styles/Microsoft/FirstPerson.yml +0 -16
- package/styles/Microsoft/Foreign.yml +0 -13
- package/styles/Microsoft/Gender.yml +0 -8
- package/styles/Microsoft/GenderBias.yml +0 -42
- package/styles/Microsoft/GeneralURL.yml +0 -11
- package/styles/Microsoft/HeadingAcronyms.yml +0 -7
- package/styles/Microsoft/HeadingColons.yml +0 -8
- package/styles/Microsoft/HeadingPunctuation.yml +0 -13
- package/styles/Microsoft/Headings.yml +0 -28
- package/styles/Microsoft/Hyphens.yml +0 -14
- package/styles/Microsoft/Negative.yml +0 -13
- package/styles/Microsoft/Ordinal.yml +0 -13
- package/styles/Microsoft/OxfordComma.yml +0 -8
- package/styles/Microsoft/Passive.yml +0 -183
- package/styles/Microsoft/Percentages.yml +0 -7
- package/styles/Microsoft/Plurals.yml +0 -7
- package/styles/Microsoft/Quotes.yml +0 -7
- package/styles/Microsoft/RangeTime.yml +0 -13
- package/styles/Microsoft/Semicolon.yml +0 -8
- package/styles/Microsoft/SentenceLength.yml +0 -6
- package/styles/Microsoft/Spacing.yml +0 -8
- package/styles/Microsoft/Suspended.yml +0 -7
- package/styles/Microsoft/Terms.yml +0 -42
- package/styles/Microsoft/URLFormat.yml +0 -9
- package/styles/Microsoft/Units.yml +0 -16
- package/styles/Microsoft/Vocab.yml +0 -25
- package/styles/Microsoft/We.yml +0 -11
- package/styles/Microsoft/Wordiness.yml +0 -127
- package/styles/Microsoft/meta.json +0 -4
- package/styles/alex/Ablist.yml +0 -274
- package/styles/alex/Condescending.yml +0 -16
- package/styles/alex/Gendered.yml +0 -110
- package/styles/alex/LGBTQ.yml +0 -55
- package/styles/alex/OCD.yml +0 -10
- package/styles/alex/Press.yml +0 -12
- package/styles/alex/ProfanityLikely.yml +0 -1289
- package/styles/alex/ProfanityMaybe.yml +0 -282
- package/styles/alex/ProfanityUnlikely.yml +0 -251
- package/styles/alex/README.md +0 -27
- package/styles/alex/Race.yml +0 -85
- package/styles/alex/Suicide.yml +0 -26
- package/styles/alex/meta.json +0 -4
- package/styles/config/vocabularies/Docs/accept.txt +0 -47
- package/styles/config/vocabularies/Docs/reject.txt +0 -4
- package/styles/proselint/Airlinese.yml +0 -8
- package/styles/proselint/AnimalLabels.yml +0 -48
- package/styles/proselint/Annotations.yml +0 -9
- package/styles/proselint/Apologizing.yml +0 -8
- package/styles/proselint/Archaisms.yml +0 -52
- package/styles/proselint/But.yml +0 -8
- package/styles/proselint/Cliches.yml +0 -782
- package/styles/proselint/CorporateSpeak.yml +0 -30
- package/styles/proselint/Currency.yml +0 -5
- package/styles/proselint/Cursing.yml +0 -15
- package/styles/proselint/DateCase.yml +0 -7
- package/styles/proselint/DateMidnight.yml +0 -7
- package/styles/proselint/DateRedundancy.yml +0 -10
- package/styles/proselint/DateSpacing.yml +0 -7
- package/styles/proselint/DenizenLabels.yml +0 -52
- package/styles/proselint/Diacritical.yml +0 -95
- package/styles/proselint/GenderBias.yml +0 -45
- package/styles/proselint/GroupTerms.yml +0 -39
- package/styles/proselint/Hedging.yml +0 -8
- package/styles/proselint/Hyperbole.yml +0 -6
- package/styles/proselint/Jargon.yml +0 -11
- package/styles/proselint/LGBTOffensive.yml +0 -13
- package/styles/proselint/LGBTTerms.yml +0 -15
- package/styles/proselint/Malapropisms.yml +0 -8
- package/styles/proselint/Needless.yml +0 -358
- package/styles/proselint/Nonwords.yml +0 -38
- package/styles/proselint/Oxymorons.yml +0 -22
- package/styles/proselint/P-Value.yml +0 -6
- package/styles/proselint/RASSyndrome.yml +0 -30
- package/styles/proselint/README.md +0 -12
- package/styles/proselint/Skunked.yml +0 -13
- package/styles/proselint/Spelling.yml +0 -17
- package/styles/proselint/Typography.yml +0 -11
- package/styles/proselint/Uncomparables.yml +0 -50
- package/styles/proselint/Very.yml +0 -6
- package/styles/proselint/meta.json +0 -15
- package/styles/write-good/Cliches.yml +0 -702
- package/styles/write-good/E-Prime.yml +0 -32
- package/styles/write-good/Illusions.yml +0 -11
- package/styles/write-good/Passive.yml +0 -183
- package/styles/write-good/README.md +0 -27
- package/styles/write-good/So.yml +0 -5
- package/styles/write-good/ThereIs.yml +0 -6
- package/styles/write-good/TooWordy.yml +0 -221
- package/styles/write-good/Weasel.yml +0 -29
- package/styles/write-good/meta.json +0 -4
- package/test/mcp-example-test.yaml +0 -27
- package/test/test_parser.js +0 -47
- package/testdriver/acceptance-sdk/QUICK_REFERENCE.md +0 -61
- package/testdriver/acceptance-sdk/README.md +0 -128
- package/testdriver/acceptance-sdk/TEST_REPORTING.md +0 -245
- package/testdriver/acceptance-sdk/assert.test.mjs +0 -44
- package/testdriver/acceptance-sdk/scroll-until-text.test.mjs +0 -42
- package/testdriver/acceptance-sdk/setup/lifecycleHelpers.mjs +0 -239
- package/testdriver/acceptance-sdk/type-checking-demo.js +0 -49
- package/testdriver/acceptance-sdk/type.test.mjs +0 -84
- package/vale.ini +0 -18
- package/vitest.config.example.js +0 -19
- package/vitest.config.mjs.bak +0 -44
- /package/docs/{ARCHITECTURE.md → v7/_drafts/architecture.mdx} +0 -0
- /package/docs/{AWESOME_LOGS_QUICK_REF.md → v7/_drafts/awesome-logs-quick-ref.mdx} +0 -0
- /package/{CONTRIBUTING.md → docs/v7/_drafts/contributing.mdx} +0 -0
- /package/docs/v7/{guides → _drafts}/migration.mdx +0 -0
- /package/{PLUGIN_MIGRATION.md → docs/v7/_drafts/plugin-migration.mdx} +0 -0
- /package/{PROMPT_CACHE.md → docs/v7/_drafts/prompt-cache.mdx} +0 -0
- /package/docs/{SDK_AWESOME_LOGS.md → v7/_drafts/sdk-awesome-logs.mdx} +0 -0
- /package/docs/{sdk-browser-rendering.md → v7/_drafts/sdk-browser-rendering.mdx} +0 -0
- /package/{SDK_LOGGING.md → docs/v7/_drafts/sdk-logging.mdx} +0 -0
- /package/{SDK_MIGRATION.md → docs/v7/_drafts/sdk-migration.mdx} +0 -0
- /package/docs/{TEST_RECORDING.md → v7/_drafts/test-recording.mdx} +0 -0
- /package/docs/v7/{README.md → overview/readme.mdx} +0 -0
- /package/{debug-locate-response.js → test/manual/debug-locate-response.js} +0 -0
- /package/{test-find-api.js → test/manual/test-find-api.js} +0 -0
- /package/{test-prompt-cache.js → test/manual/test-prompt-cache.js} +0 -0
- /package/{test-sandbox-render.js → test/manual/test-sandbox-render.js} +0 -0
- /package/{test-sdk-methods.js → test/manual/test-sdk-methods.js} +0 -0
- /package/{test-sdk-refactor.js → test/manual/test-sdk-refactor.js} +0 -0
- /package/{test-stack-trace.mjs → test/manual/test-stack-trace.mjs} +0 -0
- /package/{verify-element-api.js → test/manual/verify-element-api.js} +0 -0
- /package/{verify-types.js → test/manual/verify-types.js} +0 -0
- /package/{testdriver/acceptance-sdk → test/testdriver}/setup/globalTeardown.mjs +0 -0
- /package/{testdriver/acceptance-sdk → test/testdriver}/setup/vitestSetup.mjs +0 -0
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Performance Optimization"
|
|
3
|
+
description: "Speed up your TestDriver tests"
|
|
4
|
+
icon: "gauge"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
TestDriver tests run in cloud sandboxes, which adds latency. This guide shows you how to minimize overhead and maximize test speed.
|
|
10
|
+
|
|
11
|
+
## Baseline Performance
|
|
12
|
+
|
|
13
|
+
Typical test execution:
|
|
14
|
+
|
|
15
|
+
| Phase | Time | What's Happening |
|
|
16
|
+
|-------|------|------------------|
|
|
17
|
+
| Sandbox startup | 20-60s | First test creates VM |
|
|
18
|
+
| Sandbox reuse | 0s | Subsequent tests reuse VM |
|
|
19
|
+
| Page load | 1-5s | Browser navigates to URL |
|
|
20
|
+
| Element finding | 0.5-3s | AI locates element |
|
|
21
|
+
| Element finding (cached) | 0.1-0.5s | Cache hit |
|
|
22
|
+
| Command execution | 0.1-1s | Click, type, etc. |
|
|
23
|
+
| AI command | 2-5s | Natural language parsing |
|
|
24
|
+
| AI command (cached) | 0.1-0.5s | Cache hit |
|
|
25
|
+
|
|
26
|
+
**First test**: 60-90s
|
|
27
|
+
**Subsequent tests**: 5-30s
|
|
28
|
+
**Optimized tests**: 2-10s
|
|
29
|
+
|
|
30
|
+
## Optimization Strategies
|
|
31
|
+
|
|
32
|
+
### 1. Reuse Sandboxes
|
|
33
|
+
|
|
34
|
+
The biggest performance win is reusing sandboxes across tests.
|
|
35
|
+
|
|
36
|
+
#### ❌ Slow - Create new sandbox per test
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
test('test 1', async () => {
|
|
40
|
+
const testdriver = await TestDriver.create({
|
|
41
|
+
apiKey: process.env.TD_API_KEY
|
|
42
|
+
});
|
|
43
|
+
// Test logic
|
|
44
|
+
await testdriver.cleanup();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('test 2', async () => {
|
|
48
|
+
const testdriver = await TestDriver.create({
|
|
49
|
+
apiKey: process.env.TD_API_KEY
|
|
50
|
+
});
|
|
51
|
+
// Test logic
|
|
52
|
+
await testdriver.cleanup();
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Time**: 60s + 60s = 120s
|
|
57
|
+
|
|
58
|
+
#### ✅ Fast - Reuse sandbox with context
|
|
59
|
+
|
|
60
|
+
```javascript
|
|
61
|
+
import { chrome } from '../setup/lifecycleHelpers.mjs';
|
|
62
|
+
|
|
63
|
+
test('test 1', async (context) => {
|
|
64
|
+
const { testdriver } = await chrome(context, { url: 'https://app.com' });
|
|
65
|
+
// Test logic
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('test 2', async (context) => {
|
|
69
|
+
const { testdriver } = await chrome(context, { url: 'https://app.com' });
|
|
70
|
+
// Test logic
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Time**: 60s + 5s = 65s (54% faster)
|
|
75
|
+
|
|
76
|
+
### 2. Enable Caching
|
|
77
|
+
|
|
78
|
+
TestDriver has two cache layers:
|
|
79
|
+
|
|
80
|
+
#### AI Prompt Cache
|
|
81
|
+
|
|
82
|
+
Caches AI-generated commands locally:
|
|
83
|
+
|
|
84
|
+
```yaml
|
|
85
|
+
# testdriver.yaml
|
|
86
|
+
cache:
|
|
87
|
+
ai: true # Enable prompt caching
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Impact**: 2-5s → 0.1-0.5s per AI command
|
|
91
|
+
|
|
92
|
+
#### Selector Cache
|
|
93
|
+
|
|
94
|
+
Caches element locations on server:
|
|
95
|
+
|
|
96
|
+
```yaml
|
|
97
|
+
# testdriver.yaml
|
|
98
|
+
cache:
|
|
99
|
+
selectors: true
|
|
100
|
+
selectorThreshold: 0.95 # 95% similarity required
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Impact**: 0.5-3s → 0.1-0.5s per element find
|
|
104
|
+
|
|
105
|
+
**Combined**: Tests run 3-5x faster on subsequent runs.
|
|
106
|
+
|
|
107
|
+
### 3. Parallel Test Execution
|
|
108
|
+
|
|
109
|
+
Run multiple tests simultaneously:
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
// vitest.config.mjs
|
|
113
|
+
export default defineConfig({
|
|
114
|
+
test: {
|
|
115
|
+
maxConcurrency: 5, // Run 5 tests at once
|
|
116
|
+
fileParallelism: true
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Impact**: 5 tests in 300s → 5 tests in 90s (70% faster)
|
|
122
|
+
|
|
123
|
+
**Tradeoffs**:
|
|
124
|
+
- Uses more test minutes
|
|
125
|
+
- May hit API rate limits
|
|
126
|
+
- Requires adequate plan limits
|
|
127
|
+
|
|
128
|
+
### 4. Reduce AI Commands
|
|
129
|
+
|
|
130
|
+
AI commands are slower than direct commands.
|
|
131
|
+
|
|
132
|
+
#### ❌ Slow - AI for everything
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
await testdriver.ai('click the login button');
|
|
136
|
+
await testdriver.ai('type email@example.com');
|
|
137
|
+
await testdriver.ai('type mypassword');
|
|
138
|
+
await testdriver.ai('press enter');
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Time**: ~15s
|
|
142
|
+
|
|
143
|
+
#### ✅ Fast - AI only for finding
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
await testdriver.find('email field').then(el => el.click());
|
|
147
|
+
await testdriver.type('email@example.com');
|
|
148
|
+
|
|
149
|
+
await testdriver.find('password field').then(el => el.click());
|
|
150
|
+
await testdriver.type('mypassword');
|
|
151
|
+
|
|
152
|
+
await testdriver.find('login button').then(el => el.click());
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Time**: ~5s (66% faster)
|
|
156
|
+
|
|
157
|
+
### 5. Batch Operations
|
|
158
|
+
|
|
159
|
+
Minimize round trips to sandbox:
|
|
160
|
+
|
|
161
|
+
#### ❌ Slow - Sequential operations
|
|
162
|
+
|
|
163
|
+
```javascript
|
|
164
|
+
await testdriver.find('first name').then(el => el.click());
|
|
165
|
+
await testdriver.type('John');
|
|
166
|
+
|
|
167
|
+
await testdriver.find('last name').then(el => el.click());
|
|
168
|
+
await testdriver.type('Doe');
|
|
169
|
+
|
|
170
|
+
await testdriver.find('email').then(el => el.click());
|
|
171
|
+
await testdriver.type('john@example.com');
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Time**: 6 round trips
|
|
175
|
+
|
|
176
|
+
#### ✅ Fast - Batch with keyboard navigation
|
|
177
|
+
|
|
178
|
+
```javascript
|
|
179
|
+
await testdriver.find('first name').then(el => el.click());
|
|
180
|
+
await testdriver.type('John');
|
|
181
|
+
|
|
182
|
+
await testdriver.pressKeys(['tab']);
|
|
183
|
+
await testdriver.type('Doe');
|
|
184
|
+
|
|
185
|
+
await testdriver.pressKeys(['tab']);
|
|
186
|
+
await testdriver.type('john@example.com');
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Time**: 4 round trips (33% faster)
|
|
190
|
+
|
|
191
|
+
### 6. Smart Waiting
|
|
192
|
+
|
|
193
|
+
Avoid unnecessary delays:
|
|
194
|
+
|
|
195
|
+
#### ❌ Slow - Fixed delays
|
|
196
|
+
|
|
197
|
+
```javascript
|
|
198
|
+
await testdriver.find('button').then(el => el.click());
|
|
199
|
+
await new Promise(r => setTimeout(r, 5000)); // Always wait 5s
|
|
200
|
+
await testdriver.find('success message');
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
#### ✅ Fast - Poll until found
|
|
204
|
+
|
|
205
|
+
```javascript
|
|
206
|
+
await testdriver.find('button').then(el => el.click());
|
|
207
|
+
|
|
208
|
+
// Poll for success message
|
|
209
|
+
let element;
|
|
210
|
+
for (let i = 0; i < 30; i++) {
|
|
211
|
+
element = await testdriver.find('success message');
|
|
212
|
+
if (element.found()) break;
|
|
213
|
+
await new Promise(r => setTimeout(r, 500));
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
#### ✅ Better - Use assertions
|
|
218
|
+
|
|
219
|
+
```javascript
|
|
220
|
+
await testdriver.find('button').then(el => el.click());
|
|
221
|
+
await testdriver.assert('success message appeared'); // Waits intelligently
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### 7. Optimize Element Descriptions
|
|
225
|
+
|
|
226
|
+
More specific = faster finding:
|
|
227
|
+
|
|
228
|
+
#### ❌ Slow - Vague description
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
await testdriver.find('button'); // Many buttons to check
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Time**: 2-3s (checks all buttons)
|
|
235
|
+
|
|
236
|
+
#### ✅ Fast - Specific description
|
|
237
|
+
|
|
238
|
+
```javascript
|
|
239
|
+
await testdriver.find('blue submit button at bottom right');
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**Time**: 0.5-1s (narrows search area)
|
|
243
|
+
|
|
244
|
+
### 8. Preload Resources
|
|
245
|
+
|
|
246
|
+
Speed up page load:
|
|
247
|
+
|
|
248
|
+
#### ❌ Slow - Load on demand
|
|
249
|
+
|
|
250
|
+
```javascript
|
|
251
|
+
test('test 1', async (context) => {
|
|
252
|
+
const { testdriver } = await chrome(context, { url: 'https://app.com' });
|
|
253
|
+
// First test loads everything
|
|
254
|
+
});
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
#### ✅ Fast - Preload in beforeAll
|
|
258
|
+
|
|
259
|
+
```javascript
|
|
260
|
+
import { beforeAll, test } from 'vitest';
|
|
261
|
+
|
|
262
|
+
beforeAll(async (context) => {
|
|
263
|
+
const { testdriver } = await chrome(context, { url: 'https://app.com' });
|
|
264
|
+
// Preload app, login, navigate to test area
|
|
265
|
+
await testdriver.find('email').then(el => el.click());
|
|
266
|
+
await testdriver.type(process.env.TEST_EMAIL);
|
|
267
|
+
await testdriver.find('password').then(el => el.click());
|
|
268
|
+
await testdriver.type(process.env.TEST_PASSWORD);
|
|
269
|
+
await testdriver.find('login').then(el => el.click());
|
|
270
|
+
}, 120000);
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### 9. Clean Cache Strategically
|
|
274
|
+
|
|
275
|
+
Don't clear cache unnecessarily:
|
|
276
|
+
|
|
277
|
+
#### ❌ Slow - Clear cache every run
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
# package.json
|
|
281
|
+
{
|
|
282
|
+
"scripts": {
|
|
283
|
+
"test": "rm -rf .testdriver/.cache && vitest"
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
#### ✅ Fast - Clear cache when needed
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
# Only clear when UI changes
|
|
292
|
+
npm run test:clean # Separate script
|
|
293
|
+
|
|
294
|
+
# Normal runs use cache
|
|
295
|
+
npm test
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### 10. Monitor Performance
|
|
299
|
+
|
|
300
|
+
Track test execution time:
|
|
301
|
+
|
|
302
|
+
```javascript
|
|
303
|
+
import { test } from 'vitest';
|
|
304
|
+
|
|
305
|
+
test('slow test detector', async (context) => {
|
|
306
|
+
const start = Date.now();
|
|
307
|
+
|
|
308
|
+
// Test logic
|
|
309
|
+
const { testdriver } = await chrome(context, { url });
|
|
310
|
+
await testdriver.find('button').then(el => el.click());
|
|
311
|
+
|
|
312
|
+
const duration = Date.now() - start;
|
|
313
|
+
console.log(`Test took ${duration}ms`);
|
|
314
|
+
|
|
315
|
+
if (duration > 30000) {
|
|
316
|
+
console.warn('⚠️ Test exceeded 30s threshold');
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## Configuration Tuning
|
|
322
|
+
|
|
323
|
+
### Timeout Settings
|
|
324
|
+
|
|
325
|
+
Balance reliability vs speed:
|
|
326
|
+
|
|
327
|
+
```javascript
|
|
328
|
+
// vitest.config.mjs
|
|
329
|
+
export default defineConfig({
|
|
330
|
+
test: {
|
|
331
|
+
testTimeout: 60000, // Default: 60s
|
|
332
|
+
hookTimeout: 30000 // Setup/teardown: 30s
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
For fast, stable tests:
|
|
338
|
+
```javascript
|
|
339
|
+
testTimeout: 30000 // 30s
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
For slower, complex tests:
|
|
343
|
+
```javascript
|
|
344
|
+
testTimeout: 120000 // 2 minutes
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Verbosity Level
|
|
348
|
+
|
|
349
|
+
Lower verbosity = less overhead:
|
|
350
|
+
|
|
351
|
+
```javascript
|
|
352
|
+
const testdriver = await TestDriver.create({
|
|
353
|
+
apiKey: process.env.TD_API_KEY,
|
|
354
|
+
verbosity: 0 // 0=silent, 1=normal, 2=debug
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
**Impact**: Small (~100ms per test), but adds up.
|
|
359
|
+
|
|
360
|
+
### Resolution
|
|
361
|
+
|
|
362
|
+
Lower resolution = faster screenshots:
|
|
363
|
+
|
|
364
|
+
```javascript
|
|
365
|
+
const testdriver = await TestDriver.create({
|
|
366
|
+
apiKey: process.env.TD_API_KEY,
|
|
367
|
+
resolution: '1280x720' // Default: 1920x1080
|
|
368
|
+
});
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
**Impact**: 10-20% faster element finding.
|
|
372
|
+
|
|
373
|
+
## Advanced Techniques
|
|
374
|
+
|
|
375
|
+
### Connection Pooling
|
|
376
|
+
|
|
377
|
+
Reuse connections across test suites:
|
|
378
|
+
|
|
379
|
+
```javascript
|
|
380
|
+
// setup/pool.mjs
|
|
381
|
+
const clients = new Map();
|
|
382
|
+
|
|
383
|
+
export async function getClient(context) {
|
|
384
|
+
const key = `${context.task.file.name}`;
|
|
385
|
+
|
|
386
|
+
if (!clients.has(key)) {
|
|
387
|
+
clients.set(key, await TestDriver.create({
|
|
388
|
+
apiKey: process.env.TD_API_KEY
|
|
389
|
+
}));
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return clients.get(key);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
export async function cleanup() {
|
|
396
|
+
for (const client of clients.values()) {
|
|
397
|
+
await client.cleanup();
|
|
398
|
+
}
|
|
399
|
+
clients.clear();
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Lazy Loading
|
|
404
|
+
|
|
405
|
+
Only load what you need:
|
|
406
|
+
|
|
407
|
+
```javascript
|
|
408
|
+
// ❌ Load everything upfront
|
|
409
|
+
import { chrome, firefox, electron } from './setup/lifecycleHelpers.mjs';
|
|
410
|
+
|
|
411
|
+
// ✅ Import only what you use
|
|
412
|
+
import { chrome } from './setup/lifecycleHelpers.mjs';
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Snapshot Testing
|
|
416
|
+
|
|
417
|
+
Compare screenshots instead of re-running:
|
|
418
|
+
|
|
419
|
+
```javascript
|
|
420
|
+
test('visual regression', async (context) => {
|
|
421
|
+
const { testdriver } = await chrome(context, { url });
|
|
422
|
+
|
|
423
|
+
const element = await testdriver.find('hero section');
|
|
424
|
+
|
|
425
|
+
// First run: saves screenshot
|
|
426
|
+
// Subsequent runs: compares screenshot
|
|
427
|
+
expect(element.screenshot).toMatchImageSnapshot();
|
|
428
|
+
});
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
## Profiling
|
|
432
|
+
|
|
433
|
+
### Find Slow Tests
|
|
434
|
+
|
|
435
|
+
```bash
|
|
436
|
+
# Run with timing report
|
|
437
|
+
npm test -- --reporter=verbose
|
|
438
|
+
|
|
439
|
+
# Output shows duration per test
|
|
440
|
+
✓ fast test (1.2s)
|
|
441
|
+
✓ medium test (5.4s)
|
|
442
|
+
✗ slow test (45.2s)
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### Measure Operations
|
|
446
|
+
|
|
447
|
+
```javascript
|
|
448
|
+
async function timedOperation(name, fn) {
|
|
449
|
+
const start = Date.now();
|
|
450
|
+
const result = await fn();
|
|
451
|
+
console.log(`${name}: ${Date.now() - start}ms`);
|
|
452
|
+
return result;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
test('profiled test', async (context) => {
|
|
456
|
+
const { testdriver } = await timedOperation('Setup', async () => {
|
|
457
|
+
return await chrome(context, { url });
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
await timedOperation('Find button', async () => {
|
|
461
|
+
return await testdriver.find('button');
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
await timedOperation('Click button', async () => {
|
|
465
|
+
const el = await testdriver.find('button');
|
|
466
|
+
return await el.click();
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### Identify Bottlenecks
|
|
472
|
+
|
|
473
|
+
Common slow operations:
|
|
474
|
+
|
|
475
|
+
1. **Sandbox creation** (20-60s) - Reuse sandboxes
|
|
476
|
+
2. **Page navigation** (1-5s) - Minimize navigation
|
|
477
|
+
3. **AI commands** (2-5s) - Use direct commands
|
|
478
|
+
4. **Element finding** (0.5-3s) - Enable caching
|
|
479
|
+
5. **Fixed delays** (varies) - Replace with smart waiting
|
|
480
|
+
|
|
481
|
+
## Production Checklist
|
|
482
|
+
|
|
483
|
+
- [ ] Reuse sandboxes via context
|
|
484
|
+
- [ ] Enable AI and selector caching
|
|
485
|
+
- [ ] Use parallel execution (maxConcurrency: 5)
|
|
486
|
+
- [ ] Minimize AI commands
|
|
487
|
+
- [ ] Batch operations
|
|
488
|
+
- [ ] Use smart waiting (assertions)
|
|
489
|
+
- [ ] Specific element descriptions
|
|
490
|
+
- [ ] Appropriate timeout settings
|
|
491
|
+
- [ ] Monitor test duration
|
|
492
|
+
- [ ] Profile slow tests
|
|
493
|
+
|
|
494
|
+
Expected performance:
|
|
495
|
+
- **First run**: 60-90s for suite
|
|
496
|
+
- **Cached runs**: 10-30s for suite
|
|
497
|
+
- **Per test**: 2-10s (cached)
|
|
498
|
+
|
|
499
|
+
## See Also
|
|
500
|
+
|
|
501
|
+
<CardGroup cols={2}>
|
|
502
|
+
<Card title="Caching (AI)" icon="brain" href="/v7/guides/caching-ai">
|
|
503
|
+
AI prompt caching
|
|
504
|
+
</Card>
|
|
505
|
+
|
|
506
|
+
<Card title="Caching (Selectors)" icon="bullseye" href="/v7/guides/caching-selectors">
|
|
507
|
+
Selector caching
|
|
508
|
+
</Card>
|
|
509
|
+
|
|
510
|
+
<Card title="Best Practices" icon="star" href="/v7/guides/best-practices">
|
|
511
|
+
Testing patterns
|
|
512
|
+
</Card>
|
|
513
|
+
|
|
514
|
+
<Card title="CI/CD Integration" icon="arrows-spin" href="/v7/guides/ci-cd">
|
|
515
|
+
Optimize CI pipelines
|
|
516
|
+
</Card>
|
|
517
|
+
</CardGroup>
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# TestDriver Presets
|
|
2
|
+
|
|
3
|
+
Presets provide pre-configured setups for common applications, reducing boilerplate and making your tests easier to write.
|
|
4
|
+
|
|
5
|
+
## Available Presets
|
|
6
|
+
|
|
7
|
+
### chromePreset
|
|
8
|
+
|
|
9
|
+
Automatically sets up Chrome browser with TestDriver and Dashcam.
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
import { test } from 'vitest';
|
|
13
|
+
import { chromePreset } from 'testdriverai/presets';
|
|
14
|
+
|
|
15
|
+
test('my test', async (context) => {
|
|
16
|
+
const { client } = await chromePreset(context, {
|
|
17
|
+
url: 'https://myapp.com/login'
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
await client.find('email input').type('user@example.com');
|
|
21
|
+
await client.find('Login button').click();
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Options:**
|
|
26
|
+
- `url` - URL to navigate to (default: 'http://testdriver-sandbox.vercel.app/')
|
|
27
|
+
- `os` - Target OS: 'linux', 'mac', 'windows' (default: 'linux')
|
|
28
|
+
- `dashcam` - Enable Dashcam recording (default: true)
|
|
29
|
+
- `maximized` - Start maximized (default: true)
|
|
30
|
+
- `guest` - Use guest mode (default: true)
|
|
31
|
+
|
|
32
|
+
**Returns:**
|
|
33
|
+
- `client` - TestDriver instance
|
|
34
|
+
- `dashcam` - Dashcam instance (if enabled)
|
|
35
|
+
|
|
36
|
+
### vscodePreset
|
|
37
|
+
|
|
38
|
+
Automatically sets up VS Code with TestDriver and Dashcam.
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
import { vscodePreset } from 'testdriverai/presets';
|
|
42
|
+
|
|
43
|
+
test('extension test', async (context) => {
|
|
44
|
+
const { vscode } = await vscodePreset(context, {
|
|
45
|
+
workspace: '/tmp/test-project',
|
|
46
|
+
extensions: ['ms-python.python']
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
await vscode.find('File menu').click();
|
|
50
|
+
await vscode.find('New File').click();
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Options:**
|
|
55
|
+
- `workspace` - Workspace/folder to open
|
|
56
|
+
- `os` - Target OS (default: 'linux')
|
|
57
|
+
- `dashcam` - Enable Dashcam recording (default: true)
|
|
58
|
+
- `extensions` - Array of extension IDs to install
|
|
59
|
+
|
|
60
|
+
**Returns:**
|
|
61
|
+
- `client` - TestDriver instance
|
|
62
|
+
- `vscode` - Alias for client
|
|
63
|
+
- `dashcam` - Dashcam instance (if enabled)
|
|
64
|
+
|
|
65
|
+
### electronPreset
|
|
66
|
+
|
|
67
|
+
Automatically sets up an Electron application.
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
import { electronPreset } from 'testdriverai/presets';
|
|
71
|
+
|
|
72
|
+
test('electron app test', async (context) => {
|
|
73
|
+
const { app } = await electronPreset(context, {
|
|
74
|
+
appPath: '/path/to/electron/app',
|
|
75
|
+
args: ['--enable-logging']
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
await app.find('main window').click();
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Options:**
|
|
83
|
+
- `appPath` - Path to Electron app (required)
|
|
84
|
+
- `os` - Target OS (default: 'linux')
|
|
85
|
+
- `dashcam` - Enable Dashcam recording (default: true)
|
|
86
|
+
- `args` - Additional electron arguments
|
|
87
|
+
|
|
88
|
+
**Returns:**
|
|
89
|
+
- `client` - TestDriver instance
|
|
90
|
+
- `app` - Alias for client
|
|
91
|
+
- `dashcam` - Dashcam instance (if enabled)
|
|
92
|
+
|
|
93
|
+
### webAppPreset
|
|
94
|
+
|
|
95
|
+
Generic web application preset (currently uses Chrome).
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
import { webAppPreset } from 'testdriverai/presets';
|
|
99
|
+
|
|
100
|
+
test('web app test', async (context) => {
|
|
101
|
+
const { client } = await webAppPreset(context, {
|
|
102
|
+
url: 'https://example.com',
|
|
103
|
+
browser: 'chrome' // Only Chrome supported currently
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
await client.find('login form').click();
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Creating Custom Presets
|
|
111
|
+
|
|
112
|
+
Use `createPreset` to build your own presets:
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
import { createPreset } from 'testdriverai/presets';
|
|
116
|
+
|
|
117
|
+
const firefoxPreset = createPreset({
|
|
118
|
+
name: 'Firefox Browser',
|
|
119
|
+
defaults: { os: 'linux', dashcam: true },
|
|
120
|
+
async setup(context, client, dashcam, options) {
|
|
121
|
+
const { url } = options;
|
|
122
|
+
|
|
123
|
+
// Launch Firefox
|
|
124
|
+
await client.exec('sh', `firefox "${url}" >/dev/null 2>&1 &`, 30000);
|
|
125
|
+
await client.focusApplication('Firefox');
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
// client is already included automatically
|
|
129
|
+
};
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Use your custom preset
|
|
134
|
+
test('my test', async (context) => {
|
|
135
|
+
const { client } = await firefoxPreset(context, {
|
|
136
|
+
url: 'https://example.com',
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
await client.find('page content').click();
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### createPreset API
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
createPreset({
|
|
147
|
+
name: string, // Preset name (for errors)
|
|
148
|
+
defaults: object, // Default options
|
|
149
|
+
setup: async function // Setup function
|
|
150
|
+
})
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The `setup` function receives:
|
|
154
|
+
- `context` - Vitest test context
|
|
155
|
+
- `client` - TestDriver instance (already connected)
|
|
156
|
+
- `dashcam` - Dashcam instance (if enabled)
|
|
157
|
+
- `options` - Merged defaults + user options
|
|
158
|
+
|
|
159
|
+
The `setup` function should return an object with any custom properties. The returned object will automatically include `client` and `dashcam`.
|
|
160
|
+
|
|
161
|
+
## How Presets Work
|
|
162
|
+
|
|
163
|
+
Presets automatically:
|
|
164
|
+
|
|
165
|
+
1. **Create TestDriver client** - Uses `useTestDriver` hook
|
|
166
|
+
2. **Connect to sandbox** - Authenticates and connects
|
|
167
|
+
3. **Set up Dashcam** - If enabled (default: true)
|
|
168
|
+
4. **Configure application** - Launch and focus the app
|
|
169
|
+
5. **Handle cleanup** - Automatic disconnect and dashcam stop
|
|
170
|
+
|
|
171
|
+
All lifecycle is managed automatically via Vitest hooks.
|
|
172
|
+
|
|
173
|
+
## Progressive Disclosure
|
|
174
|
+
|
|
175
|
+
Presets fit into the progressive disclosure pattern:
|
|
176
|
+
|
|
177
|
+
### Beginner (Presets)
|
|
178
|
+
```javascript
|
|
179
|
+
const { client } = await chromePreset(context, { url: 'https://example.com' });
|
|
180
|
+
```
|
|
181
|
+
Everything automatic - just pass URL and start testing.
|
|
182
|
+
|
|
183
|
+
### Intermediate (Hooks)
|
|
184
|
+
```javascript
|
|
185
|
+
const client = useTestDriver(context, { os: 'linux' });
|
|
186
|
+
const dashcam = useDashcam(context, client, { autoStart: true });
|
|
187
|
+
// Custom setup code
|
|
188
|
+
```
|
|
189
|
+
More control over lifecycle, still automatic cleanup.
|
|
190
|
+
|
|
191
|
+
### Advanced (Direct)
|
|
192
|
+
```javascript
|
|
193
|
+
const client = new TestDriver(apiKey, { os: 'linux' });
|
|
194
|
+
await client.auth();
|
|
195
|
+
await client.connect();
|
|
196
|
+
// Full manual control
|
|
197
|
+
```
|
|
198
|
+
Complete control, manual everything.
|
|
199
|
+
|
|
200
|
+
## Best Practices
|
|
201
|
+
|
|
202
|
+
1. **Use presets for common scenarios** - Chrome, VS Code, Electron
|
|
203
|
+
2. **Create custom presets for your apps** - Encapsulate setup logic
|
|
204
|
+
3. **Enable dashcam by default** - Great for debugging failures
|
|
205
|
+
4. **Keep presets focused** - One app/scenario per preset
|
|
206
|
+
5. **Use descriptive variable names** - `client`, `vscode`, `app` based on what you're testing
|
|
207
|
+
|
|
208
|
+
## Examples
|
|
209
|
+
|
|
210
|
+
See `testdriver/acceptance-sdk/presets-example.test.mjs` for working examples.
|