@jsenv/test 1.1.7 → 1.2.1
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/dist/jsenv_test.js +206 -21
- package/package.json +2 -2
- package/src/coverage/babel_plugin_instrument.js +2 -2
- package/src/coverage/coverage_reporter_html_directory.js +3 -3
- package/src/coverage/coverage_reporter_text_log.js +3 -3
- package/src/coverage/empty_coverage_factory.js +2 -2
- package/src/coverage/istanbul_coverage_composition.js +2 -2
- package/src/coverage/istanbul_coverage_map_from_coverage.js +2 -2
- package/src/coverage/v8_coverage_composition.js +2 -2
- package/src/coverage/v8_coverage_to_istanbul.js +2 -2
- package/src/execution/web_server_param.js +8 -3
- package/src/helpers/basic_fetch.js +53 -0
- package/src/helpers/import_with_require.js +3 -0
- package/src/helpers/ping_server.js +30 -0
- package/src/helpers/web_url_converter.js +28 -0
- package/src/runtime_browsers/middleware_istanbul.js +1 -1
- package/src/runtime_browsers/middleware_js_supervisor.js +1 -1
- package/src/runtime_browsers/using_playwright.js +1 -1
- package/src/runtime_node/kill_process_tree.js +2 -3
package/dist/jsenv_test.js
CHANGED
|
@@ -7,17 +7,15 @@ import process$1, { memoryUsage } from "node:process";
|
|
|
7
7
|
import os from "node:os";
|
|
8
8
|
import tty from "node:tty";
|
|
9
9
|
import stringWidth from "string-width";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { basicFetch } from "@jsenv/core/src/helpers/basic_fetch.js";
|
|
10
|
+
import { createRequire } from "node:module";
|
|
11
|
+
import { createServer } from "node:net";
|
|
13
12
|
import v8, { takeCoverage } from "node:v8";
|
|
14
13
|
import stripAnsi from "strip-ansi";
|
|
15
14
|
import { applyBabelPlugins } from "@jsenv/ast";
|
|
16
15
|
import { createId } from "@paralleldrive/cuid2";
|
|
17
16
|
import { runInNewContext } from "node:vm";
|
|
18
17
|
import wrapAnsi from "wrap-ansi";
|
|
19
|
-
import {
|
|
20
|
-
import { injectSupervisorIntoHTML, supervisorFileUrl } from "@jsenv/core/src/plugins/supervisor/html_supervisor_injection.js";
|
|
18
|
+
import { injectSupervisorIntoHTML, supervisorFileUrl } from "@jsenv/plugin-supervisor/src/html_supervisor_injection.js";
|
|
21
19
|
import { SOURCEMAP, generateSourcemapDataUrl } from "@jsenv/sourcemap";
|
|
22
20
|
import { fork } from "node:child_process";
|
|
23
21
|
import { findFreePort } from "@jsenv/server";
|
|
@@ -218,6 +216,24 @@ const pathnameToParentPathname = pathname => {
|
|
|
218
216
|
return pathname.slice(0, slashLastIndex + 1);
|
|
219
217
|
};
|
|
220
218
|
|
|
219
|
+
const moveUrl = ({
|
|
220
|
+
url,
|
|
221
|
+
from,
|
|
222
|
+
to,
|
|
223
|
+
preferRelative
|
|
224
|
+
}) => {
|
|
225
|
+
let relativeUrl = urlToRelativeUrl(url, from);
|
|
226
|
+
if (relativeUrl.slice(0, 2) === "//") {
|
|
227
|
+
// restore the protocol
|
|
228
|
+
relativeUrl = new URL(relativeUrl, url).href;
|
|
229
|
+
}
|
|
230
|
+
const absoluteUrl = new URL(relativeUrl, to).href;
|
|
231
|
+
if (preferRelative) {
|
|
232
|
+
return urlToRelativeUrl(absoluteUrl, to);
|
|
233
|
+
}
|
|
234
|
+
return absoluteUrl;
|
|
235
|
+
};
|
|
236
|
+
|
|
221
237
|
const urlIsInsideOf = (url, otherUrl) => {
|
|
222
238
|
const urlObject = new URL(url);
|
|
223
239
|
const otherUrlObject = new URL(otherUrl);
|
|
@@ -458,7 +474,7 @@ const getPermissionOrComputeDefault = (action, subject, permissions) => {
|
|
|
458
474
|
* https://nodejs.org/docs/latest-v13.x/api/fs.html#fs_class_fs_stats
|
|
459
475
|
*/
|
|
460
476
|
|
|
461
|
-
const isWindows$
|
|
477
|
+
const isWindows$2 = process.platform === "win32";
|
|
462
478
|
const readEntryStat = async (source, {
|
|
463
479
|
nullIfNotFound = false,
|
|
464
480
|
followLink = true
|
|
@@ -472,7 +488,7 @@ const readEntryStat = async (source, {
|
|
|
472
488
|
return readStat(sourcePath, {
|
|
473
489
|
followLink,
|
|
474
490
|
...handleNotFoundOption,
|
|
475
|
-
...(isWindows$
|
|
491
|
+
...(isWindows$2 ? {
|
|
476
492
|
// Windows can EPERM on stat
|
|
477
493
|
handlePermissionDeniedError: async error => {
|
|
478
494
|
console.error(`trying to fix windows EPERM after stats on ${sourcePath}`);
|
|
@@ -1399,8 +1415,60 @@ const ensureParentDirectories = async destination => {
|
|
|
1399
1415
|
});
|
|
1400
1416
|
};
|
|
1401
1417
|
|
|
1402
|
-
process.platform === "win32";
|
|
1403
|
-
fileSystemPathToUrl(process.cwd());
|
|
1418
|
+
const isWindows$1 = process.platform === "win32";
|
|
1419
|
+
const baseUrlFallback = fileSystemPathToUrl(process.cwd());
|
|
1420
|
+
|
|
1421
|
+
/**
|
|
1422
|
+
* Some url might be resolved or remapped to url without the windows drive letter.
|
|
1423
|
+
* For instance
|
|
1424
|
+
* new URL('/foo.js', 'file:///C:/dir/file.js')
|
|
1425
|
+
* resolves to
|
|
1426
|
+
* 'file:///foo.js'
|
|
1427
|
+
*
|
|
1428
|
+
* But on windows it becomes a problem because we need the drive letter otherwise
|
|
1429
|
+
* url cannot be converted to a filesystem path.
|
|
1430
|
+
*
|
|
1431
|
+
* ensureWindowsDriveLetter ensure a resolved url still contains the drive letter.
|
|
1432
|
+
*/
|
|
1433
|
+
|
|
1434
|
+
const ensureWindowsDriveLetter = (url, baseUrl) => {
|
|
1435
|
+
try {
|
|
1436
|
+
url = String(new URL(url));
|
|
1437
|
+
} catch (e) {
|
|
1438
|
+
throw new Error(`absolute url expected but got ${url}`);
|
|
1439
|
+
}
|
|
1440
|
+
if (!isWindows$1) {
|
|
1441
|
+
return url;
|
|
1442
|
+
}
|
|
1443
|
+
try {
|
|
1444
|
+
baseUrl = String(new URL(baseUrl));
|
|
1445
|
+
} catch (e) {
|
|
1446
|
+
throw new Error(`absolute baseUrl expected but got ${baseUrl} to ensure windows drive letter on ${url}`);
|
|
1447
|
+
}
|
|
1448
|
+
if (!url.startsWith("file://")) {
|
|
1449
|
+
return url;
|
|
1450
|
+
}
|
|
1451
|
+
const afterProtocol = url.slice("file://".length);
|
|
1452
|
+
// we still have the windows drive letter
|
|
1453
|
+
if (extractDriveLetter(afterProtocol)) {
|
|
1454
|
+
return url;
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
// drive letter was lost, restore it
|
|
1458
|
+
const baseUrlOrFallback = baseUrl.startsWith("file://") ? baseUrl : baseUrlFallback;
|
|
1459
|
+
const driveLetter = extractDriveLetter(baseUrlOrFallback.slice("file://".length));
|
|
1460
|
+
if (!driveLetter) {
|
|
1461
|
+
throw new Error(`drive letter expected on baseUrl but got ${baseUrl} to ensure windows drive letter on ${url}`);
|
|
1462
|
+
}
|
|
1463
|
+
return `file:///${driveLetter}:${afterProtocol}`;
|
|
1464
|
+
};
|
|
1465
|
+
const extractDriveLetter = resource => {
|
|
1466
|
+
// we still have the windows drive letter
|
|
1467
|
+
if (/[a-zA-Z]/.test(resource[1]) && resource[2] === ":") {
|
|
1468
|
+
return resource[1];
|
|
1469
|
+
}
|
|
1470
|
+
return null;
|
|
1471
|
+
};
|
|
1404
1472
|
|
|
1405
1473
|
process.platform === "win32";
|
|
1406
1474
|
|
|
@@ -2349,10 +2417,12 @@ const generateCoverageJsonFile = async ({
|
|
|
2349
2417
|
await writeFile(coverageJsonFileUrl, coverageAsText);
|
|
2350
2418
|
};
|
|
2351
2419
|
|
|
2420
|
+
const importWithRequire = createRequire(import.meta.url);
|
|
2421
|
+
|
|
2352
2422
|
const istanbulCoverageMapFromCoverage = coverage => {
|
|
2353
2423
|
const {
|
|
2354
2424
|
createCoverageMap
|
|
2355
|
-
} =
|
|
2425
|
+
} = importWithRequire("istanbul-lib-coverage");
|
|
2356
2426
|
const coverageAdjusted = {};
|
|
2357
2427
|
Object.keys(coverage).forEach(key => {
|
|
2358
2428
|
coverageAdjusted[key.slice(2)] = {
|
|
@@ -2370,8 +2440,8 @@ const generateCoverageHtmlDirectory = async (coverage, {
|
|
|
2370
2440
|
coverageReportSkipEmpty,
|
|
2371
2441
|
coverageReportSkipFull
|
|
2372
2442
|
}) => {
|
|
2373
|
-
const libReport =
|
|
2374
|
-
const reports =
|
|
2443
|
+
const libReport = importWithRequire("istanbul-lib-report");
|
|
2444
|
+
const reports = importWithRequire("istanbul-reports");
|
|
2375
2445
|
const context = libReport.createContext({
|
|
2376
2446
|
dir: fileURLToPath(rootDirectoryUrl),
|
|
2377
2447
|
coverageMap: istanbulCoverageMapFromCoverage(coverage),
|
|
@@ -2389,8 +2459,8 @@ const generateCoverageTextLog = (coverage, {
|
|
|
2389
2459
|
coverageReportSkipEmpty,
|
|
2390
2460
|
coverageReportSkipFull
|
|
2391
2461
|
}) => {
|
|
2392
|
-
const libReport =
|
|
2393
|
-
const reports =
|
|
2462
|
+
const libReport = importWithRequire("istanbul-lib-report");
|
|
2463
|
+
const reports = importWithRequire("istanbul-reports");
|
|
2394
2464
|
const context = libReport.createContext({
|
|
2395
2465
|
coverageMap: istanbulCoverageMapFromCoverage(coverage)
|
|
2396
2466
|
});
|
|
@@ -2401,6 +2471,92 @@ const generateCoverageTextLog = (coverage, {
|
|
|
2401
2471
|
report.execute(context);
|
|
2402
2472
|
};
|
|
2403
2473
|
|
|
2474
|
+
const pingServer = async url => {
|
|
2475
|
+
const server = createServer();
|
|
2476
|
+
const {
|
|
2477
|
+
hostname,
|
|
2478
|
+
port
|
|
2479
|
+
} = new URL(url);
|
|
2480
|
+
try {
|
|
2481
|
+
await new Promise((resolve, reject) => {
|
|
2482
|
+
server.on("error", reject);
|
|
2483
|
+
server.on("listening", () => {
|
|
2484
|
+
resolve();
|
|
2485
|
+
});
|
|
2486
|
+
server.listen(port, hostname);
|
|
2487
|
+
});
|
|
2488
|
+
} catch (error) {
|
|
2489
|
+
if (error && error.code === "EADDRINUSE") {
|
|
2490
|
+
return true;
|
|
2491
|
+
}
|
|
2492
|
+
if (error && error.code === "EACCES") {
|
|
2493
|
+
return true;
|
|
2494
|
+
}
|
|
2495
|
+
throw error;
|
|
2496
|
+
}
|
|
2497
|
+
await new Promise((resolve, reject) => {
|
|
2498
|
+
server.on("error", reject);
|
|
2499
|
+
server.on("close", resolve);
|
|
2500
|
+
server.close();
|
|
2501
|
+
});
|
|
2502
|
+
return false;
|
|
2503
|
+
};
|
|
2504
|
+
|
|
2505
|
+
const basicFetch = async (url, {
|
|
2506
|
+
rejectUnauthorized = true,
|
|
2507
|
+
method = "GET",
|
|
2508
|
+
headers = {}
|
|
2509
|
+
} = {}) => {
|
|
2510
|
+
let requestModule;
|
|
2511
|
+
if (url.startsWith("http:")) {
|
|
2512
|
+
requestModule = await import("node:http");
|
|
2513
|
+
} else {
|
|
2514
|
+
requestModule = await import("node:https");
|
|
2515
|
+
}
|
|
2516
|
+
const {
|
|
2517
|
+
request
|
|
2518
|
+
} = requestModule;
|
|
2519
|
+
const urlObject = new URL(url);
|
|
2520
|
+
return new Promise((resolve, reject) => {
|
|
2521
|
+
const req = request({
|
|
2522
|
+
rejectUnauthorized,
|
|
2523
|
+
hostname: urlObject.hostname,
|
|
2524
|
+
port: urlObject.port,
|
|
2525
|
+
path: urlObject.pathname,
|
|
2526
|
+
method,
|
|
2527
|
+
headers
|
|
2528
|
+
});
|
|
2529
|
+
req.on("response", response => {
|
|
2530
|
+
resolve({
|
|
2531
|
+
status: response.statusCode,
|
|
2532
|
+
headers: response.headers,
|
|
2533
|
+
json: () => {
|
|
2534
|
+
req.setTimeout(0);
|
|
2535
|
+
req.destroy();
|
|
2536
|
+
return new Promise(resolve => {
|
|
2537
|
+
if (response.headers["content-type"] !== "application/json") {
|
|
2538
|
+
console.warn("not json");
|
|
2539
|
+
}
|
|
2540
|
+
let responseBody = "";
|
|
2541
|
+
response.setEncoding("utf8");
|
|
2542
|
+
response.on("data", chunk => {
|
|
2543
|
+
responseBody += chunk;
|
|
2544
|
+
});
|
|
2545
|
+
response.on("end", () => {
|
|
2546
|
+
resolve(JSON.parse(responseBody));
|
|
2547
|
+
});
|
|
2548
|
+
response.on("error", e => {
|
|
2549
|
+
reject(e);
|
|
2550
|
+
});
|
|
2551
|
+
});
|
|
2552
|
+
}
|
|
2553
|
+
});
|
|
2554
|
+
});
|
|
2555
|
+
req.on("error", reject);
|
|
2556
|
+
req.end();
|
|
2557
|
+
});
|
|
2558
|
+
};
|
|
2559
|
+
|
|
2404
2560
|
const assertAndNormalizeWebServer = async webServer => {
|
|
2405
2561
|
if (!webServer) {
|
|
2406
2562
|
throw new TypeError(`webServer is required when running tests on browser(s)`);
|
|
@@ -2421,7 +2577,7 @@ const assertAndNormalizeWebServer = async webServer => {
|
|
|
2421
2577
|
await import(webServer.moduleUrl);
|
|
2422
2578
|
delete process.env.IMPORTED_BY_TEST_PLAN;
|
|
2423
2579
|
} catch (e) {
|
|
2424
|
-
if (e.code === "ERR_MODULE_NOT_FOUND") {
|
|
2580
|
+
if (e.code === "ERR_MODULE_NOT_FOUND" && e.message.includes(fileURLToPath(webServer.moduleUrl))) {
|
|
2425
2581
|
throw new Error(`webServer.moduleUrl does not lead to a file at "${webServer.moduleUrl}"`);
|
|
2426
2582
|
}
|
|
2427
2583
|
throw e;
|
|
@@ -2601,7 +2757,7 @@ const composeTwoV8Coverages = (firstV8Coverage, secondV8Coverage) => {
|
|
|
2601
2757
|
// eslint-disable-next-line import/no-unresolved
|
|
2602
2758
|
const {
|
|
2603
2759
|
mergeProcessCovs
|
|
2604
|
-
} =
|
|
2760
|
+
} = importWithRequire("@c88/v8-coverage");
|
|
2605
2761
|
// "mergeProcessCovs" do not preserves source-map-cache during the merge
|
|
2606
2762
|
// so we store sourcemap cache now
|
|
2607
2763
|
const sourceMapCache = {};
|
|
@@ -2632,7 +2788,7 @@ const composeTwoFileByFileIstanbulCoverages = (firstFileByFileIstanbulCoverage,
|
|
|
2632
2788
|
const merge = (firstIstanbulCoverage, secondIstanbulCoverage) => {
|
|
2633
2789
|
const {
|
|
2634
2790
|
createFileCoverage
|
|
2635
|
-
} =
|
|
2791
|
+
} = importWithRequire("istanbul-lib-coverage");
|
|
2636
2792
|
const istanbulFileCoverageObject = createFileCoverage(firstIstanbulCoverage);
|
|
2637
2793
|
istanbulFileCoverageObject.merge(secondIstanbulCoverage);
|
|
2638
2794
|
const istanbulCoverage = istanbulFileCoverageObject.toJSON();
|
|
@@ -2645,7 +2801,7 @@ const v8CoverageToIstanbul = async (v8Coverage, {
|
|
|
2645
2801
|
const operation = Abort.startOperation();
|
|
2646
2802
|
operation.addAbortSignal(signal);
|
|
2647
2803
|
try {
|
|
2648
|
-
const v8ToIstanbul =
|
|
2804
|
+
const v8ToIstanbul = importWithRequire("v8-to-istanbul");
|
|
2649
2805
|
const sourcemapCache = v8Coverage["source-map-cache"];
|
|
2650
2806
|
let istanbulCoverageComposed = null;
|
|
2651
2807
|
await v8Coverage.result.reduce(async (previous, fileV8Coverage) => {
|
|
@@ -2795,7 +2951,7 @@ const babelPluginInstrument = (api, {
|
|
|
2795
2951
|
}) => {
|
|
2796
2952
|
const {
|
|
2797
2953
|
programVisitor
|
|
2798
|
-
} =
|
|
2954
|
+
} = importWithRequire("istanbul-lib-instrument");
|
|
2799
2955
|
const {
|
|
2800
2956
|
types
|
|
2801
2957
|
} = api;
|
|
@@ -2882,7 +3038,7 @@ const relativeUrlToEmptyCoverage = async (relativeUrl, {
|
|
|
2882
3038
|
const createEmptyCoverage = relativeUrl => {
|
|
2883
3039
|
const {
|
|
2884
3040
|
createFileCoverage
|
|
2885
|
-
} =
|
|
3041
|
+
} = importWithRequire("istanbul-lib-coverage");
|
|
2886
3042
|
return createFileCoverage(relativeUrl).toJSON();
|
|
2887
3043
|
};
|
|
2888
3044
|
|
|
@@ -4288,6 +4444,35 @@ const memoize = compute => {
|
|
|
4288
4444
|
return fnWithMemoization;
|
|
4289
4445
|
};
|
|
4290
4446
|
|
|
4447
|
+
const WEB_URL_CONVERTER = {
|
|
4448
|
+
asWebUrl: (fileUrl, webServer) => {
|
|
4449
|
+
if (urlIsInsideOf(fileUrl, webServer.rootDirectoryUrl)) {
|
|
4450
|
+
return moveUrl({
|
|
4451
|
+
url: fileUrl,
|
|
4452
|
+
from: webServer.rootDirectoryUrl,
|
|
4453
|
+
to: `${webServer.origin}/`
|
|
4454
|
+
});
|
|
4455
|
+
}
|
|
4456
|
+
const fsRootUrl = ensureWindowsDriveLetter("file:///", fileUrl);
|
|
4457
|
+
return `${webServer.origin}/@fs/${fileUrl.slice(fsRootUrl.length)}`;
|
|
4458
|
+
},
|
|
4459
|
+
asFileUrl: (webUrl, webServer) => {
|
|
4460
|
+
const {
|
|
4461
|
+
pathname,
|
|
4462
|
+
search
|
|
4463
|
+
} = new URL(webUrl);
|
|
4464
|
+
if (pathname.startsWith("/@fs/")) {
|
|
4465
|
+
const fsRootRelativeUrl = pathname.slice("/@fs/".length);
|
|
4466
|
+
return `file:///${fsRootRelativeUrl}${search}`;
|
|
4467
|
+
}
|
|
4468
|
+
return moveUrl({
|
|
4469
|
+
url: webUrl,
|
|
4470
|
+
from: `${webServer.origin}/`,
|
|
4471
|
+
to: webServer.rootDirectoryUrl
|
|
4472
|
+
});
|
|
4473
|
+
}
|
|
4474
|
+
};
|
|
4475
|
+
|
|
4291
4476
|
const initJsSupervisorMiddleware = async (page, {
|
|
4292
4477
|
webServer,
|
|
4293
4478
|
fileUrl,
|
|
@@ -5258,7 +5443,7 @@ const killProcessTree = async (processId, {
|
|
|
5258
5443
|
signal,
|
|
5259
5444
|
timeout = 2000
|
|
5260
5445
|
}) => {
|
|
5261
|
-
const pidtree =
|
|
5446
|
+
const pidtree = importWithRequire("pidtree");
|
|
5262
5447
|
let descendantProcessIds;
|
|
5263
5448
|
try {
|
|
5264
5449
|
descendantProcessIds = await pidtree(processId);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/test",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
"playwright": "1.x"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@jsenv/core": "36.0.2",
|
|
37
36
|
"@jsenv/abort": "4.2.4",
|
|
38
37
|
"@jsenv/ast": "4.0.0",
|
|
39
38
|
"@jsenv/filesystem": "4.2.3",
|
|
40
39
|
"@jsenv/log": "3.3.5",
|
|
40
|
+
"@jsenv/plugin-supervisor": "1.0.0",
|
|
41
41
|
"@jsenv/urls": "2.0.0",
|
|
42
42
|
"@jsenv/url-meta": "8.1.0",
|
|
43
43
|
"@jsenv/uneval": "1.6.0",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { importWithRequire } from "../helpers/import_with_require.js";
|
|
2
2
|
|
|
3
3
|
// https://github.com/istanbuljs/babel-plugin-istanbul/blob/321740f7b25d803f881466ea819d870f7ed6a254/src/index.js
|
|
4
4
|
|
|
5
5
|
export const babelPluginInstrument = (api, { useInlineSourceMaps = false }) => {
|
|
6
|
-
const { programVisitor } =
|
|
6
|
+
const { programVisitor } = importWithRequire("istanbul-lib-instrument");
|
|
7
7
|
const { types } = api;
|
|
8
8
|
|
|
9
9
|
return {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { fileURLToPath } from "node:url";
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { importWithRequire } from "../helpers/import_with_require.js";
|
|
5
5
|
import { istanbulCoverageMapFromCoverage } from "./istanbul_coverage_map_from_coverage.js";
|
|
6
6
|
|
|
7
7
|
export const generateCoverageHtmlDirectory = async (
|
|
@@ -13,8 +13,8 @@ export const generateCoverageHtmlDirectory = async (
|
|
|
13
13
|
coverageReportSkipFull,
|
|
14
14
|
},
|
|
15
15
|
) => {
|
|
16
|
-
const libReport =
|
|
17
|
-
const reports =
|
|
16
|
+
const libReport = importWithRequire("istanbul-lib-report");
|
|
17
|
+
const reports = importWithRequire("istanbul-reports");
|
|
18
18
|
|
|
19
19
|
const context = libReport.createContext({
|
|
20
20
|
dir: fileURLToPath(rootDirectoryUrl),
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { importWithRequire } from "../helpers/import_with_require.js";
|
|
2
2
|
import { istanbulCoverageMapFromCoverage } from "./istanbul_coverage_map_from_coverage.js";
|
|
3
3
|
|
|
4
4
|
export const generateCoverageTextLog = (
|
|
5
5
|
coverage,
|
|
6
6
|
{ coverageReportSkipEmpty, coverageReportSkipFull },
|
|
7
7
|
) => {
|
|
8
|
-
const libReport =
|
|
9
|
-
const reports =
|
|
8
|
+
const libReport = importWithRequire("istanbul-lib-report");
|
|
9
|
+
const reports = importWithRequire("istanbul-reports");
|
|
10
10
|
|
|
11
11
|
const context = libReport.createContext({
|
|
12
12
|
coverageMap: istanbulCoverageMapFromCoverage(coverage),
|
|
@@ -2,8 +2,8 @@ import { readFile } from "@jsenv/filesystem";
|
|
|
2
2
|
import { resolveUrl } from "@jsenv/urls";
|
|
3
3
|
import { Abort } from "@jsenv/abort";
|
|
4
4
|
import { applyBabelPlugins } from "@jsenv/ast";
|
|
5
|
-
import { requireFromJsenv } from "@jsenv/core/src/helpers/require_from_jsenv.js";
|
|
6
5
|
|
|
6
|
+
import { importWithRequire } from "../helpers/import_with_require.js";
|
|
7
7
|
import { babelPluginInstrument } from "./babel_plugin_instrument.js";
|
|
8
8
|
|
|
9
9
|
export const relativeUrlToEmptyCoverage = async (
|
|
@@ -47,6 +47,6 @@ export const relativeUrlToEmptyCoverage = async (
|
|
|
47
47
|
};
|
|
48
48
|
|
|
49
49
|
const createEmptyCoverage = (relativeUrl) => {
|
|
50
|
-
const { createFileCoverage } =
|
|
50
|
+
const { createFileCoverage } = importWithRequire("istanbul-lib-coverage");
|
|
51
51
|
return createFileCoverage(relativeUrl).toJSON();
|
|
52
52
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { importWithRequire } from "../helpers/import_with_require.js";
|
|
2
2
|
|
|
3
3
|
export const composeTwoFileByFileIstanbulCoverages = (
|
|
4
4
|
firstFileByFileIstanbulCoverage,
|
|
@@ -20,7 +20,7 @@ export const composeTwoFileByFileIstanbulCoverages = (
|
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
const merge = (firstIstanbulCoverage, secondIstanbulCoverage) => {
|
|
23
|
-
const { createFileCoverage } =
|
|
23
|
+
const { createFileCoverage } = importWithRequire("istanbul-lib-coverage");
|
|
24
24
|
const istanbulFileCoverageObject = createFileCoverage(firstIstanbulCoverage);
|
|
25
25
|
istanbulFileCoverageObject.merge(secondIstanbulCoverage);
|
|
26
26
|
const istanbulCoverage = istanbulFileCoverageObject.toJSON();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { importWithRequire } from "../helpers/import_with_require.js";
|
|
2
2
|
|
|
3
3
|
export const istanbulCoverageMapFromCoverage = (coverage) => {
|
|
4
|
-
const { createCoverageMap } =
|
|
4
|
+
const { createCoverageMap } = importWithRequire("istanbul-lib-coverage");
|
|
5
5
|
|
|
6
6
|
const coverageAdjusted = {};
|
|
7
7
|
Object.keys(coverage).forEach((key) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { importWithRequire } from "../helpers/import_with_require.js";
|
|
2
2
|
|
|
3
3
|
export const composeTwoV8Coverages = (firstV8Coverage, secondV8Coverage) => {
|
|
4
4
|
if (secondV8Coverage.result.length === 0) {
|
|
@@ -6,7 +6,7 @@ export const composeTwoV8Coverages = (firstV8Coverage, secondV8Coverage) => {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
// eslint-disable-next-line import/no-unresolved
|
|
9
|
-
const { mergeProcessCovs } =
|
|
9
|
+
const { mergeProcessCovs } = importWithRequire("@c88/v8-coverage");
|
|
10
10
|
// "mergeProcessCovs" do not preserves source-map-cache during the merge
|
|
11
11
|
// so we store sourcemap cache now
|
|
12
12
|
const sourceMapCache = {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { urlToFileSystemPath } from "@jsenv/urls";
|
|
2
2
|
import { Abort } from "@jsenv/abort";
|
|
3
|
-
import { requireFromJsenv } from "@jsenv/core/src/helpers/require_from_jsenv.js";
|
|
4
3
|
|
|
4
|
+
import { importWithRequire } from "../helpers/import_with_require.js";
|
|
5
5
|
import { composeTwoFileByFileIstanbulCoverages } from "./istanbul_coverage_composition.js";
|
|
6
6
|
|
|
7
7
|
export const v8CoverageToIstanbul = async (v8Coverage, { signal }) => {
|
|
@@ -9,7 +9,7 @@ export const v8CoverageToIstanbul = async (v8Coverage, { signal }) => {
|
|
|
9
9
|
operation.addAbortSignal(signal);
|
|
10
10
|
|
|
11
11
|
try {
|
|
12
|
-
const v8ToIstanbul =
|
|
12
|
+
const v8ToIstanbul = importWithRequire("v8-to-istanbul");
|
|
13
13
|
const sourcemapCache = v8Coverage["source-map-cache"];
|
|
14
14
|
let istanbulCoverageComposed = null;
|
|
15
15
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
1
2
|
import { assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem";
|
|
2
|
-
|
|
3
|
-
import {
|
|
3
|
+
|
|
4
|
+
import { pingServer } from "../helpers/ping_server.js";
|
|
5
|
+
import { basicFetch } from "../helpers/basic_fetch.js";
|
|
4
6
|
|
|
5
7
|
export const assertAndNormalizeWebServer = async (webServer) => {
|
|
6
8
|
if (!webServer) {
|
|
@@ -29,7 +31,10 @@ export const assertAndNormalizeWebServer = async (webServer) => {
|
|
|
29
31
|
await import(webServer.moduleUrl);
|
|
30
32
|
delete process.env.IMPORTED_BY_TEST_PLAN;
|
|
31
33
|
} catch (e) {
|
|
32
|
-
if (
|
|
34
|
+
if (
|
|
35
|
+
e.code === "ERR_MODULE_NOT_FOUND" &&
|
|
36
|
+
e.message.includes(fileURLToPath(webServer.moduleUrl))
|
|
37
|
+
) {
|
|
33
38
|
throw new Error(
|
|
34
39
|
`webServer.moduleUrl does not lead to a file at "${webServer.moduleUrl}"`,
|
|
35
40
|
);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export const basicFetch = async (
|
|
2
|
+
url,
|
|
3
|
+
{ rejectUnauthorized = true, method = "GET", headers = {} } = {},
|
|
4
|
+
) => {
|
|
5
|
+
let requestModule;
|
|
6
|
+
if (url.startsWith("http:")) {
|
|
7
|
+
requestModule = await import("node:http");
|
|
8
|
+
} else {
|
|
9
|
+
requestModule = await import("node:https");
|
|
10
|
+
}
|
|
11
|
+
const { request } = requestModule;
|
|
12
|
+
|
|
13
|
+
const urlObject = new URL(url);
|
|
14
|
+
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
const req = request({
|
|
17
|
+
rejectUnauthorized,
|
|
18
|
+
hostname: urlObject.hostname,
|
|
19
|
+
port: urlObject.port,
|
|
20
|
+
path: urlObject.pathname,
|
|
21
|
+
method,
|
|
22
|
+
headers,
|
|
23
|
+
});
|
|
24
|
+
req.on("response", (response) => {
|
|
25
|
+
resolve({
|
|
26
|
+
status: response.statusCode,
|
|
27
|
+
headers: response.headers,
|
|
28
|
+
json: () => {
|
|
29
|
+
req.setTimeout(0);
|
|
30
|
+
req.destroy();
|
|
31
|
+
return new Promise((resolve) => {
|
|
32
|
+
if (response.headers["content-type"] !== "application/json") {
|
|
33
|
+
console.warn("not json");
|
|
34
|
+
}
|
|
35
|
+
let responseBody = "";
|
|
36
|
+
response.setEncoding("utf8");
|
|
37
|
+
response.on("data", (chunk) => {
|
|
38
|
+
responseBody += chunk;
|
|
39
|
+
});
|
|
40
|
+
response.on("end", () => {
|
|
41
|
+
resolve(JSON.parse(responseBody));
|
|
42
|
+
});
|
|
43
|
+
response.on("error", (e) => {
|
|
44
|
+
reject(e);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
req.on("error", reject);
|
|
51
|
+
req.end();
|
|
52
|
+
});
|
|
53
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createServer } from "node:net";
|
|
2
|
+
|
|
3
|
+
export const pingServer = async (url) => {
|
|
4
|
+
const server = createServer();
|
|
5
|
+
const { hostname, port } = new URL(url);
|
|
6
|
+
|
|
7
|
+
try {
|
|
8
|
+
await new Promise((resolve, reject) => {
|
|
9
|
+
server.on("error", reject);
|
|
10
|
+
server.on("listening", () => {
|
|
11
|
+
resolve();
|
|
12
|
+
});
|
|
13
|
+
server.listen(port, hostname);
|
|
14
|
+
});
|
|
15
|
+
} catch (error) {
|
|
16
|
+
if (error && error.code === "EADDRINUSE") {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
if (error && error.code === "EACCES") {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
await new Promise((resolve, reject) => {
|
|
25
|
+
server.on("error", reject);
|
|
26
|
+
server.on("close", resolve);
|
|
27
|
+
server.close();
|
|
28
|
+
});
|
|
29
|
+
return false;
|
|
30
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ensureWindowsDriveLetter } from "@jsenv/filesystem";
|
|
2
|
+
import { urlIsInsideOf, moveUrl } from "@jsenv/urls";
|
|
3
|
+
|
|
4
|
+
export const WEB_URL_CONVERTER = {
|
|
5
|
+
asWebUrl: (fileUrl, webServer) => {
|
|
6
|
+
if (urlIsInsideOf(fileUrl, webServer.rootDirectoryUrl)) {
|
|
7
|
+
return moveUrl({
|
|
8
|
+
url: fileUrl,
|
|
9
|
+
from: webServer.rootDirectoryUrl,
|
|
10
|
+
to: `${webServer.origin}/`,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
const fsRootUrl = ensureWindowsDriveLetter("file:///", fileUrl);
|
|
14
|
+
return `${webServer.origin}/@fs/${fileUrl.slice(fsRootUrl.length)}`;
|
|
15
|
+
},
|
|
16
|
+
asFileUrl: (webUrl, webServer) => {
|
|
17
|
+
const { pathname, search } = new URL(webUrl);
|
|
18
|
+
if (pathname.startsWith("/@fs/")) {
|
|
19
|
+
const fsRootRelativeUrl = pathname.slice("/@fs/".length);
|
|
20
|
+
return `file:///${fsRootRelativeUrl}${search}`;
|
|
21
|
+
}
|
|
22
|
+
return moveUrl({
|
|
23
|
+
url: webUrl,
|
|
24
|
+
from: `${webServer.origin}/`,
|
|
25
|
+
to: webServer.rootDirectoryUrl,
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { URL_META } from "@jsenv/url-meta";
|
|
2
2
|
import { applyBabelPlugins } from "@jsenv/ast";
|
|
3
3
|
import { SOURCEMAP, generateSourcemapDataUrl } from "@jsenv/sourcemap";
|
|
4
|
-
import { WEB_URL_CONVERTER } from "@jsenv/core/src/helpers/web_url_converter.js";
|
|
5
4
|
|
|
5
|
+
import { WEB_URL_CONVERTER } from "../helpers/web_url_converter.js";
|
|
6
6
|
import { babelPluginInstrument } from "../coverage/babel_plugin_instrument.js";
|
|
7
7
|
|
|
8
8
|
export const initIstanbulMiddleware = async (
|
|
@@ -3,7 +3,7 @@ import { urlToExtension } from "@jsenv/urls";
|
|
|
3
3
|
import {
|
|
4
4
|
injectSupervisorIntoHTML,
|
|
5
5
|
supervisorFileUrl,
|
|
6
|
-
} from "@jsenv/
|
|
6
|
+
} from "@jsenv/plugin-supervisor/src/html_supervisor_injection.js";
|
|
7
7
|
|
|
8
8
|
export const initJsSupervisorMiddleware = async (
|
|
9
9
|
page,
|
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
} from "@jsenv/abort";
|
|
9
9
|
import { urlIsInsideOf } from "@jsenv/urls";
|
|
10
10
|
import { memoize } from "@jsenv/utils/src/memoize/memoize.js";
|
|
11
|
-
import { WEB_URL_CONVERTER } from "@jsenv/core/src/helpers/web_url_converter.js";
|
|
12
11
|
|
|
12
|
+
import { WEB_URL_CONVERTER } from "../helpers/web_url_converter.js";
|
|
13
13
|
import { filterV8Coverage } from "../coverage/v8_coverage.js";
|
|
14
14
|
import { composeTwoFileByFileIstanbulCoverages } from "../coverage/istanbul_coverage_composition.js";
|
|
15
15
|
import { initJsSupervisorMiddleware } from "./middleware_js_supervisor.js";
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { importWithRequire } from "../helpers/import_with_require.js";
|
|
3
2
|
// see also https://github.com/sindresorhus/execa/issues/96
|
|
4
3
|
export const killProcessTree = async (
|
|
5
4
|
processId,
|
|
6
5
|
{ signal, timeout = 2000 },
|
|
7
6
|
) => {
|
|
8
|
-
const pidtree =
|
|
7
|
+
const pidtree = importWithRequire("pidtree");
|
|
9
8
|
|
|
10
9
|
let descendantProcessIds;
|
|
11
10
|
try {
|