@jsenv/test 1.1.2 → 1.1.3

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.
Files changed (50) hide show
  1. package/dist/jsenv_test.js +4 -2
  2. package/package.json +2 -2
  3. package/src/coverage/babel_plugin_instrument.js +15 -15
  4. package/src/coverage/coverage_reporter_html_directory.js +10 -10
  5. package/src/coverage/coverage_reporter_json_file.js +7 -7
  6. package/src/coverage/coverage_reporter_text_log.js +8 -8
  7. package/src/coverage/empty_coverage_factory.js +24 -24
  8. package/src/coverage/file_by_file_coverage.js +10 -10
  9. package/src/coverage/istanbul_coverage_composition.js +16 -16
  10. package/src/coverage/istanbul_coverage_map_from_coverage.js +8 -8
  11. package/src/coverage/list_files_not_covered.js +4 -4
  12. package/src/coverage/missing_coverage.js +17 -17
  13. package/src/coverage/report_to_coverage.js +52 -52
  14. package/src/coverage/v8_and_istanbul.js +17 -16
  15. package/src/coverage/v8_coverage.js +8 -8
  16. package/src/coverage/v8_coverage_composition.js +12 -12
  17. package/src/coverage/v8_coverage_node_directory.js +42 -42
  18. package/src/coverage/v8_coverage_to_istanbul.js +45 -45
  19. package/src/execution/execute.js +21 -21
  20. package/src/execution/execute_steps.js +129 -129
  21. package/src/execution/execute_test_plan.js +72 -68
  22. package/src/execution/execution_colors.js +2 -2
  23. package/src/execution/execution_steps.js +20 -20
  24. package/src/execution/gc.js +5 -5
  25. package/src/execution/logs_file_execution.js +126 -126
  26. package/src/execution/logs_file_execution.test.mjs +11 -11
  27. package/src/execution/run.js +51 -51
  28. package/src/execution/web_server_param.js +24 -24
  29. package/src/main.js +7 -7
  30. package/src/runtime_browsers/chromium.js +7 -7
  31. package/src/runtime_browsers/firefox.js +10 -10
  32. package/src/runtime_browsers/middleware_istanbul.js +23 -23
  33. package/src/runtime_browsers/middleware_js_supervisor.js +32 -32
  34. package/src/runtime_browsers/using_playwright.js +186 -186
  35. package/src/runtime_browsers/webkit.js +11 -11
  36. package/src/runtime_node/child_exec_options.js +43 -43
  37. package/src/runtime_node/controllable_child_process.mjs +47 -47
  38. package/src/runtime_node/controllable_worker_thread.mjs +37 -37
  39. package/src/runtime_node/exec_options.js +26 -26
  40. package/src/runtime_node/execute_using_dynamic_import.js +26 -26
  41. package/src/runtime_node/exit_codes.js +4 -4
  42. package/src/runtime_node/importmap_node_loader.mjs +24 -24
  43. package/src/runtime_node/importmap_node_loader_file_url.js +1 -1
  44. package/src/runtime_node/kill_process_tree.js +30 -30
  45. package/src/runtime_node/no_experimental_warnings.cjs +4 -4
  46. package/src/runtime_node/no_experimental_warnings_file_url.js +1 -1
  47. package/src/runtime_node/node_child_process.js +128 -128
  48. package/src/runtime_node/node_execution_performance.js +28 -28
  49. package/src/runtime_node/node_worker_thread.js +108 -108
  50. package/src/runtime_node/profiler_v8_coverage.js +21 -21
@@ -1,19 +1,19 @@
1
- import { existsSync } from "node:fs"
2
- import { URL_META } from "@jsenv/url-meta"
3
- import { urlToFileSystemPath, urlToRelativeUrl } from "@jsenv/urls"
1
+ import { existsSync } from "node:fs";
2
+ import { URL_META } from "@jsenv/url-meta";
3
+ import { urlToFileSystemPath, urlToRelativeUrl } from "@jsenv/urls";
4
4
  import {
5
5
  ensureEmptyDirectory,
6
6
  assertAndNormalizeDirectoryUrl,
7
7
  assertAndNormalizeFileUrl,
8
- } from "@jsenv/filesystem"
9
- import { createLogger, createDetailedMessage } from "@jsenv/log"
8
+ } from "@jsenv/filesystem";
9
+ import { createLogger, createDetailedMessage } from "@jsenv/log";
10
10
 
