testdriverai 7.3.7 → 7.3.9
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/CHANGELOG.md +8 -0
- package/agent/lib/commands.js +24 -0
- package/agent/lib/sandbox.js +2 -0
- package/docs/_data/examples-manifest.json +64 -64
- package/docs/v7/examples/ai.mdx +1 -1
- package/docs/v7/examples/assert.mdx +1 -1
- package/docs/v7/examples/captcha-api.mdx +1 -1
- package/docs/v7/examples/chrome-extension.mdx +1 -1
- package/docs/v7/examples/drag-and-drop.mdx +1 -1
- package/docs/v7/examples/element-not-found.mdx +1 -1
- package/docs/v7/examples/hover-image.mdx +1 -1
- package/docs/v7/examples/hover-text.mdx +1 -1
- package/docs/v7/examples/installer.mdx +1 -1
- package/docs/v7/examples/launch-vscode-linux.mdx +1 -1
- package/docs/v7/examples/match-image.mdx +1 -1
- package/docs/v7/examples/press-keys.mdx +1 -1
- package/docs/v7/examples/scroll-keyboard.mdx +1 -1
- package/docs/v7/examples/scroll-until-image.mdx +1 -1
- package/docs/v7/examples/scroll-until-text.mdx +1 -1
- package/docs/v7/examples/scroll.mdx +1 -1
- package/docs/v7/examples/type.mdx +1 -1
- package/docs/v7/examples/windows-installer.mdx +1 -1
- package/examples/z_flake-shared.mjs +1 -0
- package/interfaces/vitest-plugin.d.ts +19 -5
- package/interfaces/vitest-plugin.mjs +87 -16
- package/lib/vitest/hooks.mjs +36 -7
- package/lib/vitest/setup.mjs +10 -8
- package/package.json +1 -1
- package/sdk.js +52 -23
- package/vitest.config.mjs +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## [7.3.9](https://github.com/testdriverai/testdriverai/compare/v7.3.8...v7.3.9) (2026-02-12)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
## [7.3.8](https://github.com/testdriverai/testdriverai/compare/v7.3.7...v7.3.8) (2026-02-12)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
1
9
|
## [7.3.7](https://github.com/testdriverai/testdriverai/compare/v7.3.6...v7.3.7) (2026-02-11)
|
|
2
10
|
|
|
3
11
|
|
package/agent/lib/commands.js
CHANGED
|
@@ -255,12 +255,17 @@ const createCommands = (
|
|
|
255
255
|
let cacheHit = false;
|
|
256
256
|
let similarity = null;
|
|
257
257
|
|
|
258
|
+
let confidence = null;
|
|
259
|
+
let reasoning = null;
|
|
260
|
+
|
|
258
261
|
if (typeof response.data === 'object' && response.data !== null) {
|
|
259
262
|
// New structured response
|
|
260
263
|
passed = response.data.passed;
|
|
261
264
|
responseText = response.data.content || response.data.reasoning || '';
|
|
262
265
|
cacheHit = response.cacheHit || response.data.cacheHit || false;
|
|
263
266
|
similarity = response.similarity || response.data.cacheSimilarity;
|
|
267
|
+
confidence = response.confidence != null ? response.confidence : (response.data.confidence != null ? response.data.confidence : null);
|
|
268
|
+
reasoning = response.data.reasoning || null;
|
|
264
269
|
} else {
|
|
265
270
|
// Old string response (backward compatibility)
|
|
266
271
|
responseText = response.data || '';
|
|
@@ -283,6 +288,10 @@ const createCommands = (
|
|
|
283
288
|
success: passed,
|
|
284
289
|
error: passed ? undefined : responseText,
|
|
285
290
|
cacheHit: cacheHit,
|
|
291
|
+
confidence: confidence,
|
|
292
|
+
reasoning: reasoning,
|
|
293
|
+
similarity: similarity,
|
|
294
|
+
screenshotUrl: response?.screenshotKey ?? null,
|
|
286
295
|
}).catch((err) => {
|
|
287
296
|
console.warn("Failed to track assert interaction:", err.message);
|
|
288
297
|
});
|
|
@@ -560,6 +569,10 @@ const createCommands = (
|
|
|
560
569
|
cacheHit: elementData.cacheHit,
|
|
561
570
|
selector: elementData.selector,
|
|
562
571
|
selectorUsed: elementData.selectorUsed,
|
|
572
|
+
confidence: elementData.confidence ?? null,
|
|
573
|
+
reasoning: elementData.reasoning ?? null,
|
|
574
|
+
similarity: elementData.similarity ?? null,
|
|
575
|
+
screenshotUrl: elementData.screenshotUrl ?? null,
|
|
563
576
|
}).catch((err) => {
|
|
564
577
|
console.warn("Failed to track click interaction:", err.message);
|
|
565
578
|
});
|
|
@@ -610,6 +623,9 @@ const createCommands = (
|
|
|
610
623
|
cacheHit: elementData.cacheHit,
|
|
611
624
|
selector: elementData.selector,
|
|
612
625
|
selectorUsed: elementData.selectorUsed,
|
|
626
|
+
confidence: elementData.confidence ?? null,
|
|
627
|
+
reasoning: elementData.reasoning ?? null,
|
|
628
|
+
similarity: elementData.similarity ?? null,
|
|
613
629
|
}).catch((err) => {
|
|
614
630
|
console.warn("Failed to track click interaction:", err.message);
|
|
615
631
|
});
|
|
@@ -679,6 +695,10 @@ const createCommands = (
|
|
|
679
695
|
cacheHit: elementData.cacheHit,
|
|
680
696
|
selector: elementData.selector,
|
|
681
697
|
selectorUsed: elementData.selectorUsed,
|
|
698
|
+
confidence: elementData.confidence ?? null,
|
|
699
|
+
reasoning: elementData.reasoning ?? null,
|
|
700
|
+
similarity: elementData.similarity ?? null,
|
|
701
|
+
screenshotUrl: elementData.screenshotUrl ?? null,
|
|
682
702
|
}).catch((err) => {
|
|
683
703
|
console.warn("Failed to track hover interaction:", err.message);
|
|
684
704
|
});
|
|
@@ -717,6 +737,10 @@ const createCommands = (
|
|
|
717
737
|
cacheHit: elementData.cacheHit,
|
|
718
738
|
selector: elementData.selector,
|
|
719
739
|
selectorUsed: elementData.selectorUsed,
|
|
740
|
+
confidence: elementData.confidence ?? null,
|
|
741
|
+
reasoning: elementData.reasoning ?? null,
|
|
742
|
+
similarity: elementData.similarity ?? null,
|
|
743
|
+
screenshotUrl: elementData.screenshotUrl ?? null,
|
|
720
744
|
}).catch((err) => {
|
|
721
745
|
console.warn("Failed to track hover interaction:", err.message);
|
|
722
746
|
});
|
package/agent/lib/sandbox.js
CHANGED
|
@@ -2,6 +2,7 @@ const WebSocket = require("ws");
|
|
|
2
2
|
const crypto = require("crypto");
|
|
3
3
|
const { events } = require("../events");
|
|
4
4
|
const logger = require("./logger");
|
|
5
|
+
const { version } = require("../../package.json");
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Generate Sentry trace headers for distributed tracing
|
|
@@ -135,6 +136,7 @@ const createSandbox = (emitter, analytics, sessionInstance) => {
|
|
|
135
136
|
let reply = await this.send({
|
|
136
137
|
type: "authenticate",
|
|
137
138
|
apiKey,
|
|
139
|
+
version,
|
|
138
140
|
});
|
|
139
141
|
|
|
140
142
|
if (reply.success) {
|
|
@@ -2,136 +2,136 @@
|
|
|
2
2
|
"$schema": "./examples-manifest.schema.json",
|
|
3
3
|
"examples": {
|
|
4
4
|
"assert.test.mjs": {
|
|
5
|
-
"url": "https://console.testdriver.ai/runs/
|
|
6
|
-
"lastUpdated": "2026-02-
|
|
5
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d16d4a2aa03cd95d96b60",
|
|
6
|
+
"lastUpdated": "2026-02-12T00:06:25.201Z"
|
|
7
7
|
},
|
|
8
8
|
"drag-and-drop.test.mjs": {
|
|
9
|
-
"url": "https://console.testdriver.ai/runs/
|
|
10
|
-
"lastUpdated": "2026-02-
|
|
9
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d1528a2aa03cd95d96a2c",
|
|
10
|
+
"lastUpdated": "2026-02-12T00:06:25.196Z"
|
|
11
11
|
},
|
|
12
12
|
"exec-pwsh.test.mjs": {
|
|
13
|
-
"url": "https://console.testdriver.ai/runs/
|
|
14
|
-
"lastUpdated": "2026-02-
|
|
13
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d152aa2aa03cd95d96a33",
|
|
14
|
+
"lastUpdated": "2026-02-12T00:06:25.197Z"
|
|
15
15
|
},
|
|
16
16
|
"match-image.test.mjs": {
|
|
17
|
-
"url": "https://console.testdriver.ai/runs/
|
|
18
|
-
"lastUpdated": "2026-02-
|
|
17
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d152ba2aa03cd95d96a34",
|
|
18
|
+
"lastUpdated": "2026-02-12T00:06:25.197Z"
|
|
19
19
|
},
|
|
20
20
|
"scroll-until-text.test.mjs": {
|
|
21
|
-
"url": "https://console.testdriver.ai/runs/
|
|
22
|
-
"lastUpdated": "2026-02-
|
|
21
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d1590a2aa03cd95d96a82",
|
|
22
|
+
"lastUpdated": "2026-02-12T00:06:25.198Z"
|
|
23
23
|
},
|
|
24
24
|
"hover-text-with-description.test.mjs": {
|
|
25
|
-
"url": "https://console.testdriver.ai/runs/
|
|
26
|
-
"lastUpdated": "2026-02-
|
|
25
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d157fa2aa03cd95d96a73",
|
|
26
|
+
"lastUpdated": "2026-02-12T00:06:25.197Z"
|
|
27
27
|
},
|
|
28
28
|
"windows-installer.test.mjs": {
|
|
29
|
-
"url": "https://console.testdriver.ai/runs/
|
|
30
|
-
"lastUpdated": "2026-02-
|
|
29
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d1591a2aa03cd95d96a84",
|
|
30
|
+
"lastUpdated": "2026-02-12T00:06:25.198Z"
|
|
31
31
|
},
|
|
32
32
|
"exec-output.test.mjs": {
|
|
33
|
-
"url": "https://console.testdriver.ai/runs/
|
|
34
|
-
"lastUpdated": "2026-02-
|
|
33
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d1592a2aa03cd95d96a85",
|
|
34
|
+
"lastUpdated": "2026-02-12T00:06:25.198Z"
|
|
35
35
|
},
|
|
36
36
|
"chrome-extension.test.mjs": {
|
|
37
|
-
"url": "https://console.testdriver.ai/runs/
|
|
38
|
-
"lastUpdated": "2026-02-
|
|
37
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d15eea2aa03cd95d96ac8",
|
|
38
|
+
"lastUpdated": "2026-02-12T00:06:25.198Z"
|
|
39
39
|
},
|
|
40
40
|
"launch-vscode-linux.test.mjs": {
|
|
41
|
-
"url": "https://console.testdriver.ai/runs/
|
|
42
|
-
"lastUpdated": "2026-02-
|
|
41
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d15eda2aa03cd95d96ac7",
|
|
42
|
+
"lastUpdated": "2026-02-12T00:06:25.198Z"
|
|
43
43
|
},
|
|
44
44
|
"hover-image.test.mjs": {
|
|
45
|
-
"url": "https://console.testdriver.ai/runs/
|
|
46
|
-
"lastUpdated": "2026-02-
|
|
45
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d15dfa2aa03cd95d96abd",
|
|
46
|
+
"lastUpdated": "2026-02-12T00:06:25.198Z"
|
|
47
47
|
},
|
|
48
48
|
"installer.test.mjs": {
|
|
49
|
-
"url": "https://console.testdriver.ai/runs/
|
|
50
|
-
"lastUpdated": "2026-02-
|
|
49
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d1640a2aa03cd95d96af3",
|
|
50
|
+
"lastUpdated": "2026-02-12T00:06:25.200Z"
|
|
51
51
|
},
|
|
52
52
|
"type.test.mjs": {
|
|
53
|
-
"url": "https://console.testdriver.ai/runs/
|
|
54
|
-
"lastUpdated": "2026-02-
|
|
53
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d1665a2aa03cd95d96b08",
|
|
54
|
+
"lastUpdated": "2026-02-12T00:06:25.200Z"
|
|
55
55
|
},
|
|
56
56
|
"press-keys.test.mjs": {
|
|
57
|
-
"url": "https://console.testdriver.ai/runs/
|
|
58
|
-
"lastUpdated": "2026-02-
|
|
57
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d16aca2aa03cd95d96b40",
|
|
58
|
+
"lastUpdated": "2026-02-12T00:06:25.201Z"
|
|
59
59
|
},
|
|
60
60
|
"scroll-keyboard.test.mjs": {
|
|
61
|
-
"url": "https://console.testdriver.ai/runs/
|
|
62
|
-
"lastUpdated": "2026-02-
|
|
61
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d169fa2aa03cd95d96b35",
|
|
62
|
+
"lastUpdated": "2026-02-12T00:06:25.201Z"
|
|
63
63
|
},
|
|
64
64
|
"scroll.test.mjs": {
|
|
65
|
-
"url": "https://console.testdriver.ai/runs/
|
|
66
|
-
"lastUpdated": "2026-02-
|
|
65
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d164ca2aa03cd95d96afc",
|
|
66
|
+
"lastUpdated": "2026-02-12T00:06:25.200Z"
|
|
67
67
|
},
|
|
68
68
|
"scroll-until-image.test.mjs": {
|
|
69
|
-
"url": "https://console.testdriver.ai/runs/
|
|
70
|
-
"lastUpdated": "2026-02-
|
|
69
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d16ada2aa03cd95d96b42",
|
|
70
|
+
"lastUpdated": "2026-02-12T00:06:25.201Z"
|
|
71
71
|
},
|
|
72
72
|
"prompt.test.mjs": {
|
|
73
|
-
"url": "https://console.testdriver.ai/runs/
|
|
74
|
-
"lastUpdated": "2026-02-
|
|
73
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d16afa2aa03cd95d96b43",
|
|
74
|
+
"lastUpdated": "2026-02-12T00:06:25.201Z"
|
|
75
75
|
},
|
|
76
76
|
"focus-window.test.mjs": {
|
|
77
|
-
"url": "https://console.testdriver.ai/runs/
|
|
78
|
-
"lastUpdated": "2026-02-
|
|
77
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d16b0a2aa03cd95d96b44",
|
|
78
|
+
"lastUpdated": "2026-02-12T00:06:25.201Z"
|
|
79
79
|
},
|
|
80
80
|
"captcha-api.test.mjs": {
|
|
81
|
-
"url": "https://console.testdriver.ai/runs/
|
|
82
|
-
"lastUpdated": "2026-02-
|
|
81
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d16cfa2aa03cd95d96b57",
|
|
82
|
+
"lastUpdated": "2026-02-12T00:06:25.201Z"
|
|
83
83
|
},
|
|
84
84
|
"element-not-found.test.mjs": {
|
|
85
|
-
"url": "https://console.testdriver.ai/runs/
|
|
86
|
-
"lastUpdated": "2026-02-
|
|
85
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d1705a2aa03cd95d96b79",
|
|
86
|
+
"lastUpdated": "2026-02-12T00:06:25.202Z"
|
|
87
87
|
},
|
|
88
88
|
"formatted-logging.test.mjs": {
|
|
89
|
-
"url": "https://console.testdriver.ai/runs/
|
|
90
|
-
"lastUpdated": "2026-02-
|
|
89
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d16eaa2aa03cd95d96b6b",
|
|
90
|
+
"lastUpdated": "2026-02-12T00:06:25.202Z"
|
|
91
91
|
},
|
|
92
92
|
"hover-text.test.mjs": {
|
|
93
|
-
"url": "https://console.testdriver.ai/runs/
|
|
94
|
-
"lastUpdated": "2026-02-
|
|
93
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d1724a2aa03cd95d96b8d",
|
|
94
|
+
"lastUpdated": "2026-02-12T00:06:25.203Z"
|
|
95
95
|
},
|
|
96
96
|
"no-provision.test.mjs": {
|
|
97
|
-
"url": "https://console.testdriver.ai/runs/
|
|
98
|
-
"lastUpdated": "2026-02-
|
|
97
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d173ea2aa03cd95d96b9d",
|
|
98
|
+
"lastUpdated": "2026-02-12T00:06:25.203Z"
|
|
99
99
|
},
|
|
100
100
|
"ai.test.mjs": {
|
|
101
|
-
"url": "https://console.testdriver.ai/runs/
|
|
102
|
-
"lastUpdated": "2026-02-
|
|
101
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d1763a2aa03cd95d96bae",
|
|
102
|
+
"lastUpdated": "2026-02-12T00:06:25.203Z"
|
|
103
103
|
},
|
|
104
104
|
"popup-loading.test.mjs": {
|
|
105
105
|
"url": "https://console.testdriver.ai/runs/698bc89f7140c3fa7daaca8d/698bca7f7140c3fa7daacbf7",
|
|
106
106
|
"lastUpdated": "2026-02-11T00:20:33.687Z"
|
|
107
107
|
},
|
|
108
108
|
"z_flake-diffthreshold-001.test.mjs": {
|
|
109
|
-
"url": "https://console.testdriver.ai/runs/
|
|
110
|
-
"lastUpdated": "2026-02-
|
|
109
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d186aa2aa03cd95d96c33",
|
|
110
|
+
"lastUpdated": "2026-02-12T00:06:25.204Z"
|
|
111
111
|
},
|
|
112
112
|
"z_flake-diffthreshold-01.test.mjs": {
|
|
113
|
-
"url": "https://console.testdriver.ai/runs/
|
|
114
|
-
"lastUpdated": "2026-02-
|
|
113
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d1838a2aa03cd95d96c16",
|
|
114
|
+
"lastUpdated": "2026-02-12T00:06:25.203Z"
|
|
115
115
|
},
|
|
116
116
|
"z_flake-diffthreshold-05.test.mjs": {
|
|
117
|
-
"url": "https://console.testdriver.ai/runs/
|
|
118
|
-
"lastUpdated": "2026-02-
|
|
117
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d183ba2aa03cd95d96c1d",
|
|
118
|
+
"lastUpdated": "2026-02-12T00:06:25.203Z"
|
|
119
119
|
},
|
|
120
120
|
"z_flake-noredraw-cache.test.mjs": {
|
|
121
|
-
"url": "https://console.testdriver.ai/runs/
|
|
122
|
-
"lastUpdated": "2026-02-
|
|
121
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d18b0a2aa03cd95d96c61",
|
|
122
|
+
"lastUpdated": "2026-02-12T00:06:25.205Z"
|
|
123
123
|
},
|
|
124
124
|
"z_flake-redraw-nocache.test.mjs": {
|
|
125
|
-
"url": "https://console.testdriver.ai/runs/
|
|
126
|
-
"lastUpdated": "2026-02-
|
|
125
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d1901a2aa03cd95d96c85",
|
|
126
|
+
"lastUpdated": "2026-02-12T00:06:25.205Z"
|
|
127
127
|
},
|
|
128
128
|
"z_flake-redraw-cache.test.mjs": {
|
|
129
|
-
"url": "https://console.testdriver.ai/runs/
|
|
130
|
-
"lastUpdated": "2026-02-
|
|
129
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d1976a2aa03cd95d96c9c",
|
|
130
|
+
"lastUpdated": "2026-02-12T00:06:25.205Z"
|
|
131
131
|
},
|
|
132
132
|
"z_flake-noredraw-nocache.test.mjs": {
|
|
133
|
-
"url": "https://console.testdriver.ai/runs/
|
|
134
|
-
"lastUpdated": "2026-02-
|
|
133
|
+
"url": "https://console.testdriver.ai/runs/698d1527a2aa03cd95d96a2b/698d190ca2aa03cd95d96c8a",
|
|
134
|
+
"lastUpdated": "2026-02-12T00:06:25.205Z"
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
}
|
package/docs/v7/examples/ai.mdx
CHANGED
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* ai.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/
|
|
15
|
+
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/698d1763a2aa03cd95d96bae/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* assert.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/
|
|
15
|
+
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/698d16d4a2aa03cd95d96b60/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* captcha-api.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/
|
|
15
|
+
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/698d16cfa2aa03cd95d96b57/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* chrome-extension.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/
|
|
15
|
+
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/698d15eea2aa03cd95d96ac8/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* drag-and-drop.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/
|
|
15
|
+
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/698d1528a2aa03cd95d96a2c/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* element-not-found.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/
|
|
15
|
+
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/698d1705a2aa03cd95d96b79/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* hover-image.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/
|
|
15
|
+
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/698d15dfa2aa03cd95d96abd/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* hover-text.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/
|
|
15
|
+
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/698d1724a2aa03cd95d96b8d/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* installer.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/
|
|
15
|
+
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/698d1640a2aa03cd95d96af3/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* launch-vscode-linux.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/
|
|
15
|
+
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/698d15eda2aa03cd95d96ac7/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* match-image.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/
|
|
15
|
+
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/698d152ba2aa03cd95d96a34/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* press-keys.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/
|
|
15
|
+
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/698d16aca2aa03cd95d96b40/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* scroll-keyboard.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/
|
|
15
|
+
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/698d169fa2aa03cd95d96b35/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* scroll-until-image.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/
|
|
15
|
+
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/698d16ada2aa03cd95d96b42/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* scroll-until-text.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/
|
|
15
|
+
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/698d1590a2aa03cd95d96a82/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* scroll.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/
|
|
15
|
+
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/698d164ca2aa03cd95d96afc/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* type.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/
|
|
15
|
+
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/698d1665a2aa03cd95d96b08/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -12,7 +12,7 @@ Watch this test execute in a real sandbox environment:
|
|
|
12
12
|
|
|
13
13
|
{/* windows-installer.test.mjs output */}
|
|
14
14
|
<iframe
|
|
15
|
-
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/
|
|
15
|
+
src="https://testdriver-api.onrender.com/api/v1/testdriver/testcase/698d1591a2aa03cd95d96a84/replay"
|
|
16
16
|
width="100%"
|
|
17
17
|
height="390"
|
|
18
18
|
style={{ border: "1px solid #333", borderRadius: "8px" }}
|
|
@@ -9,6 +9,7 @@ export function popupLoadingTest(label, options = {}) {
|
|
|
9
9
|
describe(`Popup with Loading (${label})`, () => {
|
|
10
10
|
it("should accept cookies and wait for completion", async (context) => {
|
|
11
11
|
const testdriver = TestDriver(context, {
|
|
12
|
+
preview: 'ide',
|
|
12
13
|
ip: context.ip || process.env.TD_IP,
|
|
13
14
|
...options,
|
|
14
15
|
});
|
|
@@ -5,11 +5,20 @@
|
|
|
5
5
|
|
|
6
6
|
import TestDriverSDK, { TestDriverOptions } from '../sdk';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* A single dashcam URL entry for one retry attempt
|
|
10
|
+
*/
|
|
11
|
+
export interface DashcamUrlEntry {
|
|
12
|
+
url: string | null;
|
|
13
|
+
platform: string;
|
|
14
|
+
attempt: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
8
17
|
/**
|
|
9
18
|
* Plugin state object
|
|
10
19
|
*/
|
|
11
20
|
export interface PluginState {
|
|
12
|
-
dashcamUrls: Map<string,
|
|
21
|
+
dashcamUrls: Map<string, DashcamUrlEntry[]>;
|
|
13
22
|
suiteTestRuns: Map<string, any>;
|
|
14
23
|
testDriverOptions: TestDriverOptions;
|
|
15
24
|
}
|
|
@@ -20,14 +29,19 @@ export interface PluginState {
|
|
|
20
29
|
export const pluginState: PluginState;
|
|
21
30
|
|
|
22
31
|
/**
|
|
23
|
-
* Register a Dashcam URL for a test
|
|
32
|
+
* Register a Dashcam URL for a test attempt
|
|
33
|
+
*/
|
|
34
|
+
export function registerDashcamUrl(testId: string, url: string, platform: string, attempt?: number): void;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get the latest Dashcam URL entry for a test (backward compatible)
|
|
24
38
|
*/
|
|
25
|
-
export function
|
|
39
|
+
export function getDashcamUrl(testId: string): DashcamUrlEntry | undefined;
|
|
26
40
|
|
|
27
41
|
/**
|
|
28
|
-
* Get Dashcam URL for a test
|
|
42
|
+
* Get all Dashcam URL entries for a test (all retry attempts)
|
|
29
43
|
*/
|
|
30
|
-
export function
|
|
44
|
+
export function getAllDashcamUrls(testId: string): DashcamUrlEntry[];
|
|
31
45
|
|
|
32
46
|
/**
|
|
33
47
|
* Clear all Dashcam URLs
|
|
@@ -9,6 +9,29 @@ import { setTestRunInfo } from "./shared-test-state.mjs";
|
|
|
9
9
|
// Use createRequire to import CommonJS modules without esbuild processing
|
|
10
10
|
const require = createRequire(import.meta.url);
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Resolve the TestDriver SDK version using multiple strategies.
|
|
14
|
+
* Similar to resolveVitestVersion(), guards against import.meta.url rewriting.
|
|
15
|
+
* @returns {string|null}
|
|
16
|
+
*/
|
|
17
|
+
function resolveTestDriverVersion() {
|
|
18
|
+
try {
|
|
19
|
+
return require("../package.json").version;
|
|
20
|
+
} catch {}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const cwdRequire = createRequire(path.join(process.cwd(), "package.json"));
|
|
24
|
+
return cwdRequire("testdriverai/package.json").version;
|
|
25
|
+
} catch {}
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const pkgPath = path.join(process.cwd(), "node_modules", "testdriverai", "package.json");
|
|
29
|
+
return JSON.parse(fs.readFileSync(pkgPath, "utf8")).version;
|
|
30
|
+
} catch {}
|
|
31
|
+
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
12
35
|
/**
|
|
13
36
|
* Minimum required Vitest major version
|
|
14
37
|
*/
|
|
@@ -170,21 +193,32 @@ export const pluginState = {
|
|
|
170
193
|
// TestDriver options to pass to all instances
|
|
171
194
|
testDriverOptions: {},
|
|
172
195
|
// Dashcam URL tracking (in-memory, no files needed!)
|
|
173
|
-
dashcamUrls: new Map(), // testId ->
|
|
196
|
+
dashcamUrls: new Map(), // testId -> [{url, platform, attempt}]
|
|
174
197
|
lastDashcamUrl: null, // Fallback for when test ID isn't available
|
|
175
198
|
// Suite-level test run tracking
|
|
176
199
|
suiteTestRuns: new Map(), // suiteId -> { runId, testRunDbId, token }
|
|
177
200
|
};
|
|
178
201
|
|
|
179
202
|
// Export functions that can be used by the reporter or tests
|
|
180
|
-
export function registerDashcamUrl(testId, url, platform) {
|
|
181
|
-
logger.debug(`Registering dashcam URL for test ${testId}:`, url);
|
|
182
|
-
|
|
203
|
+
export function registerDashcamUrl(testId, url, platform, attempt) {
|
|
204
|
+
logger.debug(`Registering dashcam URL for test ${testId} (attempt ${attempt || 1}):`, url);
|
|
205
|
+
// Support multiple attempts per test - store as array
|
|
206
|
+
if (!pluginState.dashcamUrls.has(testId)) {
|
|
207
|
+
pluginState.dashcamUrls.set(testId, []);
|
|
208
|
+
}
|
|
209
|
+
pluginState.dashcamUrls.get(testId).push({ url, platform, attempt: attempt || 1 });
|
|
183
210
|
pluginState.lastDashcamUrl = url;
|
|
184
211
|
}
|
|
185
212
|
|
|
186
213
|
export function getDashcamUrl(testId) {
|
|
187
|
-
|
|
214
|
+
const entries = pluginState.dashcamUrls.get(testId);
|
|
215
|
+
if (!entries) return undefined;
|
|
216
|
+
// Return the last entry for backward compatibility (single URL callers)
|
|
217
|
+
return entries[entries.length - 1];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function getAllDashcamUrls(testId) {
|
|
221
|
+
return pluginState.dashcamUrls.get(testId) || [];
|
|
188
222
|
}
|
|
189
223
|
|
|
190
224
|
export function clearDashcamUrls() {
|
|
@@ -743,6 +777,17 @@ class TestDriverReporter {
|
|
|
743
777
|
// Default to linux if no tests write platform info
|
|
744
778
|
testRunData.platform = "linux";
|
|
745
779
|
|
|
780
|
+
// Send version metadata
|
|
781
|
+
testRunData.nodeVersion = process.version;
|
|
782
|
+
const tdVer = resolveTestDriverVersion();
|
|
783
|
+
if (tdVer) {
|
|
784
|
+
testRunData.testDriverVersion = tdVer;
|
|
785
|
+
}
|
|
786
|
+
const vitestVer = resolveVitestVersion();
|
|
787
|
+
if (vitestVer) {
|
|
788
|
+
testRunData.vitestVersion = vitestVer;
|
|
789
|
+
}
|
|
790
|
+
|
|
746
791
|
logger.debug("Creating test run with data:", JSON.stringify(testRunData));
|
|
747
792
|
pluginState.testRun = await createTestRun(testRunData);
|
|
748
793
|
logger.debug("Test run created:", JSON.stringify(pluginState.testRun));
|
|
@@ -929,6 +974,7 @@ class TestDriverReporter {
|
|
|
929
974
|
logger.debug(`Test meta for ${test.id}:`, meta);
|
|
930
975
|
|
|
931
976
|
const dashcamUrl = meta.dashcamUrl || null;
|
|
977
|
+
const dashcamUrls = meta.dashcamUrls || []; // Per-attempt URLs
|
|
932
978
|
const sessionId = meta.sessionId || null;
|
|
933
979
|
const platform = meta.platform || null;
|
|
934
980
|
const sandboxId = meta.sandboxId || null;
|
|
@@ -986,8 +1032,12 @@ class TestDriverReporter {
|
|
|
986
1032
|
|
|
987
1033
|
const suiteName = test.suite?.name;
|
|
988
1034
|
const startTime = Date.now() - duration; // Calculate start time from duration
|
|
1035
|
+
const retryCount = result.retryCount || 0;
|
|
1036
|
+
const testRunDbId = process.env.TD_TEST_RUN_DB_ID;
|
|
1037
|
+
const consoleUrl = getConsoleUrl(pluginState.apiRoot);
|
|
1038
|
+
const hasRetries = retryCount > 0 && dashcamUrls.length > 1;
|
|
989
1039
|
|
|
990
|
-
// Record test case with all metadata
|
|
1040
|
+
// Record a single test case with all metadata
|
|
991
1041
|
const testCaseData = {
|
|
992
1042
|
runId: testRunId,
|
|
993
1043
|
testName: test.name,
|
|
@@ -997,7 +1047,7 @@ class TestDriverReporter {
|
|
|
997
1047
|
startTime: startTime,
|
|
998
1048
|
endTime: Date.now(),
|
|
999
1049
|
duration: duration,
|
|
1000
|
-
retries:
|
|
1050
|
+
retries: retryCount,
|
|
1001
1051
|
};
|
|
1002
1052
|
|
|
1003
1053
|
// Add sessionId if available
|
|
@@ -1010,6 +1060,13 @@ class TestDriverReporter {
|
|
|
1010
1060
|
testCaseData.replayUrl = dashcamUrl;
|
|
1011
1061
|
}
|
|
1012
1062
|
|
|
1063
|
+
// Include per-attempt replay URLs for retry visibility
|
|
1064
|
+
if (dashcamUrls.length > 0) {
|
|
1065
|
+
const attemptUrls = dashcamUrls
|
|
1066
|
+
.map(a => ({ attempt: a.attempt, url: a.url || null, sessionId: a.sessionId || null }));
|
|
1067
|
+
testCaseData.replayUrls = attemptUrls;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1013
1070
|
if (suiteName) testCaseData.suiteName = suiteName;
|
|
1014
1071
|
if (errorMessage) testCaseData.errorMessage = errorMessage;
|
|
1015
1072
|
if (errorStack) testCaseData.errorStack = errorStack;
|
|
@@ -1025,7 +1082,6 @@ class TestDriverReporter {
|
|
|
1025
1082
|
);
|
|
1026
1083
|
|
|
1027
1084
|
const testCaseDbId = testCaseResponse.data?.id;
|
|
1028
|
-
const testRunDbId = process.env.TD_TEST_RUN_DB_ID;
|
|
1029
1085
|
|
|
1030
1086
|
// Store test case data for GitHub comment generation
|
|
1031
1087
|
pluginState.recordedTestCases.push({
|
|
@@ -1035,14 +1091,25 @@ class TestDriverReporter {
|
|
|
1035
1091
|
|
|
1036
1092
|
console.log("");
|
|
1037
1093
|
console.log(
|
|
1038
|
-
`🔗 Test Report: ${
|
|
1094
|
+
`🔗 Test Report: ${consoleUrl}/runs/${testRunDbId}/${testCaseDbId}`,
|
|
1039
1095
|
);
|
|
1096
|
+
|
|
1097
|
+
// If there were retries, list all per-attempt dashcam URLs for debugging
|
|
1098
|
+
if (hasRetries) {
|
|
1099
|
+
const validAttempts = dashcamUrls.filter(a => a.url);
|
|
1100
|
+
if (validAttempts.length > 0) {
|
|
1101
|
+
console.log(`📋 Retry attempts (${dashcamUrls.length} total):`);
|
|
1102
|
+
for (const attempt of validAttempts) {
|
|
1103
|
+
console.log(` Attempt ${attempt.attempt}: ${attempt.url}`);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1040
1107
|
|
|
1041
1108
|
// Output parseable format for docs generation (examples only)
|
|
1042
1109
|
if (testFile.startsWith("examples/")) {
|
|
1043
1110
|
const testFileName = path.basename(testFile);
|
|
1044
1111
|
console.log(
|
|
1045
|
-
`TESTDRIVER_EXAMPLE_URL::${testFileName}::${
|
|
1112
|
+
`TESTDRIVER_EXAMPLE_URL::${testFileName}::${consoleUrl}/runs/${testRunDbId}/${testCaseDbId}`,
|
|
1046
1113
|
);
|
|
1047
1114
|
}
|
|
1048
1115
|
} catch (error) {
|
|
@@ -1099,12 +1166,16 @@ function getPlatform() {
|
|
|
1099
1166
|
}
|
|
1100
1167
|
|
|
1101
1168
|
// Try to get platform from dashcam URLs (registered during test cleanup)
|
|
1102
|
-
for (const [,
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
)
|
|
1107
|
-
|
|
1169
|
+
for (const [, entries] of pluginState.dashcamUrls) {
|
|
1170
|
+
// entries is now an array of {url, platform, attempt}
|
|
1171
|
+
const arr = Array.isArray(entries) ? entries : [entries];
|
|
1172
|
+
for (const data of arr) {
|
|
1173
|
+
if (data.platform) {
|
|
1174
|
+
logger.debug(
|
|
1175
|
+
`Using platform from dashcam URL registration: ${data.platform}`,
|
|
1176
|
+
);
|
|
1177
|
+
return data.platform;
|
|
1178
|
+
}
|
|
1108
1179
|
}
|
|
1109
1180
|
}
|
|
1110
1181
|
|
package/lib/vitest/hooks.mjs
CHANGED
|
@@ -415,11 +415,29 @@ export function TestDriver(context, options = {}) {
|
|
|
415
415
|
context.task.meta.testOrder = 0;
|
|
416
416
|
context.task.meta.sessionId = currentInstance.getSessionId?.() || null;
|
|
417
417
|
|
|
418
|
+
// Initialize dashcamUrls array for tracking per-attempt URLs (persists across retries)
|
|
419
|
+
if (!context.task.meta.dashcamUrls) {
|
|
420
|
+
context.task.meta.dashcamUrls = [];
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Determine the current attempt number (1-based)
|
|
424
|
+
const attemptNumber = context.task.meta.dashcamUrls.length + 1;
|
|
425
|
+
const isRetry = attemptNumber > 1;
|
|
426
|
+
const attemptLabel = isRetry ? ` (attempt ${attemptNumber})` : "";
|
|
427
|
+
|
|
418
428
|
// Stop dashcam if it was started - with timeout to prevent hanging
|
|
419
429
|
if (currentInstance._dashcam && currentInstance._dashcam.recording) {
|
|
420
430
|
try {
|
|
421
431
|
const dashcamUrl = await currentInstance.dashcam.stop();
|
|
422
|
-
|
|
432
|
+
|
|
433
|
+
// Track this attempt's URL in the per-attempt array
|
|
434
|
+
context.task.meta.dashcamUrls.push({
|
|
435
|
+
attempt: attemptNumber,
|
|
436
|
+
url: dashcamUrl || null,
|
|
437
|
+
sessionId: currentInstance.getSessionId?.() || null,
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
// Keep backward compatibility - last attempt's URL
|
|
423
441
|
context.task.meta.dashcamUrl = dashcamUrl || null;
|
|
424
442
|
|
|
425
443
|
// Also register in memory if plugin is available (for cross-process scenarios)
|
|
@@ -428,16 +446,15 @@ export function TestDriver(context, options = {}) {
|
|
|
428
446
|
context.task.id,
|
|
429
447
|
dashcamUrl,
|
|
430
448
|
platform,
|
|
449
|
+
attemptNumber,
|
|
431
450
|
);
|
|
432
451
|
}
|
|
433
452
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
if (debugMode) {
|
|
453
|
+
// Always print the dashcam URL for each attempt so it's visible in logs
|
|
454
|
+
if (dashcamUrl) {
|
|
438
455
|
console.log("");
|
|
439
456
|
console.log(
|
|
440
|
-
"🎥" + chalk.yellow(` Dashcam URL`) + `: ${dashcamUrl}`,
|
|
457
|
+
"🎥" + chalk.yellow(` Dashcam URL${attemptLabel}`) + `: ${dashcamUrl}`,
|
|
441
458
|
);
|
|
442
459
|
console.log("");
|
|
443
460
|
}
|
|
@@ -461,11 +478,23 @@ export function TestDriver(context, options = {}) {
|
|
|
461
478
|
if (currentInstance._dashcam) {
|
|
462
479
|
currentInstance._dashcam.recording = false;
|
|
463
480
|
}
|
|
481
|
+
// Track failed attempt
|
|
482
|
+
context.task.meta.dashcamUrls.push({
|
|
483
|
+
attempt: attemptNumber,
|
|
484
|
+
url: null,
|
|
485
|
+
sessionId: currentInstance.getSessionId?.() || null,
|
|
486
|
+
error: error.message,
|
|
487
|
+
});
|
|
464
488
|
// Ensure dashcamUrl is set to null if stop failed
|
|
465
489
|
context.task.meta.dashcamUrl = null;
|
|
466
490
|
}
|
|
467
491
|
} else {
|
|
468
|
-
// No dashcam recording
|
|
492
|
+
// No dashcam recording - still track the attempt
|
|
493
|
+
context.task.meta.dashcamUrls.push({
|
|
494
|
+
attempt: attemptNumber,
|
|
495
|
+
url: null,
|
|
496
|
+
sessionId: currentInstance.getSessionId?.() || null,
|
|
497
|
+
});
|
|
469
498
|
context.task.meta.dashcamUrl = null;
|
|
470
499
|
}
|
|
471
500
|
|
package/lib/vitest/setup.mjs
CHANGED
|
@@ -15,14 +15,15 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
clearDashcamUrls,
|
|
19
|
+
clearSuiteTestRun,
|
|
20
|
+
getAllDashcamUrls,
|
|
21
|
+
getDashcamUrl,
|
|
22
|
+
getPluginState,
|
|
23
|
+
getSuiteTestRun,
|
|
24
|
+
pluginState,
|
|
25
|
+
registerDashcamUrl,
|
|
26
|
+
setSuiteTestRun,
|
|
26
27
|
} from '../../interfaces/vitest-plugin.mjs';
|
|
27
28
|
|
|
28
29
|
// Set up global TestDriver plugin interface
|
|
@@ -31,6 +32,7 @@ globalThis.__testdriverPlugin = {
|
|
|
31
32
|
state: pluginState,
|
|
32
33
|
registerDashcamUrl,
|
|
33
34
|
getDashcamUrl,
|
|
35
|
+
getAllDashcamUrls,
|
|
34
36
|
clearDashcamUrls,
|
|
35
37
|
getPluginState,
|
|
36
38
|
getSuiteTestRun,
|
package/package.json
CHANGED
package/sdk.js
CHANGED
|
@@ -256,6 +256,7 @@ class ElementNotFoundError extends Error {
|
|
|
256
256
|
|
|
257
257
|
if (this.aiResponse) {
|
|
258
258
|
const responseText =
|
|
259
|
+
this.aiResponse.reasoning ||
|
|
259
260
|
this.aiResponse.response?.content?.[0]?.text ||
|
|
260
261
|
this.aiResponse.content?.[0]?.text ||
|
|
261
262
|
"No detailed response available";
|
|
@@ -603,6 +604,10 @@ class Element {
|
|
|
603
604
|
false,
|
|
604
605
|
selector: response?.selector,
|
|
605
606
|
selectorUsed: !!response?.selector,
|
|
607
|
+
confidence: response?.confidence ?? null,
|
|
608
|
+
reasoning: response?.reasoning ?? null,
|
|
609
|
+
similarity: response?.similarity ?? null,
|
|
610
|
+
screenshotUrl: response?.screenshotKey ?? null,
|
|
606
611
|
})
|
|
607
612
|
.catch((err) => {
|
|
608
613
|
console.warn("Failed to track find interaction:", err.message);
|
|
@@ -969,6 +974,10 @@ class Element {
|
|
|
969
974
|
cacheHit: this._response?.cacheHit,
|
|
970
975
|
selectorUsed: !!this._response?.selector,
|
|
971
976
|
selector: this._response?.selector,
|
|
977
|
+
confidence: this._response?.confidence ?? null,
|
|
978
|
+
reasoning: this._response?.reasoning ?? null,
|
|
979
|
+
similarity: this._response?.similarity ?? null,
|
|
980
|
+
screenshotUrl: this._response?.screenshotKey ?? null,
|
|
972
981
|
};
|
|
973
982
|
|
|
974
983
|
if (action === "hover") {
|
|
@@ -1018,6 +1027,7 @@ class Element {
|
|
|
1018
1027
|
cacheHit: this._response?.cacheHit,
|
|
1019
1028
|
selectorUsed: !!this._response?.selector,
|
|
1020
1029
|
selector: this._response?.selector,
|
|
1030
|
+
screenshotUrl: this._response?.screenshotKey ?? null,
|
|
1021
1031
|
};
|
|
1022
1032
|
|
|
1023
1033
|
await this.commands.hover(
|
|
@@ -1646,10 +1656,24 @@ class TestDriverSDK {
|
|
|
1646
1656
|
guest = false,
|
|
1647
1657
|
} = options;
|
|
1648
1658
|
|
|
1649
|
-
// If dashcam is
|
|
1659
|
+
// If dashcam is enabled, add web logs for all websites
|
|
1650
1660
|
// Note: File log and dashcam.start() are handled by the connection promise in hooks.mjs
|
|
1651
|
-
if (this.
|
|
1652
|
-
|
|
1661
|
+
if (this.dashcamEnabled) {
|
|
1662
|
+
// get the domain from the url for more specific logging, e.g. "Web Logs - example.com"
|
|
1663
|
+
let domain = url;
|
|
1664
|
+
let protocol = "https:";
|
|
1665
|
+
try {
|
|
1666
|
+
const urlObj = new URL(url);
|
|
1667
|
+
domain = urlObj.hostname;
|
|
1668
|
+
protocol = urlObj.protocol;
|
|
1669
|
+
} catch (err) {
|
|
1670
|
+
// If URL parsing fails, fall back to using the full URL as the domain
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
// the pattern should be protocol://domain* to match all subpages of the domain
|
|
1674
|
+
const webLogPattern = `${protocol}//${domain}*`;
|
|
1675
|
+
|
|
1676
|
+
await this.dashcam.addWebLog(webLogPattern, "Web Logs");
|
|
1653
1677
|
}
|
|
1654
1678
|
|
|
1655
1679
|
// Set up Chrome profile with preferences
|
|
@@ -1906,10 +1930,10 @@ with zipfile.ZipFile(io.BytesIO(zip_data)) as zf:
|
|
|
1906
1930
|
);
|
|
1907
1931
|
}
|
|
1908
1932
|
|
|
1909
|
-
// If dashcam is
|
|
1933
|
+
// If dashcam is enabled, add web logs for all websites
|
|
1910
1934
|
// Note: File log and dashcam.start() are handled by the connection promise in hooks.mjs
|
|
1911
|
-
if (this.
|
|
1912
|
-
await this.
|
|
1935
|
+
if (this.dashcamEnabled) {
|
|
1936
|
+
await this.dashcam.addWebLog("**", "Web Logs");
|
|
1913
1937
|
}
|
|
1914
1938
|
|
|
1915
1939
|
// Set up Chrome profile with preferences
|
|
@@ -2032,10 +2056,10 @@ with zipfile.ZipFile(io.BytesIO(zip_data)) as zf:
|
|
|
2032
2056
|
|
|
2033
2057
|
const shell = this.os === "windows" ? "pwsh" : "sh";
|
|
2034
2058
|
|
|
2035
|
-
// If dashcam is
|
|
2059
|
+
// If dashcam is enabled, add web logs for all websites
|
|
2036
2060
|
// Note: File log and dashcam.start() are handled by the connection promise in hooks.mjs
|
|
2037
|
-
if (this.
|
|
2038
|
-
await this.
|
|
2061
|
+
if (this.dashcamEnabled) {
|
|
2062
|
+
await this.dashcam.addWebLog("**", "Web Logs");
|
|
2039
2063
|
}
|
|
2040
2064
|
|
|
2041
2065
|
// Install extensions if provided
|
|
@@ -2108,10 +2132,10 @@ with zipfile.ZipFile(io.BytesIO(zip_data)) as zf:
|
|
|
2108
2132
|
|
|
2109
2133
|
const shell = this.os === "windows" ? "pwsh" : "sh";
|
|
2110
2134
|
|
|
2111
|
-
// If dashcam is
|
|
2135
|
+
// If dashcam is enabled, add web logs for all websites
|
|
2112
2136
|
// Note: File log and dashcam.start() are handled by the connection promise in hooks.mjs
|
|
2113
|
-
if (this.
|
|
2114
|
-
await this.
|
|
2137
|
+
if (this.dashcamEnabled) {
|
|
2138
|
+
await this.dashcam.addWebLog("**", "Web Logs");
|
|
2115
2139
|
}
|
|
2116
2140
|
|
|
2117
2141
|
// Determine download directory
|
|
@@ -2248,10 +2272,10 @@ with zipfile.ZipFile(io.BytesIO(zip_data)) as zf:
|
|
|
2248
2272
|
|
|
2249
2273
|
const shell = this.os === "windows" ? "pwsh" : "sh";
|
|
2250
2274
|
|
|
2251
|
-
// If dashcam is
|
|
2275
|
+
// If dashcam is enabled, add web logs for all websites
|
|
2252
2276
|
// Note: File log and dashcam.start() are handled by the connection promise in hooks.mjs
|
|
2253
|
-
if (this.
|
|
2254
|
-
await this.
|
|
2277
|
+
if (this.dashcamEnabled) {
|
|
2278
|
+
await this.dashcam.addWebLog("**", "Web Logs");
|
|
2255
2279
|
}
|
|
2256
2280
|
|
|
2257
2281
|
const argsString = args.join(" ");
|
|
@@ -2290,17 +2314,17 @@ with zipfile.ZipFile(io.BytesIO(zip_data)) as zf:
|
|
|
2290
2314
|
title,
|
|
2291
2315
|
} = options;
|
|
2292
2316
|
|
|
2293
|
-
// Ensure dashcam is
|
|
2294
|
-
if (!this.
|
|
2317
|
+
// Ensure dashcam is enabled
|
|
2318
|
+
if (!this.dashcamEnabled) {
|
|
2295
2319
|
console.warn(
|
|
2296
|
-
"[provision.dashcam] Dashcam is not
|
|
2320
|
+
"[provision.dashcam] Dashcam is not enabled. Skipping.",
|
|
2297
2321
|
);
|
|
2298
2322
|
return;
|
|
2299
2323
|
}
|
|
2300
2324
|
|
|
2301
2325
|
// Set custom title if provided
|
|
2302
2326
|
if (title) {
|
|
2303
|
-
this.
|
|
2327
|
+
this.dashcam.setTitle(title);
|
|
2304
2328
|
}
|
|
2305
2329
|
|
|
2306
2330
|
// Add file log tracking
|
|
@@ -2310,16 +2334,16 @@ with zipfile.ZipFile(io.BytesIO(zip_data)) as zf:
|
|
|
2310
2334
|
? "C:\\Users\\testdriver\\testdriver.log"
|
|
2311
2335
|
: "/tmp/testdriver.log");
|
|
2312
2336
|
|
|
2313
|
-
await this.
|
|
2337
|
+
await this.dashcam.addFileLog(actualLogPath, logName);
|
|
2314
2338
|
|
|
2315
2339
|
// Add web log tracking if enabled
|
|
2316
2340
|
if (webLogs) {
|
|
2317
|
-
await this.
|
|
2341
|
+
await this.dashcam.addWebLog("**", "Web Logs");
|
|
2318
2342
|
}
|
|
2319
2343
|
|
|
2320
2344
|
// Start recording if not already recording
|
|
2321
|
-
if (!(await this.
|
|
2322
|
-
await this.
|
|
2345
|
+
if (!(await this.dashcam.isRecording())) {
|
|
2346
|
+
await this.dashcam.start();
|
|
2323
2347
|
}
|
|
2324
2348
|
|
|
2325
2349
|
console.log("[provision.dashcam] ✅ Dashcam recording started");
|
|
@@ -3038,6 +3062,7 @@ CAPTCHA_SOLVER_EOF`,
|
|
|
3038
3062
|
cacheHit: response.cached || false,
|
|
3039
3063
|
selector: response.selector,
|
|
3040
3064
|
selectorUsed: !!response.selector,
|
|
3065
|
+
screenshotUrl: response.screenshotKey ?? null,
|
|
3041
3066
|
})
|
|
3042
3067
|
.catch((err) => {
|
|
3043
3068
|
console.warn("Failed to track findAll interaction:", err.message);
|
|
@@ -3094,6 +3119,7 @@ CAPTCHA_SOLVER_EOF`,
|
|
|
3094
3119
|
cacheHit: response?.cached || false,
|
|
3095
3120
|
selector: response?.selector,
|
|
3096
3121
|
selectorUsed: !!response?.selector,
|
|
3122
|
+
screenshotUrl: response?.screenshotKey ?? null,
|
|
3097
3123
|
})
|
|
3098
3124
|
.catch((err) => {
|
|
3099
3125
|
console.warn("Failed to track findAll interaction:", err.message);
|
|
@@ -4049,6 +4075,9 @@ CAPTCHA_SOLVER_EOF`,
|
|
|
4049
4075
|
}
|
|
4050
4076
|
}
|
|
4051
4077
|
|
|
4078
|
+
// Expose SDK version as a static property for use by vitest hooks/plugins
|
|
4079
|
+
TestDriverSDK.version = require("./package.json").version;
|
|
4080
|
+
|
|
4052
4081
|
module.exports = TestDriverSDK;
|
|
4053
4082
|
module.exports.Element = Element;
|
|
4054
4083
|
module.exports.ElementNotFoundError = ElementNotFoundError;
|