testdriverai 7.2.37 → 7.2.39
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/testdriver.yml +6 -0
- package/interfaces/vitest-plugin.d.ts +101 -0
- package/interfaces/vitest-plugin.mjs +1 -1
- package/jsconfig.json +26 -0
- package/lib/github-comment.mjs +17 -7
- package/lib/vitest/hooks.d.ts +26 -76
- package/package.json +23 -8
- package/sdk.d.ts +130 -0
- package/setup/aws/cloudformation.yaml +2 -2
- package/test/testdriver/hover-text.test.mjs +1 -1
- package/.github/workflows/test-with-comments.yml +0 -73
|
@@ -9,6 +9,10 @@ on:
|
|
|
9
9
|
jobs:
|
|
10
10
|
test:
|
|
11
11
|
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
pull-requests: write # Required to post comments on PRs
|
|
12
16
|
|
|
13
17
|
steps:
|
|
14
18
|
- uses: actions/checkout@v4
|
|
@@ -25,6 +29,8 @@ jobs:
|
|
|
25
29
|
- name: Run TestDriver.ai tests
|
|
26
30
|
env:
|
|
27
31
|
TD_API_KEY: ${{ secrets.TD_API_KEY }}
|
|
32
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
33
|
+
GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
28
34
|
run: npx vitest run
|
|
29
35
|
|
|
30
36
|
- name: Upload test results
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript definitions for TestDriver Vitest Plugin
|
|
3
|
+
* @module testdriverai/vitest/plugin
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import TestDriverSDK, { TestDriverOptions } from '../sdk';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Plugin state object
|
|
10
|
+
*/
|
|
11
|
+
export interface PluginState {
|
|
12
|
+
dashcamUrls: Map<string, { url: string; platform: string }>;
|
|
13
|
+
suiteTestRuns: Map<string, any>;
|
|
14
|
+
testDriverOptions: TestDriverOptions;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Current plugin state
|
|
19
|
+
*/
|
|
20
|
+
export const pluginState: PluginState;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Register a Dashcam URL for a test
|
|
24
|
+
*/
|
|
25
|
+
export function registerDashcamUrl(testId: string, url: string, platform: string): void;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get Dashcam URL for a test
|
|
29
|
+
*/
|
|
30
|
+
export function getDashcamUrl(testId: string): { url: string; platform: string } | undefined;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Clear all Dashcam URLs
|
|
34
|
+
*/
|
|
35
|
+
export function clearDashcamUrls(): void;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get suite test run data
|
|
39
|
+
*/
|
|
40
|
+
export function getSuiteTestRun(suiteId: string): any;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Set suite test run data
|
|
44
|
+
*/
|
|
45
|
+
export function setSuiteTestRun(suiteId: string, runData: any): void;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Clear suite test run data
|
|
49
|
+
*/
|
|
50
|
+
export function clearSuiteTestRun(suiteId: string): void;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get the current plugin state
|
|
54
|
+
*/
|
|
55
|
+
export function getPluginState(): PluginState;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Authenticate with API key
|
|
59
|
+
*/
|
|
60
|
+
export function authenticateWithApiKey(apiKey: string, apiRoot?: string): Promise<string>;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Create a test run directly via API
|
|
64
|
+
*/
|
|
65
|
+
export function createTestRunDirect(token: string, apiRoot: string, testRunData: any): Promise<any>;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Record a test case directly via API
|
|
69
|
+
*/
|
|
70
|
+
export function recordTestCaseDirect(token: string, apiRoot: string, testCaseData: any): Promise<any>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Create a TestDriver instance
|
|
74
|
+
*/
|
|
75
|
+
export function createTestDriver(options?: TestDriverOptions): Promise<TestDriverSDK>;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Register a test with TestDriver
|
|
79
|
+
*/
|
|
80
|
+
export function registerTest(testdriver: TestDriverSDK, context: any): void;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Cleanup a TestDriver instance
|
|
84
|
+
*/
|
|
85
|
+
export function cleanupTestDriver(testdriver: TestDriverSDK): Promise<void>;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Plugin options
|
|
89
|
+
*/
|
|
90
|
+
export interface TestDriverPluginOptions extends TestDriverOptions {
|
|
91
|
+
/**
|
|
92
|
+
* API key (defaults to TD_API_KEY env var)
|
|
93
|
+
*/
|
|
94
|
+
apiKey?: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* TestDriver Vitest Plugin
|
|
99
|
+
* @param options - Plugin configuration options
|
|
100
|
+
*/
|
|
101
|
+
export default function testDriverPlugin(options?: TestDriverPluginOptions): any;
|
|
@@ -2,8 +2,8 @@ import { execSync } from "child_process";
|
|
|
2
2
|
import crypto from "crypto";
|
|
3
3
|
import { createRequire } from "module";
|
|
4
4
|
import path from "path";
|
|
5
|
+
import { postOrUpdateTestResults } from "../lib/github-comment.mjs";
|
|
5
6
|
import { setTestRunInfo } from "./shared-test-state.mjs";
|
|
6
|
-
import { generateGitHubComment, postOrUpdateTestResults } from "../lib/github-comment.mjs";
|
|
7
7
|
|
|
8
8
|
// Use createRequire to import CommonJS modules without esbuild processing
|
|
9
9
|
const require = createRequire(import.meta.url);
|
package/jsconfig.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "ESNext",
|
|
4
|
+
"moduleResolution": "bundler",
|
|
5
|
+
"target": "ES2022",
|
|
6
|
+
"checkJs": true,
|
|
7
|
+
"strict": false,
|
|
8
|
+
"allowSyntheticDefaultImports": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"baseUrl": ".",
|
|
11
|
+
"typeRoots": ["."]
|
|
12
|
+
},
|
|
13
|
+
"include": [
|
|
14
|
+
"**/*.js",
|
|
15
|
+
"**/*.mjs",
|
|
16
|
+
"**/*.d.ts",
|
|
17
|
+
"sdk.d.ts",
|
|
18
|
+
"lib/**/*.d.ts",
|
|
19
|
+
"interfaces/**/*.d.ts"
|
|
20
|
+
],
|
|
21
|
+
"exclude": [
|
|
22
|
+
"node_modules",
|
|
23
|
+
"dist",
|
|
24
|
+
"build"
|
|
25
|
+
]
|
|
26
|
+
}
|
package/lib/github-comment.mjs
CHANGED
|
@@ -47,10 +47,17 @@ function generateTestResultsTable(testCases, testRunUrl) {
|
|
|
47
47
|
return '_No test cases recorded_';
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
// Filter out skipped tests
|
|
51
|
+
const nonSkippedTests = testCases.filter(test => test.status !== 'skipped');
|
|
52
|
+
|
|
53
|
+
if (nonSkippedTests.length === 0) {
|
|
54
|
+
return '_No test cases to display (all tests were skipped)_';
|
|
55
|
+
}
|
|
56
|
+
|
|
50
57
|
let table = '| Status | Test | File | Duration | Replay |\n';
|
|
51
58
|
table += '|--------|------|------|----------|--------|\n';
|
|
52
59
|
|
|
53
|
-
for (const test of
|
|
60
|
+
for (const test of nonSkippedTests) {
|
|
54
61
|
const status = getStatusEmoji(test.status);
|
|
55
62
|
const name = test.testName || 'Unknown';
|
|
56
63
|
const file = test.testFile || 'unknown';
|
|
@@ -65,8 +72,8 @@ function generateTestResultsTable(testCases, testRunUrl) {
|
|
|
65
72
|
const replayId = extractReplayId(test.replayUrl);
|
|
66
73
|
if (replayId) {
|
|
67
74
|
const gifUrl = getReplayGifUrl(test.replayUrl, replayId);
|
|
68
|
-
// Embed GIF with link using HTML for
|
|
69
|
-
replay = `<a href="${linkUrl}"><img src="${gifUrl}"
|
|
75
|
+
// Embed GIF with link using HTML for height control
|
|
76
|
+
replay = `<a href="${linkUrl}"><img src="${gifUrl}" height="100" alt="Test replay" /></a>`;
|
|
70
77
|
} else {
|
|
71
78
|
// Fallback to text link if no GIF available
|
|
72
79
|
replay = `[🎥 View](${linkUrl})`;
|
|
@@ -258,9 +265,15 @@ export function generateGitHubComment(testRunData, testCases = []) {
|
|
|
258
265
|
comment += ` • **Duration:** ${formatDuration(duration)}`;
|
|
259
266
|
comment += ` • ${passedTests} passed`;
|
|
260
267
|
if (failedTests > 0) comment += `, ${failedTests} failed`;
|
|
261
|
-
if
|
|
268
|
+
// Only show skipped count if there are no passed or failed tests
|
|
269
|
+
if (skippedTests > 0 && passedTests === 0 && failedTests === 0) {
|
|
270
|
+
comment += `, ${skippedTests} skipped`;
|
|
271
|
+
}
|
|
262
272
|
comment += `\n\n`;
|
|
263
273
|
|
|
274
|
+
// Exceptions section (only if there are failures) - show first
|
|
275
|
+
comment += generateExceptionsSection(testCases, testRunUrl);
|
|
276
|
+
|
|
264
277
|
// Test results table (now includes embedded GIFs)
|
|
265
278
|
comment += '## 📝 Test Results\n\n';
|
|
266
279
|
comment += generateTestResultsTable(testCases, testRunUrl);
|
|
@@ -270,9 +283,6 @@ export function generateGitHubComment(testRunData, testCases = []) {
|
|
|
270
283
|
comment += `\n[📋 View Full Test Run](${testRunUrl})\n`;
|
|
271
284
|
}
|
|
272
285
|
|
|
273
|
-
// Exceptions section (only if there are failures)
|
|
274
|
-
comment += generateExceptionsSection(testCases, testRunUrl);
|
|
275
|
-
|
|
276
286
|
// Footer
|
|
277
287
|
comment += '\n---\n';
|
|
278
288
|
comment += `<sub>Generated by [TestDriver](https://testdriver.ai) • Run ID: \`${runId}\`</sub>\n`;
|
package/lib/vitest/hooks.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module testdriverai/vitest/hooks
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import
|
|
6
|
+
import TestDriverSDK, { TestDriverOptions } from '../../sdk';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Vitest test context (from test function parameter)
|
|
@@ -21,99 +21,49 @@ export interface VitestContext {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
* Options for
|
|
24
|
+
* Options for TestDriver hook
|
|
25
25
|
*/
|
|
26
|
-
export interface
|
|
26
|
+
export interface TestDriverHookOptions extends TestDriverOptions {
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
28
|
+
* Force creation of a new sandbox (default: true)
|
|
29
29
|
*/
|
|
30
|
-
|
|
30
|
+
newSandbox?: boolean;
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* Reconnect to the last used sandbox
|
|
34
34
|
*/
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Options for useDashcam hook
|
|
40
|
-
*/
|
|
41
|
-
export interface UseDashcamOptions extends DashcamOptions {
|
|
42
|
-
/**
|
|
43
|
-
* Automatically authenticate (default: true)
|
|
44
|
-
*/
|
|
45
|
-
autoAuth?: boolean;
|
|
35
|
+
reconnect?: boolean;
|
|
46
36
|
|
|
47
37
|
/**
|
|
48
|
-
*
|
|
38
|
+
* Direct IP address to connect to a running sandbox instance
|
|
49
39
|
*/
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Automatically stop recording at test end (default: false)
|
|
54
|
-
*/
|
|
55
|
-
autoStop?: boolean;
|
|
40
|
+
ip?: string;
|
|
56
41
|
}
|
|
57
42
|
|
|
58
43
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
44
|
+
* Create a TestDriver client for use in Vitest tests
|
|
45
|
+
* Manages lifecycle automatically (connects on first use, disconnects after test)
|
|
61
46
|
*
|
|
62
47
|
* @param context - Vitest test context (from async (context) => {})
|
|
63
48
|
* @param options - TestDriver options
|
|
64
|
-
* @returns TestDriver
|
|
49
|
+
* @returns TestDriver SDK instance
|
|
65
50
|
*
|
|
66
51
|
* @example
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* await client.find('Login button').click();
|
|
70
|
-
* });
|
|
71
|
-
*/
|
|
72
|
-
export function useTestDriver(context: VitestContext, options?: UseTestDriverOptions): TestDriver;
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Use Dashcam in a test
|
|
76
|
-
* Creates and manages Dashcam instance for the current test
|
|
77
|
-
*
|
|
78
|
-
* @param context - Vitest test context
|
|
79
|
-
* @param client - TestDriver client instance (from useTestDriver)
|
|
80
|
-
* @param options - Dashcam options
|
|
81
|
-
* @returns Dashcam instance
|
|
52
|
+
* import { describe, expect, it } from "vitest";
|
|
53
|
+
* import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
|
|
82
54
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
|
|
94
|
-
export function useDashcam(context: VitestContext, client: TestDriver, options?: UseDashcamOptions): Dashcam;
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Use TestDriver with Dashcam in one call
|
|
98
|
-
* Combined hook for the simplest usage pattern
|
|
99
|
-
*
|
|
100
|
-
* @param context - Vitest test context
|
|
101
|
-
* @param options - Combined options for TestDriver and Dashcam
|
|
102
|
-
* @returns Object with client and dashcam instances
|
|
103
|
-
*
|
|
104
|
-
* @example
|
|
105
|
-
* test('my test', async (context) => {
|
|
106
|
-
* const { client, dashcam } = useTestDriverWithDashcam(context, {
|
|
107
|
-
* os: 'linux'
|
|
55
|
+
* describe("My Test Suite", () => {
|
|
56
|
+
* it("should do something", async (context) => {
|
|
57
|
+
* const testdriver = TestDriver(context, { newSandbox: true, headless: false });
|
|
58
|
+
*
|
|
59
|
+
* await testdriver.provision.chrome({ url: 'https://example.com' });
|
|
60
|
+
*
|
|
61
|
+
* const button = await testdriver.find("Sign In button");
|
|
62
|
+
* await button.click();
|
|
63
|
+
*
|
|
64
|
+
* const result = await testdriver.assert("the dashboard is visible");
|
|
65
|
+
* expect(result).toBeTruthy();
|
|
108
66
|
* });
|
|
109
|
-
*
|
|
110
|
-
* await client.find('button').click();
|
|
111
67
|
* });
|
|
112
68
|
*/
|
|
113
|
-
export function
|
|
114
|
-
context: VitestContext,
|
|
115
|
-
options?: UseTestDriverOptions & UseDashcamOptions
|
|
116
|
-
): {
|
|
117
|
-
client: TestDriver;
|
|
118
|
-
dashcam: Dashcam;
|
|
119
|
-
};
|
|
69
|
+
export function TestDriver(context: VitestContext, options?: TestDriverHookOptions): TestDriverSDK;
|
package/package.json
CHANGED
|
@@ -1,15 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "testdriverai",
|
|
3
|
-
"version": "7.2.
|
|
3
|
+
"version": "7.2.39",
|
|
4
4
|
"description": "Next generation autonomous AI agent for end-to-end testing of web & desktop",
|
|
5
5
|
"main": "sdk.js",
|
|
6
|
+
"types": "sdk.d.ts",
|
|
6
7
|
"exports": {
|
|
7
|
-
".":
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./sdk.d.ts",
|
|
10
|
+
"default": "./sdk.js"
|
|
11
|
+
},
|
|
12
|
+
"./core": {
|
|
13
|
+
"types": "./lib/core/index.d.ts",
|
|
14
|
+
"default": "./lib/core/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./vitest": {
|
|
17
|
+
"types": "./interfaces/vitest-plugin.d.ts",
|
|
18
|
+
"default": "./interfaces/vitest-plugin.mjs"
|
|
19
|
+
},
|
|
20
|
+
"./vitest/plugin": {
|
|
21
|
+
"types": "./interfaces/vitest-plugin.d.ts",
|
|
22
|
+
"default": "./interfaces/vitest-plugin.mjs"
|
|
23
|
+
},
|
|
11
24
|
"./vitest/setup": "./lib/vitest/setup.mjs",
|
|
12
|
-
"./vitest/hooks":
|
|
25
|
+
"./vitest/hooks": {
|
|
26
|
+
"types": "./lib/vitest/hooks.d.ts",
|
|
27
|
+
"default": "./lib/vitest/hooks.mjs"
|
|
28
|
+
},
|
|
13
29
|
"./presets": "./lib/presets/index.mjs"
|
|
14
30
|
},
|
|
15
31
|
"bin": {
|
|
@@ -47,12 +63,12 @@
|
|
|
47
63
|
"license": "ISC",
|
|
48
64
|
"dependencies": {
|
|
49
65
|
"@npmcli/redact": "^3.2.2",
|
|
50
|
-
"@octokit/rest": "^20.1.1",
|
|
51
66
|
"@oclif/core": "^4.5.0",
|
|
52
67
|
"@oclif/plugin-commands": "^4.1.28",
|
|
53
68
|
"@oclif/plugin-help": "^6.2.30",
|
|
54
69
|
"@oclif/plugin-not-found": "^3.2.59",
|
|
55
70
|
"@oclif/plugin-warn-if-update-available": "^3.1.43",
|
|
71
|
+
"@octokit/rest": "^20.1.1",
|
|
56
72
|
"@sentry/node": "^9.47.1",
|
|
57
73
|
"@stoplight/yaml-ast-parser": "^0.0.50",
|
|
58
74
|
"ajv": "^8.17.1",
|
|
@@ -107,7 +123,6 @@
|
|
|
107
123
|
"mocha": "^10.8.2",
|
|
108
124
|
"node-addon-api": "^8.0.0",
|
|
109
125
|
"prettier": "3.3.3",
|
|
110
|
-
"testdriverai": "^7.2.3",
|
|
111
126
|
"vitest": "^4.0.16"
|
|
112
127
|
},
|
|
113
128
|
"optionalDependencies": {
|
package/sdk.d.ts
CHANGED
|
@@ -683,9 +683,139 @@ export class Element {
|
|
|
683
683
|
readonly label: string | null;
|
|
684
684
|
}
|
|
685
685
|
|
|
686
|
+
// ====================================
|
|
687
|
+
// Provision API Interfaces
|
|
688
|
+
// ====================================
|
|
689
|
+
|
|
690
|
+
/** Options for provision.chrome */
|
|
691
|
+
export interface ProvisionChromeOptions {
|
|
692
|
+
/** URL to navigate to (default: 'http://testdriver-sandbox.vercel.app/') */
|
|
693
|
+
url?: string;
|
|
694
|
+
/** Start maximized (default: true) */
|
|
695
|
+
maximized?: boolean;
|
|
696
|
+
/** Use guest mode (default: false) */
|
|
697
|
+
guest?: boolean;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/** Options for provision.chromeExtension */
|
|
701
|
+
export interface ProvisionChromeExtensionOptions {
|
|
702
|
+
/** Local filesystem path to the unpacked extension directory */
|
|
703
|
+
extensionPath?: string;
|
|
704
|
+
/** Chrome Web Store extension ID */
|
|
705
|
+
extensionId?: string;
|
|
706
|
+
/** Start maximized (default: true) */
|
|
707
|
+
maximized?: boolean;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
/** Options for provision.vscode */
|
|
711
|
+
export interface ProvisionVSCodeOptions {
|
|
712
|
+
/** Path to workspace or folder to open */
|
|
713
|
+
workspace?: string;
|
|
714
|
+
/** Array of extension IDs to install */
|
|
715
|
+
extensions?: string[];
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/** Options for provision.installer */
|
|
719
|
+
export interface ProvisionInstallerOptions {
|
|
720
|
+
/** URL to download the installer from */
|
|
721
|
+
url: string;
|
|
722
|
+
/** Filename to save as (auto-detected from URL if not provided) */
|
|
723
|
+
filename?: string;
|
|
724
|
+
/** Application name to focus after install */
|
|
725
|
+
appName?: string;
|
|
726
|
+
/** Whether to launch the app after installation (default: true) */
|
|
727
|
+
launch?: boolean;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/** Options for provision.electron */
|
|
731
|
+
export interface ProvisionElectronOptions {
|
|
732
|
+
/** Path to Electron app (required) */
|
|
733
|
+
appPath: string;
|
|
734
|
+
/** Additional electron args */
|
|
735
|
+
args?: string[];
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/** Provision API for launching applications */
|
|
739
|
+
export interface ProvisionAPI {
|
|
740
|
+
/**
|
|
741
|
+
* Launch Chrome browser
|
|
742
|
+
* @param options - Chrome launch options
|
|
743
|
+
*/
|
|
744
|
+
chrome(options?: ProvisionChromeOptions): Promise<void>;
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* Launch Chrome browser with a custom extension loaded
|
|
748
|
+
* @param options - Chrome extension launch options
|
|
749
|
+
*/
|
|
750
|
+
chromeExtension(options?: ProvisionChromeExtensionOptions): Promise<void>;
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Launch VS Code
|
|
754
|
+
* @param options - VS Code launch options
|
|
755
|
+
*/
|
|
756
|
+
vscode(options?: ProvisionVSCodeOptions): Promise<void>;
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* Download and install an application
|
|
760
|
+
* @param options - Installer options
|
|
761
|
+
* @returns Path to the downloaded file
|
|
762
|
+
*/
|
|
763
|
+
installer(options: ProvisionInstallerOptions): Promise<string>;
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* Launch Electron app
|
|
767
|
+
* @param options - Electron launch options
|
|
768
|
+
*/
|
|
769
|
+
electron(options: ProvisionElectronOptions): Promise<void>;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/** Dashcam API for screen recording */
|
|
773
|
+
export interface DashcamAPI {
|
|
774
|
+
/**
|
|
775
|
+
* Start recording
|
|
776
|
+
*/
|
|
777
|
+
start(): Promise<void>;
|
|
778
|
+
|
|
779
|
+
/**
|
|
780
|
+
* Stop recording and get replay URL
|
|
781
|
+
*/
|
|
782
|
+
stop(): Promise<string | null>;
|
|
783
|
+
|
|
784
|
+
/**
|
|
785
|
+
* Check if currently recording
|
|
786
|
+
*/
|
|
787
|
+
isRecording(): boolean;
|
|
788
|
+
}
|
|
789
|
+
|
|
686
790
|
export default class TestDriverSDK {
|
|
687
791
|
constructor(apiKey: string, options?: TestDriverOptions);
|
|
688
792
|
|
|
793
|
+
/**
|
|
794
|
+
* Whether the SDK is currently connected to a sandbox
|
|
795
|
+
*/
|
|
796
|
+
readonly connected: boolean;
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* The operating system of the sandbox
|
|
800
|
+
*/
|
|
801
|
+
readonly os: 'windows' | 'linux';
|
|
802
|
+
|
|
803
|
+
/**
|
|
804
|
+
* Provision API for launching applications
|
|
805
|
+
*/
|
|
806
|
+
readonly provision: ProvisionAPI;
|
|
807
|
+
|
|
808
|
+
/**
|
|
809
|
+
* Dashcam API for screen recording
|
|
810
|
+
*/
|
|
811
|
+
readonly dashcam: DashcamAPI;
|
|
812
|
+
|
|
813
|
+
/**
|
|
814
|
+
* Wait for the sandbox to be ready
|
|
815
|
+
* Called automatically by provision methods
|
|
816
|
+
*/
|
|
817
|
+
ready(): Promise<void>;
|
|
818
|
+
|
|
689
819
|
/**
|
|
690
820
|
* Authenticate with TestDriver API
|
|
691
821
|
*/
|
|
@@ -168,8 +168,8 @@ Resources:
|
|
|
168
168
|
IpProtocol: tcp,
|
|
169
169
|
FromPort: 8765,
|
|
170
170
|
ToPort: 8765,
|
|
171
|
-
CidrIp:
|
|
172
|
-
Description: "pyautogui-cli WebSockets
|
|
171
|
+
CidrIp: !Ref AllowedIngressCidr,
|
|
172
|
+
Description: "pyautogui-cli WebSockets"
|
|
173
173
|
}
|
|
174
174
|
- {
|
|
175
175
|
IpProtocol: tcp,
|
|
@@ -8,7 +8,7 @@ import { TestDriver } from "../../lib/vitest/hooks.mjs";
|
|
|
8
8
|
|
|
9
9
|
describe("Hover Text Test", () => {
|
|
10
10
|
it("should click Sign In and verify error message", async (context) => {
|
|
11
|
-
const testdriver = TestDriver(context, { headless: false,
|
|
11
|
+
const testdriver = TestDriver(context, { headless: false, ip: '3.138.116.105'});
|
|
12
12
|
await testdriver.provision.chrome({ url: 'http://testdriver-sandbox.vercel.app/login' });
|
|
13
13
|
|
|
14
14
|
// Click on Sign In button using new find() API
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
name: TestDriver Tests with GitHub Comments
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
types: [opened, synchronize, reopened]
|
|
6
|
-
push:
|
|
7
|
-
branches: [main]
|
|
8
|
-
workflow_dispatch: # Allows manual trigger from Actions tab
|
|
9
|
-
|
|
10
|
-
jobs:
|
|
11
|
-
test:
|
|
12
|
-
runs-on: ubuntu-latest
|
|
13
|
-
|
|
14
|
-
permissions:
|
|
15
|
-
contents: read
|
|
16
|
-
pull-requests: write # Required to post comments on PRs
|
|
17
|
-
|
|
18
|
-
steps:
|
|
19
|
-
- name: Checkout code
|
|
20
|
-
uses: actions/checkout@v4
|
|
21
|
-
|
|
22
|
-
- name: Setup Node.js
|
|
23
|
-
uses: actions/setup-node@v4
|
|
24
|
-
with:
|
|
25
|
-
node-version: '20'
|
|
26
|
-
cache: 'npm'
|
|
27
|
-
|
|
28
|
-
- name: Install dependencies
|
|
29
|
-
run: npm ci
|
|
30
|
-
|
|
31
|
-
- name: Run assert test with GitHub comments
|
|
32
|
-
env:
|
|
33
|
-
# TestDriver API key (from repository secrets)
|
|
34
|
-
TD_API_KEY: ${{ secrets.TD_API_KEY }}
|
|
35
|
-
|
|
36
|
-
# GitHub token for posting comments (auto-provided)
|
|
37
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
38
|
-
|
|
39
|
-
# PR number for PR comments (auto-extracted for pull_request events)
|
|
40
|
-
GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
41
|
-
|
|
42
|
-
# Git information (automatically provided by GitHub Actions)
|
|
43
|
-
# GITHUB_SHA, GITHUB_REF, GITHUB_REPOSITORY are already set
|
|
44
|
-
|
|
45
|
-
run: |
|
|
46
|
-
echo "🚀 Running TestDriver assert test..."
|
|
47
|
-
echo "📍 Repository: $GITHUB_REPOSITORY"
|
|
48
|
-
echo "🔢 PR Number: ${{ github.event.pull_request.number || 'N/A (not a PR)' }}"
|
|
49
|
-
echo "📦 Running test..."
|
|
50
|
-
npm run test:sdk -- test/testdriver/assert.test.mjs
|
|
51
|
-
|
|
52
|
-
- name: Upload test results (on failure)
|
|
53
|
-
if: failure()
|
|
54
|
-
uses: actions/upload-artifact@v4
|
|
55
|
-
with:
|
|
56
|
-
name: test-results
|
|
57
|
-
path: |
|
|
58
|
-
test-report.junit.xml
|
|
59
|
-
.testdriver/
|
|
60
|
-
retention-days: 7
|
|
61
|
-
|
|
62
|
-
- name: Comment on PR (manual fallback if auto-comment fails)
|
|
63
|
-
if: failure() && github.event_name == 'pull_request'
|
|
64
|
-
uses: actions/github-script@v7
|
|
65
|
-
with:
|
|
66
|
-
script: |
|
|
67
|
-
const testRunUrl = process.env.TESTDRIVER_RUN_URL || 'Check workflow logs';
|
|
68
|
-
github.rest.issues.createComment({
|
|
69
|
-
issue_number: context.issue.number,
|
|
70
|
-
owner: context.repo.owner,
|
|
71
|
-
repo: context.repo.repo,
|
|
72
|
-
body: `⚠️ TestDriver tests encountered an error. ${testRunUrl}`
|
|
73
|
-
})
|