testdriverai 6.2.2 → 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 +15 -4
- 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
package/agent/lib/validation.js
CHANGED
|
@@ -62,33 +62,27 @@ const types = () =>
|
|
|
62
62
|
},
|
|
63
63
|
// - command: scroll # Scroll up or down. Make sure the correct portion of the page is focused before scrolling.
|
|
64
64
|
// direction: down # Available directions are: up, down, left, right
|
|
65
|
-
//
|
|
66
|
-
// amount: 300 # Optional. The amount of pixels to scroll. Defaults to 300 for keyboard and 200 for mouse.
|
|
65
|
+
// amount: 300 # Optional. The amount of pixels to scroll. Defaults to 300.
|
|
67
66
|
ScrollCommand: {
|
|
68
67
|
command: '"scroll"',
|
|
69
68
|
direction: '"up" | "down" | "left" | "right"',
|
|
70
|
-
"method?": '"keyboard" | "mouse"',
|
|
71
69
|
"amount?": "number",
|
|
72
70
|
},
|
|
73
71
|
// - command: scroll-until-text # Scroll until text is found
|
|
74
72
|
// text: Sign Up # The text to find on screen. The longer and more unique the better.
|
|
75
73
|
// direction: down # Available directions are: up, down, left, right
|
|
76
|
-
// method: keyboard # Optional. Available methods are: keyboard (default), mouse. Use mouse only if the prompt explicitly asks for it.
|
|
77
74
|
ScrollUntilTextCommand: {
|
|
78
75
|
command: '"scroll-until-text"',
|
|
79
76
|
text: "string",
|
|
80
77
|
direction: '"up" | "down" | "left" | "right"',
|
|
81
|
-
"method?": '"keyboard" | "mouse"',
|
|
82
78
|
},
|
|
83
79
|
// - command: scroll-until-image # Scroll until icon or image is found
|
|
84
80
|
// description: Submit at the bottom of the form
|
|
85
81
|
// direction: down # Available directions are: up, down, left, rights
|
|
86
|
-
// method: keyboard # Optional. Available methods are: keyboard (default), mouse. Use mouse only if the prompt explicitly asks for it.
|
|
87
82
|
ScrollUntilImageCommand: {
|
|
88
83
|
command: '"scroll-until-image"',
|
|
89
84
|
description: "string",
|
|
90
85
|
direction: '"up" | "down" | "left" | "right"',
|
|
91
|
-
"method?": '"keyboard" | "mouse"',
|
|
92
86
|
},
|
|
93
87
|
// - command: wait-for-text # Wait until text is seen on screen. Not recommended unless explicitly requested by user.
|
|
94
88
|
// text: Copyright 2024 # The text to find on screen.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Debug script to inspect the full locate API response
|
|
5
|
+
* Run this with: TD_API_KEY=your_key node debug-locate-response.js
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const TestDriverSDK = require("./sdk.js");
|
|
9
|
+
|
|
10
|
+
async function debugLocateResponse() {
|
|
11
|
+
const client = new TestDriverSDK(process.env.TD_API_KEY);
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
console.log("Connecting to sandbox (Linux)...");
|
|
15
|
+
await client.connect({ headless: true });
|
|
16
|
+
|
|
17
|
+
console.log("Opening a test page...");
|
|
18
|
+
await client.focusApplication("Google Chrome");
|
|
19
|
+
await client.type("https://example.com");
|
|
20
|
+
await client.pressKeys(["enter"]);
|
|
21
|
+
|
|
22
|
+
// Wait for page to load
|
|
23
|
+
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
24
|
+
|
|
25
|
+
console.log("\nFinding an element to inspect the response...");
|
|
26
|
+
const element = await client.find("the heading that says Example Domain");
|
|
27
|
+
|
|
28
|
+
console.log("\n=".repeat(60));
|
|
29
|
+
console.log("FULL LOCATE API RESPONSE:");
|
|
30
|
+
console.log("=".repeat(60));
|
|
31
|
+
|
|
32
|
+
const response = element.getResponse();
|
|
33
|
+
console.log(JSON.stringify(response, null, 2));
|
|
34
|
+
|
|
35
|
+
console.log("\n=".repeat(60));
|
|
36
|
+
console.log("RESPONSE KEYS:");
|
|
37
|
+
console.log("=".repeat(60));
|
|
38
|
+
|
|
39
|
+
if (response) {
|
|
40
|
+
Object.keys(response).forEach((key) => {
|
|
41
|
+
const value = response[key];
|
|
42
|
+
const type = Array.isArray(value) ? "array" : typeof value;
|
|
43
|
+
const preview =
|
|
44
|
+
typeof value === "string" && value.length > 100
|
|
45
|
+
? `${value.substring(0, 100)}... (${value.length} chars)`
|
|
46
|
+
: typeof value === "object"
|
|
47
|
+
? JSON.stringify(value)
|
|
48
|
+
: value;
|
|
49
|
+
|
|
50
|
+
console.log(` ${key} (${type}): ${preview}`);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
console.log("\n=".repeat(60));
|
|
55
|
+
console.log("ELEMENT PROPERTIES:");
|
|
56
|
+
console.log("=".repeat(60));
|
|
57
|
+
console.log(" found:", element.found());
|
|
58
|
+
console.log(" x:", element.x);
|
|
59
|
+
console.log(" y:", element.y);
|
|
60
|
+
console.log(" centerX:", element.centerX);
|
|
61
|
+
console.log(" centerY:", element.centerY);
|
|
62
|
+
console.log(" width:", element.width);
|
|
63
|
+
console.log(" height:", element.height);
|
|
64
|
+
console.log(" confidence:", element.confidence);
|
|
65
|
+
console.log(" text:", element.text);
|
|
66
|
+
console.log(" label:", element.label);
|
|
67
|
+
console.log(
|
|
68
|
+
" screenshot:",
|
|
69
|
+
element.screenshot ? `${element.screenshot.length} chars` : null,
|
|
70
|
+
);
|
|
71
|
+
console.log(" boundingBox:", element.boundingBox);
|
|
72
|
+
|
|
73
|
+
await client.disconnect();
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error("Error:", error.message);
|
|
76
|
+
console.error(error.stack);
|
|
77
|
+
await client.disconnect();
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
debugLocateResponse();
|
|
Binary file
|
package/debugger/index.html
CHANGED
|
@@ -34,10 +34,14 @@
|
|
|
34
34
|
top: 0;
|
|
35
35
|
left: 0;
|
|
36
36
|
transform-origin: top left;
|
|
37
|
+
overflow: hidden;
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
html,
|
|
39
41
|
body {
|
|
40
42
|
overflow: hidden;
|
|
43
|
+
width: 100%;
|
|
44
|
+
height: 100%;
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
*::-webkit-scrollbar {
|
|
@@ -66,6 +70,7 @@
|
|
|
66
70
|
|
|
67
71
|
.overlay {
|
|
68
72
|
position: relative;
|
|
73
|
+
overflow: hidden;
|
|
69
74
|
}
|
|
70
75
|
|
|
71
76
|
.screenshot {
|
|
@@ -179,6 +184,7 @@
|
|
|
179
184
|
width: 100%;
|
|
180
185
|
height: 100%;
|
|
181
186
|
z-index: 1;
|
|
187
|
+
overflow: hidden;
|
|
182
188
|
}
|
|
183
189
|
|
|
184
190
|
/* Loading screen styles */
|
|
@@ -354,6 +360,10 @@
|
|
|
354
360
|
|
|
355
361
|
const iframe = document.querySelector("#vm-iframe");
|
|
356
362
|
|
|
363
|
+
// Detect if OS is Linux
|
|
364
|
+
const isLinux = parsedData.os === "linux";
|
|
365
|
+
const topBarOffset = isLinux ? 14 : 0;
|
|
366
|
+
|
|
357
367
|
// set overlay width and height to match the given resolution
|
|
358
368
|
const overlayWidth = parsedData.resolution[0];
|
|
359
369
|
const overlayHeight = parsedData.resolution[1];
|
|
@@ -361,7 +371,8 @@
|
|
|
361
371
|
iframe.style.display = "block";
|
|
362
372
|
iframe.src = parsedData.url;
|
|
363
373
|
iframe.style.width = overlayWidth + "px";
|
|
364
|
-
iframe
|
|
374
|
+
// Increase iframe height by 14px for Linux to account for top bar
|
|
375
|
+
iframe.style.height = overlayHeight + topBarOffset + "px";
|
|
365
376
|
|
|
366
377
|
// Calculate scale factor to fit within window if needed
|
|
367
378
|
const windowWidth = window.innerWidth;
|
|
@@ -513,7 +524,7 @@
|
|
|
513
524
|
const boxElement = document.createElement("div");
|
|
514
525
|
boxElement.className = "bounding-box";
|
|
515
526
|
boxElement.style.left = toCss(box.x);
|
|
516
|
-
boxElement.style.top = toCss(box.y);
|
|
527
|
+
boxElement.style.top = toCss(box.y + topBarOffset);
|
|
517
528
|
boxElement.style.width = toCss(box.width);
|
|
518
529
|
boxElement.style.height = toCss(box.height);
|
|
519
530
|
effects.appendChild(boxElement);
|
|
@@ -541,14 +552,14 @@
|
|
|
541
552
|
// Mouse event handlers
|
|
542
553
|
addEventHandler(events.mouseMove, (event, { x, y } = {}) => {
|
|
543
554
|
mouse.style.marginLeft = toCss(x);
|
|
544
|
-
mouse.style.marginTop = toCss(y);
|
|
555
|
+
mouse.style.marginTop = toCss(y + topBarOffset);
|
|
545
556
|
});
|
|
546
557
|
|
|
547
558
|
addEventHandler(
|
|
548
559
|
events.mouseClick,
|
|
549
560
|
(event, { x, y, click = "single" } = {}) => {
|
|
550
561
|
mouse.style.marginLeft = toCss(x);
|
|
551
|
-
mouse.style.marginTop = toCss(y);
|
|
562
|
+
mouse.style.marginTop = toCss(y + topBarOffset);
|
|
552
563
|
// Reset class so animation can restart
|
|
553
564
|
mouse.setAttribute("class", "mouse");
|
|
554
565
|
// Force reflow
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
# TestDriver Test Recording Architecture
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This system provides comprehensive test execution tracking, linking test runs with dashcam screen recordings and CI/CD pipelines in the TestDriver dashboard.
|
|
6
|
+
|
|
7
|
+
## Architecture Diagram
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
11
|
+
│ Developer's Machine / CI │
|
|
12
|
+
├─────────────────────────────────────────────────────────────┤
|
|
13
|
+
│ │
|
|
14
|
+
│ ┌──────────────┐ ┌──────────────┐ │
|
|
15
|
+
│ │ Vitest │────────▶│ TD Vitest │ │
|
|
16
|
+
│ │ Test Runner │ │ Plugin │ │
|
|
17
|
+
│ └──────────────┘ └──────┬───────┘ │
|
|
18
|
+
│ │ │
|
|
19
|
+
│ ┌──────────────┐ │ │
|
|
20
|
+
│ │ Dashcam │ │ │
|
|
21
|
+
│ │ Recording │ │ │
|
|
22
|
+
│ └──────┬───────┘ │ │
|
|
23
|
+
│ │ │ │
|
|
24
|
+
│ │ (records screen) │ (reports results) │
|
|
25
|
+
│ │ │ │
|
|
26
|
+
└─────────┼─────────────────────────┼───────────────────────────┘
|
|
27
|
+
│ │
|
|
28
|
+
│ │
|
|
29
|
+
▼ ▼
|
|
30
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
31
|
+
│ TestDriver API Server │
|
|
32
|
+
├─────────────────────────────────────────────────────────────┤
|
|
33
|
+
│ │
|
|
34
|
+
│ ┌──────────────┐ ┌──────────────┐ │
|
|
35
|
+
│ │ Replay API │ │ Test Run API │ │
|
|
36
|
+
│ │ (dashcam) │ │ (new) │ │
|
|
37
|
+
│ └──────┬───────┘ └──────┬───────┘ │
|
|
38
|
+
│ │ │ │
|
|
39
|
+
│ └────────┬───────────────┘ │
|
|
40
|
+
│ │ │
|
|
41
|
+
│ ▼ │
|
|
42
|
+
│ ┌────────────────┐ │
|
|
43
|
+
│ │ MongoDB │ │
|
|
44
|
+
│ │ │ │
|
|
45
|
+
│ │ • TdTestRun │ │
|
|
46
|
+
│ │ • TdTestCase │ │
|
|
47
|
+
│ │ • TdSandbox │ │
|
|
48
|
+
│ │ • Replay │ │
|
|
49
|
+
│ └────────────────┘ │
|
|
50
|
+
│ │
|
|
51
|
+
└───────────────────────────┬───────────────────────────────────┘
|
|
52
|
+
│
|
|
53
|
+
│
|
|
54
|
+
▼
|
|
55
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
56
|
+
│ TestDriver Web Dashboard │
|
|
57
|
+
├─────────────────────────────────────────────────────────────┤
|
|
58
|
+
│ │
|
|
59
|
+
│ ┌─────────────────────────────────────────┐ │
|
|
60
|
+
│ │ Test Runs View (NEW) │ │
|
|
61
|
+
│ │ │ │
|
|
62
|
+
│ │ • List all test runs │ │
|
|
63
|
+
│ │ • Filter by status, date, CI │ │
|
|
64
|
+
│ │ • Show pass/fail statistics │ │
|
|
65
|
+
│ │ • Link to CI/CD runs │ │
|
|
66
|
+
│ └─────────────────────────────────────────┘ │
|
|
67
|
+
│ │
|
|
68
|
+
│ ┌─────────────────────────────────────────┐ │
|
|
69
|
+
│ │ Test Run Detail View (NEW) │ │
|
|
70
|
+
│ │ │ │
|
|
71
|
+
│ │ • Test case list with status │ │
|
|
72
|
+
│ │ • Dashcam replay player (embedded) │ │
|
|
73
|
+
│ │ • Error messages and stack traces │ │
|
|
74
|
+
│ │ • Sandbox details │ │
|
|
75
|
+
│ │ • Git commit info │ │
|
|
76
|
+
│ └─────────────────────────────────────────┘ │
|
|
77
|
+
│ │
|
|
78
|
+
└───────────────────────────────────────────────────────────────┘
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Data Models
|
|
82
|
+
|
|
83
|
+
### TdTestRun
|
|
84
|
+
Represents a complete test suite execution (e.g., `npx vitest run`).
|
|
85
|
+
|
|
86
|
+
**Key Fields:**
|
|
87
|
+
- `runId`: Unique identifier
|
|
88
|
+
- `suiteName`: Name of the test suite
|
|
89
|
+
- `status`: running | passed | failed | cancelled
|
|
90
|
+
- `totalTests`, `passedTests`, `failedTests`: Statistics
|
|
91
|
+
- `platform`: windows | mac | linux
|
|
92
|
+
- CI/CD metadata (provider, runId, url)
|
|
93
|
+
- Git metadata (repo, branch, commit)
|
|
94
|
+
- `dashcamSessionId`: Links to dashcam recordings
|
|
95
|
+
|
|
96
|
+
**Relationships:**
|
|
97
|
+
- `team`: Owner team
|
|
98
|
+
- `sandbox`: TdSandbox where tests ran
|
|
99
|
+
- `testCases`: Collection of TdTestCase
|
|
100
|
+
- `replays`: Associated Replay records
|
|
101
|
+
|
|
102
|
+
### TdTestCase
|
|
103
|
+
Represents an individual test within a test run.
|
|
104
|
+
|
|
105
|
+
**Key Fields:**
|
|
106
|
+
- `testName`: Test name from `test('...')`
|
|
107
|
+
- `testFile`: Path to test file
|
|
108
|
+
- `suiteName`: Describe block name
|
|
109
|
+
- `status`: passed | failed | skipped | pending
|
|
110
|
+
- `duration`: Test duration in ms
|
|
111
|
+
- `errorMessage`, `errorStack`: Failure details
|
|
112
|
+
- `replayUrl`: Direct link to dashcam replay
|
|
113
|
+
- `replayStartTime`, `replayEndTime`: Timestamps within replay
|
|
114
|
+
|
|
115
|
+
**Relationships:**
|
|
116
|
+
- `testRun`: Parent TdTestRun
|
|
117
|
+
- `replay`: Associated Replay record
|
|
118
|
+
|
|
119
|
+
### TdSandbox
|
|
120
|
+
Represents a spawned VM/sandbox instance.
|
|
121
|
+
|
|
122
|
+
**Key Fields:**
|
|
123
|
+
- `sandboxId`: Unique identifier
|
|
124
|
+
- `platform`: windows | mac | linux
|
|
125
|
+
- `status`: provisioning | ready | running | stopped | terminated
|
|
126
|
+
- `instanceId`, `instanceType`: AWS EC2 details
|
|
127
|
+
- `ipAddress`, `vncUrl`, `wsUrl`: Connection details
|
|
128
|
+
- `spawnTime`, `readyTime`, `terminateTime`: Lifecycle timestamps
|
|
129
|
+
- `dashcamAuth`: Whether dashcam was authenticated
|
|
130
|
+
- `dashcamProjectId`: Dashcam project for replays
|
|
131
|
+
|
|
132
|
+
**Relationships:**
|
|
133
|
+
- `team`: Owner team
|
|
134
|
+
- `user`: User who spawned it
|
|
135
|
+
- `testRuns`: Tests that ran on this sandbox
|
|
136
|
+
- `replays`: Dashcam recordings from this sandbox
|
|
137
|
+
|
|
138
|
+
**Note:** Sandbox creation/updates happen via WebSocket (not REST API) as part of the sandbox provisioning flow.
|
|
139
|
+
|
|
140
|
+
### Replay (Extended)
|
|
141
|
+
Existing model extended with test run associations.
|
|
142
|
+
|
|
143
|
+
**New Fields:**
|
|
144
|
+
- `tdTestRun`: Associated test run
|
|
145
|
+
- `tdTestCase`: Associated test case
|
|
146
|
+
- `tdSandbox`: Sandbox where recorded
|
|
147
|
+
|
|
148
|
+
## API Endpoints
|
|
149
|
+
|
|
150
|
+
### POST /api/v1/testdriver/test-run-create
|
|
151
|
+
Create a new test run.
|
|
152
|
+
|
|
153
|
+
**Auth:** Required (Bearer token)
|
|
154
|
+
|
|
155
|
+
**Request:**
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"runId": "vitest-1234567890-abc123",
|
|
159
|
+
"suiteName": "Integration Tests",
|
|
160
|
+
"platform": "windows",
|
|
161
|
+
"sandboxId": "sandbox-xyz",
|
|
162
|
+
"ciProvider": "GitHub Actions",
|
|
163
|
+
"ciRunId": "12345",
|
|
164
|
+
"repo": "myorg/myrepo",
|
|
165
|
+
"branch": "main",
|
|
166
|
+
"commit": "abc123def456"
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Response:**
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"data": {
|
|
174
|
+
"id": "...",
|
|
175
|
+
"runId": "vitest-1234567890-abc123",
|
|
176
|
+
"status": "running",
|
|
177
|
+
"startTime": 1700000000000
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### POST /api/v1/testdriver/test-run-complete
|
|
183
|
+
Mark a test run as complete.
|
|
184
|
+
|
|
185
|
+
**Auth:** Required
|
|
186
|
+
|
|
187
|
+
**Request:**
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"runId": "vitest-1234567890-abc123",
|
|
191
|
+
"status": "passed",
|
|
192
|
+
"totalTests": 25,
|
|
193
|
+
"passedTests": 24,
|
|
194
|
+
"failedTests": 1,
|
|
195
|
+
"skippedTests": 0
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### POST /api/v1/testdriver/test-case-create
|
|
200
|
+
Record a test case result (create or update).
|
|
201
|
+
|
|
202
|
+
**Auth:** Required
|
|
203
|
+
|
|
204
|
+
**Request:**
|
|
205
|
+
```json
|
|
206
|
+
{
|
|
207
|
+
"runId": "vitest-1234567890-abc123",
|
|
208
|
+
"testName": "should login successfully",
|
|
209
|
+
"testFile": "tests/auth/login.test.js",
|
|
210
|
+
"suiteName": "Authentication Tests",
|
|
211
|
+
"status": "passed",
|
|
212
|
+
"startTime": 1700000001000,
|
|
213
|
+
"endTime": 1700000002500,
|
|
214
|
+
"duration": 1500,
|
|
215
|
+
"replayUrl": "https://app.dashcam.io/replay/abc123"
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Components
|
|
220
|
+
|
|
221
|
+
### Vitest Plugin (`interfaces/vitest-plugin.mjs`)
|
|
222
|
+
Automatically integrates with Vitest test runs.
|
|
223
|
+
|
|
224
|
+
**Features:**
|
|
225
|
+
- Auto-detects CI/CD environment (GitHub Actions, GitLab, etc.)
|
|
226
|
+
- Extracts Git metadata from environment or git commands
|
|
227
|
+
- Creates test run at start
|
|
228
|
+
- Records each test case result
|
|
229
|
+
- Associates with dashcam session if `DASHCAM_SESSION_ID` is set
|
|
230
|
+
- Completes test run with statistics
|
|
231
|
+
- Uses plugin architecture for better global state management
|
|
232
|
+
|
|
233
|
+
**Usage:**
|
|
234
|
+
```javascript
|
|
235
|
+
// vitest.config.mjs
|
|
236
|
+
import testDriverPlugin from './interfaces/vitest-plugin.mjs';
|
|
237
|
+
|
|
238
|
+
export default {
|
|
239
|
+
plugins: [
|
|
240
|
+
testDriverPlugin({
|
|
241
|
+
apiKey: process.env.TD_API_KEY,
|
|
242
|
+
apiRoot: process.env.TD_API_ROOT || 'https://testdriver-api.onrender.com',
|
|
243
|
+
}),
|
|
244
|
+
],
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### SDK Methods (`sdk.js`)
|
|
249
|
+
|
|
250
|
+
#### `client.createTestRun(options)`
|
|
251
|
+
Create a test run programmatically.
|
|
252
|
+
|
|
253
|
+
#### `client.recordTestCase(options)`
|
|
254
|
+
Record a test case result.
|
|
255
|
+
|
|
256
|
+
#### `client.completeTestRun(options)`
|
|
257
|
+
Mark test run as complete.
|
|
258
|
+
|
|
259
|
+
## Integration Flows
|
|
260
|
+
|
|
261
|
+
### Flow 1: Automated with Vitest Reporter
|
|
262
|
+
|
|
263
|
+
```
|
|
264
|
+
1. Developer runs: npx vitest run
|
|
265
|
+
2. Vitest starts, reporter initializes
|
|
266
|
+
3. Reporter creates TdTestRun
|
|
267
|
+
4. For each test:
|
|
268
|
+
- Vitest runs test
|
|
269
|
+
- Reporter records TdTestCase (passed/failed)
|
|
270
|
+
5. All tests complete
|
|
271
|
+
6. Reporter calls completeTestRun()
|
|
272
|
+
7. Results visible in dashboard
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Flow 2: With Dashcam Recording
|
|
276
|
+
|
|
277
|
+
```
|
|
278
|
+
1. Start dashcam: dashcam start
|
|
279
|
+
2. Set session ID: export DASHCAM_SESSION_ID=$(dashcam session-id)
|
|
280
|
+
3. Run tests: npx vitest run
|
|
281
|
+
4. Reporter creates test run with dashcamSessionId
|
|
282
|
+
5. Tests execute, dashcam records
|
|
283
|
+
6. Stop dashcam: dashcam stop
|
|
284
|
+
7. Publish: dashcam publish -p PROJECT_ID
|
|
285
|
+
8. Replay URL returned
|
|
286
|
+
9. Dashboard shows test results + replay link
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Flow 3: CI/CD Pipeline (GitHub Actions)
|
|
290
|
+
|
|
291
|
+
```yaml
|
|
292
|
+
jobs:
|
|
293
|
+
test:
|
|
294
|
+
runs-on: windows-latest
|
|
295
|
+
steps:
|
|
296
|
+
- uses: actions/checkout@v3
|
|
297
|
+
- run: npm install
|
|
298
|
+
- name: Start Dashcam
|
|
299
|
+
run: |
|
|
300
|
+
dashcam start
|
|
301
|
+
echo "DASHCAM_SESSION_ID=$(dashcam session-id)" >> $GITHUB_ENV
|
|
302
|
+
- name: Run Tests
|
|
303
|
+
env:
|
|
304
|
+
TD_API_KEY: ${{ secrets.TD_API_KEY }}
|
|
305
|
+
run: npx vitest run
|
|
306
|
+
- name: Publish Recording
|
|
307
|
+
if: always()
|
|
308
|
+
run: |
|
|
309
|
+
dashcam stop
|
|
310
|
+
dashcam publish -p ${{ secrets.DASHCAM_PROJECT_ID }}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Reporter auto-detects:
|
|
314
|
+
- GitHub repo, branch, commit
|
|
315
|
+
- Workflow run ID and URL
|
|
316
|
+
- Job ID
|
|
317
|
+
- Actor (who triggered)
|
|
318
|
+
|
|
319
|
+
## Dashcam Association Strategies
|
|
320
|
+
|
|
321
|
+
### Strategy 1: Session ID (Implemented)
|
|
322
|
+
- Set `DASHCAM_SESSION_ID` environment variable
|
|
323
|
+
- Reporter includes in test run creation
|
|
324
|
+
- Dashboard queries replays by session ID
|
|
325
|
+
- Shows all replays from that session
|
|
326
|
+
|
|
327
|
+
### Strategy 2: Explicit URL (Implemented)
|
|
328
|
+
- Dashcam publishes, returns URL
|
|
329
|
+
- Pass URL to `recordTestCase()`
|
|
330
|
+
- Direct 1:1 link between test and replay
|
|
331
|
+
|
|
332
|
+
### Strategy 3: Timestamp Matching (Future)
|
|
333
|
+
- Parse dashcam logs for replay timestamps
|
|
334
|
+
- Match test start/end times with replay markers
|
|
335
|
+
- Automatically associate without manual linking
|
|
336
|
+
- Allows seeking to exact test within long replay
|
|
337
|
+
|
|
338
|
+
### Strategy 4: Log Parsing (Future)
|
|
339
|
+
- Dashcam logs test names/files during recording
|
|
340
|
+
- Parse logs to extract test-to-timestamp mapping
|
|
341
|
+
- Generate replay URLs with timestamp seek parameters
|
|
342
|
+
- Example: `https://app.dashcam.io/replay/abc123?t=45000` (seek to 45s)
|
|
343
|
+
|
|
344
|
+
## Dashboard Views (To Be Built)
|
|
345
|
+
|
|
346
|
+
### Test Runs List
|
|
347
|
+
- Table of all test runs
|
|
348
|
+
- Columns: Suite Name, Status, Tests (passed/failed), Duration, Date, CI Link
|
|
349
|
+
- Filters: Status, Date range, CI provider, Platform
|
|
350
|
+
- Search: By suite name, repo, branch
|
|
351
|
+
|
|
352
|
+
### Test Run Detail
|
|
353
|
+
- Header: Suite name, status, duration, platform
|
|
354
|
+
- Statistics card: Total/passed/failed/skipped
|
|
355
|
+
- Test cases table: Name, Status, Duration, Replay link
|
|
356
|
+
- Sidebar: Git info, CI info, Sandbox details
|
|
357
|
+
- Dashcam replay player (embedded iframe)
|
|
358
|
+
- Click test case → seek replay to that test's time range
|
|
359
|
+
|
|
360
|
+
### Sandbox Management
|
|
361
|
+
- List of active/terminated sandboxes
|
|
362
|
+
- Lifecycle timeline visualization
|
|
363
|
+
- Cost tracking (duration × instance type)
|
|
364
|
+
- Associated test runs
|
|
365
|
+
|
|
366
|
+
## Environment Variables
|
|
367
|
+
|
|
368
|
+
| Variable | Required | Description |
|
|
369
|
+
|----------|----------|-------------|
|
|
370
|
+
| `TD_API_KEY` | Yes | TestDriver API key for authentication |
|
|
371
|
+
| `DASHCAM_SESSION_ID` | No | Links test run to dashcam session |
|
|
372
|
+
| `TD_SANDBOX_ID` | No | Sandbox ID if running in TestDriver sandbox |
|
|
373
|
+
| `GITHUB_ACTIONS` | Auto | Detected for GitHub Actions integration |
|
|
374
|
+
| `GITLAB_CI` | Auto | Detected for GitLab CI integration |
|
|
375
|
+
| `CIRCLECI` | Auto | Detected for CircleCI integration |
|
|
376
|
+
|
|
377
|
+
## Future Enhancements
|
|
378
|
+
|
|
379
|
+
1. **Real-time Test Streaming**
|
|
380
|
+
- WebSocket connection from reporter
|
|
381
|
+
- Live test progress in dashboard
|
|
382
|
+
- See tests pass/fail as they run
|
|
383
|
+
|
|
384
|
+
2. **Flaky Test Detection**
|
|
385
|
+
- Track test history across runs
|
|
386
|
+
- Identify tests that intermittently fail
|
|
387
|
+
- Suggest fixes based on error patterns
|
|
388
|
+
|
|
389
|
+
3. **Performance Regression Detection**
|
|
390
|
+
- Compare test durations across runs
|
|
391
|
+
- Alert on significant slowdowns
|
|
392
|
+
- Visualize performance trends
|
|
393
|
+
|
|
394
|
+
4. **Advanced Dashcam Integration**
|
|
395
|
+
- Automatic timestamp extraction from logs
|
|
396
|
+
- AI-powered test failure analysis from replays
|
|
397
|
+
- Highlight exact moment of failure in replay
|
|
398
|
+
|
|
399
|
+
5. **Multi-Framework Support**
|
|
400
|
+
- Jest reporter
|
|
401
|
+
- Mocha reporter
|
|
402
|
+
- Playwright reporter
|
|
403
|
+
- Cypress plugin
|
|
404
|
+
|
|
405
|
+
6. **Cost Analytics**
|
|
406
|
+
- Track sandbox costs per test run
|
|
407
|
+
- Optimize instance types
|
|
408
|
+
- Budget alerts
|
|
409
|
+
|
|
410
|
+
## Security Considerations
|
|
411
|
+
|
|
412
|
+
- API keys stored securely (environment variables)
|
|
413
|
+
- Bearer token authentication for all API calls
|
|
414
|
+
- Team-based access control (tests only visible to team members)
|
|
415
|
+
- Replay access control (dashcam's existing permissions)
|
|
416
|
+
- No sensitive data in test metadata (sanitize error messages)
|
|
417
|
+
|
|
418
|
+
## Performance Considerations
|
|
419
|
+
|
|
420
|
+
- Async test case recording (doesn't slow tests)
|
|
421
|
+
- Batch updates for large test suites
|
|
422
|
+
- Efficient database indexing (runId, testFile, status)
|
|
423
|
+
- Replay association is lazy (doesn't block test recording)
|
|
424
|
+
- Optional reporter (disable in local development)
|