11
- import { generateCoverageJsonFile } from "../coverage/coverage_reporter_json_file.js"
12
- import { generateCoverageHtmlDirectory } from "../coverage/coverage_reporter_html_directory.js"
13
- import { generateCoverageTextLog } from "../coverage/coverage_reporter_text_log.js"
14
- import { assertAndNormalizeWebServer } from "./web_server_param.js"
15
- import { executionStepsFromTestPlan } from "./execution_steps.js"
16
- import { executeSteps } from "./execute_steps.js"
11
+ import { generateCoverageJsonFile } from "../coverage/coverage_reporter_json_file.js";
12
+ import { generateCoverageHtmlDirectory } from "../coverage/coverage_reporter_html_directory.js";
13
+ import { generateCoverageTextLog } from "../coverage/coverage_reporter_text_log.js";
14
+ import { assertAndNormalizeWebServer } from "./web_server_param.js";
15
+ import { executionStepsFromTestPlan } from "./execution_steps.js";
16
+ import { executeSteps } from "./execute_steps.js";
17
17
 
18
18
  /**
19
19
  * Execute a list of files and log how it goes.
@@ -73,6 +73,7 @@ export const executeTestPlan = async ({
73
73
  "./**/src/**/*.tsx": true,
74
74
  "./**/tests/": false,
75
75
  "./**/*.test.html": false,
76
+ "./**/*.test.html@*.js": false,
76
77
  "./**/*.test.js": false,
77
78
  "./**/*.test.mjs": false,
78
79
  },
@@ -102,83 +103,83 @@ export const executeTestPlan = async ({
102
103
  coverageReportHtmlDirectoryUrl,
103
104
  ...rest
104
105
  }) => {
105
- let someNeedsServer = false
106
- let someHasCoverageV8 = false
107
- let someNodeRuntime = false
108
- const runtimes = {}
106
+ let someNeedsServer = false;
107
+ let someHasCoverageV8 = false;
108
+ let someNodeRuntime = false;
109
+ const runtimes = {};
109
110
  // param validation
110
111
  {
111
- const unexpectedParamNames = Object.keys(rest)
112
+ const unexpectedParamNames = Object.keys(rest);
112
113
  if (unexpectedParamNames.length > 0) {
113
114
  throw new TypeError(
114
115
  `${unexpectedParamNames.join(",")}: there is no such param`,
115
- )
116
+ );
116
117
  }
117
118
  rootDirectoryUrl = assertAndNormalizeDirectoryUrl(
118
119
  rootDirectoryUrl,
119
120
  "rootDirectoryUrl",
120
- )
121
+ );
121
122
  if (!existsSync(new URL(rootDirectoryUrl))) {
122
- throw new Error(`ENOENT on rootDirectoryUrl at ${rootDirectoryUrl}`)
123
+ throw new Error(`ENOENT on rootDirectoryUrl at ${rootDirectoryUrl}`);
123
124
  }
124
125
  if (typeof testPlan !== "object") {
125
- throw new Error(`testPlan must be an object, got ${testPlan}`)
126
+ throw new Error(`testPlan must be an object, got ${testPlan}`);
126
127
  }
127
128
 
128
129
  Object.keys(testPlan).forEach((filePattern) => {
129
- const filePlan = testPlan[filePattern]
130
- if (!filePlan) return
130
+ const filePlan = testPlan[filePattern];
131
+ if (!filePlan) return;
131
132
  Object.keys(filePlan).forEach((executionName) => {
132
- const executionConfig = filePlan[executionName]
133
- const { runtime } = executionConfig
133
+ const executionConfig = filePlan[executionName];
134
+ const { runtime } = executionConfig;
134
135
  if (runtime) {
135
- runtimes[runtime.name] = runtime.version
136
+ runtimes[runtime.name] = runtime.version;
136
137
  if (runtime.type === "browser") {
137
138
  if (runtime.capabilities && runtime.capabilities.coverageV8) {
138
- someHasCoverageV8 = true
139
+ someHasCoverageV8 = true;
139
140
  }
140
- someNeedsServer = true
141
+ someNeedsServer = true;
141
142
  }
142
143
  if (runtime.type === "node") {
143
- someNodeRuntime = true
144
+ someNodeRuntime = true;
144
145
  }
145
146
  }
146
- })
147
- })
147
+ });
148
+ });
148
149
 
