testdriverai 7.1.0 → 7.1.2
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/agent/index.js +18 -45
- package/agent/interface.js +13 -2
- package/agent/lib/commands.js +1 -1
- package/agent/lib/redraw.js +1 -1
- package/agent/lib/sandbox.js +30 -2
- package/agent/lib/valid-version.js +2 -2
- package/debugger/index.html +1 -1
- package/docs/docs.json +140 -131
- 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/{guides → _drafts}/caching-selectors.mdx +125 -17
- package/docs/v7/_drafts/dashcam-title-feature.mdx +89 -0
- package/docs/v7/_drafts/error-handling.mdx +501 -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/plugin-migration.mdx +222 -0
- package/docs/v7/_drafts/prompt-cache.mdx +200 -0
- package/docs/{QUICK_START_TEST_RECORDING.md → v7/_drafts/quick-start-test-recording.mdx} +3 -3
- package/docs/v7/_drafts/sdk-logging.mdx +222 -0
- package/docs/v7/_drafts/sdk-migration.mdx +474 -0
- package/docs/v7/_drafts/sdk-v7-complete.mdx +345 -0
- package/docs/v7/{guides → _drafts}/self-hosting.mdx +1 -1
- package/docs/v7/{guides → _drafts}/troubleshooting.mdx +2 -2
- package/docs/v7/{guides → _drafts}/vitest-plugin.mdx +4 -4
- package/docs/v7/api/{ai.mdx → act.mdx} +24 -24
- package/docs/v7/api/client.mdx +1 -1
- package/docs/v7/api/dashcam.mdx +2 -2
- package/docs/v7/api/elements.mdx +143 -41
- package/docs/v7/api/find.mdx +258 -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 +1 -1
- 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 +51 -5
- 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/playwright.mdx +3 -3
- package/docs/v7/presets/chrome.mdx +16 -0
- package/docs/v7/presets/electron.mdx +18 -0
- package/docs/v7/presets/vscode.mdx +19 -0
- 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/commands/init.js +358 -0
- package/interfaces/vitest-plugin.mjs +214 -10
- package/{src → lib}/core/Dashcam.js +41 -4
- package/{src → lib}/vitest/hooks.mjs +118 -100
- package/lib/vitest/setup.mjs +44 -0
- package/package.json +9 -10
- package/sdk.d.ts +15 -2
- package/sdk.js +72 -17
- package/{self-hosted.yml → setup/aws/self-hosted.yml} +1 -1
- package/{testdriver/acceptance-sdk → test/manual}/test-console-logs.test.mjs +1 -1
- package/test/manual/test-find-api.js +73 -0
- package/test/manual/test-init.sh +54 -0
- package/test/manual/test-prompt-cache.js +96 -0
- package/test/manual/test-provision-auth.mjs +22 -0
- package/test/manual/test-sandbox-render.js +28 -0
- package/test/manual/test-sdk-methods.js +15 -0
- package/test/manual/test-sdk-refactor.js +53 -0
- package/test/manual/test-stack-trace.mjs +57 -0
- package/test/testdriver/assert.test.mjs +41 -0
- package/{testdriver/acceptance-sdk → test/testdriver}/auto-cache-key-demo.test.mjs +1 -1
- package/{testdriver/acceptance-sdk → test/testdriver}/drag-and-drop.test.mjs +1 -1
- package/{testdriver/acceptance-sdk → test/testdriver}/element-not-found.test.mjs +1 -1
- package/{testdriver/acceptance-sdk → test/testdriver}/exec-js.test.mjs +1 -1
- package/{testdriver/acceptance-sdk → test/testdriver}/exec-output.test.mjs +3 -3
- package/{testdriver/acceptance-sdk → test/testdriver}/exec-pwsh.test.mjs +3 -3
- package/{testdriver/acceptance-sdk → test/testdriver}/focus-window.test.mjs +1 -1
- package/{testdriver/acceptance-sdk → test/testdriver}/formatted-logging.test.mjs +1 -1
- package/{testdriver/acceptance-sdk → test/testdriver}/hover-image.test.mjs +1 -1
- package/{testdriver/acceptance-sdk → test/testdriver}/hover-text-with-description.test.mjs +1 -1
- package/{testdriver/acceptance-sdk → test/testdriver}/hover-text.test.mjs +1 -1
- package/{testdriver/acceptance-sdk → test/testdriver}/match-image.test.mjs +1 -1
- package/{testdriver/acceptance-sdk → test/testdriver}/press-keys.test.mjs +1 -1
- package/{testdriver/acceptance-sdk → test/testdriver}/prompt.test.mjs +2 -2
- package/{testdriver/acceptance-sdk → test/testdriver}/scroll-keyboard.test.mjs +1 -1
- package/{testdriver/acceptance-sdk → test/testdriver}/scroll-until-image.test.mjs +1 -1
- package/{testdriver/acceptance-sdk → test/testdriver}/scroll-until-text.test.mjs +1 -1
- package/{testdriver/acceptance-sdk → test/testdriver}/scroll.test.mjs +1 -1
- package/{src/vitest/lifecycle.mjs → test/testdriver/setup/lifecycleHelpers.mjs} +84 -99
- package/test/testdriver/setup/testHelpers.mjs +653 -0
- package/{testdriver/acceptance-sdk → test/testdriver}/type.test.mjs +1 -1
- package/vitest.config.mjs +8 -59
- 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/settings.json +0 -14
- package/AGENTS.md +0 -550
- package/CODEOWNERS +0 -2
- 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/docs/v7/guides/ci-cd/azure.mdx +0 -587
- package/docs/v7/guides/ci-cd/circleci.mdx +0 -523
- package/docs/v7/guides/ci-cd/github-actions.mdx +0 -457
- package/docs/v7/guides/ci-cd/gitlab.mdx +0 -498
- package/docs/v7/guides/ci-cd/jenkins.mdx +0 -664
- package/docs/v7/guides/ci-cd/travis.mdx +0 -438
- package/scripts/view-test-results.mjs +0 -96
- package/src/vitest/extended.mjs +0 -108
- package/src/vitest/index.mjs +0 -64
- package/src/vitest/utils.mjs +0 -150
- 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/dashcam.test.js +0 -137
- 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 -26
- package/testdriver/acceptance-sdk/hooks-example.test.mjs +0 -38
- package/testdriver/acceptance-sdk/presets-example.test.mjs +0 -87
- package/testdriver/acceptance-sdk/setup/testHelpers.mjs +0 -420
- package/testdriver/acceptance-sdk/sully-ai.test.mjs +0 -234
- package/testdriver/acceptance-sdk/type-checking-demo.js +0 -49
- 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/docs/v7/{guides → _drafts}/best-practices.mdx +0 -0
- /package/docs/v7/{guides → _drafts}/caching-ai.mdx +0 -0
- /package/docs/v7/{guides → _drafts}/caching.mdx +0 -0
- /package/docs/{MIGRATION.md → v7/_drafts/cli-to-sdk-migration.mdx} +0 -0
- /package/{CONTRIBUTING.md → docs/v7/_drafts/contributing.mdx} +0 -0
- /package/docs/v7/{progressive-apis/CORE.md → _drafts/core.mdx} +0 -0
- /package/docs/v7/{guides → _drafts}/debugging.mdx +0 -0
- /package/docs/v7/{guides → _drafts}/faq.mdx +0 -0
- /package/docs/v7/{progressive-apis/HOOKS.md → _drafts/hooks.mdx} +0 -0
- /package/docs/v7/{guides → _drafts}/migration.mdx +0 -0
- /package/docs/v7/{guides → _drafts}/performance.mdx +0 -0
- /package/docs/{PRESETS.md → v7/_drafts/presets.mdx} +0 -0
- /package/docs/v7/{progressive-apis/PROGRESSIVE_DISCLOSURE.md → _drafts/progressive-disclosure.mdx} +0 -0
- /package/docs/v7/{progressive-apis/PROVISION.md → _drafts/provision.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/docs/{TEST_RECORDING.md → v7/_drafts/test-recording.mdx} +0 -0
- /package/docs/v7/{guides → _drafts}/vitest.mdx +0 -0
- /package/docs/v7/{README.md → overview/readme.mdx} +0 -0
- /package/{src → lib}/core/index.d.ts +0 -0
- /package/{src → lib}/core/index.js +0 -0
- /package/{src → lib}/presets/index.mjs +0 -0
- /package/{src → lib}/vitest/hooks.d.ts +0 -0
- /package/{debug-locate-response.js → test/manual/debug-locate-response.js} +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}/chrome-extension.test.mjs +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,514 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Stable & Reliable"
|
|
3
|
+
description: "Anti-flake technology that eliminates test instability"
|
|
4
|
+
icon: "shield-check"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Test flakiness is the bane of CI/CD pipelines. TestDriver eliminates flaky tests with built-in anti-flake technology that automatically handles timing issues, animations, and dynamic content.
|
|
8
|
+
|
|
9
|
+
## The Flaky Test Problem
|
|
10
|
+
|
|
11
|
+
Traditional test frameworks suffer from race conditions and timing issues:
|
|
12
|
+
|
|
13
|
+
<CodeGroup>
|
|
14
|
+
```javascript Traditional - Flaky
|
|
15
|
+
// ❌ May fail randomly
|
|
16
|
+
await page.click('button');
|
|
17
|
+
await page.click('.dropdown-item'); // Element might not be ready!
|
|
18
|
+
|
|
19
|
+
// ❌ Arbitrary waits
|
|
20
|
+
await page.click('button');
|
|
21
|
+
await page.waitForTimeout(1000); // Hope 1 second is enough
|
|
22
|
+
await page.click('.dropdown-item');
|
|
23
|
+
|
|
24
|
+
// ❌ Complex wait logic
|
|
25
|
+
await page.click('button');
|
|
26
|
+
await page.waitForSelector('.dropdown-item', {
|
|
27
|
+
state: 'visible',
|
|
28
|
+
timeout: 5000
|
|
29
|
+
});
|
|
30
|
+
await page.waitForLoadState('networkidle');
|
|
31
|
+
await page.waitForTimeout(200); // Still need extra buffer!
|
|
32
|
+
await page.click('.dropdown-item');
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```javascript TestDriver - Stable
|
|
36
|
+
// ✅ Just works
|
|
37
|
+
await testdriver.find('button').click();
|
|
38
|
+
await testdriver.find('dropdown item').click();
|
|
39
|
+
// TestDriver automatically waits for stability
|
|
40
|
+
```
|
|
41
|
+
</CodeGroup>
|
|
42
|
+
|
|
43
|
+
<Check>
|
|
44
|
+
TestDriver handles all timing automatically. No explicit waits, no arbitrary timeouts, no flaky tests.
|
|
45
|
+
</Check>
|
|
46
|
+
|
|
47
|
+
## Redraw Detection
|
|
48
|
+
|
|
49
|
+
TestDriver's redraw detection system automatically waits for the UI to stabilize before taking any action.
|
|
50
|
+
|
|
51
|
+
<Card title="What Redraw Detects" icon="eye">
|
|
52
|
+
The system monitors multiple stability signals:
|
|
53
|
+
|
|
54
|
+
- **DOM Mutations** - Element additions, removals, or attribute changes
|
|
55
|
+
- **Layout Reflows** - Position or size changes
|
|
56
|
+
- **CSS Animations** - Running animations and transitions
|
|
57
|
+
- **Network Activity** - Pending XHR/fetch requests
|
|
58
|
+
- **Visual Changes** - Pixel-level screenshot differences
|
|
59
|
+
- **Loading Indicators** - Spinners, progress bars, skeleton screens
|
|
60
|
+
</Card>
|
|
61
|
+
|
|
62
|
+
### How It Works
|
|
63
|
+
|
|
64
|
+
```mermaid
|
|
65
|
+
sequenceDiagram
|
|
66
|
+
participant Test as Your Test
|
|
67
|
+
participant TD as TestDriver
|
|
68
|
+
participant Monitor as Redraw Monitor
|
|
69
|
+
participant UI as Application UI
|
|
70
|
+
|
|
71
|
+
Test->>TD: find('dropdown item').click()
|
|
72
|
+
TD->>Monitor: Start monitoring stability
|
|
73
|
+
Monitor->>UI: Capture initial state
|
|
74
|
+
|
|
75
|
+
loop Stability Check
|
|
76
|
+
Monitor->>UI: Check for changes
|
|
77
|
+
alt UI is changing
|
|
78
|
+
UI-->>Monitor: DOM mutation detected
|
|
79
|
+
Monitor->>Monitor: Reset stability timer
|
|
80
|
+
else UI is stable
|
|
81
|
+
UI-->>Monitor: No changes
|
|
82
|
+
Monitor->>Monitor: Increment stable duration
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
Monitor->>TD: UI stable for 200ms
|
|
87
|
+
TD->>UI: Perform click action
|
|
88
|
+
TD-->>Test: Action completed
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Configurable Stability
|
|
92
|
+
|
|
93
|
+
Fine-tune stability detection for your application's needs:
|
|
94
|
+
|
|
95
|
+
```javascript
|
|
96
|
+
// Default stability settings (recommended)
|
|
97
|
+
await testdriver.find('button').click();
|
|
98
|
+
|
|
99
|
+
// Custom stability delay
|
|
100
|
+
await testdriver.find('animated button', {
|
|
101
|
+
stabilityDelay: 500 // Wait 500ms of stability before acting
|
|
102
|
+
}).click();
|
|
103
|
+
|
|
104
|
+
// Bypass stability (advanced)
|
|
105
|
+
await testdriver.find('element', {
|
|
106
|
+
stabilityDelay: 0 // Act immediately
|
|
107
|
+
}).click();
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
<Tip>
|
|
111
|
+
The default 200ms stability delay works for 95% of applications. Only adjust if you have unusually long animations or need instant actions.
|
|
112
|
+
</Tip>
|
|
113
|
+
|
|
114
|
+
## Network Monitoring
|
|
115
|
+
|
|
116
|
+
TestDriver waits for network activity to complete before asserting or locating elements:
|
|
117
|
+
|
|
118
|
+
<AccordionGroup>
|
|
119
|
+
<Accordion title="Automatic Network Waiting">
|
|
120
|
+
```javascript
|
|
121
|
+
// TestDriver automatically waits for:
|
|
122
|
+
// 1. Pending XHR/fetch requests to complete
|
|
123
|
+
// 2. WebSocket messages to be processed
|
|
124
|
+
// 3. Image/asset loading to finish
|
|
125
|
+
|
|
126
|
+
await testdriver.find('submit button').click();
|
|
127
|
+
// ↑ Triggers API call
|
|
128
|
+
|
|
129
|
+
await testdriver.assert('Success message is visible');
|
|
130
|
+
// ↑ Automatically waits for API response before asserting
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
No need for manual `waitForResponse` or `waitForLoadState` calls.
|
|
134
|
+
</Accordion>
|
|
135
|
+
|
|
136
|
+
<Accordion title="Loading Indicator Detection">
|
|
137
|
+
```javascript
|
|
138
|
+
// TestDriver detects common loading patterns:
|
|
139
|
+
await testdriver.find('Load More button').click();
|
|
140
|
+
|
|
141
|
+
// Automatically waits for:
|
|
142
|
+
// - Loading spinner to appear and disappear
|
|
143
|
+
// - Skeleton screens to be replaced
|
|
144
|
+
// - Progress bars to complete
|
|
145
|
+
// - "Loading..." text to disappear
|
|
146
|
+
|
|
147
|
+
await testdriver.find('newly loaded content').click();
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Common loading indicators are recognized and waited for automatically.
|
|
151
|
+
</Accordion>
|
|
152
|
+
|
|
153
|
+
<Accordion title="Custom Network Conditions">
|
|
154
|
+
```javascript
|
|
155
|
+
// For slow networks or long-running requests
|
|
156
|
+
await testdriver.find('submit button', {
|
|
157
|
+
timeout: 60000, // Wait up to 60 seconds
|
|
158
|
+
networkTimeout: 30000 // Allow 30s for network requests
|
|
159
|
+
}).click();
|
|
160
|
+
```
|
|
161
|
+
</Accordion>
|
|
162
|
+
</AccordionGroup>
|
|
163
|
+
|
|
164
|
+
## Screen Stability Monitoring
|
|
165
|
+
|
|
166
|
+
Visual stability is critical for reliable element location:
|
|
167
|
+
|
|
168
|
+
```javascript
|
|
169
|
+
// TestDriver monitors pixel-level changes
|
|
170
|
+
await testdriver.find('animated element').click();
|
|
171
|
+
|
|
172
|
+
// Waits for:
|
|
173
|
+
// ✓ CSS animations to complete
|
|
174
|
+
// ✓ Fade-in/fade-out effects to finish
|
|
175
|
+
// ✓ Slide transitions to settle
|
|
176
|
+
// ✓ Scroll animations to stop
|
|
177
|
+
// ✓ Dynamic content to load
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
<Card title="Example: Accordion Animation" icon="angles-down">
|
|
181
|
+
```javascript
|
|
182
|
+
// Traditional approach - prone to failure
|
|
183
|
+
await page.click('.accordion-header');
|
|
184
|
+
await page.waitForTimeout(300); // Hope animation is done
|
|
185
|
+
await page.click('.accordion-content button'); // Might fail!
|
|
186
|
+
|
|
187
|
+
// TestDriver - just works
|
|
188
|
+
await testdriver.find('accordion header').click();
|
|
189
|
+
await testdriver.find('button inside accordion content').click();
|
|
190
|
+
// ✅ Automatically waits for accordion animation to complete
|
|
191
|
+
```
|
|
192
|
+
</Card>
|
|
193
|
+
|
|
194
|
+
## Retry Logic
|
|
195
|
+
|
|
196
|
+
TestDriver includes intelligent retry logic that adapts to your application:
|
|
197
|
+
|
|
198
|
+
<Steps>
|
|
199
|
+
<Step title="Initial Attempt">
|
|
200
|
+
Try to locate the element immediately.
|
|
201
|
+
|
|
202
|
+
```javascript
|
|
203
|
+
const element = await testdriver.find('button');
|
|
204
|
+
// Attempts location immediately
|
|
205
|
+
```
|
|
206
|
+
</Step>
|
|
207
|
+
|
|
208
|
+
<Step title="Wait for Stability">
|
|
209
|
+
If not found, wait for UI stability and retry.
|
|
210
|
+
|
|
211
|
+
```javascript
|
|
212
|
+
// Waits for:
|
|
213
|
+
// - DOM mutations to stop
|
|
214
|
+
// - Network requests to complete
|
|
215
|
+
// - Animations to finish
|
|
216
|
+
```
|
|
217
|
+
</Step>
|
|
218
|
+
|
|
219
|
+
<Step title="Retry with Interval">
|
|
220
|
+
Continue retrying at regular intervals until timeout.
|
|
221
|
+
|
|
222
|
+
```javascript
|
|
223
|
+
await testdriver.find('button', {
|
|
224
|
+
timeout: 30000, // Try for up to 30 seconds
|
|
225
|
+
retryInterval: 500 // Check every 500ms
|
|
226
|
+
});
|
|
227
|
+
```
|
|
228
|
+
</Step>
|
|
229
|
+
|
|
230
|
+
<Step title="Provide Debug Info">
|
|
231
|
+
If still not found, provide detailed debugging information.
|
|
232
|
+
|
|
233
|
+
```javascript
|
|
234
|
+
try {
|
|
235
|
+
await testdriver.find('missing button');
|
|
236
|
+
} catch (error) {
|
|
237
|
+
console.log('Debug screenshot:', error.debugScreenshot);
|
|
238
|
+
console.log('Similarity score:', error.similarity);
|
|
239
|
+
console.log('Cache info:', error.cacheInfo);
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
</Step>
|
|
243
|
+
</Steps>
|
|
244
|
+
|
|
245
|
+
## Configurable Timeouts
|
|
246
|
+
|
|
247
|
+
Customize retry behavior for different scenarios:
|
|
248
|
+
|
|
249
|
+
<Tabs>
|
|
250
|
+
<Tab title="Fast Elements">
|
|
251
|
+
```javascript
|
|
252
|
+
// For elements that appear quickly
|
|
253
|
+
await testdriver.find('header logo', {
|
|
254
|
+
timeout: 5000 // 5 seconds (faster failure)
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
</Tab>
|
|
258
|
+
|
|
259
|
+
<Tab title="Slow Elements">
|
|
260
|
+
```javascript
|
|
261
|
+
// For elements that take time to load
|
|
262
|
+
await testdriver.find('search results', {
|
|
263
|
+
timeout: 30000, // 30 seconds
|
|
264
|
+
retryInterval: 1000 // Check every second
|
|
265
|
+
});
|
|
266
|
+
```
|
|
267
|
+
</Tab>
|
|
268
|
+
|
|
269
|
+
<Tab title="Critical Elements">
|
|
270
|
+
```javascript
|
|
271
|
+
// For absolutely critical elements
|
|
272
|
+
await testdriver.find('payment confirmation', {
|
|
273
|
+
timeout: 60000, // 1 minute
|
|
274
|
+
retryInterval: 2000, // Check every 2 seconds
|
|
275
|
+
stabilityDelay: 1000 // Wait 1 second of stability
|
|
276
|
+
});
|
|
277
|
+
```
|
|
278
|
+
</Tab>
|
|
279
|
+
</Tabs>
|
|
280
|
+
|
|
281
|
+
## Real-World Stability Improvements
|
|
282
|
+
|
|
283
|
+
Compare flake rates before and after TestDriver:
|
|
284
|
+
|
|
285
|
+
<CardGroup cols={2}>
|
|
286
|
+
<Card title="Before TestDriver" icon="triangle-exclamation">
|
|
287
|
+
```
|
|
288
|
+
Test Suite: E2E Tests
|
|
289
|
+
Total: 100 tests
|
|
290
|
+
Passed: 87
|
|
291
|
+
Failed: 13
|
|
292
|
+
|
|
293
|
+
Flaky tests:
|
|
294
|
+
- login_test (timing)
|
|
295
|
+
- dropdown_test (animation)
|
|
296
|
+
- modal_test (async content)
|
|
297
|
+
- search_test (debounce)
|
|
298
|
+
|
|
299
|
+
Flake rate: 13%
|
|
300
|
+
CI reruns needed: 3-5x
|
|
301
|
+
```
|
|
302
|
+
</Card>
|
|
303
|
+
|
|
304
|
+
<Card title="After TestDriver" icon="circle-check">
|
|
305
|
+
```
|
|
306
|
+
Test Suite: E2E Tests
|
|
307
|
+
Total: 100 tests
|
|
308
|
+
Passed: 100
|
|
309
|
+
Failed: 0
|
|
310
|
+
|
|
311
|
+
Flaky tests: None
|
|
312
|
+
|
|
313
|
+
Flake rate: 0%
|
|
314
|
+
CI reruns needed: 0
|
|
315
|
+
Stable builds: 100%
|
|
316
|
+
```
|
|
317
|
+
</Card>
|
|
318
|
+
</CardGroup>
|
|
319
|
+
|
|
320
|
+
<Check>
|
|
321
|
+
**Result: 100% stability** - Eliminated all flaky tests without changing test code.
|
|
322
|
+
</Check>
|
|
323
|
+
|
|
324
|
+
## Advanced: Redraw Configuration
|
|
325
|
+
|
|
326
|
+
The redraw system is configurable through [redraw.js](/agent/lib/redraw.js):
|
|
327
|
+
|
|
328
|
+
```javascript
|
|
329
|
+
// Global redraw settings
|
|
330
|
+
const testdriver = new TestDriver({
|
|
331
|
+
apiKey: process.env.TD_API_KEY,
|
|
332
|
+
redraw: {
|
|
333
|
+
enabled: true,
|
|
334
|
+
stabilityDelay: 200, // Default stability wait (ms)
|
|
335
|
+
maxStabilityWait: 5000, // Maximum time to wait for stability
|
|
336
|
+
checkInterval: 50, // How often to check for stability
|
|
337
|
+
networkIdle: true, // Wait for network idle
|
|
338
|
+
domIdle: true, // Wait for DOM mutations to stop
|
|
339
|
+
animationIdle: true, // Wait for CSS animations
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Per-Action Configuration
|
|
345
|
+
|
|
346
|
+
```javascript
|
|
347
|
+
// Override redraw settings for specific actions
|
|
348
|
+
await testdriver.find('fast element', {
|
|
349
|
+
redraw: {
|
|
350
|
+
enabled: false // Skip redraw detection
|
|
351
|
+
}
|
|
352
|
+
}).click();
|
|
353
|
+
|
|
354
|
+
await testdriver.find('slow element', {
|
|
355
|
+
redraw: {
|
|
356
|
+
stabilityDelay: 1000, // Wait longer for stability
|
|
357
|
+
networkIdle: true
|
|
358
|
+
}
|
|
359
|
+
}).click();
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
## Debugging Stability Issues
|
|
363
|
+
|
|
364
|
+
If you encounter stability issues, TestDriver provides detailed diagnostics:
|
|
365
|
+
|
|
366
|
+
```javascript
|
|
367
|
+
try {
|
|
368
|
+
await testdriver.find('unstable element', {
|
|
369
|
+
debug: true // Enable debug logging
|
|
370
|
+
});
|
|
371
|
+
} catch (error) {
|
|
372
|
+
console.log('Stability info:', error.stabilityInfo);
|
|
373
|
+
// Output:
|
|
374
|
+
// {
|
|
375
|
+
// domMutations: 15,
|
|
376
|
+
// layoutReflows: 3,
|
|
377
|
+
// networkRequests: 2,
|
|
378
|
+
// animations: ['fade-in', 'slide-up'],
|
|
379
|
+
// waitedMs: 5000,
|
|
380
|
+
// stableMs: 150
|
|
381
|
+
// }
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## Common Stability Patterns
|
|
386
|
+
|
|
387
|
+
<AccordionGroup>
|
|
388
|
+
<Accordion title="Dropdown Menus">
|
|
389
|
+
```javascript
|
|
390
|
+
// Traditional - flaky
|
|
391
|
+
await page.click('.menu-button');
|
|
392
|
+
await page.waitForTimeout(200);
|
|
393
|
+
await page.click('.menu-item');
|
|
394
|
+
|
|
395
|
+
// TestDriver - stable
|
|
396
|
+
await testdriver.find('menu button').click();
|
|
397
|
+
await testdriver.find('menu item').click();
|
|
398
|
+
```
|
|
399
|
+
</Accordion>
|
|
400
|
+
|
|
401
|
+
<Accordion title="Modal Dialogs">
|
|
402
|
+
```javascript
|
|
403
|
+
// Traditional - flaky
|
|
404
|
+
await page.click('.open-modal');
|
|
405
|
+
await page.waitForSelector('.modal', { state: 'visible' });
|
|
406
|
+
await page.waitForTimeout(300); // Wait for animation
|
|
407
|
+
await page.click('.modal-button');
|
|
408
|
+
|
|
409
|
+
// TestDriver - stable
|
|
410
|
+
await testdriver.find('open modal button').click();
|
|
411
|
+
await testdriver.find('modal button').click();
|
|
412
|
+
```
|
|
413
|
+
</Accordion>
|
|
414
|
+
|
|
415
|
+
<Accordion title="Infinite Scroll">
|
|
416
|
+
```javascript
|
|
417
|
+
// Traditional - flaky
|
|
418
|
+
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
|
|
419
|
+
await page.waitForTimeout(1000);
|
|
420
|
+
await page.waitForLoadState('networkidle');
|
|
421
|
+
await page.click('.load-more');
|
|
422
|
+
|
|
423
|
+
// TestDriver - stable
|
|
424
|
+
await testdriver.scroll('down', 1000);
|
|
425
|
+
await testdriver.find('load more button').click();
|
|
426
|
+
```
|
|
427
|
+
</Accordion>
|
|
428
|
+
|
|
429
|
+
<Accordion title="Form Submissions">
|
|
430
|
+
```javascript
|
|
431
|
+
// Traditional - flaky
|
|
432
|
+
await page.fill('input[name="email"]', 'user@example.com');
|
|
433
|
+
await page.click('button[type="submit"]');
|
|
434
|
+
await page.waitForNavigation();
|
|
435
|
+
await page.waitForTimeout(500);
|
|
436
|
+
|
|
437
|
+
// TestDriver - stable
|
|
438
|
+
await testdriver.find('email input').type('user@example.com');
|
|
439
|
+
await testdriver.find('submit button').click();
|
|
440
|
+
await testdriver.assert('success message is visible');
|
|
441
|
+
```
|
|
442
|
+
</Accordion>
|
|
443
|
+
</AccordionGroup>
|
|
444
|
+
|
|
445
|
+
## Best Practices
|
|
446
|
+
|
|
447
|
+
<Card title="Let TestDriver Handle Timing" icon="clock">
|
|
448
|
+
**Don't:**
|
|
449
|
+
```javascript
|
|
450
|
+
await testdriver.find('button').click();
|
|
451
|
+
await new Promise(resolve => setTimeout(resolve, 1000)); // ❌
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
**Do:**
|
|
455
|
+
```javascript
|
|
456
|
+
await testdriver.find('button').click();
|
|
457
|
+
await testdriver.find('next element').click(); // ✅
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
Trust TestDriver's automatic stability detection.
|
|
461
|
+
</Card>
|
|
462
|
+
|
|
463
|
+
<Card title="Use Natural Assertions" icon="check">
|
|
464
|
+
**Don't:**
|
|
465
|
+
```javascript
|
|
466
|
+
await testdriver.find('button').click();
|
|
467
|
+
const element = await testdriver.find('result');
|
|
468
|
+
expect(element).toBeTruthy(); // ❌ Redundant
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
**Do:**
|
|
472
|
+
```javascript
|
|
473
|
+
await testdriver.find('button').click();
|
|
474
|
+
await testdriver.assert('result is visible'); // ✅ Natural
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
TestDriver's assert automatically waits for stability.
|
|
478
|
+
</Card>
|
|
479
|
+
|
|
480
|
+
## Learn More
|
|
481
|
+
|
|
482
|
+
<CardGroup cols={2}>
|
|
483
|
+
<Card
|
|
484
|
+
title="Redraw Implementation"
|
|
485
|
+
icon="code"
|
|
486
|
+
href="/agent/lib/redraw.js"
|
|
487
|
+
>
|
|
488
|
+
View the redraw detection source code
|
|
489
|
+
</Card>
|
|
490
|
+
|
|
491
|
+
<Card
|
|
492
|
+
title="Error Handling Guide"
|
|
493
|
+
icon="triangle-exclamation"
|
|
494
|
+
href="/v7/guides/error-handling"
|
|
495
|
+
>
|
|
496
|
+
Learn about error handling patterns
|
|
497
|
+
</Card>
|
|
498
|
+
|
|
499
|
+
<Card
|
|
500
|
+
title="Best Practices"
|
|
501
|
+
icon="star"
|
|
502
|
+
href="/v7/guides/best-practices"
|
|
503
|
+
>
|
|
504
|
+
Testing best practices with TestDriver
|
|
505
|
+
</Card>
|
|
506
|
+
|
|
507
|
+
<Card
|
|
508
|
+
title="Debugging Guide"
|
|
509
|
+
icon="bug"
|
|
510
|
+
href="/v7/guides/debugging"
|
|
511
|
+
>
|
|
512
|
+
Debug failing tests effectively
|
|
513
|
+
</Card>
|
|
514
|
+
</CardGroup>
|
|
@@ -236,7 +236,7 @@ await testdriver.find('button', { threshold: -1 }); // disable cache
|
|
|
236
236
|
## Dashcam Configuration
|
|
237
237
|
|
|
238
238
|
```javascript
|
|
239
|
-
import Dashcam from 'testdriverai/
|
|
239
|
+
import Dashcam from 'testdriverai/lib/core/Dashcam.js';
|
|
240
240
|
|
|
241
241
|
const dashcam = new Dashcam(client, {
|
|
242
242
|
apiKey: process.env.TD_API_KEY,
|