testeranto 0.85.0 → 0.90.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -3
- package/bin/init-docs.js +24 -0
- package/bundle.js +53 -0
- package/dist/common/dist/module/src/Init.js +40 -0
- package/dist/common/src/Init.js +30 -0
- package/dist/common/src/PM/main.js +45 -9
- package/dist/common/src/Project.js +80 -0
- package/dist/common/src/Puppeteer.js +1 -1
- package/dist/common/{run-tests.js → src/build-tests.js} +10 -5
- package/dist/common/src/defaultConfig.js +19 -0
- package/dist/common/src/esbuildConfigs/inputFilesPlugin.js +27 -15
- package/dist/common/src/init-docs.js +43 -0
- package/dist/common/src/lib/abstractBase.js +0 -64
- package/dist/common/src/lib/core.js +5 -3
- package/dist/common/{build-tests.js → src/run-tests.js} +10 -9
- package/dist/common/tsconfig.common.tsbuildinfo +1 -1
- package/dist/module/src/Init.js +30 -0
- package/dist/module/src/PM/main.js +45 -9
- package/dist/module/src/Project.js +80 -0
- package/dist/module/src/Puppeteer.js +1 -1
- package/dist/module/src/build-tests.js +11 -0
- package/dist/module/src/defaultConfig.js +17 -0
- package/dist/module/src/esbuildConfigs/inputFilesPlugin.js +27 -15
- package/dist/module/src/init-docs.js +15 -0
- package/dist/module/src/lib/abstractBase.js +0 -64
- package/dist/module/src/lib/core.js +5 -3
- package/dist/module/src/run-tests.js +11 -0
- package/dist/module/tsconfig.module.tsbuildinfo +1 -1
- package/dist/prebuild/build-tests.mjs +552 -0
- package/dist/prebuild/init-docs.mjs +48 -0
- package/dist/prebuild/run-tests.mjs +907 -0
- package/dist/types/dist/module/src/Init.d.ts +2 -0
- package/dist/types/src/build-tests.d.ts +1 -0
- package/dist/types/src/defaultConfig.d.ts +3 -0
- package/dist/types/src/init-docs.d.ts +1 -0
- package/dist/types/src/run-tests.d.ts +1 -0
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/package.json +9 -12
- package/src/Init.ts +28 -0
- package/src/PM/main.ts +58 -10
- package/src/Project.ts +102 -0
- package/src/Puppeteer.ts +1 -1
- package/src/build-tests.ts +12 -0
- package/src/defaultConfig.ts +20 -0
- package/src/esbuildConfigs/inputFilesPlugin.ts +48 -16
- package/src/init-docs.ts +19 -0
- package/src/lib/abstractBase.ts +0 -67
- package/src/lib/core.ts +3 -3
- package/src/run-tests.ts +12 -0
- package/tsconfig.json +1 -1
- package/build-tests.ts +0 -16
- package/dist/common/init-docs.js +0 -8
- package/dist/module/build-tests.js +0 -10
- package/dist/module/init-docs.js +0 -3
- package/dist/module/run-tests.js +0 -6
- package/dist/prebuild/Puppeteer.mjs +0 -82033
- package/dist/types/build-tests.d.ts +0 -3
- package/dist/types/init-docs.d.ts +0 -2
- package/dist/types/run-tests.d.ts +0 -2
- package/init-docs.ts +0 -5
- package/pupBuild.js +0 -18
- package/run-tests.ts +0 -9
|
@@ -0,0 +1,907 @@
|
|
|
1
|
+
import { createRequire } from 'module';const require = createRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/Puppeteer.ts
|
|
4
|
+
import readline from "readline";
|
|
5
|
+
import fs2 from "fs";
|
|
6
|
+
import watch from "recursive-watch";
|
|
7
|
+
|
|
8
|
+
// src/PM/main.ts
|
|
9
|
+
import fs from "fs";
|
|
10
|
+
import path2 from "path";
|
|
11
|
+
import puppeteer from "puppeteer-core";
|
|
12
|
+
import crypto from "crypto";
|
|
13
|
+
|
|
14
|
+
// src/PM/index.ts
|
|
15
|
+
var PM = class {
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// src/utils.ts
|
|
19
|
+
import path from "path";
|
|
20
|
+
var destinationOfRuntime = (f, r, configs) => {
|
|
21
|
+
return path.normalize(`${configs.buildDir}/${r}/${f}`).split(".").slice(0, -1).join(".");
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// src/PM/main.ts
|
|
25
|
+
var fileStreams3 = [];
|
|
26
|
+
var fPaths = [];
|
|
27
|
+
var files = {};
|
|
28
|
+
var screenshots = {};
|
|
29
|
+
var PM_Main = class extends PM {
|
|
30
|
+
constructor(configs) {
|
|
31
|
+
super();
|
|
32
|
+
this.shutdownMode = false;
|
|
33
|
+
this.checkForShutdown = () => {
|
|
34
|
+
const anyRunning = Object.values(this.registry).filter((x) => x === false).length > 0;
|
|
35
|
+
if (anyRunning) {
|
|
36
|
+
} else {
|
|
37
|
+
this.browser.disconnect().then(() => {
|
|
38
|
+
console.log("Goodbye");
|
|
39
|
+
process.exit();
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
this.register = (src) => {
|
|
44
|
+
this.registry[src] = false;
|
|
45
|
+
};
|
|
46
|
+
this.deregister = (src) => {
|
|
47
|
+
this.registry[src] = true;
|
|
48
|
+
if (this.shutdownMode) {
|
|
49
|
+
this.checkForShutdown();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
this.launchNode = async (src, dest) => {
|
|
53
|
+
console.log("launchNode", src);
|
|
54
|
+
this.register(src);
|
|
55
|
+
const destFolder = dest.replace(".mjs", "");
|
|
56
|
+
let argz = "";
|
|
57
|
+
const testConfig = this.configs.tests.find((t) => {
|
|
58
|
+
return t[0] === src;
|
|
59
|
+
});
|
|
60
|
+
if (!testConfig) {
|
|
61
|
+
console.error("missing test config");
|
|
62
|
+
process.exit(-1);
|
|
63
|
+
}
|
|
64
|
+
const testConfigResource = testConfig[2];
|
|
65
|
+
let portsToUse = [];
|
|
66
|
+
if (testConfigResource.ports === 0) {
|
|
67
|
+
argz = JSON.stringify({
|
|
68
|
+
scheduled: true,
|
|
69
|
+
name: src,
|
|
70
|
+
ports: portsToUse,
|
|
71
|
+
fs: destFolder,
|
|
72
|
+
browserWSEndpoint: this.browser.wsEndpoint()
|
|
73
|
+
});
|
|
74
|
+
} else if (testConfigResource.ports > 0) {
|
|
75
|
+
const openPorts = Object.entries(this.ports).filter(
|
|
76
|
+
([portnumber, portopen]) => portopen
|
|
77
|
+
);
|
|
78
|
+
if (openPorts.length >= testConfigResource.ports) {
|
|
79
|
+
for (let i = 0; i < testConfigResource.ports; i++) {
|
|
80
|
+
portsToUse.push(openPorts[i][0]);
|
|
81
|
+
this.ports[openPorts[i][0]] = false;
|
|
82
|
+
}
|
|
83
|
+
argz = JSON.stringify({
|
|
84
|
+
scheduled: true,
|
|
85
|
+
name: src,
|
|
86
|
+
// ports: [3333],
|
|
87
|
+
ports: portsToUse,
|
|
88
|
+
fs: destFolder,
|
|
89
|
+
browserWSEndpoint: this.browser.wsEndpoint()
|
|
90
|
+
});
|
|
91
|
+
} else {
|
|
92
|
+
this.queue.push(src);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
console.error("negative port makes no sense", src);
|
|
97
|
+
process.exit(-1);
|
|
98
|
+
}
|
|
99
|
+
const builtfile = dest + ".mjs";
|
|
100
|
+
await Promise.all(
|
|
101
|
+
testConfig[3].map((sidecar) => {
|
|
102
|
+
if (sidecar[1] === "web") {
|
|
103
|
+
return this.launchWebSideCar(
|
|
104
|
+
sidecar[0],
|
|
105
|
+
destinationOfRuntime(sidecar[0], "web", this.configs),
|
|
106
|
+
sidecar
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
if (sidecar[1] === "node") {
|
|
110
|
+
return this.launchNodeSideCar(
|
|
111
|
+
sidecar[0],
|
|
112
|
+
destinationOfRuntime(sidecar[0], "node", this.configs),
|
|
113
|
+
sidecar
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
);
|
|
118
|
+
this.server[builtfile] = await import(`${builtfile}?cacheBust=${Date.now()}`).then((module) => {
|
|
119
|
+
return module.default.then((defaultModule) => {
|
|
120
|
+
defaultModule.receiveTestResourceConfig(argz).then(async (features) => {
|
|
121
|
+
this.receiveFeatures(features, destFolder);
|
|
122
|
+
}).catch((e) => {
|
|
123
|
+
console.log("catch", e);
|
|
124
|
+
}).finally(() => {
|
|
125
|
+
this.deregister(src);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
for (let i = 0; i <= portsToUse.length; i++) {
|
|
130
|
+
if (portsToUse[i]) {
|
|
131
|
+
this.ports[portsToUse[i]] = "true";
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
this.launchWebSideCar = async (src, dest, testConfig) => {
|
|
136
|
+
const d = dest + ".mjs";
|
|
137
|
+
console.log("launchWebSideCar", src, dest, d);
|
|
138
|
+
const destFolder = dest.replace(".mjs", "");
|
|
139
|
+
const webArgz = JSON.stringify({
|
|
140
|
+
name: dest,
|
|
141
|
+
ports: [].toString(),
|
|
142
|
+
fs: destFolder,
|
|
143
|
+
browserWSEndpoint: this.browser.wsEndpoint()
|
|
144
|
+
});
|
|
145
|
+
const fileStreams2 = [];
|
|
146
|
+
const doneFileStream2 = [];
|
|
147
|
+
return new Promise((res, rej) => {
|
|
148
|
+
this.browser.newPage().then((page) => {
|
|
149
|
+
page.exposeFunction(
|
|
150
|
+
"custom-screenshot",
|
|
151
|
+
async (ssOpts, testName) => {
|
|
152
|
+
const p = ssOpts.path;
|
|
153
|
+
const dir = path2.dirname(p);
|
|
154
|
+
fs.mkdirSync(dir, {
|
|
155
|
+
recursive: true
|
|
156
|
+
});
|
|
157
|
+
files[testName].add(ssOpts.path);
|
|
158
|
+
const sPromise = page.screenshot({
|
|
159
|
+
...ssOpts,
|
|
160
|
+
path: p
|
|
161
|
+
});
|
|
162
|
+
if (!screenshots[testName]) {
|
|
163
|
+
screenshots[testName] = [];
|
|
164
|
+
}
|
|
165
|
+
screenshots[testName].push(sPromise);
|
|
166
|
+
await sPromise;
|
|
167
|
+
return sPromise;
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
page.exposeFunction(
|
|
171
|
+
"writeFileSync",
|
|
172
|
+
(fp, contents, testName) => {
|
|
173
|
+
const dir = path2.dirname(fp);
|
|
174
|
+
fs.mkdirSync(dir, {
|
|
175
|
+
recursive: true
|
|
176
|
+
});
|
|
177
|
+
const p = new Promise(async (res2, rej2) => {
|
|
178
|
+
fs.writeFileSync(fp, contents);
|
|
179
|
+
res2(fp);
|
|
180
|
+
});
|
|
181
|
+
doneFileStream2.push(p);
|
|
182
|
+
if (!files[testName]) {
|
|
183
|
+
files[testName] = /* @__PURE__ */ new Set();
|
|
184
|
+
}
|
|
185
|
+
files[testName].add(fp);
|
|
186
|
+
return p;
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
page.exposeFunction("existsSync", (fp, contents) => {
|
|
190
|
+
return fs.existsSync(fp);
|
|
191
|
+
});
|
|
192
|
+
page.exposeFunction("mkdirSync", (fp) => {
|
|
193
|
+
if (!fs.existsSync(fp)) {
|
|
194
|
+
return fs.mkdirSync(fp, {
|
|
195
|
+
recursive: true
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
return false;
|
|
199
|
+
});
|
|
200
|
+
page.exposeFunction(
|
|
201
|
+
"createWriteStream",
|
|
202
|
+
(fp, testName) => {
|
|
203
|
+
const f = fs.createWriteStream(fp);
|
|
204
|
+
files[testName].add(fp);
|
|
205
|
+
const p = new Promise((res2, rej2) => {
|
|
206
|
+
res2(fp);
|
|
207
|
+
});
|
|
208
|
+
doneFileStream2.push(p);
|
|
209
|
+
f.on("close", async () => {
|
|
210
|
+
await p;
|
|
211
|
+
});
|
|
212
|
+
fileStreams2.push(f);
|
|
213
|
+
return {
|
|
214
|
+
...JSON.parse(JSON.stringify(f)),
|
|
215
|
+
uid: fileStreams2.length - 1
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
);
|
|
219
|
+
page.exposeFunction(
|
|
220
|
+
"write",
|
|
221
|
+
async (uid, contents) => {
|
|
222
|
+
return fileStreams2[uid].write(contents);
|
|
223
|
+
}
|
|
224
|
+
);
|
|
225
|
+
page.exposeFunction("end", async (uid) => {
|
|
226
|
+
return fileStreams2[uid].end();
|
|
227
|
+
});
|
|
228
|
+
page.exposeFunction("customclose", (p, testName) => {
|
|
229
|
+
fs.writeFileSync(
|
|
230
|
+
p + "/manifest.json",
|
|
231
|
+
JSON.stringify(Array.from(files[testName]))
|
|
232
|
+
);
|
|
233
|
+
delete files[testName];
|
|
234
|
+
Promise.all(screenshots[testName] || []).then(() => {
|
|
235
|
+
delete screenshots[testName];
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
return page;
|
|
239
|
+
}).then(async (page) => {
|
|
240
|
+
await page.goto(`file://${`${dest}.html`}`, {});
|
|
241
|
+
res(page);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
};
|
|
245
|
+
this.launchNodeSideCar = async (src, dest, testConfig) => {
|
|
246
|
+
const d = dest + ".mjs";
|
|
247
|
+
console.log("launchNodeSideCar", src, dest, d);
|
|
248
|
+
const destFolder = dest.replace(".mjs", "");
|
|
249
|
+
let argz = "";
|
|
250
|
+
const testConfigResource = testConfig[2];
|
|
251
|
+
let portsToUse = [];
|
|
252
|
+
if (testConfigResource.ports === 0) {
|
|
253
|
+
argz = JSON.stringify({
|
|
254
|
+
scheduled: true,
|
|
255
|
+
name: src,
|
|
256
|
+
ports: portsToUse,
|
|
257
|
+
fs: destFolder,
|
|
258
|
+
browserWSEndpoint: this.browser.wsEndpoint()
|
|
259
|
+
});
|
|
260
|
+
} else if (testConfigResource.ports > 0) {
|
|
261
|
+
const openPorts = Object.entries(this.ports).filter(
|
|
262
|
+
([portnumber, portopen]) => portopen
|
|
263
|
+
);
|
|
264
|
+
if (openPorts.length >= testConfigResource.ports) {
|
|
265
|
+
for (let i = 0; i < testConfigResource.ports; i++) {
|
|
266
|
+
portsToUse.push(openPorts[i][0]);
|
|
267
|
+
this.ports[openPorts[i][0]] = false;
|
|
268
|
+
}
|
|
269
|
+
argz = JSON.stringify({
|
|
270
|
+
scheduled: true,
|
|
271
|
+
name: src,
|
|
272
|
+
// ports: [3333],
|
|
273
|
+
ports: portsToUse,
|
|
274
|
+
fs: ".",
|
|
275
|
+
browserWSEndpoint: this.browser.wsEndpoint()
|
|
276
|
+
});
|
|
277
|
+
} else {
|
|
278
|
+
this.queue.push(src);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
} else {
|
|
282
|
+
console.error("negative port makes no sense", src);
|
|
283
|
+
process.exit(-1);
|
|
284
|
+
}
|
|
285
|
+
const builtfile = dest + ".mjs";
|
|
286
|
+
this.server[builtfile] = await import(`${builtfile}?cacheBust=${Date.now()}`).then((module) => {
|
|
287
|
+
return module.default.then((defaultModule) => {
|
|
288
|
+
const s = new defaultModule();
|
|
289
|
+
s.receiveTestResourceConfig(argz);
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
for (let i = 0; i <= portsToUse.length; i++) {
|
|
293
|
+
if (portsToUse[i]) {
|
|
294
|
+
this.ports[portsToUse[i]] = "true";
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
this.launchWeb = (t, dest, sidecars) => {
|
|
299
|
+
console.log("launchWeb", t, dest);
|
|
300
|
+
this.register(t);
|
|
301
|
+
sidecars.map((sidecar) => {
|
|
302
|
+
if (sidecar[1] === "node") {
|
|
303
|
+
return this.launchNodeSideCar(
|
|
304
|
+
sidecar[0],
|
|
305
|
+
destinationOfRuntime(sidecar[0], "node", this.configs),
|
|
306
|
+
sidecar
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
const destFolder = dest.replace(".mjs", "");
|
|
311
|
+
const webArgz = JSON.stringify({
|
|
312
|
+
name: dest,
|
|
313
|
+
ports: [].toString(),
|
|
314
|
+
fs: destFolder,
|
|
315
|
+
browserWSEndpoint: this.browser.wsEndpoint()
|
|
316
|
+
});
|
|
317
|
+
const evaluation = `
|
|
318
|
+
console.log("importing ${dest}.mjs");
|
|
319
|
+
import('${dest}.mjs').then(async (x) => {
|
|
320
|
+
console.log("imported", (await x.default));
|
|
321
|
+
try {
|
|
322
|
+
return await (await x.default).receiveTestResourceConfig(${webArgz})
|
|
323
|
+
} catch (e) {
|
|
324
|
+
console.log("fail", e)
|
|
325
|
+
}
|
|
326
|
+
})`;
|
|
327
|
+
const fileStreams2 = [];
|
|
328
|
+
const doneFileStream2 = [];
|
|
329
|
+
const stdoutStream = fs.createWriteStream(`${dest}/stdout.log`);
|
|
330
|
+
const stderrStream = fs.createWriteStream(`${dest}/stderr.log`);
|
|
331
|
+
this.browser.newPage().then((page) => {
|
|
332
|
+
page.exposeFunction(
|
|
333
|
+
"screencast",
|
|
334
|
+
async (ssOpts, testName) => {
|
|
335
|
+
const p = ssOpts.path;
|
|
336
|
+
const dir = path2.dirname(p);
|
|
337
|
+
fs.mkdirSync(dir, {
|
|
338
|
+
recursive: true
|
|
339
|
+
});
|
|
340
|
+
if (!files[testName]) {
|
|
341
|
+
files[testName] = /* @__PURE__ */ new Set();
|
|
342
|
+
}
|
|
343
|
+
files[testName].add(ssOpts.path);
|
|
344
|
+
const sPromise = page.screenshot({
|
|
345
|
+
...ssOpts,
|
|
346
|
+
path: p
|
|
347
|
+
});
|
|
348
|
+
if (!screenshots[testName]) {
|
|
349
|
+
screenshots[testName] = [];
|
|
350
|
+
}
|
|
351
|
+
screenshots[testName].push(sPromise);
|
|
352
|
+
await sPromise;
|
|
353
|
+
return sPromise;
|
|
354
|
+
}
|
|
355
|
+
);
|
|
356
|
+
page.exposeFunction(
|
|
357
|
+
"customScreenShot",
|
|
358
|
+
async (ssOpts, testName) => {
|
|
359
|
+
const p = ssOpts.path;
|
|
360
|
+
const dir = path2.dirname(p);
|
|
361
|
+
fs.mkdirSync(dir, {
|
|
362
|
+
recursive: true
|
|
363
|
+
});
|
|
364
|
+
if (!files[testName]) {
|
|
365
|
+
files[testName] = /* @__PURE__ */ new Set();
|
|
366
|
+
}
|
|
367
|
+
files[testName].add(ssOpts.path);
|
|
368
|
+
const sPromise = page.screenshot({
|
|
369
|
+
...ssOpts,
|
|
370
|
+
path: p
|
|
371
|
+
});
|
|
372
|
+
if (!screenshots[testName]) {
|
|
373
|
+
screenshots[testName] = [];
|
|
374
|
+
}
|
|
375
|
+
screenshots[testName].push(sPromise);
|
|
376
|
+
await sPromise;
|
|
377
|
+
return sPromise;
|
|
378
|
+
}
|
|
379
|
+
);
|
|
380
|
+
page.exposeFunction(
|
|
381
|
+
"writeFileSync",
|
|
382
|
+
(fp, contents, testName) => {
|
|
383
|
+
const dir = path2.dirname(fp);
|
|
384
|
+
fs.mkdirSync(dir, {
|
|
385
|
+
recursive: true
|
|
386
|
+
});
|
|
387
|
+
const p = new Promise(async (res, rej) => {
|
|
388
|
+
fs.writeFileSync(fp, contents);
|
|
389
|
+
res(fp);
|
|
390
|
+
});
|
|
391
|
+
doneFileStream2.push(p);
|
|
392
|
+
if (!files[testName]) {
|
|
393
|
+
files[testName] = /* @__PURE__ */ new Set();
|
|
394
|
+
}
|
|
395
|
+
files[testName].add(fp);
|
|
396
|
+
return p;
|
|
397
|
+
}
|
|
398
|
+
);
|
|
399
|
+
page.exposeFunction("existsSync", (fp, contents) => {
|
|
400
|
+
return fs.existsSync(fp);
|
|
401
|
+
});
|
|
402
|
+
page.exposeFunction("mkdirSync", (fp) => {
|
|
403
|
+
if (!fs.existsSync(fp)) {
|
|
404
|
+
return fs.mkdirSync(fp, {
|
|
405
|
+
recursive: true
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
return false;
|
|
409
|
+
});
|
|
410
|
+
page.exposeFunction(
|
|
411
|
+
"createWriteStream",
|
|
412
|
+
(fp, testName) => {
|
|
413
|
+
const f = fs.createWriteStream(fp);
|
|
414
|
+
if (!files[testName]) {
|
|
415
|
+
files[testName] = /* @__PURE__ */ new Set();
|
|
416
|
+
}
|
|
417
|
+
files[testName].add(fp);
|
|
418
|
+
const p = new Promise((res, rej) => {
|
|
419
|
+
res(fp);
|
|
420
|
+
});
|
|
421
|
+
doneFileStream2.push(p);
|
|
422
|
+
f.on("close", async () => {
|
|
423
|
+
await p;
|
|
424
|
+
});
|
|
425
|
+
fileStreams2.push(f);
|
|
426
|
+
return {
|
|
427
|
+
...JSON.parse(JSON.stringify(f)),
|
|
428
|
+
uid: fileStreams2.length - 1
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
);
|
|
432
|
+
page.exposeFunction("write", async (uid, contents) => {
|
|
433
|
+
return fileStreams2[uid].write(contents);
|
|
434
|
+
});
|
|
435
|
+
page.exposeFunction("end", async (uid) => {
|
|
436
|
+
return fileStreams2[uid].end();
|
|
437
|
+
});
|
|
438
|
+
page.exposeFunction("customclose", (p, testName) => {
|
|
439
|
+
fs.writeFileSync(
|
|
440
|
+
p + "/manifest.json",
|
|
441
|
+
JSON.stringify(Array.from(files[testName]))
|
|
442
|
+
);
|
|
443
|
+
delete files[testName];
|
|
444
|
+
Promise.all(screenshots[testName] || []).then(() => {
|
|
445
|
+
delete screenshots[testName];
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
page.exposeFunction("page", () => {
|
|
449
|
+
return page.mainFrame()._id;
|
|
450
|
+
});
|
|
451
|
+
page.exposeFunction("click", (sel) => {
|
|
452
|
+
return page.click(sel);
|
|
453
|
+
});
|
|
454
|
+
page.exposeFunction("focusOn", (sel) => {
|
|
455
|
+
return page.focus(sel);
|
|
456
|
+
});
|
|
457
|
+
page.exposeFunction(
|
|
458
|
+
"typeInto",
|
|
459
|
+
async (value) => await page.keyboard.type(value)
|
|
460
|
+
);
|
|
461
|
+
page.exposeFunction(
|
|
462
|
+
"getValue",
|
|
463
|
+
(selector) => page.$eval(selector, (input) => input.getAttribute("value"))
|
|
464
|
+
);
|
|
465
|
+
page.exposeFunction(
|
|
466
|
+
"getAttribute",
|
|
467
|
+
async (selector, attribute) => {
|
|
468
|
+
const attributeValue = await page.$eval(selector, (input) => {
|
|
469
|
+
return input.getAttribute(attribute);
|
|
470
|
+
});
|
|
471
|
+
return attributeValue;
|
|
472
|
+
}
|
|
473
|
+
);
|
|
474
|
+
page.exposeFunction("isDisabled", async (selector) => {
|
|
475
|
+
const attributeValue = await page.$eval(
|
|
476
|
+
selector,
|
|
477
|
+
(input) => {
|
|
478
|
+
return input.disabled;
|
|
479
|
+
}
|
|
480
|
+
);
|
|
481
|
+
return attributeValue;
|
|
482
|
+
});
|
|
483
|
+
page.exposeFunction("$", async (selector) => {
|
|
484
|
+
const x = page.$(selector);
|
|
485
|
+
const y = await x;
|
|
486
|
+
return y;
|
|
487
|
+
});
|
|
488
|
+
return page;
|
|
489
|
+
}).then(async (page) => {
|
|
490
|
+
const close = () => {
|
|
491
|
+
console.log("evaluation complete.", dest);
|
|
492
|
+
page.off("pageerror");
|
|
493
|
+
page.close();
|
|
494
|
+
this.deregister(t);
|
|
495
|
+
stderrStream.close();
|
|
496
|
+
stdoutStream.close();
|
|
497
|
+
};
|
|
498
|
+
page.on("pageerror", (err) => {
|
|
499
|
+
console.debug(`Error from ${t}: [${err.name}] `);
|
|
500
|
+
stderrStream.write(err.name);
|
|
501
|
+
if (err.cause) {
|
|
502
|
+
console.debug(`Error from ${t} cause: [${err.cause}] `);
|
|
503
|
+
stderrStream.write(err.cause);
|
|
504
|
+
}
|
|
505
|
+
if (err.stack) {
|
|
506
|
+
console.debug(`Error from stack ${t}: [${err.stack}] `);
|
|
507
|
+
stderrStream.write(err.stack);
|
|
508
|
+
}
|
|
509
|
+
console.debug(`Error from message ${t}: [${err.message}] `);
|
|
510
|
+
stderrStream.write(err.message);
|
|
511
|
+
});
|
|
512
|
+
page.on("console", (log) => {
|
|
513
|
+
stdoutStream.write(log.text());
|
|
514
|
+
stdoutStream.write(JSON.stringify(log.location()));
|
|
515
|
+
stdoutStream.write(JSON.stringify(log.stackTrace()));
|
|
516
|
+
});
|
|
517
|
+
await page.goto(`file://${`${dest}.html`}`, {});
|
|
518
|
+
await page.evaluate(evaluation).then(async (features) => {
|
|
519
|
+
this.receiveFeatures(features, destFolder);
|
|
520
|
+
}).catch((e) => {
|
|
521
|
+
console.log("evaluation failed.", dest);
|
|
522
|
+
console.log(e);
|
|
523
|
+
}).finally(() => {
|
|
524
|
+
close();
|
|
525
|
+
});
|
|
526
|
+
return page;
|
|
527
|
+
});
|
|
528
|
+
};
|
|
529
|
+
this.receiveFeatures = (features, destFolder) => {
|
|
530
|
+
console.log("this.receiveFeatures", features);
|
|
531
|
+
features.reduce(async (mm, featureStringKey) => {
|
|
532
|
+
const accum = await mm;
|
|
533
|
+
const isUrl = isValidUrl(featureStringKey);
|
|
534
|
+
if (isUrl) {
|
|
535
|
+
const u = new URL(featureStringKey);
|
|
536
|
+
if (u.protocol === "file:") {
|
|
537
|
+
const newPath = `${process.cwd()}/docs/features/internal/${path2.relative(
|
|
538
|
+
process.cwd(),
|
|
539
|
+
u.pathname
|
|
540
|
+
)}`;
|
|
541
|
+
await fs.promises.mkdir(path2.dirname(newPath), { recursive: true });
|
|
542
|
+
try {
|
|
543
|
+
await fs.unlinkSync(newPath);
|
|
544
|
+
} catch (error) {
|
|
545
|
+
if (error.code !== "ENOENT") {
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
fs.symlink(u.pathname, newPath, (err) => {
|
|
549
|
+
if (err) {
|
|
550
|
+
} else {
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
accum.push(newPath);
|
|
554
|
+
} else if (u.protocol === "http:" || u.protocol === "https:") {
|
|
555
|
+
const newPath = `${process.cwd()}/docs/features/external${u.hostname}${u.pathname}`;
|
|
556
|
+
const body = await this.configs.featureIngestor(featureStringKey);
|
|
557
|
+
writeFileAndCreateDir(newPath, body);
|
|
558
|
+
accum.push(newPath);
|
|
559
|
+
}
|
|
560
|
+
} else {
|
|
561
|
+
const newPath = `${process.cwd()}/docs/features/plain/${await sha256(
|
|
562
|
+
featureStringKey
|
|
563
|
+
)}`;
|
|
564
|
+
writeFileAndCreateDir(newPath, featureStringKey);
|
|
565
|
+
accum.push(newPath);
|
|
566
|
+
}
|
|
567
|
+
return accum;
|
|
568
|
+
}, Promise.resolve([])).then((features2) => {
|
|
569
|
+
fs.writeFileSync(
|
|
570
|
+
`${destFolder}/featurePrompt.txt`,
|
|
571
|
+
features2.map((f) => {
|
|
572
|
+
return `/read ${f}`;
|
|
573
|
+
}).join("\n")
|
|
574
|
+
);
|
|
575
|
+
});
|
|
576
|
+
};
|
|
577
|
+
this.server = {};
|
|
578
|
+
this.configs = configs;
|
|
579
|
+
this.ports = {};
|
|
580
|
+
this.registry = {};
|
|
581
|
+
this.configs.ports.forEach((element) => {
|
|
582
|
+
this.ports[element] = "true";
|
|
583
|
+
});
|
|
584
|
+
globalThis["mkdirSync"] = (fp) => {
|
|
585
|
+
if (!fs.existsSync(fp)) {
|
|
586
|
+
return fs.mkdirSync(fp, {
|
|
587
|
+
recursive: true
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
return false;
|
|
591
|
+
};
|
|
592
|
+
globalThis["writeFileSync"] = (filepath, contents, testName) => {
|
|
593
|
+
const dir = path2.dirname(filepath.split("/").slice(0, -1).join("/"));
|
|
594
|
+
fs.mkdirSync(dir, {
|
|
595
|
+
recursive: true
|
|
596
|
+
});
|
|
597
|
+
if (!files[testName]) {
|
|
598
|
+
files[testName] = /* @__PURE__ */ new Set();
|
|
599
|
+
}
|
|
600
|
+
files[testName].add(filepath);
|
|
601
|
+
return fs.writeFileSync(filepath, contents);
|
|
602
|
+
};
|
|
603
|
+
globalThis["createWriteStream"] = (filepath, testName) => {
|
|
604
|
+
const f = fs.createWriteStream(filepath);
|
|
605
|
+
fileStreams3.push(f);
|
|
606
|
+
if (!files[testName]) {
|
|
607
|
+
files[testName] = /* @__PURE__ */ new Set();
|
|
608
|
+
}
|
|
609
|
+
files[testName].add(filepath);
|
|
610
|
+
return {
|
|
611
|
+
...JSON.parse(JSON.stringify(f)),
|
|
612
|
+
uid: fileStreams3.length - 1
|
|
613
|
+
};
|
|
614
|
+
};
|
|
615
|
+
globalThis["write"] = (uid, contents) => {
|
|
616
|
+
fileStreams3[uid].write(contents);
|
|
617
|
+
};
|
|
618
|
+
globalThis["end"] = (uid) => {
|
|
619
|
+
fileStreams3[uid].end();
|
|
620
|
+
};
|
|
621
|
+
globalThis["customScreenShot"] = async (opts, page) => {
|
|
622
|
+
const p = opts.path;
|
|
623
|
+
const dir = path2.dirname(p);
|
|
624
|
+
fs.mkdirSync(dir, {
|
|
625
|
+
recursive: true
|
|
626
|
+
});
|
|
627
|
+
if (!files[opts.path]) {
|
|
628
|
+
files[opts.path] = /* @__PURE__ */ new Set();
|
|
629
|
+
}
|
|
630
|
+
files[opts.path].add(opts.path);
|
|
631
|
+
const sPromise = page.screenshot({
|
|
632
|
+
...opts,
|
|
633
|
+
path: p
|
|
634
|
+
});
|
|
635
|
+
if (!screenshots[opts.path]) {
|
|
636
|
+
screenshots[opts.path] = [];
|
|
637
|
+
}
|
|
638
|
+
screenshots[opts.path].push(sPromise);
|
|
639
|
+
await sPromise;
|
|
640
|
+
return sPromise;
|
|
641
|
+
};
|
|
642
|
+
globalThis["customclose"] = (p, testName) => {
|
|
643
|
+
if (!files[testName]) {
|
|
644
|
+
files[testName] = /* @__PURE__ */ new Set();
|
|
645
|
+
}
|
|
646
|
+
fs.writeFileSync(
|
|
647
|
+
p + "/manifest.json",
|
|
648
|
+
JSON.stringify(Array.from(files[testName]))
|
|
649
|
+
);
|
|
650
|
+
delete files[testName];
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
$(selector) {
|
|
654
|
+
throw new Error("Method not implemented.");
|
|
655
|
+
}
|
|
656
|
+
screencast(opts) {
|
|
657
|
+
throw new Error("Method not implemented.");
|
|
658
|
+
}
|
|
659
|
+
customScreenShot(opts) {
|
|
660
|
+
throw new Error("Method not implemented.");
|
|
661
|
+
}
|
|
662
|
+
end(accessObject) {
|
|
663
|
+
throw new Error("Method not implemented.");
|
|
664
|
+
}
|
|
665
|
+
existsSync(destFolder) {
|
|
666
|
+
return fs.existsSync(destFolder);
|
|
667
|
+
}
|
|
668
|
+
async mkdirSync(fp) {
|
|
669
|
+
if (!fs.existsSync(fp)) {
|
|
670
|
+
return fs.mkdirSync(fp, {
|
|
671
|
+
recursive: true
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
return false;
|
|
675
|
+
}
|
|
676
|
+
writeFileSync(fp, contents) {
|
|
677
|
+
fs.writeFileSync(fp, contents);
|
|
678
|
+
}
|
|
679
|
+
createWriteStream(filepath) {
|
|
680
|
+
return fs.createWriteStream(filepath);
|
|
681
|
+
}
|
|
682
|
+
testArtiFactoryfileWriter(tLog, callback) {
|
|
683
|
+
return (fPath, value) => {
|
|
684
|
+
callback(
|
|
685
|
+
new Promise((res, rej) => {
|
|
686
|
+
tLog("testArtiFactory =>", fPath);
|
|
687
|
+
const cleanPath = path2.resolve(fPath);
|
|
688
|
+
fPaths.push(cleanPath.replace(process.cwd(), ``));
|
|
689
|
+
const targetDir = cleanPath.split("/").slice(0, -1).join("/");
|
|
690
|
+
fs.mkdir(targetDir, { recursive: true }, async (error) => {
|
|
691
|
+
if (error) {
|
|
692
|
+
console.error(`\u2757\uFE0FtestArtiFactory failed`, targetDir, error);
|
|
693
|
+
}
|
|
694
|
+
fs.writeFileSync(
|
|
695
|
+
path2.resolve(
|
|
696
|
+
targetDir.split("/").slice(0, -1).join("/"),
|
|
697
|
+
"manifest"
|
|
698
|
+
),
|
|
699
|
+
fPaths.join(`
|
|
700
|
+
`),
|
|
701
|
+
{
|
|
702
|
+
encoding: "utf-8"
|
|
703
|
+
}
|
|
704
|
+
);
|
|
705
|
+
if (Buffer.isBuffer(value)) {
|
|
706
|
+
fs.writeFileSync(fPath, value, "binary");
|
|
707
|
+
res();
|
|
708
|
+
} else if (`string` === typeof value) {
|
|
709
|
+
fs.writeFileSync(fPath, value.toString(), {
|
|
710
|
+
encoding: "utf-8"
|
|
711
|
+
});
|
|
712
|
+
res();
|
|
713
|
+
} else {
|
|
714
|
+
const pipeStream = value;
|
|
715
|
+
const myFile = fs.createWriteStream(fPath);
|
|
716
|
+
pipeStream.pipe(myFile);
|
|
717
|
+
pipeStream.on("close", () => {
|
|
718
|
+
myFile.close();
|
|
719
|
+
res();
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
})
|
|
724
|
+
);
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
write(accessObject, contents) {
|
|
728
|
+
throw new Error("Method not implemented.");
|
|
729
|
+
}
|
|
730
|
+
page() {
|
|
731
|
+
throw new Error("Method not implemented.");
|
|
732
|
+
}
|
|
733
|
+
click(selector) {
|
|
734
|
+
throw new Error("Method not implemented.");
|
|
735
|
+
}
|
|
736
|
+
focusOn(selector) {
|
|
737
|
+
throw new Error("Method not implemented.");
|
|
738
|
+
}
|
|
739
|
+
typeInto(value) {
|
|
740
|
+
throw new Error("Method not implemented.");
|
|
741
|
+
}
|
|
742
|
+
getValue(value) {
|
|
743
|
+
throw new Error("Method not implemented.");
|
|
744
|
+
}
|
|
745
|
+
getAttribute(selector, attribute) {
|
|
746
|
+
throw new Error("Method not implemented.");
|
|
747
|
+
}
|
|
748
|
+
isDisabled(selector) {
|
|
749
|
+
throw new Error("Method not implemented.");
|
|
750
|
+
}
|
|
751
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
752
|
+
async startPuppeteer(options, destfolder) {
|
|
753
|
+
this.browser = await puppeteer.launch(options);
|
|
754
|
+
}
|
|
755
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
756
|
+
shutDown() {
|
|
757
|
+
console.log("shutting down...");
|
|
758
|
+
this.shutdownMode = true;
|
|
759
|
+
this.checkForShutdown();
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
async function writeFileAndCreateDir(filePath, data) {
|
|
763
|
+
const dirPath = path2.dirname(filePath);
|
|
764
|
+
try {
|
|
765
|
+
await fs.promises.mkdir(dirPath, { recursive: true });
|
|
766
|
+
await fs.promises.writeFile(filePath, data);
|
|
767
|
+
} catch (error) {
|
|
768
|
+
console.error(`Error writing file: ${error}`);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
async function sha256(rawData) {
|
|
772
|
+
const data = typeof rawData === "object" ? JSON.stringify(rawData) : String(rawData);
|
|
773
|
+
const msgBuffer = new TextEncoder().encode(data);
|
|
774
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer);
|
|
775
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
776
|
+
return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
777
|
+
}
|
|
778
|
+
function isValidUrl(string) {
|
|
779
|
+
try {
|
|
780
|
+
new URL(string);
|
|
781
|
+
return true;
|
|
782
|
+
} catch (err) {
|
|
783
|
+
return false;
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
// src/Puppeteer.ts
|
|
788
|
+
readline.emitKeypressEvents(process.stdin);
|
|
789
|
+
if (process.stdin.isTTY)
|
|
790
|
+
process.stdin.setRawMode(true);
|
|
791
|
+
var Puppeteer_default = async (partialConfig) => {
|
|
792
|
+
const config = {
|
|
793
|
+
...partialConfig,
|
|
794
|
+
buildDir: process.cwd() + "/" + partialConfig.outdir
|
|
795
|
+
};
|
|
796
|
+
fs2.writeFileSync(
|
|
797
|
+
`${config.outdir}/testeranto.json`,
|
|
798
|
+
JSON.stringify(
|
|
799
|
+
{
|
|
800
|
+
...config,
|
|
801
|
+
buildDir: process.cwd() + "/" + config.outdir
|
|
802
|
+
},
|
|
803
|
+
null,
|
|
804
|
+
2
|
|
805
|
+
)
|
|
806
|
+
);
|
|
807
|
+
const pm = new PM_Main(config);
|
|
808
|
+
await pm.startPuppeteer(
|
|
809
|
+
{
|
|
810
|
+
// timeout: 1,
|
|
811
|
+
waitForInitialPage: false,
|
|
812
|
+
executablePath: (
|
|
813
|
+
// process.env.CHROMIUM_PATH || "/opt/homebrew/bin/chromium",
|
|
814
|
+
"/opt/homebrew/bin/chromium"
|
|
815
|
+
),
|
|
816
|
+
headless: false,
|
|
817
|
+
dumpio: true,
|
|
818
|
+
// timeout: 0,
|
|
819
|
+
devtools: true,
|
|
820
|
+
args: [
|
|
821
|
+
"--auto-open-devtools-for-tabs",
|
|
822
|
+
`--remote-debugging-port=3234`,
|
|
823
|
+
// "--disable-features=IsolateOrigins,site-per-process",
|
|
824
|
+
"--disable-site-isolation-trials",
|
|
825
|
+
"--allow-insecure-localhost",
|
|
826
|
+
"--allow-file-access-from-files",
|
|
827
|
+
"--allow-running-insecure-content",
|
|
828
|
+
"--disable-dev-shm-usage",
|
|
829
|
+
"--disable-extensions",
|
|
830
|
+
"--disable-gpu",
|
|
831
|
+
"--disable-setuid-sandbox",
|
|
832
|
+
"--disable-site-isolation-trials",
|
|
833
|
+
"--disable-web-security",
|
|
834
|
+
"--no-first-run",
|
|
835
|
+
"--no-sandbox",
|
|
836
|
+
"--no-startup-window",
|
|
837
|
+
// "--no-zygote",
|
|
838
|
+
"--reduce-security-for-testing",
|
|
839
|
+
"--remote-allow-origins=*",
|
|
840
|
+
"--unsafely-treat-insecure-origin-as-secure=*"
|
|
841
|
+
// "--disable-features=IsolateOrigins",
|
|
842
|
+
// "--remote-allow-origins=ws://localhost:3234",
|
|
843
|
+
// "--single-process",
|
|
844
|
+
// "--unsafely-treat-insecure-origin-as-secure",
|
|
845
|
+
// "--unsafely-treat-insecure-origin-as-secure=ws://192.168.0.101:3234",
|
|
846
|
+
// "--disk-cache-dir=/dev/null",
|
|
847
|
+
// "--disk-cache-size=1",
|
|
848
|
+
// "--start-maximized",
|
|
849
|
+
]
|
|
850
|
+
},
|
|
851
|
+
"."
|
|
852
|
+
);
|
|
853
|
+
console.log(
|
|
854
|
+
"\n Puppeteer is running. Press 'q' to shutdown softly. Press 'x' to shutdown forcefully.\n"
|
|
855
|
+
);
|
|
856
|
+
process.stdin.on("keypress", (str, key) => {
|
|
857
|
+
if (key.name === "q") {
|
|
858
|
+
pm.shutDown();
|
|
859
|
+
}
|
|
860
|
+
if (key.name === "x") {
|
|
861
|
+
process.exit(-1);
|
|
862
|
+
}
|
|
863
|
+
});
|
|
864
|
+
config.tests.forEach(([test, runtime, tr, sidecars]) => {
|
|
865
|
+
if (runtime === "node") {
|
|
866
|
+
pm.launchNode(test, destinationOfRuntime(test, "node", config));
|
|
867
|
+
} else if (runtime === "web") {
|
|
868
|
+
pm.launchWeb(test, destinationOfRuntime(test, "web", config), sidecars);
|
|
869
|
+
} else {
|
|
870
|
+
console.error("runtime makes no sense", runtime);
|
|
871
|
+
}
|
|
872
|
+
});
|
|
873
|
+
if (config.devMode) {
|
|
874
|
+
console.log("ready and watching for changes...", config.buildDir);
|
|
875
|
+
watch(config.buildDir, (eventType, changedFile) => {
|
|
876
|
+
if (changedFile) {
|
|
877
|
+
config.tests.forEach(([test, runtime, tr, sidecars]) => {
|
|
878
|
+
if (eventType === "change" || eventType === "rename") {
|
|
879
|
+
if (changedFile === test.replace("./", "node/").split(".").slice(0, -1).concat("mjs").join(".")) {
|
|
880
|
+
pm.launchNode(test, destinationOfRuntime(test, "node", config));
|
|
881
|
+
}
|
|
882
|
+
if (changedFile === test.replace("./", "web/").split(".").slice(0, -1).concat("mjs").join(".")) {
|
|
883
|
+
pm.launchWeb(
|
|
884
|
+
test,
|
|
885
|
+
destinationOfRuntime(test, "web", config),
|
|
886
|
+
sidecars
|
|
887
|
+
);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
});
|
|
893
|
+
} else {
|
|
894
|
+
pm.shutDown();
|
|
895
|
+
}
|
|
896
|
+
};
|
|
897
|
+
|
|
898
|
+
// src/run-tests.ts
|
|
899
|
+
import process2 from "process";
|
|
900
|
+
if (!process2.argv[2]) {
|
|
901
|
+
console.log("You didn't pass a config file");
|
|
902
|
+
process2.exit(-1);
|
|
903
|
+
} else {
|
|
904
|
+
import(process2.cwd() + "/" + process2.argv[2]).then((module) => {
|
|
905
|
+
Puppeteer_default(module.default);
|
|
906
|
+
});
|
|
907
|
+
}
|