149
150
  if (someNeedsServer) {
150
- await assertAndNormalizeWebServer(webServer)
151
+ await assertAndNormalizeWebServer(webServer);
151
152
  }
152
153
 
153
154
  if (coverageEnabled) {
154
155
  if (coverageMethodForBrowsers === undefined) {
155
156
  coverageMethodForBrowsers = someHasCoverageV8
156
157
  ? "playwright"
157
- : "istanbul"
158
+ : "istanbul";
158
159
  }
159
160
  if (typeof coverageConfig !== "object") {
160
161
  throw new TypeError(
161
162
  `coverageConfig must be an object, got ${coverageConfig}`,
162
- )
163
+ );
163
164
  }
164
165
  if (!coverageAndExecutionAllowed) {
165
166
  const associationsForExecute = URL_META.resolveAssociations(
166
167
  { execute: testPlan },
167
168
  "file:///",
168
- )
169
+ );
169
170
  const associationsForCover = URL_META.resolveAssociations(
170
171
  { cover: coverageConfig },
171
172
  "file:///",
172
- )
173
+ );
173
174
  const patternsMatchingCoverAndExecute = Object.keys(
174
175
  associationsForExecute.execute,
175
176
  ).filter((testPlanPattern) => {
176
177
  const { cover } = URL_META.applyAssociations({
177
178
  url: testPlanPattern,
178
179
  associations: associationsForCover,
179
- })
180
- return cover
181
- })
180
+ });
181
+ return cover;
182
+ });
182
183
  if (patternsMatchingCoverAndExecute.length) {
183
184
  // It would be strange, for a given file to be both covered and executed
184
185
  throw new Error(
@@ -188,29 +189,32 @@ export const executeTestPlan = async ({
188
189
  patterns: patternsMatchingCoverAndExecute,
189
190
  },
190
191
  ),
191
- )
192
+ );
192
193
  }
193
194
  }
194
195
 
195
196
  if (coverageTempDirectoryUrl === undefined) {
196
- coverageTempDirectoryUrl = new URL("./.coverage/tmp/", rootDirectoryUrl)
197
+ coverageTempDirectoryUrl = new URL(
198
+ "./.coverage/tmp/",
199
+ rootDirectoryUrl,
200
+ );
197
201
  } else {
198
202
  coverageTempDirectoryUrl = assertAndNormalizeDirectoryUrl(
199
203
  coverageTempDirectoryUrl,
200
204
  "coverageTempDirectoryUrl",
201
- )
205
+ );
202
206
  }
203
207
  if (coverageReportJson) {
204
208
  if (coverageReportJsonFileUrl === undefined) {
205
209
  coverageReportJsonFileUrl = new URL(
206
210
  "./.coverage/coverage.json",
207
211
  rootDirectoryUrl,
208
- )
212
+ );
209
213
  } else {
210
214
  coverageReportJsonFileUrl = assertAndNormalizeFileUrl(
211
215
  coverageReportJsonFileUrl,
212
216
  "coverageReportJsonFileUrl",
213
- )
217
+ );
214
218
  }
215
219
  }
216
220
  if (coverageReportHtml) {
@@ -218,23 +222,23 @@ export const executeTestPlan = async ({
218
222
  coverageReportHtmlDirectoryUrl = new URL(
219
223
  "./.coverage/",
220
224
  rootDirectoryUrl,
221
- )
225
+ );
222
226
  } else {
223
227
  coverageReportHtmlDirectoryUrl = assertAndNormalizeDirectoryUrl(
224
228
  coverageReportHtmlDirectoryUrl,
225
229
  "coverageReportHtmlDirectoryUrl",
226
- )
230
+ );
227
231
  }
228
232
  }
229
233
  }
230
234
  }
231
235
 
232
- const logger = createLogger({ logLevel })
236
+ const logger = createLogger({ logLevel });
233
237
  logger.debug(
234
238
  createDetailedMessage(`Prepare executing plan`, {
235
239
  runtimes: JSON.stringify(runtimes, null, " "),
236
240
  }),
237
- )
241
+ );
238
242
 
239
243
  // param normalization
