testdriverai 5.7.43 → 5.7.44
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/agent.js +44 -44
- package/index.js +0 -2
- package/lib/commander.js +199 -203
- package/lib/commands.js +63 -35
- package/lib/config.js +1 -3
- package/lib/events.js +1 -1
- package/lib/focus-application.js +14 -8
- package/lib/generator.js +3 -4
- package/lib/init.js +10 -10
- package/lib/logger.js +226 -5
- package/lib/network.js +0 -3
- package/lib/outputs.js +1 -1
- package/lib/parser.js +22 -23
- package/lib/redraw.js +47 -27
- package/lib/resources/prerun.yaml +2 -2
- package/lib/sandbox.js +20 -20
- package/lib/sdk.js +4 -4
- package/lib/session.js +0 -2
- package/lib/system.js +1 -1
- package/lib/theme.js +13 -0
- package/lib/upload-secrets.js +1 -1
- package/package.json +1 -1
- package/testdriver/type-repeated.yaml +21 -0
package/lib/logger.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
const winston = require("winston");
|
|
3
3
|
const os = require("os");
|
|
4
4
|
const server = require("./ipc");
|
|
5
|
+
const chalk = require("chalk");
|
|
6
|
+
const theme = require("./theme");
|
|
5
7
|
|
|
6
8
|
// simple match for aws instance i-*
|
|
7
9
|
const shouldLog =
|
|
@@ -49,14 +51,233 @@ const logger = winston.createLogger({
|
|
|
49
51
|
transports: [new winston.transports.Console()],
|
|
50
52
|
});
|
|
51
53
|
|
|
54
|
+
const plain = (codePart) => codePart;
|
|
55
|
+
|
|
52
56
|
// marked is a markdown parser
|
|
53
57
|
// markedTerminal allows us to render markdown in CLI
|
|
54
58
|
marked.use(
|
|
55
|
-
markedTerminal(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
markedTerminal(
|
|
60
|
+
{
|
|
61
|
+
width: 58, // 58 is the width of the terminal output on a 16" macbook pro
|
|
62
|
+
reflowText: true,
|
|
63
|
+
tab: 2,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
theme: {
|
|
67
|
+
/**
|
|
68
|
+
* keyword in a regular Algol-style language
|
|
69
|
+
*/
|
|
70
|
+
keyword: theme.blue,
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* built-in or library object (constant, class, function)
|
|
74
|
+
*/
|
|
75
|
+
built_in: theme.cyan,
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* user-defined type in a language with first-class syntactically significant types, like
|
|
79
|
+
* Haskell
|
|
80
|
+
*/
|
|
81
|
+
type: theme.cyan,
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* special identifier for a built-in value ("true", "false", "null")
|
|
85
|
+
*/
|
|
86
|
+
literal: theme.blue,
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* number, including units and modifiers, if any.
|
|
90
|
+
*/
|
|
91
|
+
number: theme.green,
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* literal regular expression
|
|
95
|
+
*/
|
|
96
|
+
regexp: theme.red,
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* literal string, character
|
|
100
|
+
*/
|
|
101
|
+
string: theme.green,
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* parsed section inside a literal string
|
|
105
|
+
*/
|
|
106
|
+
subst: plain,
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* symbolic constant, interned string, goto label
|
|
110
|
+
*/
|
|
111
|
+
symbol: plain,
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* class or class-level declaration (interfaces, traits, modules, etc)
|
|
115
|
+
*/
|
|
116
|
+
class: theme.blue,
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* function or method declaration
|
|
120
|
+
*/
|
|
121
|
+
function: theme.yellow,
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* name of a class or a function at the place of declaration
|
|
125
|
+
*/
|
|
126
|
+
title: plain,
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* block of function arguments (parameters) at the place of declaration
|
|
130
|
+
*/
|
|
131
|
+
params: plain,
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* comment
|
|
135
|
+
*/
|
|
136
|
+
comment: theme.green,
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* documentation markup within comments
|
|
140
|
+
*/
|
|
141
|
+
doctag: theme.green,
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* flags, modifiers, annotations, processing instructions, preprocessor directive, etc
|
|
145
|
+
*/
|
|
146
|
+
meta: theme.grey,
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* keyword or built-in within meta construct
|
|
150
|
+
*/
|
|
151
|
+
"meta-keyword": plain,
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* string within meta construct
|
|
155
|
+
*/
|
|
156
|
+
"meta-string": plain,
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* heading of a section in a config file, heading in text markup
|
|
160
|
+
*/
|
|
161
|
+
section: plain,
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* XML/HTML tag
|
|
165
|
+
*/
|
|
166
|
+
tag: theme.grey,
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* name of an XML tag, the first word in an s-expression
|
|
170
|
+
*/
|
|
171
|
+
name: theme.blue,
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* s-expression name from the language standard library
|
|
175
|
+
*/
|
|
176
|
+
"builtin-name": plain,
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* name of an attribute with no language defined semantics (keys in JSON, setting names in
|
|
180
|
+
* .ini), also sub-attribute within another highlighted object, like XML tag
|
|
181
|
+
*/
|
|
182
|
+
attr: theme.cyan,
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* name of an attribute followed by a structured value part, like CSS properties
|
|
186
|
+
*/
|
|
187
|
+
attribute: plain,
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* variable in a config or a template file, environment var expansion in a script
|
|
191
|
+
*/
|
|
192
|
+
variable: plain,
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* list item bullet in text markup
|
|
196
|
+
*/
|
|
197
|
+
bullet: plain,
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* code block in text markup
|
|
201
|
+
*/
|
|
202
|
+
code: plain,
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* emphasis in text markup
|
|
206
|
+
*/
|
|
207
|
+
emphasis: chalk.italic,
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* strong emphasis in text markup
|
|
211
|
+
*/
|
|
212
|
+
strong: chalk.bold,
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* mathematical formula in text markup
|
|
216
|
+
*/
|
|
217
|
+
formula: plain,
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* hyperlink in text markup
|
|
221
|
+
*/
|
|
222
|
+
link: chalk.underline,
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* quotation in text markup
|
|
226
|
+
*/
|
|
227
|
+
quote: plain,
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* tag selector in CSS
|
|
231
|
+
*/
|
|
232
|
+
"selector-tag": plain,
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* #id selector in CSS
|
|
236
|
+
*/
|
|
237
|
+
"selector-id": plain,
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* .class selector in CSS
|
|
241
|
+
*/
|
|
242
|
+
"selector-class": plain,
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* [attr] selector in CSS
|
|
246
|
+
*/
|
|
247
|
+
"selector-attr": plain,
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* :pseudo selector in CSS
|
|
251
|
+
*/
|
|
252
|
+
"selector-pseudo": plain,
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* tag of a template language
|
|
256
|
+
*/
|
|
257
|
+
"template-tag": plain,
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* variable in a template language
|
|
261
|
+
*/
|
|
262
|
+
"template-variable": plain,
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* added or changed line in a diff
|
|
266
|
+
*/
|
|
267
|
+
addition: theme.green,
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* deleted line in a diff
|
|
271
|
+
*/
|
|
272
|
+
deletion: theme.red,
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* things not matched by any token
|
|
276
|
+
*/
|
|
277
|
+
default: plain,
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
),
|
|
60
281
|
);
|
|
61
282
|
|
|
62
283
|
const spaceChar = " ";
|
package/lib/network.js
CHANGED
package/lib/outputs.js
CHANGED
package/lib/parser.js
CHANGED
|
@@ -2,35 +2,34 @@
|
|
|
2
2
|
const Parser = require("markdown-parser");
|
|
3
3
|
const yaml = require("js-yaml");
|
|
4
4
|
const Ajv = require("ajv");
|
|
5
|
+
const theme = require("./theme");
|
|
5
6
|
|
|
6
7
|
let parser = new Parser();
|
|
7
8
|
|
|
8
|
-
const chalk = require('chalk');
|
|
9
|
-
|
|
10
9
|
function formatAjvError(error) {
|
|
11
|
-
|
|
12
10
|
return [
|
|
13
|
-
|
|
14
|
-
`${
|
|
15
|
-
`${
|
|
16
|
-
`${
|
|
11
|
+
theme.yellow("❌ Validation Warning (beta)"),
|
|
12
|
+
`${theme.yellow("Path:")} ${theme.white(error.instancePath)}`,
|
|
13
|
+
`${theme.yellow("Schema:")} ${theme.cyan(error.schemaPath)}`,
|
|
14
|
+
`${theme.yellow("Keyword:")} ${theme.magenta(error.keyword)}`,
|
|
17
15
|
error.params?.missingProperty
|
|
18
|
-
? `${
|
|
19
|
-
:
|
|
20
|
-
`${
|
|
21
|
-
`\n
|
|
22
|
-
]
|
|
16
|
+
? `${theme.yellow("Missing:")} ${theme.yellow(error.params.missingProperty)}`
|
|
17
|
+
: "",
|
|
18
|
+
`${theme.yellow("Message:")} ${theme.white(error.message)}`,
|
|
19
|
+
`\n`,
|
|
20
|
+
]
|
|
21
|
+
.filter(Boolean)
|
|
22
|
+
.join("\n");
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
// use markdown parser to find code blocks within AI response
|
|
26
26
|
const findCodeBlocks = async function (markdownContent) {
|
|
27
|
-
|
|
28
27
|
let md = markdownContent.match(/```yaml\n([\s\S]*?)```/);
|
|
29
28
|
|
|
30
29
|
if (md) {
|
|
31
|
-
return [{code: md[1]}];
|
|
30
|
+
return [{ code: md[1] }];
|
|
32
31
|
} else {
|
|
33
|
-
return []
|
|
32
|
+
return [];
|
|
34
33
|
}
|
|
35
34
|
};
|
|
36
35
|
|
|
@@ -44,7 +43,6 @@ const findGenerativePrompts = async function (markdownContent) {
|
|
|
44
43
|
|
|
45
44
|
// parse the markdown content of each code block
|
|
46
45
|
let codes = result.codes.map((code) => {
|
|
47
|
-
|
|
48
46
|
return new Promise((resolve2, reject2) => {
|
|
49
47
|
try {
|
|
50
48
|
const yamlContent = getYAMLFromCodeBlock(code);
|
|
@@ -93,13 +91,12 @@ const parseYAML = async function (inputYaml) {
|
|
|
93
91
|
// validate yaml using schema.json in root
|
|
94
92
|
let schema = require("../schema.json");
|
|
95
93
|
const validateYAML = async function (yaml) {
|
|
96
|
-
|
|
97
|
-
let ajv = new Ajv({allowUnionTypes: true});
|
|
94
|
+
let ajv = new Ajv({ allowUnionTypes: true });
|
|
98
95
|
let validate = ajv.compile(schema);
|
|
99
96
|
let valid = validate(await parseYAML(yaml));
|
|
100
97
|
|
|
101
98
|
if (!valid) {
|
|
102
|
-
validate.errors.forEach(err => console.log(formatAjvError(err)));
|
|
99
|
+
validate.errors.forEach((err) => console.log(formatAjvError(err)));
|
|
103
100
|
// throw new Error("Invalid YAML");
|
|
104
101
|
}
|
|
105
102
|
|
|
@@ -108,12 +105,14 @@ const validateYAML = async function (yaml) {
|
|
|
108
105
|
|
|
109
106
|
// Replace ${VAR} with the value from the vars object
|
|
110
107
|
// Will skip variables that are not in the vars object
|
|
111
|
-
// Will skip escaped variables like \${VAR}
|
|
112
|
-
function interpolate
|
|
113
|
-
|
|
108
|
+
// Will skip escaped variables like \${VAR}
|
|
109
|
+
function interpolate(yaml, vars) {
|
|
114
110
|
let newyaml = yaml;
|
|
115
111
|
Object.keys(vars).forEach((key) => {
|
|
116
|
-
newyaml = newyaml.replace(
|
|
112
|
+
newyaml = newyaml.replace(
|
|
113
|
+
new RegExp(`(?<!\\\\)\\$\\{${key}\\}`, "g"),
|
|
114
|
+
vars[key],
|
|
115
|
+
);
|
|
117
116
|
});
|
|
118
117
|
// Replace \$ with $
|
|
119
118
|
newyaml = newyaml.replace(/\\(\${[^}]+})/g, "$1");
|
package/lib/redraw.js
CHANGED
|
@@ -3,10 +3,10 @@ const os = require("os");
|
|
|
3
3
|
const path = require("path");
|
|
4
4
|
const { compare } = require("odiff-bin");
|
|
5
5
|
const logger = require("./logger").logger;
|
|
6
|
+
const theme = require("./theme");
|
|
6
7
|
|
|
7
8
|
// network
|
|
8
|
-
const si = require(
|
|
9
|
-
const chalk = require('chalk');
|
|
9
|
+
const si = require("systeminformation");
|
|
10
10
|
|
|
11
11
|
const redrawThresholdPercent = 3;
|
|
12
12
|
const networkUpdateInterval = 2000;
|
|
@@ -29,8 +29,7 @@ async function resetState() {
|
|
|
29
29
|
screenHasRedrawn = false;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
const parseNetworkStats = (thisRxBytes,thisTxBytes) => {
|
|
33
|
-
|
|
32
|
+
const parseNetworkStats = (thisRxBytes, thisTxBytes) => {
|
|
34
33
|
diffRxBytes = lastRxBytes !== null ? thisRxBytes - lastRxBytes : 0;
|
|
35
34
|
diffTxBytes = lastTxBytes !== null ? thisTxBytes - lastTxBytes : 0;
|
|
36
35
|
|
|
@@ -43,27 +42,34 @@ const parseNetworkStats = (thisRxBytes,thisTxBytes) => {
|
|
|
43
42
|
measurements.shift();
|
|
44
43
|
}
|
|
45
44
|
|
|
46
|
-
let avgRx =
|
|
47
|
-
|
|
45
|
+
let avgRx =
|
|
46
|
+
measurements.reduce((acc, m) => acc + m.rx, 0) / measurements.length;
|
|
47
|
+
let avgTx =
|
|
48
|
+
measurements.reduce((acc, m) => acc + m.tx, 0) / measurements.length;
|
|
48
49
|
|
|
49
|
-
let stdDevRx = Math.sqrt(
|
|
50
|
-
|
|
50
|
+
let stdDevRx = Math.sqrt(
|
|
51
|
+
measurements.reduce((acc, m) => acc + Math.pow(m.rx - avgRx, 2), 0) /
|
|
52
|
+
measurements.length,
|
|
53
|
+
);
|
|
54
|
+
let stdDevTx = Math.sqrt(
|
|
55
|
+
measurements.reduce((acc, m) => acc + Math.pow(m.tx - avgTx, 2), 0) /
|
|
56
|
+
measurements.length,
|
|
57
|
+
);
|
|
51
58
|
|
|
52
59
|
let zIndexRx = stdDevRx !== 0 ? (diffRxBytes - avgRx) / stdDevRx : 0;
|
|
53
60
|
let zIndexTx = stdDevTx !== 0 ? (diffTxBytes - avgTx) / stdDevTx : 0;
|
|
54
61
|
|
|
55
|
-
if (
|
|
62
|
+
if (zIndexRx < 0 && zIndexTx < 0) {
|
|
56
63
|
networkSettled = true;
|
|
57
64
|
} else {
|
|
58
65
|
networkSettled = false;
|
|
59
66
|
}
|
|
60
|
-
}
|
|
67
|
+
};
|
|
61
68
|
|
|
62
69
|
async function updateNetwork() {
|
|
63
|
-
|
|
64
|
-
const { exec } = require('child_process');
|
|
70
|
+
const { exec } = require("child_process");
|
|
65
71
|
const scriptPath = path.join(__dirname, "network.ps1");
|
|
66
|
-
if (os.platform() ===
|
|
72
|
+
if (os.platform() === "win32") {
|
|
67
73
|
exec(`powershell -File ${scriptPath}`, (error, stdout, stderr) => {
|
|
68
74
|
if (error) {
|
|
69
75
|
logger.error(`Error executing PowerShell script: ${error}`);
|
|
@@ -73,7 +79,7 @@ async function updateNetwork() {
|
|
|
73
79
|
logger.error(`PowerShell error: ${stderr}`);
|
|
74
80
|
return;
|
|
75
81
|
}
|
|
76
|
-
|
|
82
|
+
|
|
77
83
|
try {
|
|
78
84
|
// Parse the JSON output
|
|
79
85
|
const result = JSON.parse(stdout.trim());
|
|
@@ -82,15 +88,14 @@ async function updateNetwork() {
|
|
|
82
88
|
logger.error(`Error parsing JSON: ${parseError}`);
|
|
83
89
|
}
|
|
84
90
|
});
|
|
85
|
-
} else if (os.platform() ===
|
|
86
|
-
si.networkStats().then(data => {
|
|
91
|
+
} else if (os.platform() === "darwin") {
|
|
92
|
+
si.networkStats().then((data) => {
|
|
87
93
|
parseNetworkStats(data[0].rx_bytes, data[0].tx_bytes);
|
|
88
94
|
});
|
|
89
95
|
}
|
|
90
96
|
}
|
|
91
97
|
|
|
92
98
|
async function imageDiffPercent(image1Url, image2Url) {
|
|
93
|
-
|
|
94
99
|
// generate a temporary file path
|
|
95
100
|
const tmpImage = path.join(os.tmpdir(), `tmp-${Date.now()}.png`);
|
|
96
101
|
|
|
@@ -100,7 +105,7 @@ async function imageDiffPercent(image1Url, image2Url) {
|
|
|
100
105
|
tmpImage,
|
|
101
106
|
{
|
|
102
107
|
failOnLayoutDiff: false,
|
|
103
|
-
outputDiffMask: false
|
|
108
|
+
outputDiffMask: false,
|
|
104
109
|
},
|
|
105
110
|
);
|
|
106
111
|
|
|
@@ -115,7 +120,6 @@ async function imageDiffPercent(image1Url, image2Url) {
|
|
|
115
120
|
}
|
|
116
121
|
}
|
|
117
122
|
|
|
118
|
-
|
|
119
123
|
let startImage = null;
|
|
120
124
|
|
|
121
125
|
async function start() {
|
|
@@ -125,7 +129,7 @@ async function start() {
|
|
|
125
129
|
}
|
|
126
130
|
|
|
127
131
|
async function checkCondition(resolve, startTime, timeoutMs) {
|
|
128
|
-
let nowImage = await captureScreenPNG(.25, true);
|
|
132
|
+
let nowImage = await captureScreenPNG(0.25, true);
|
|
129
133
|
let timeElapsed = Date.now() - startTime;
|
|
130
134
|
let diffPercent = 0;
|
|
131
135
|
let isTimeout = timeElapsed > timeoutMs;
|
|
@@ -133,14 +137,30 @@ async function checkCondition(resolve, startTime, timeoutMs) {
|
|
|
133
137
|
if (!screenHasRedrawn) {
|
|
134
138
|
diffPercent = await imageDiffPercent(startImage, nowImage);
|
|
135
139
|
screenHasRedrawn = diffPercent > redrawThresholdPercent;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// // log redraw as output
|
|
139
|
-
let redrawText = screenHasRedrawn ? chalk.green(`y`) : chalk.dim(`${diffPercent}/${redrawThresholdPercent}%`);
|
|
140
|
-
let networkText = networkSettled ? chalk.green(`y`) : chalk.dim(`${Math.trunc((diffRxBytes + diffTxBytes) / networkUpdateInterval)}b/s`);
|
|
141
|
-
let timeoutText = isTimeout ? chalk.green(`y`) : chalk.dim(`${Math.floor((timeElapsed)/1000)}/${(timeoutMs / 1000)}s`);
|
|
140
|
+
}
|
|
142
141
|
|
|
143
|
-
|
|
142
|
+
// // log redraw as output
|
|
143
|
+
let redrawText = screenHasRedrawn
|
|
144
|
+
? theme.green(`y`)
|
|
145
|
+
: theme.dim(`${diffPercent}/${redrawThresholdPercent}%`);
|
|
146
|
+
let networkText = networkSettled
|
|
147
|
+
? theme.green(`y`)
|
|
148
|
+
: theme.dim(
|
|
149
|
+
`${Math.trunc((diffRxBytes + diffTxBytes) / networkUpdateInterval)}b/s`,
|
|
150
|
+
);
|
|
151
|
+
let timeoutText = isTimeout
|
|
152
|
+
? theme.green(`y`)
|
|
153
|
+
: theme.dim(`${Math.floor(timeElapsed / 1000)}/${timeoutMs / 1000}s`);
|
|
154
|
+
|
|
155
|
+
logger.debug(
|
|
156
|
+
` ` +
|
|
157
|
+
theme.dim("redraw=") +
|
|
158
|
+
redrawText +
|
|
159
|
+
theme.dim(" network=") +
|
|
160
|
+
networkText +
|
|
161
|
+
theme.dim(" timeout=") +
|
|
162
|
+
timeoutText,
|
|
163
|
+
);
|
|
144
164
|
|
|
145
165
|
if ((screenHasRedrawn && networkSettled) || isTimeout) {
|
|
146
166
|
logger.debug(` `);
|
|
@@ -5,10 +5,10 @@ steps:
|
|
|
5
5
|
commands:
|
|
6
6
|
- command: exec
|
|
7
7
|
lang: shell
|
|
8
|
-
linux: |
|
|
8
|
+
linux: |
|
|
9
9
|
jumpapp google-chrome --disable-fre --no-default-browser-check --no-first-run "${TESTDRIVER_WEBSITE}" &
|
|
10
10
|
exit
|
|
11
|
-
mac: |
|
|
11
|
+
mac: |
|
|
12
12
|
open -na "Google Chrome" --args --disable-fre --no-default-browser-check --no-first-run "${TESTDRIVER_WEBSITE}" &
|
|
13
13
|
exit
|
|
14
14
|
windows:
|
package/lib/sandbox.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const WebSocket = require(
|
|
2
|
-
const config = require(
|
|
1
|
+
const WebSocket = require("ws");
|
|
2
|
+
const config = require("./config");
|
|
3
3
|
|
|
4
4
|
class Sandbox {
|
|
5
5
|
constructor() {
|
|
@@ -11,60 +11,60 @@ class Sandbox {
|
|
|
11
11
|
send(message) {
|
|
12
12
|
let resolvePromise;
|
|
13
13
|
if (this.socket) {
|
|
14
|
-
message.requestId =
|
|
14
|
+
message.requestId =
|
|
15
|
+
Math.random().toString(36).substring(7) + new Date().getTime();
|
|
15
16
|
let p = new Promise((resolve) => {
|
|
16
17
|
this.socket.send(JSON.stringify(message));
|
|
17
18
|
resolvePromise = resolve;
|
|
18
19
|
});
|
|
19
|
-
this.ps[message.requestId] = {promise: p, resolve: resolvePromise};
|
|
20
|
+
this.ps[message.requestId] = { promise: p, resolve: resolvePromise };
|
|
20
21
|
return p;
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
async boot() {
|
|
25
26
|
return new Promise((resolve, reject) => {
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
this.socket = new WebSocket(
|
|
28
|
+
`${config.TD_API_ROOT.replace("https://", "wss://")}`,
|
|
29
|
+
);
|
|
28
30
|
|
|
29
31
|
// handle errors
|
|
30
|
-
this.socket.on(
|
|
31
|
-
console.log(
|
|
32
|
+
this.socket.on("close", () => {
|
|
33
|
+
console.log("Socket Closed. Check your API KEY (TD_API_KEY)");
|
|
32
34
|
clearInterval(this.heartbeat);
|
|
33
35
|
reject();
|
|
34
36
|
process.exit(1);
|
|
35
|
-
});
|
|
37
|
+
});
|
|
36
38
|
|
|
37
|
-
this.socket.on(
|
|
38
|
-
console.log(
|
|
39
|
+
this.socket.on("error", (err) => {
|
|
40
|
+
console.log("Socket Error");
|
|
39
41
|
err && console.log(err);
|
|
40
42
|
clearInterval(this.heartbeat);
|
|
41
43
|
throw err;
|
|
42
|
-
});
|
|
44
|
+
});
|
|
43
45
|
|
|
44
|
-
this.socket.on(
|
|
45
|
-
|
|
46
|
+
this.socket.on("open", async () => {
|
|
46
47
|
this.heartbeat = setInterval(() => {
|
|
47
|
-
this.send({type:
|
|
48
|
+
this.send({ type: "ping" });
|
|
48
49
|
}, 5000);
|
|
49
50
|
|
|
50
51
|
resolve(this);
|
|
51
52
|
});
|
|
52
53
|
|
|
53
|
-
this.socket.on(
|
|
54
|
+
this.socket.on("message", (raw) => {
|
|
54
55
|
let message = JSON.parse(raw);
|
|
55
56
|
|
|
56
|
-
if (message.type ===
|
|
57
|
+
if (message.type === "error") {
|
|
57
58
|
console.error(message);
|
|
58
|
-
}
|
|
59
|
+
}
|
|
59
60
|
|
|
60
61
|
if (this.ps[message.requestId]) {
|
|
61
62
|
this.ps[message.requestId].resolve(message);
|
|
62
63
|
delete this.ps[message.requestId];
|
|
63
64
|
} else {
|
|
64
|
-
console.log(
|
|
65
|
+
console.log("unhandled message", message);
|
|
65
66
|
}
|
|
66
67
|
});
|
|
67
|
-
|
|
68
68
|
});
|
|
69
69
|
}
|
|
70
70
|
}
|
package/lib/sdk.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
const config = require("./config");
|
|
2
|
-
const chalk = require("chalk");
|
|
3
2
|
const session = require("./session");
|
|
4
3
|
|
|
5
4
|
// get the version from package.json
|
|
6
5
|
const { version } = require("../package.json");
|
|
7
6
|
const root = config["TD_API_ROOT"];
|
|
8
7
|
const axios = require("axios");
|
|
8
|
+
const theme = require("./theme");
|
|
9
9
|
|
|
10
10
|
const { logger } = require("./logger");
|
|
11
11
|
|
|
@@ -14,7 +14,7 @@ let token = null;
|
|
|
14
14
|
const outputError = (error) => {
|
|
15
15
|
logger.error(
|
|
16
16
|
"API Error: %s (%s)",
|
|
17
|
-
|
|
17
|
+
theme.red(
|
|
18
18
|
// HTTP status code from Axios
|
|
19
19
|
error.status ||
|
|
20
20
|
// ...or an explicit error `reason` set by Sails
|
|
@@ -22,7 +22,7 @@ const outputError = (error) => {
|
|
|
22
22
|
// ...or default to the error message
|
|
23
23
|
error.message,
|
|
24
24
|
),
|
|
25
|
-
|
|
25
|
+
theme.red(
|
|
26
26
|
// e.g. "teamNotExist" from Sails' exits
|
|
27
27
|
error.response?.data?.raw ||
|
|
28
28
|
// ...or the status text
|
|
@@ -74,7 +74,7 @@ const parseBody = async (response, body) => {
|
|
|
74
74
|
}
|
|
75
75
|
return body;
|
|
76
76
|
} catch (err) {
|
|
77
|
-
logger.error(
|
|
77
|
+
logger.error(theme.red("Parsing Error", err));
|
|
78
78
|
throw err;
|
|
79
79
|
}
|
|
80
80
|
};
|
package/lib/session.js
CHANGED
package/lib/system.js
CHANGED
|
@@ -181,7 +181,7 @@ const activeWin = async () => {
|
|
|
181
181
|
windows = await activeWindow?.();
|
|
182
182
|
} catch (e) {
|
|
183
183
|
console.error("Error getting active window", e);
|
|
184
|
-
|
|
184
|
+
return "error getting active window, proceed normally";
|
|
185
185
|
}
|
|
186
186
|
return windows;
|
|
187
187
|
}
|
package/lib/theme.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const chalk = require("chalk");
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
green: chalk.hex("#b3d334"),
|
|
5
|
+
blue: chalk.hex("#34a3d3"),
|
|
6
|
+
red: chalk.hex("#d33434"),
|
|
7
|
+
yellow: chalk.hex("#ced334"),
|
|
8
|
+
magenta: chalk.hex("#d334b3"),
|
|
9
|
+
cyan: chalk.hex("#34d3d3"),
|
|
10
|
+
dim: chalk.dim,
|
|
11
|
+
gray: chalk.gray,
|
|
12
|
+
white: chalk.white,
|
|
13
|
+
};
|
package/lib/upload-secrets.js
CHANGED
|
@@ -57,7 +57,7 @@ module.exports = async () => {
|
|
|
57
57
|
try {
|
|
58
58
|
const cmd = `gh secret set ${key} --body "${value}"`;
|
|
59
59
|
execSync(cmd, { stdio: "inherit" });
|
|
60
|
-
|
|
60
|
+
// eslint-disable-next-line no-unused-vars
|
|
61
61
|
} catch (err) {
|
|
62
62
|
console.error(`❌ Failed to upload ${key}`);
|
|
63
63
|
}
|