testdriverai 7.2.55 → 7.2.57
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/acceptance-windows-scheduled.yaml +29 -28
- package/.github/workflows/acceptance.yaml +54 -52
- package/.github/workflows/testdriver.yml +157 -156
- package/.github/workflows/windows-self-hosted.yaml +60 -46
- package/docs/docs.json +1 -0
- package/docs/v7/captcha.mdx +160 -0
- package/examples/captcha-api.test.mjs +50 -0
- package/examples/hover-text-with-description.test.mjs +9 -6
- package/interfaces/cli/commands/init.js +48 -21
- package/lib/captcha/solver.js +296 -0
- package/lib/core/Dashcam.js +135 -95
- package/lib/vitest/hooks.mjs +175 -126
- package/lib/vitest/setup-aws.mjs +69 -46
- package/package.json +1 -1
- package/sdk.d.ts +67 -20
- package/sdk.js +733 -402
- package/test/captcha-solver.test.mjs +70 -0
- package/test/chrome-remote-debugging.test.mjs +66 -0
- package/vitest.config.mjs +10 -6
|
@@ -4,13 +4,15 @@ on:
|
|
|
4
4
|
workflow_call:
|
|
5
5
|
inputs:
|
|
6
6
|
test_pattern:
|
|
7
|
-
description:
|
|
7
|
+
description: "Test file pattern to run"
|
|
8
8
|
required: false
|
|
9
9
|
type: string
|
|
10
|
-
default:
|
|
10
|
+
default: "examples/*.test.mjs"
|
|
11
11
|
secrets:
|
|
12
12
|
TD_API_KEY:
|
|
13
13
|
required: true
|
|
14
|
+
TWOCAPTCHA_API_KEY:
|
|
15
|
+
required: true
|
|
14
16
|
TD_WEBSITE:
|
|
15
17
|
required: false
|
|
16
18
|
AWS_ACCESS_KEY_ID:
|
|
@@ -21,48 +23,60 @@ on:
|
|
|
21
23
|
jobs:
|
|
22
24
|
test:
|
|
23
25
|
runs-on: ubuntu-latest
|
|
24
|
-
|
|
26
|
+
|
|
25
27
|
steps:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
28
|
+
- name: Checkout repository
|
|
29
|
+
uses: actions/checkout@v4
|
|
30
|
+
with:
|
|
31
|
+
fetch-depth: 0
|
|
32
|
+
|
|
33
|
+
- name: Set up Node.js
|
|
34
|
+
uses: actions/setup-node@v4
|
|
35
|
+
with:
|
|
36
|
+
node-version: "20"
|
|
37
|
+
cache: "npm"
|
|
38
|
+
|
|
39
|
+
- name: Install dependencies
|
|
40
|
+
run: npm ci
|
|
41
|
+
|
|
42
|
+
- name: Debug Environment
|
|
43
|
+
run: |
|
|
44
|
+
echo "Checking environment variables..."
|
|
45
|
+
if [ -n "${{ secrets.TWOCAPTCHA_API_KEY }}" ]; then
|
|
46
|
+
echo "TWOCAPTCHA_API_KEY is set (length: ${#TWOCAPTCHA_API_KEY})"
|
|
47
|
+
else
|
|
48
|
+
echo "TWOCAPTCHA_API_KEY is NOT set"
|
|
49
|
+
fi
|
|
50
|
+
env:
|
|
51
|
+
TWOCAPTCHA_API_KEY: ${{ secrets.TWOCAPTCHA_API_KEY }}
|
|
52
|
+
|
|
53
|
+
- name: Run Windows tests with self-hosted instances
|
|
54
|
+
run: npx vitest run ${{ inputs.test_pattern }}
|
|
55
|
+
env:
|
|
56
|
+
TD_API_KEY: ${{ secrets.TD_API_KEY }}
|
|
57
|
+
TWOCAPTCHA_API_KEY: ${{ secrets.TWOCAPTCHA_API_KEY }}
|
|
58
|
+
TD_WEBSITE: ${{ secrets.TD_WEBSITE }}
|
|
59
|
+
TD_OS: windows
|
|
60
|
+
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
61
|
+
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
62
|
+
AWS_REGION: us-east-2
|
|
63
|
+
AWS_LAUNCH_TEMPLATE_ID: lt-0ef9bf26a945fb442
|
|
64
|
+
AMI_ID: ami-0dd5fa241273a7d50
|
|
65
|
+
RESOLUTION: 1920x1080
|
|
66
|
+
|
|
67
|
+
- name: Upload test results
|
|
68
|
+
if: always()
|
|
69
|
+
uses: actions/upload-artifact@v4
|
|
70
|
+
with:
|
|
71
|
+
name: test-results-windows
|
|
72
|
+
path: test-report.junit.xml
|
|
73
|
+
retention-days: 30
|
|
74
|
+
|
|
75
|
+
- name: Upload TestDriver AI CLI logs
|
|
76
|
+
if: always()
|
|
77
|
+
uses: actions/upload-artifact@v4
|
|
78
|
+
with:
|
|
79
|
+
name: testdriverai-cli-logs-windows
|
|
80
|
+
path: /tmp/testdriverai-cli-*.log
|
|
81
|
+
if-no-files-found: warn
|
|
82
|
+
retention-days: 30
|
package/docs/docs.json
CHANGED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "captcha()"
|
|
3
|
+
sidebarTitle: "captcha"
|
|
4
|
+
description: "Solve captchas using 2captcha service"
|
|
5
|
+
icon: "shield-check"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Captcha Solving
|
|
9
|
+
|
|
10
|
+
TestDriver can automatically solve captchas during your tests using the 2captcha service. This feature works on both **Linux** and **Windows** sandboxes.
|
|
11
|
+
|
|
12
|
+
## Quick Start
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
const result = await testdriver.captcha({
|
|
17
|
+
apiKey: process.env.TWOCAPTCHA_API_KEY,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
console.log(result.success); // true
|
|
21
|
+
console.log(result.token); // The solved captcha token
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
That's it! TestDriver will automatically:
|
|
25
|
+
- Detect the captcha type on the page
|
|
26
|
+
- Extract the sitekey
|
|
27
|
+
- Solve the captcha via 2captcha
|
|
28
|
+
- Inject the token into the page
|
|
29
|
+
- Trigger any callbacks
|
|
30
|
+
|
|
31
|
+
## Supported Captcha Types
|
|
32
|
+
|
|
33
|
+
| Type | Auto-Detected | Notes |
|
|
34
|
+
|------|---------------|-------|
|
|
35
|
+
| reCAPTCHA v2 | ✅ | Including invisible |
|
|
36
|
+
| reCAPTCHA v3 | ✅ | Action is auto-detected |
|
|
37
|
+
| hCaptcha | ✅ | |
|
|
38
|
+
| Cloudflare Turnstile | ✅ | |
|
|
39
|
+
|
|
40
|
+
## Getting a 2captcha API Key
|
|
41
|
+
|
|
42
|
+
1. Sign up at [2captcha.com](https://2captcha.com)
|
|
43
|
+
2. Add funds to your account
|
|
44
|
+
3. Copy your API key from the dashboard
|
|
45
|
+
|
|
46
|
+
## Configuration Options
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
const result = await testdriver.captcha({
|
|
50
|
+
// Required
|
|
51
|
+
apiKey: '2CAPTCHA_API_KEY',
|
|
52
|
+
|
|
53
|
+
// Optional - usually auto-detected
|
|
54
|
+
sitekey: '6Le...', // Override auto-detected sitekey
|
|
55
|
+
type: 'recaptcha_v3', // Override auto-detected type
|
|
56
|
+
action: 'submit', // reCAPTCHA v3 action
|
|
57
|
+
|
|
58
|
+
// Timing
|
|
59
|
+
timeout: 120000, // Max wait time (default: 120s)
|
|
60
|
+
pollInterval: 5000, // Poll interval (default: 5s)
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Full Example
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
import { describe, expect, it } from "vitest";
|
|
68
|
+
import { TestDriver } from "testdriver";
|
|
69
|
+
|
|
70
|
+
describe("Checkout flow", () => {
|
|
71
|
+
it("should complete checkout with captcha", async (context) => {
|
|
72
|
+
const testdriver = TestDriver(context);
|
|
73
|
+
|
|
74
|
+
// Navigate to checkout page
|
|
75
|
+
await testdriver.provision.chrome({
|
|
76
|
+
url: 'https://example.com/checkout',
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Fill out form
|
|
80
|
+
await testdriver.type({ text: 'John Doe', selector: '#name' });
|
|
81
|
+
await testdriver.type({ text: 'john@example.com', selector: '#email' });
|
|
82
|
+
|
|
83
|
+
// Solve the captcha
|
|
84
|
+
const result = await testdriver.captcha({
|
|
85
|
+
apiKey: process.env.TWOCAPTCHA_API_KEY,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
expect(result.success).toBe(true);
|
|
89
|
+
|
|
90
|
+
// Submit the form
|
|
91
|
+
await testdriver.click({ selector: '#submit' });
|
|
92
|
+
|
|
93
|
+
// Verify success
|
|
94
|
+
await testdriver.find({ text: 'Order confirmed' });
|
|
95
|
+
}, 180000);
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Environment Variables
|
|
100
|
+
|
|
101
|
+
You can set your API key as an environment variable:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
export TWOCAPTCHA_API_KEY=your_api_key_here
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Then use it in your tests:
|
|
108
|
+
|
|
109
|
+
```javascript
|
|
110
|
+
```javascript
|
|
111
|
+
const result = await testdriver.captcha({
|
|
112
|
+
apiKey: process.env.TWOCAPTCHA_API_KEY,
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### GitHub Actions
|
|
117
|
+
|
|
118
|
+
Add the key to your repository secrets and expose it in your workflow:
|
|
119
|
+
|
|
120
|
+
```yaml
|
|
121
|
+
- name: Run Tests
|
|
122
|
+
run: npm test
|
|
123
|
+
env:
|
|
124
|
+
TWOCAPTCHA_API_KEY: ${{ secrets.TWOCAPTCHA_API_KEY }}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## How It Works
|
|
128
|
+
|
|
129
|
+
1. **Detection**: Scans the page for captcha elements (`data-sitekey`, script tags, etc.)
|
|
130
|
+
2. **Submit**: Sends the captcha challenge to 2captcha's solving service
|
|
131
|
+
3. **Poll**: Waits for human solvers to complete the captcha
|
|
132
|
+
4. **Inject**: Injects the solved token into the page's hidden fields
|
|
133
|
+
5. **Callback**: Triggers any JavaScript callbacks the page expects
|
|
134
|
+
|
|
135
|
+
## Troubleshooting
|
|
136
|
+
|
|
137
|
+
### "Could not auto-detect captcha"
|
|
138
|
+
|
|
139
|
+
The captcha element wasn't found on the page. Try:
|
|
140
|
+
- Waiting for the page to fully load before calling `captcha()`
|
|
141
|
+
- Providing the `sitekey` and `type` manually
|
|
142
|
+
|
|
143
|
+
### Timeout errors
|
|
144
|
+
|
|
145
|
+
Captcha solving typically takes 10-30 seconds. If you're getting timeouts:
|
|
146
|
+
- Increase the `timeout` option
|
|
147
|
+
- Check your 2captcha balance
|
|
148
|
+
- Verify the captcha type is correct
|
|
149
|
+
|
|
150
|
+
### Token not working
|
|
151
|
+
|
|
152
|
+
Some sites validate tokens immediately. Make sure:
|
|
153
|
+
- The token is injected before form submission
|
|
154
|
+
- The captcha type matches what the site expects
|
|
155
|
+
- For reCAPTCHA v3, the `action` parameter matches the site's expected action
|
|
156
|
+
|
|
157
|
+
## Requirements
|
|
158
|
+
|
|
159
|
+
- Chrome must be launched with remote debugging enabled (automatic on all sandboxes)
|
|
160
|
+
- A valid 2captcha API key with sufficient balance
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test for testdriver.captcha() API
|
|
3
|
+
* Clean, simple API for solving captchas
|
|
4
|
+
*/
|
|
5
|
+
import { describe, expect, it } from "vitest";
|
|
6
|
+
import { TestDriver } from "../lib/vitest/hooks.mjs";
|
|
7
|
+
|
|
8
|
+
console.log("DEBUG: process.env.TD_OS:", process.env.TD_OS);
|
|
9
|
+
|
|
10
|
+
describe("testdriver.captcha() API", () => {
|
|
11
|
+
it("should solve reCAPTCHA v3 with auto-detect", async (context) => {
|
|
12
|
+
const testdriver = TestDriver(context);
|
|
13
|
+
|
|
14
|
+
// Launch Chrome (remote debugging is enabled automatically on Linux)
|
|
15
|
+
await testdriver.provision.chrome({
|
|
16
|
+
url: "https://2captcha.com/demo/recaptcha-v3",
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
await testdriver.screenshot();
|
|
20
|
+
|
|
21
|
+
// Solve the captcha with just the API key - everything else is auto-detected!
|
|
22
|
+
const result = await testdriver.captcha({
|
|
23
|
+
apiKey: process.env.TWOCAPTCHA_API_KEY,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
console.log("Captcha result:", result);
|
|
27
|
+
await testdriver.screenshot();
|
|
28
|
+
|
|
29
|
+
expect(result.success).toBe(true);
|
|
30
|
+
}, 180000);
|
|
31
|
+
|
|
32
|
+
it("should solve Cloudflare Turnstile", async (context) => {
|
|
33
|
+
const testdriver = TestDriver(context);
|
|
34
|
+
|
|
35
|
+
await testdriver.provision.chrome({
|
|
36
|
+
url: "https://2captcha.com/demo/cloudflare-turnstile",
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
await testdriver.screenshot();
|
|
40
|
+
|
|
41
|
+
const result = await testdriver.captcha({
|
|
42
|
+
apiKey: process.env.TWOCAPTCHA_API_KEY,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
console.log("Turnstile result:", result);
|
|
46
|
+
await testdriver.screenshot();
|
|
47
|
+
|
|
48
|
+
expect(result.success).toBe(true);
|
|
49
|
+
}, 180000);
|
|
50
|
+
});
|
|
@@ -14,9 +14,7 @@ import { TestDriver } from "../lib/vitest/hooks.mjs";
|
|
|
14
14
|
async function performLogin(client, username = "standard_user") {
|
|
15
15
|
await client.focusApplication("Google Chrome");
|
|
16
16
|
const password = await client.extract("the password");
|
|
17
|
-
const usernameField = await client.find(
|
|
18
|
-
"username input",
|
|
19
|
-
);
|
|
17
|
+
const usernameField = await client.find("username input");
|
|
20
18
|
await usernameField.click();
|
|
21
19
|
await client.type(username);
|
|
22
20
|
await client.pressKeys(["tab"]);
|
|
@@ -27,8 +25,13 @@ async function performLogin(client, username = "standard_user") {
|
|
|
27
25
|
|
|
28
26
|
describe("Hover Text With Description Test", () => {
|
|
29
27
|
it("should add TestDriver Hat to cart and verify", async (context) => {
|
|
30
|
-
const testdriver = TestDriver(context, {
|
|
31
|
-
|
|
28
|
+
const testdriver = TestDriver(context, {
|
|
29
|
+
ip: context.ip || process.env.TD_IP,
|
|
30
|
+
headless: true,
|
|
31
|
+
});
|
|
32
|
+
await testdriver.provision.chrome({
|
|
33
|
+
url: "http://testdriver-sandbox.vercel.app/login",
|
|
34
|
+
});
|
|
32
35
|
|
|
33
36
|
//
|
|
34
37
|
// Perform login first
|
|
@@ -47,7 +50,7 @@ describe("Hover Text With Description Test", () => {
|
|
|
47
50
|
await cartButton.click();
|
|
48
51
|
|
|
49
52
|
// Assert the TestDriver Hat is in the cart
|
|
50
|
-
const result = await testdriver.assert("
|
|
53
|
+
const result = await testdriver.assert("There is an item in the cart");
|
|
51
54
|
expect(result).toBeTruthy();
|
|
52
55
|
});
|
|
53
56
|
});
|
|
@@ -37,16 +37,22 @@ class InitCommand extends BaseCommand {
|
|
|
37
37
|
if (fs.existsSync(envPath)) {
|
|
38
38
|
const envContent = fs.readFileSync(envPath, "utf8");
|
|
39
39
|
if (envContent.includes("TD_API_KEY=")) {
|
|
40
|
-
console.log(
|
|
40
|
+
console.log(
|
|
41
|
+
chalk.gray("\n API key already configured in .env, skipping...\n"),
|
|
42
|
+
);
|
|
41
43
|
return;
|
|
42
44
|
}
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
console.log(chalk.cyan(" Setting up your TestDriver API key...\n"));
|
|
46
|
-
console.log(
|
|
48
|
+
console.log(
|
|
49
|
+
chalk.gray(" Get your API key from: https://console.testdriver.ai/team"),
|
|
50
|
+
);
|
|
47
51
|
|
|
48
52
|
// Ask if user wants to open the browser
|
|
49
|
-
const shouldOpen = await this.askYesNo(
|
|
53
|
+
const shouldOpen = await this.askYesNo(
|
|
54
|
+
" Open API keys page in browser? (Y/n): ",
|
|
55
|
+
);
|
|
50
56
|
if (shouldOpen) {
|
|
51
57
|
try {
|
|
52
58
|
// Dynamic import for ES module
|
|
@@ -54,12 +60,16 @@ class InitCommand extends BaseCommand {
|
|
|
54
60
|
await open("https://console.testdriver.ai/team");
|
|
55
61
|
console.log(chalk.gray(" Opening browser...\n"));
|
|
56
62
|
} catch (error) {
|
|
57
|
-
console.log(
|
|
63
|
+
console.log(
|
|
64
|
+
chalk.yellow(" ⚠️ Could not open browser automatically\n"),
|
|
65
|
+
);
|
|
58
66
|
}
|
|
59
67
|
}
|
|
60
68
|
|
|
61
69
|
// Prompt for API key with hidden input
|
|
62
|
-
const apiKey = await this.promptHidden(
|
|
70
|
+
const apiKey = await this.promptHidden(
|
|
71
|
+
" Enter your API key (input will be hidden): ",
|
|
72
|
+
);
|
|
63
73
|
|
|
64
74
|
if (apiKey && apiKey.trim()) {
|
|
65
75
|
// Save to .env
|
|
@@ -70,7 +80,11 @@ class InitCommand extends BaseCommand {
|
|
|
70
80
|
fs.writeFileSync(envPath, envContent + `TD_API_KEY=${apiKey.trim()}\n`);
|
|
71
81
|
console.log(chalk.green("\n ✓ API key saved to .env\n"));
|
|
72
82
|
} else {
|
|
73
|
-
console.log(
|
|
83
|
+
console.log(
|
|
84
|
+
chalk.yellow(
|
|
85
|
+
"\n ⚠️ No API key entered. You can add it later to .env:\n",
|
|
86
|
+
),
|
|
87
|
+
);
|
|
74
88
|
console.log(chalk.gray(" TD_API_KEY=your_api_key\n"));
|
|
75
89
|
}
|
|
76
90
|
}
|
|
@@ -81,7 +95,7 @@ class InitCommand extends BaseCommand {
|
|
|
81
95
|
async promptHidden(question) {
|
|
82
96
|
return new Promise((resolve) => {
|
|
83
97
|
process.stdout.write(question);
|
|
84
|
-
|
|
98
|
+
|
|
85
99
|
const stdin = process.stdin;
|
|
86
100
|
const wasRaw = stdin.isRaw;
|
|
87
101
|
stdin.setRawMode(true);
|
|
@@ -131,7 +145,9 @@ class InitCommand extends BaseCommand {
|
|
|
131
145
|
rl.question(question, (answer) => {
|
|
132
146
|
rl.close();
|
|
133
147
|
const normalized = answer.toLowerCase().trim();
|
|
134
|
-
resolve(
|
|
148
|
+
resolve(
|
|
149
|
+
normalized === "" || normalized === "y" || normalized === "yes",
|
|
150
|
+
);
|
|
135
151
|
});
|
|
136
152
|
});
|
|
137
153
|
}
|
|
@@ -153,17 +169,20 @@ class InitCommand extends BaseCommand {
|
|
|
153
169
|
scripts: {
|
|
154
170
|
test: "vitest run",
|
|
155
171
|
"test:watch": "vitest",
|
|
156
|
-
"test:ui": "vitest --ui"
|
|
172
|
+
"test:ui": "vitest --ui",
|
|
157
173
|
},
|
|
158
174
|
keywords: ["testdriver", "testing", "e2e"],
|
|
159
175
|
author: "",
|
|
160
176
|
license: "ISC",
|
|
161
177
|
engines: {
|
|
162
|
-
node: ">=20.19.0"
|
|
163
|
-
}
|
|
178
|
+
node: ">=20.19.0",
|
|
179
|
+
},
|
|
164
180
|
};
|
|
165
181
|
|
|
166
|
-
fs.writeFileSync(
|
|
182
|
+
fs.writeFileSync(
|
|
183
|
+
packageJsonPath,
|
|
184
|
+
JSON.stringify(packageJson, null, 2) + "\n",
|
|
185
|
+
);
|
|
167
186
|
console.log(chalk.green(` Created package.json`));
|
|
168
187
|
} else {
|
|
169
188
|
console.log(chalk.gray(" package.json already exists, skipping..."));
|
|
@@ -249,7 +268,7 @@ test('should login and add item to cart', async (context) => {
|
|
|
249
268
|
await cartButton.click();
|
|
250
269
|
|
|
251
270
|
// Verify item in cart
|
|
252
|
-
const result = await testdriver.assert('
|
|
271
|
+
const result = await testdriver.assert('There is an item in the cart');
|
|
253
272
|
expect(result).toBeTruthy();
|
|
254
273
|
|
|
255
274
|
});
|
|
@@ -283,7 +302,6 @@ export default defineConfig({
|
|
|
283
302
|
fs.writeFileSync(configFile, configContent);
|
|
284
303
|
console.log(chalk.green(` Created config file: ${configFile}`));
|
|
285
304
|
}
|
|
286
|
-
|
|
287
305
|
}
|
|
288
306
|
|
|
289
307
|
/**
|
|
@@ -387,10 +405,13 @@ jobs:
|
|
|
387
405
|
console.log(chalk.cyan("\n Installing dependencies...\n"));
|
|
388
406
|
|
|
389
407
|
try {
|
|
390
|
-
execSync(
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
408
|
+
execSync(
|
|
409
|
+
"npm install -D vitest testdriverai@beta && npm install dotenv",
|
|
410
|
+
{
|
|
411
|
+
cwd: process.cwd(),
|
|
412
|
+
stdio: "inherit",
|
|
413
|
+
},
|
|
414
|
+
);
|
|
394
415
|
console.log(chalk.green("\n Dependencies installed successfully!"));
|
|
395
416
|
} catch (error) {
|
|
396
417
|
console.log(
|
|
@@ -410,10 +431,16 @@ jobs:
|
|
|
410
431
|
console.log(chalk.cyan("Next steps:\n"));
|
|
411
432
|
console.log(" 1. Run your tests:");
|
|
412
433
|
console.log(chalk.gray(" npx vitest run\n"));
|
|
413
|
-
console.log(" 2. For CI/CD, add TD_API_KEY to your GitHub repository secrets");
|
|
414
|
-
console.log(chalk.gray(" Settings → Secrets → Actions → New repository secret\n"));
|
|
415
434
|
console.log(
|
|
416
|
-
|
|
435
|
+
" 2. For CI/CD, add TD_API_KEY to your GitHub repository secrets",
|
|
436
|
+
);
|
|
437
|
+
console.log(
|
|
438
|
+
chalk.gray(" Settings → Secrets → Actions → New repository secret\n"),
|
|
439
|
+
);
|
|
440
|
+
console.log(
|
|
441
|
+
chalk.cyan(
|
|
442
|
+
"Learn more at https://docs.testdriver.ai/v7/getting-started/\n",
|
|
443
|
+
),
|
|
417
444
|
);
|
|
418
445
|
}
|
|
419
446
|
}
|