240
244
  {
@@ -242,7 +246,7 @@ export const executeTestPlan = async ({
242
246
  if (Object.keys(coverageConfig).length === 0) {
243
247
  logger.warn(
244
248
  `coverageConfig is an empty object. Nothing will be instrumented for coverage so your coverage will be empty`,
245
- )
249
+ );
246
250
  }
247
251
  if (
248
252
  someNodeRuntime &&
@@ -251,9 +255,9 @@ export const executeTestPlan = async ({
251
255
  ) {
252
256
  if (process.env.NODE_V8_COVERAGE) {
253
257
  // when runned multiple times, we don't want to keep previous files in this directory
254
- await ensureEmptyDirectory(process.env.NODE_V8_COVERAGE)
258
+ await ensureEmptyDirectory(process.env.NODE_V8_COVERAGE);
255
259
  } else {
256
- coverageMethodForNodeJs = "Profiler"
260
+ coverageMethodForNodeJs = "Profiler";
257
261
  logger.warn(
258
262
  createDetailedMessage(
259
263
  `process.env.NODE_V8_COVERAGE is required to generate coverage for Node.js subprocesses`,
@@ -262,7 +266,7 @@ export const executeTestPlan = async ({
262
266
  "suggestion 2": `use coverageMethodForNodeJs: "Profiler". But it means coverage for child_process and worker_thread cannot be collected`,
263
267
  },
264
268
  ),
265
- )
269
+ );
266
270
  }
267
271
  }
268
272
  }
@@ -273,14 +277,14 @@ export const executeTestPlan = async ({
273
277
  "**/*./": null,
274
278
  ...testPlan,
275
279
  "**/.jsenv/": null,
276
- }
277
- logger.debug(`Generate executions`)
280
+ };
281
+ logger.debug(`Generate executions`);
278
282
  const executionSteps = await executionStepsFromTestPlan({
279
283
  signal,
280
284
  testPlan,
281
285
  rootDirectoryUrl,
282
- })
283
- logger.debug(`${executionSteps.length} executions planned`)
286
+ });
287
+ logger.debug(`${executionSteps.length} executions planned`);
284
288
 
285
289
  const result = await executeSteps(executionSteps, {
286
290
  signal,
@@ -312,26 +316,26 @@ export const executeTestPlan = async ({
312
316
  coverageMethodForNodeJs,
313
317
  coverageV8ConflictWarning,
314
318
  coverageTempDirectoryUrl,
315
- })
319
+ });
316
320
  if (
317
321
  updateProcessExitCode &&
318
322
  result.planSummary.counters.total !== result.planSummary.counters.completed
319
323
  ) {
320
- process.exitCode = 1
324
+ process.exitCode = 1;
321
325
  }
322
- const planCoverage = result.planCoverage
326
+ const planCoverage = result.planCoverage;
323
327
  // planCoverage can be null when execution is aborted
324
328
  if (planCoverage) {
325
- const promises = []
329
+ const promises = [];
326
330
  // keep this one first because it does ensureEmptyDirectory
327
331
  // and in case coverage json file gets written in the same directory
328
332
  // it must be done before
329
333
  if (coverageEnabled && coverageReportHtml) {
330
- await ensureEmptyDirectory(coverageReportHtmlDirectoryUrl)
331
- const htmlCoverageDirectoryIndexFileUrl = `${coverageReportHtmlDirectoryUrl}index.html`
334
+ await ensureEmptyDirectory(coverageReportHtmlDirectoryUrl);
335
+ const htmlCoverageDirectoryIndexFileUrl = `${coverageReportHtmlDirectoryUrl}index.html`;
332
336
  logger.info(
333
337
  `-> ${urlToFileSystemPath(htmlCoverageDirectoryIndexFileUrl)}`,
334
- )
338
+ );
335
339
  promises.push(
336
340
  generateCoverageHtmlDirectory(planCoverage, {
337
341
  rootDirectoryUrl,
@@ -342,7 +346,7 @@ export const executeTestPlan = async ({
342
346
  coverageReportSkipEmpty,
343
347
  coverageReportSkipFull,
344
348
  }),
345
- )
349
+ );
346
350
  }
347
351
  if (coverageEnabled && coverageReportJson) {
348
352
  promises.push(
@@ -351,7 +355,7 @@ export const executeTestPlan = async ({
351
355
  coverageJsonFileUrl: coverageReportJsonFileUrl,
352
356
  logger,
353
357
  }),
354
- )
358
+ );
355
359
  }
356
360
  if (coverageEnabled && coverageReportTextLog) {
357
361
  promises.push(
@@ -359,14 +363,14 @@ export const executeTestPlan = async ({
359
363
  coverageReportSkipEmpty,
360
364
  coverageReportSkipFull,
361
365
  }),
362
- )
366
+ );
363
367
  }
364
- await Promise.all(promises)
368
+ await Promise.all(promises);
365
369
  }
366
370
  return {
367
371
  testPlanAborted: result.aborted,
368
372
  testPlanSummary: result.planSummary,
369
373
  testPlanReport: result.planReport,
370
374
  testPlanCoverage: planCoverage,
371
- }
372
- }
375
+ };
376
+ };
@@ -1,4 +1,4 @@
1
- import { ANSI } from "@jsenv/log"
1
+ import { ANSI } from "@jsenv/log";
2
2
 
3
3
  export const EXECUTION_COLORS = {
4
4
  executing: ANSI.BLUE,
@@ -7,4 +7,4 @@ export const EXECUTION_COLORS = {
7
7
  failed: ANSI.RED,
8
8
  completed: ANSI.GREEN,
9
9
  cancelled: ANSI.GREY,
10
- }
10
+ };
@@ -1,6 +1,6 @@
1
- import { Abort } from "@jsenv/abort"
2
- import { collectFiles } from "@jsenv/filesystem"
3
- import { createDetailedMessage } from "@jsenv/log"
1
+ import { Abort } from "@jsenv/abort";
2
+ import { collectFiles } from "@jsenv/filesystem";
3
+ import { createDetailedMessage } from "@jsenv/log";
4
4
 
5
5
  export const executionStepsFromTestPlan = async ({
6
6
  signal,
@@ -13,16 +13,16 @@ export const executionStepsFromTestPlan = async ({
13
13
  directoryUrl: rootDirectoryUrl,
14
14
  associations: { testPlan },
15
15
  predicate: ({ testPlan }) => testPlan,
16
- })
17
- const executionSteps = []
16
+ });
17
+ const executionSteps = [];
18
18
  fileResultArray.forEach(({ relativeUrl, meta }) => {
19
19
  const fileExecutionSteps = generateFileExecutionSteps({
20
20
  fileRelativeUrl: relativeUrl,
21
21
  filePlan: meta.testPlan,
22
- })
23
- executionSteps.push(...fileExecutionSteps)
24
- })
25
- return executionSteps
22
+ });
23
+ executionSteps.push(...fileExecutionSteps);
24
+ });
25
+ return executionSteps;
26
26
  } catch (e) {
27
27
  if (Abort.isAbortError(e)) {
28
28
  return {
@@ -30,18 +30,18 @@ export const executionStepsFromTestPlan = async ({
30
30
  planSummary: {},
31
31
  planReport: {},
32
32
  planCoverage: null,
33
- }
33
+ };
34
34
  }
35
- throw e
35
+ throw e;
36
36
  }
37
- }
37
+ };
38
38
 
39
39
  export const generateFileExecutionSteps = ({ fileRelativeUrl, filePlan }) => {
40
- const fileExecutionSteps = []
40
+ const fileExecutionSteps = [];
41
41
  Object.keys(filePlan).forEach((executionName) => {
42
- const stepConfig = filePlan[executionName]
42
+ const stepConfig = filePlan[executionName];
43
43
  if (stepConfig === null || stepConfig === undefined) {
44
- return
44
+ return;
45
45
  }
46
46
  if (typeof stepConfig !== "object") {
47
47
  throw new TypeError(
@@ -53,13 +53,13 @@ export const generateFileExecutionSteps = ({ fileRelativeUrl, filePlan }) => {
53
53
  ["value"]: stepConfig,
54
54
  },
55
55
  ),
56
- )
56
+ );
57
57
  }
58
58
  fileExecutionSteps.push({
59
59
  executionName,
60
60
  fileRelativeUrl,
61
61
  ...stepConfig,
62
- })
63
- })
64
- return fileExecutionSteps
65
- }
62
+ });
63
+ });
64
+ return fileExecutionSteps;
65
+ };
@@ -1,9 +1,9 @@
1
- import v8 from "node:v8"
2
- import { runInNewContext } from "node:vm"
1
+ import v8 from "node:v8";
2
+ import { runInNewContext } from "node:vm";
3
3
 
4
4
  export const ensureGlobalGc = () => {
5
5
  if (!global.gc) {
6
- v8.setFlagsFromString("--expose_gc")
7
- global.gc = runInNewContext("gc")
6
+ v8.setFlagsFromString("--expose_gc");
7
+ global.gc = runInNewContext("gc");
8
8
  }
9
- }
9
+ };