@jsenv/core 34.2.2 → 35.0.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 -1
- package/dist/html/explorer.html +5 -4
- package/dist/{jsenv.js → jsenv_core.js} +840 -3914
- package/package.json +7 -21
- package/src/build/build.js +34 -16
- package/src/build/version_mappings_injection.js +20 -27
- package/src/dev/file_service.js +9 -9
- package/src/dev/start_dev_server.js +3 -3
- package/src/dev/user_agent.js +1 -1
- package/src/kitchen/kitchen.js +5 -3
- package/src/main.js +0 -23
- package/src/plugins/autoreload/jsenv_plugin_autoreload_client.js +2 -2
- package/src/plugins/importmap/jsenv_plugin_importmap.js +6 -2
- package/src/plugins/{inline/jsenv_plugin_html_inline_content.js → inline_content_analysis/jsenv_plugin_html_inline_content_analysis.js} +12 -6
- package/src/plugins/{inline/jsenv_plugin_inline.js → inline_content_analysis/jsenv_plugin_inline_content_analysis.js} +8 -10
- package/src/plugins/{inline/jsenv_plugin_js_inline_content.js → inline_content_analysis/jsenv_plugin_js_inline_content_analysis.js} +4 -2
- package/src/plugins/inlining/jsenv_plugin_inlining.js +22 -0
- package/src/plugins/{inline/jsenv_plugin_inline_query_param.js → inlining/jsenv_plugin_inlining_as_data_url.js} +16 -9
- package/src/plugins/inlining/jsenv_plugin_inlining_into_html.js +149 -0
- package/src/plugins/plugins.js +5 -2
- package/src/plugins/ribbon/jsenv_plugin_ribbon.js +11 -10
- package/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js +2 -2
- package/src/plugins/supervisor/html_supervisor_injection.js +23 -25
- package/src/plugins/supervisor/jsenv_plugin_supervisor.js +1 -1
- package/src/plugins/transpilation/babel/require_babel_plugin.js +1 -1
- package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +20 -5
- package/src/plugins/transpilation/js_module_fallback/convert_js_module_to_js_classic.js +1 -1
- package/src/plugins/transpilation/js_module_fallback/jsenv_plugin_js_module_fallback_inside_html.js +2 -2
- package/src/plugins/transpilation/js_module_fallback/jsenv_plugin_js_module_fallback_on_workers.js +3 -3
- package/src/plugins/url_analysis/html/html_urls.js +1 -1
- package/dist/controllable_child_process.mjs +0 -129
- package/dist/controllable_worker_thread.mjs +0 -91
- package/dist/js/execute_using_dynamic_import.js +0 -850
- package/dist/js/v8_coverage.js +0 -508
- package/src/execute/execute.js +0 -109
- package/src/execute/run.js +0 -161
- package/src/execute/runtimes/browsers/chromium.js +0 -10
- package/src/execute/runtimes/browsers/firefox.js +0 -9
- package/src/execute/runtimes/browsers/from_playwright.js +0 -574
- package/src/execute/runtimes/browsers/middleware_istanbul.js +0 -65
- package/src/execute/runtimes/browsers/middleware_js_supervisor.js +0 -100
- package/src/execute/runtimes/browsers/webkit.js +0 -26
- package/src/execute/runtimes/node/child_exec_options.js +0 -166
- package/src/execute/runtimes/node/controllable_child_process.mjs +0 -135
- package/src/execute/runtimes/node/controllable_worker_thread.mjs +0 -103
- package/src/execute/runtimes/node/exec_options.js +0 -44
- package/src/execute/runtimes/node/execute_using_dynamic_import.js +0 -55
- package/src/execute/runtimes/node/exit_codes.js +0 -9
- package/src/execute/runtimes/node/kill_process_tree.js +0 -76
- package/src/execute/runtimes/node/node_child_process.js +0 -348
- package/src/execute/runtimes/node/node_execution_performance.js +0 -67
- package/src/execute/runtimes/node/node_worker_thread.js +0 -282
- package/src/execute/runtimes/node/profiler_v8_coverage.js +0 -56
- package/src/execute/runtimes/readme.md +0 -13
- package/src/execute/web_server_param.js +0 -74
- package/src/test/coverage/babel_plugin_instrument.js +0 -48
- package/src/test/coverage/coverage_reporter_html_directory.js +0 -32
- package/src/test/coverage/coverage_reporter_json_file.js +0 -17
- package/src/test/coverage/coverage_reporter_text_log.js +0 -19
- package/src/test/coverage/empty_coverage_factory.js +0 -52
- package/src/test/coverage/file_by_file_coverage.js +0 -25
- package/src/test/coverage/istanbul_coverage_composition.js +0 -28
- package/src/test/coverage/istanbul_coverage_map_from_coverage.js +0 -16
- package/src/test/coverage/list_files_not_covered.js +0 -15
- package/src/test/coverage/missing_coverage.js +0 -41
- package/src/test/coverage/report_to_coverage.js +0 -198
- package/src/test/coverage/v8_and_istanbul.js +0 -37
- package/src/test/coverage/v8_coverage.js +0 -26
- package/src/test/coverage/v8_coverage_composition.js +0 -24
- package/src/test/coverage/v8_coverage_node_directory.js +0 -85
- package/src/test/coverage/v8_coverage_to_istanbul.js +0 -99
- package/src/test/execute_steps.js +0 -425
- package/src/test/execute_test_plan.js +0 -372
- package/src/test/execution_colors.js +0 -10
- package/src/test/execution_steps.js +0 -65
- package/src/test/gc.js +0 -9
- package/src/test/logs_file_execution.js +0 -427
- package/src/test/logs_file_execution.test.mjs +0 -41
- package/src/test/readme.md +0 -3
- /package/src/{basic_fetch.js → helpers/basic_fetch.js} +0 -0
- /package/src/{lookup_package_directory.js → helpers/lookup_package_directory.js} +0 -0
- /package/src/{ping_server.js → helpers/ping_server.js} +0 -0
- /package/src/{require_from_jsenv.js → helpers/require_from_jsenv.js} +0 -0
- /package/src/{watch_source_files.js → helpers/watch_source_files.js} +0 -0
- /package/src/{web_url_converter.js → helpers/web_url_converter.js} +0 -0
- /package/src/plugins/{inline → inline_content_analysis}/client/inline_content.js +0 -0
- /package/src/plugins/{inline → inline_content_analysis}/jsenv_plugin_data_urls.js +0 -0
|
@@ -1,574 +0,0 @@
|
|
|
1
|
-
import { writeFileSync } from "node:fs"
|
|
2
|
-
import { createDetailedMessage } from "@jsenv/log"
|
|
3
|
-
import {
|
|
4
|
-
Abort,
|
|
5
|
-
createCallbackListNotifiedOnce,
|
|
6
|
-
raceProcessTeardownEvents,
|
|
7
|
-
raceCallbacks,
|
|
8
|
-
} from "@jsenv/abort"
|
|
9
|
-
import { urlIsInsideOf } from "@jsenv/urls"
|
|
10
|
-
import { memoize } from "@jsenv/utils/src/memoize/memoize.js"
|
|
11
|
-
|
|
12
|
-
import { WEB_URL_CONVERTER } from "../../../web_url_converter.js"
|
|
13
|
-
import { initJsSupervisorMiddleware } from "./middleware_js_supervisor.js"
|
|
14
|
-
import { initIstanbulMiddleware } from "./middleware_istanbul.js"
|
|
15
|
-
import { filterV8Coverage } from "@jsenv/core/src/test/coverage/v8_coverage.js"
|
|
16
|
-
import { composeTwoFileByFileIstanbulCoverages } from "@jsenv/core/src/test/coverage/istanbul_coverage_composition.js"
|
|
17
|
-
|
|
18
|
-
export const createRuntimeFromPlaywright = ({
|
|
19
|
-
browserName,
|
|
20
|
-
browserVersion,
|
|
21
|
-
coveragePlaywrightAPIAvailable = false,
|
|
22
|
-
shouldIgnoreError = () => false,
|
|
23
|
-
transformErrorHook = (error) => error,
|
|
24
|
-
isolatedTab = false,
|
|
25
|
-
}) => {
|
|
26
|
-
const runtime = {
|
|
27
|
-
type: "browser",
|
|
28
|
-
name: browserName,
|
|
29
|
-
version: browserVersion,
|
|
30
|
-
capabilities: {
|
|
31
|
-
coverageV8: coveragePlaywrightAPIAvailable,
|
|
32
|
-
},
|
|
33
|
-
}
|
|
34
|
-
let browserAndContextPromise
|
|
35
|
-
runtime.run = async ({
|
|
36
|
-
signal = new AbortController().signal,
|
|
37
|
-
logger,
|
|
38
|
-
rootDirectoryUrl,
|
|
39
|
-
webServer,
|
|
40
|
-
fileRelativeUrl,
|
|
41
|
-
|
|
42
|
-
// measurePerformance,
|
|
43
|
-
collectPerformance,
|
|
44
|
-
coverageEnabled = false,
|
|
45
|
-
coverageConfig,
|
|
46
|
-
coverageMethodForBrowsers,
|
|
47
|
-
coverageFileUrl,
|
|
48
|
-
|
|
49
|
-
stopAfterAllSignal,
|
|
50
|
-
stopSignal,
|
|
51
|
-
keepRunning,
|
|
52
|
-
onConsole,
|
|
53
|
-
|
|
54
|
-
headful = keepRunning,
|
|
55
|
-
playwrightLaunchOptions = {},
|
|
56
|
-
ignoreHTTPSErrors = true,
|
|
57
|
-
}) => {
|
|
58
|
-
const fileUrl = new URL(fileRelativeUrl, rootDirectoryUrl).href
|
|
59
|
-
if (!urlIsInsideOf(fileUrl, webServer.rootDirectoryUrl)) {
|
|
60
|
-
throw new Error(`Cannot execute file that is outside web server root directory
|
|
61
|
-
--- file ---
|
|
62
|
-
${fileUrl}
|
|
63
|
-
--- web server root directory url ---
|
|
64
|
-
${webServer.rootDirectoryUrl}`)
|
|
65
|
-
}
|
|
66
|
-
const fileServerUrl = WEB_URL_CONVERTER.asWebUrl(fileUrl, webServer)
|
|
67
|
-
const cleanupCallbackList = createCallbackListNotifiedOnce()
|
|
68
|
-
const cleanup = memoize(async (reason) => {
|
|
69
|
-
await cleanupCallbackList.notify({ reason })
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
const isBrowserDedicatedToExecution = isolatedTab || !stopAfterAllSignal
|
|
73
|
-
if (isBrowserDedicatedToExecution || !browserAndContextPromise) {
|
|
74
|
-
browserAndContextPromise = (async () => {
|
|
75
|
-
const browser = await launchBrowserUsingPlaywright({
|
|
76
|
-
signal,
|
|
77
|
-
browserName,
|
|
78
|
-
stopOnExit: true,
|
|
79
|
-
playwrightLaunchOptions: {
|
|
80
|
-
...playwrightLaunchOptions,
|
|
81
|
-
headless: !headful,
|
|
82
|
-
},
|
|
83
|
-
})
|
|
84
|
-
if (browser._initializer.version) {
|
|
85
|
-
runtime.version = browser._initializer.version
|
|
86
|
-
}
|
|
87
|
-
const browserContext = await browser.newContext({ ignoreHTTPSErrors })
|
|
88
|
-
return { browser, browserContext }
|
|
89
|
-
})()
|
|
90
|
-
}
|
|
91
|
-
const { browser, browserContext } = await browserAndContextPromise
|
|
92
|
-
const closeBrowser = async () => {
|
|
93
|
-
const disconnected = browser.isConnected()
|
|
94
|
-
? new Promise((resolve) => {
|
|
95
|
-
const disconnectedCallback = () => {
|
|
96
|
-
browser.removeListener("disconnected", disconnectedCallback)
|
|
97
|
-
resolve()
|
|
98
|
-
}
|
|
99
|
-
browser.on("disconnected", disconnectedCallback)
|
|
100
|
-
})
|
|
101
|
-
: Promise.resolve()
|
|
102
|
-
// for some reason without this 150ms timeout
|
|
103
|
-
// browser.close() never resolves (playwright does not like something)
|
|
104
|
-
await new Promise((resolve) => setTimeout(resolve, 150))
|
|
105
|
-
try {
|
|
106
|
-
await browser.close()
|
|
107
|
-
} catch (e) {
|
|
108
|
-
if (isTargetClosedError(e)) {
|
|
109
|
-
return
|
|
110
|
-
}
|
|
111
|
-
throw e
|
|
112
|
-
}
|
|
113
|
-
await disconnected
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const page = await browserContext.newPage()
|
|
117
|
-
|
|
118
|
-
const istanbulInstrumentationEnabled =
|
|
119
|
-
coverageEnabled &&
|
|
120
|
-
(!runtime.capabilities.coverageV8 ||
|
|
121
|
-
coverageMethodForBrowsers === "istanbul")
|
|
122
|
-
if (istanbulInstrumentationEnabled) {
|
|
123
|
-
await initIstanbulMiddleware(page, {
|
|
124
|
-
webServer,
|
|
125
|
-
rootDirectoryUrl,
|
|
126
|
-
coverageConfig,
|
|
127
|
-
})
|
|
128
|
-
}
|
|
129
|
-
if (!webServer.isJsenvDevServer) {
|
|
130
|
-
await initJsSupervisorMiddleware(page, {
|
|
131
|
-
webServer,
|
|
132
|
-
fileUrl,
|
|
133
|
-
fileServerUrl,
|
|
134
|
-
})
|
|
135
|
-
}
|
|
136
|
-
const closePage = async () => {
|
|
137
|
-
try {
|
|
138
|
-
await page.close()
|
|
139
|
-
} catch (e) {
|
|
140
|
-
if (isTargetClosedError(e)) {
|
|
141
|
-
return
|
|
142
|
-
}
|
|
143
|
-
throw e
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const result = {
|
|
148
|
-
status: "pending",
|
|
149
|
-
namespace: null,
|
|
150
|
-
errors: [],
|
|
151
|
-
}
|
|
152
|
-
const callbacks = []
|
|
153
|
-
if (coverageEnabled) {
|
|
154
|
-
if (
|
|
155
|
-
runtime.capabilities.coverageV8 &&
|
|
156
|
-
coverageMethodForBrowsers === "playwright"
|
|
157
|
-
) {
|
|
158
|
-
await page.coverage.startJSCoverage({
|
|
159
|
-
// reportAnonymousScripts: true,
|
|
160
|
-
})
|
|
161
|
-
callbacks.push(async () => {
|
|
162
|
-
const v8CoveragesWithWebUrls = await page.coverage.stopJSCoverage()
|
|
163
|
-
// we convert urls starting with http:// to file:// because we later
|
|
164
|
-
// convert the url to filesystem path in istanbulCoverageFromV8Coverage function
|
|
165
|
-
const v8CoveragesWithFsUrls = v8CoveragesWithWebUrls.map(
|
|
166
|
-
(v8CoveragesWithWebUrl) => {
|
|
167
|
-
const fsUrl = WEB_URL_CONVERTER.asFileUrl(
|
|
168
|
-
v8CoveragesWithWebUrl.url,
|
|
169
|
-
webServer,
|
|
170
|
-
)
|
|
171
|
-
return {
|
|
172
|
-
...v8CoveragesWithWebUrl,
|
|
173
|
-
url: fsUrl,
|
|
174
|
-
}
|
|
175
|
-
},
|
|
176
|
-
)
|
|
177
|
-
const coverage = await filterV8Coverage(
|
|
178
|
-
{ result: v8CoveragesWithFsUrls },
|
|
179
|
-
{
|
|
180
|
-
rootDirectoryUrl,
|
|
181
|
-
coverageConfig,
|
|
182
|
-
},
|
|
183
|
-
)
|
|
184
|
-
writeFileSync(
|
|
185
|
-
new URL(coverageFileUrl),
|
|
186
|
-
JSON.stringify(coverage, null, " "),
|
|
187
|
-
)
|
|
188
|
-
})
|
|
189
|
-
} else {
|
|
190
|
-
callbacks.push(() => {
|
|
191
|
-
const scriptExecutionResults = result.namespace
|
|
192
|
-
if (scriptExecutionResults) {
|
|
193
|
-
const coverage =
|
|
194
|
-
generateCoverageForPage(scriptExecutionResults) || {}
|
|
195
|
-
writeFileSync(
|
|
196
|
-
new URL(coverageFileUrl),
|
|
197
|
-
JSON.stringify(coverage, null, " "),
|
|
198
|
-
)
|
|
199
|
-
}
|
|
200
|
-
})
|
|
201
|
-
}
|
|
202
|
-
} else {
|
|
203
|
-
callbacks.push(() => {
|
|
204
|
-
const scriptExecutionResults = result.namespace
|
|
205
|
-
if (scriptExecutionResults) {
|
|
206
|
-
Object.keys(scriptExecutionResults).forEach((fileRelativeUrl) => {
|
|
207
|
-
delete scriptExecutionResults[fileRelativeUrl].coverage
|
|
208
|
-
})
|
|
209
|
-
}
|
|
210
|
-
})
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
if (collectPerformance) {
|
|
214
|
-
callbacks.push(async () => {
|
|
215
|
-
const performance = await page.evaluate(
|
|
216
|
-
/* eslint-disable no-undef */
|
|
217
|
-
/* istanbul ignore next */
|
|
218
|
-
() => {
|
|
219
|
-
const { performance } = window
|
|
220
|
-
if (!performance) {
|
|
221
|
-
return null
|
|
222
|
-
}
|
|
223
|
-
const measures = {}
|
|
224
|
-
const measurePerfEntries = performance.getEntriesByType("measure")
|
|
225
|
-
measurePerfEntries.forEach((measurePerfEntry) => {
|
|
226
|
-
measures[measurePerfEntry.name] = measurePerfEntry.duration
|
|
227
|
-
})
|
|
228
|
-
return {
|
|
229
|
-
timeOrigin: performance.timeOrigin,
|
|
230
|
-
timing: performance.timing.toJSON(),
|
|
231
|
-
navigation: performance.navigation.toJSON(),
|
|
232
|
-
measures,
|
|
233
|
-
}
|
|
234
|
-
},
|
|
235
|
-
/* eslint-enable no-undef */
|
|
236
|
-
)
|
|
237
|
-
result.performance = performance
|
|
238
|
-
})
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// https://github.com/GoogleChrome/puppeteer/blob/v1.4.0/docs/api.md#event-console
|
|
242
|
-
const removeConsoleListener = registerEvent({
|
|
243
|
-
object: page,
|
|
244
|
-
eventType: "console",
|
|
245
|
-
// https://github.com/microsoft/playwright/blob/master/docs/api.md#event-console
|
|
246
|
-
callback: async (consoleMessage) => {
|
|
247
|
-
onConsole({
|
|
248
|
-
type: consoleMessage.type(),
|
|
249
|
-
text: `${extractTextFromConsoleMessage(consoleMessage)}
|
|
250
|
-
`,
|
|
251
|
-
})
|
|
252
|
-
},
|
|
253
|
-
})
|
|
254
|
-
cleanupCallbackList.add(removeConsoleListener)
|
|
255
|
-
const actionOperation = Abort.startOperation()
|
|
256
|
-
actionOperation.addAbortSignal(signal)
|
|
257
|
-
|
|
258
|
-
const winnerPromise = new Promise((resolve, reject) => {
|
|
259
|
-
raceCallbacks(
|
|
260
|
-
{
|
|
261
|
-
aborted: (cb) => {
|
|
262
|
-
return actionOperation.addAbortCallback(cb)
|
|
263
|
-
},
|
|
264
|
-
// https://github.com/GoogleChrome/puppeteer/blob/v1.4.0/docs/api.md#event-error
|
|
265
|
-
error: (cb) => {
|
|
266
|
-
return registerEvent({
|
|
267
|
-
object: page,
|
|
268
|
-
eventType: "error",
|
|
269
|
-
callback: (error) => {
|
|
270
|
-
if (shouldIgnoreError(error, "error")) {
|
|
271
|
-
return
|
|
272
|
-
}
|
|
273
|
-
cb(transformErrorHook(error))
|
|
274
|
-
},
|
|
275
|
-
})
|
|
276
|
-
},
|
|
277
|
-
// https://github.com/GoogleChrome/puppeteer/blob/v1.4.0/docs/api.md#event-pageerror
|
|
278
|
-
// pageerror: () => {
|
|
279
|
-
// return registerEvent({
|
|
280
|
-
// object: page,
|
|
281
|
-
// eventType: "pageerror",
|
|
282
|
-
// callback: (error) => {
|
|
283
|
-
// if (
|
|
284
|
-
// webServer.isJsenvDevServer ||
|
|
285
|
-
// shouldIgnoreError(error, "pageerror")
|
|
286
|
-
// ) {
|
|
287
|
-
// return
|
|
288
|
-
// }
|
|
289
|
-
// result.errors.push(transformErrorHook(error))
|
|
290
|
-
// },
|
|
291
|
-
// })
|
|
292
|
-
// },
|
|
293
|
-
closed: (cb) => {
|
|
294
|
-
// https://github.com/GoogleChrome/puppeteer/blob/v1.4.0/docs/api.md#event-disconnected
|
|
295
|
-
if (isBrowserDedicatedToExecution) {
|
|
296
|
-
browser.on("disconnected", async () => {
|
|
297
|
-
cb({ reason: "browser disconnected" })
|
|
298
|
-
})
|
|
299
|
-
cleanupCallbackList.add(closePage)
|
|
300
|
-
cleanupCallbackList.add(closeBrowser)
|
|
301
|
-
} else {
|
|
302
|
-
const disconnectedCallback = async () => {
|
|
303
|
-
throw new Error("browser disconnected during execution")
|
|
304
|
-
}
|
|
305
|
-
browser.on("disconnected", disconnectedCallback)
|
|
306
|
-
page.on("close", () => {
|
|
307
|
-
cb({ reason: "page closed" })
|
|
308
|
-
})
|
|
309
|
-
cleanupCallbackList.add(closePage)
|
|
310
|
-
cleanupCallbackList.add(() => {
|
|
311
|
-
browser.removeListener("disconnected", disconnectedCallback)
|
|
312
|
-
})
|
|
313
|
-
const notifyPrevious = stopAfterAllSignal.notify
|
|
314
|
-
stopAfterAllSignal.notify = async () => {
|
|
315
|
-
await notifyPrevious()
|
|
316
|
-
browser.removeListener("disconnected", disconnectedCallback)
|
|
317
|
-
logger.debug(
|
|
318
|
-
`stopAfterAllSignal notified -> closing ${browserName}`,
|
|
319
|
-
)
|
|
320
|
-
await closeBrowser()
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
},
|
|
324
|
-
response: async (cb) => {
|
|
325
|
-
try {
|
|
326
|
-
await page.goto(fileServerUrl, { timeout: 0 })
|
|
327
|
-
const returnValue = await page.evaluate(
|
|
328
|
-
/* eslint-disable no-undef */
|
|
329
|
-
/* istanbul ignore next */
|
|
330
|
-
async () => {
|
|
331
|
-
let startTime
|
|
332
|
-
try {
|
|
333
|
-
startTime = window.performance.timing.navigationStart
|
|
334
|
-
} catch (e) {
|
|
335
|
-
startTime = Date.now()
|
|
336
|
-
}
|
|
337
|
-
if (!window.__supervisor__) {
|
|
338
|
-
throw new Error("window.__supervisor__ is undefined")
|
|
339
|
-
}
|
|
340
|
-
const executionResultFromJsenvSupervisor =
|
|
341
|
-
await window.__supervisor__.getDocumentExecutionResult()
|
|
342
|
-
return {
|
|
343
|
-
type: "window_supervisor",
|
|
344
|
-
startTime,
|
|
345
|
-
endTime: Date.now(),
|
|
346
|
-
executionResults:
|
|
347
|
-
executionResultFromJsenvSupervisor.executionResults,
|
|
348
|
-
}
|
|
349
|
-
},
|
|
350
|
-
/* eslint-enable no-undef */
|
|
351
|
-
)
|
|
352
|
-
cb(returnValue)
|
|
353
|
-
} catch (e) {
|
|
354
|
-
reject(e)
|
|
355
|
-
}
|
|
356
|
-
},
|
|
357
|
-
},
|
|
358
|
-
resolve,
|
|
359
|
-
)
|
|
360
|
-
})
|
|
361
|
-
|
|
362
|
-
const writeResult = async () => {
|
|
363
|
-
const winner = await winnerPromise
|
|
364
|
-
if (winner.name === "aborted") {
|
|
365
|
-
result.status = "aborted"
|
|
366
|
-
return
|
|
367
|
-
}
|
|
368
|
-
if (winner.name === "error") {
|
|
369
|
-
let error = winner.data
|
|
370
|
-
result.status = "failed"
|
|
371
|
-
result.errors.push(error)
|
|
372
|
-
return
|
|
373
|
-
}
|
|
374
|
-
if (winner.name === "pageerror") {
|
|
375
|
-
let error = winner.data
|
|
376
|
-
result.status = "failed"
|
|
377
|
-
result.errors.push(error)
|
|
378
|
-
return
|
|
379
|
-
}
|
|
380
|
-
if (winner.name === "closed") {
|
|
381
|
-
result.status = "failed"
|
|
382
|
-
result.errors.push(
|
|
383
|
-
isBrowserDedicatedToExecution
|
|
384
|
-
? new Error(`browser disconnected during execution`)
|
|
385
|
-
: new Error(`page closed during execution`),
|
|
386
|
-
)
|
|
387
|
-
return
|
|
388
|
-
}
|
|
389
|
-
// winner.name === "response"
|
|
390
|
-
const { executionResults } = winner.data
|
|
391
|
-
result.status = "completed"
|
|
392
|
-
result.namespace = executionResults
|
|
393
|
-
Object.keys(executionResults).forEach((key) => {
|
|
394
|
-
const executionResult = executionResults[key]
|
|
395
|
-
if (executionResult.status === "failed") {
|
|
396
|
-
result.status = "failed"
|
|
397
|
-
if (executionResult.exception) {
|
|
398
|
-
result.errors.push({
|
|
399
|
-
...executionResult.exception,
|
|
400
|
-
stack: executionResult.exception.text,
|
|
401
|
-
})
|
|
402
|
-
} else {
|
|
403
|
-
result.errors.push({
|
|
404
|
-
...executionResult.error,
|
|
405
|
-
stack: executionResult.error.stack,
|
|
406
|
-
})
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
})
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
try {
|
|
413
|
-
await writeResult()
|
|
414
|
-
if (collectPerformance) {
|
|
415
|
-
result.performance = performance
|
|
416
|
-
}
|
|
417
|
-
await callbacks.reduce(async (previous, callback) => {
|
|
418
|
-
await previous
|
|
419
|
-
await callback()
|
|
420
|
-
}, Promise.resolve())
|
|
421
|
-
} catch (e) {
|
|
422
|
-
result.status = "failed"
|
|
423
|
-
result.errors = [e]
|
|
424
|
-
}
|
|
425
|
-
if (keepRunning) {
|
|
426
|
-
stopSignal.notify = cleanup
|
|
427
|
-
} else {
|
|
428
|
-
await cleanup("execution done")
|
|
429
|
-
}
|
|
430
|
-
return result
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
if (!isolatedTab) {
|
|
434
|
-
runtime.isolatedTab = createRuntimeFromPlaywright({
|
|
435
|
-
browserName,
|
|
436
|
-
browserVersion,
|
|
437
|
-
coveragePlaywrightAPIAvailable,
|
|
438
|
-
shouldIgnoreError,
|
|
439
|
-
transformErrorHook,
|
|
440
|
-
isolatedTab: true,
|
|
441
|
-
})
|
|
442
|
-
}
|
|
443
|
-
return runtime
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
const generateCoverageForPage = (scriptExecutionResults) => {
|
|
447
|
-
let istanbulCoverageComposed = null
|
|
448
|
-
Object.keys(scriptExecutionResults).forEach((fileRelativeUrl) => {
|
|
449
|
-
const istanbulCoverage = scriptExecutionResults[fileRelativeUrl].coverage
|
|
450
|
-
istanbulCoverageComposed = istanbulCoverageComposed
|
|
451
|
-
? composeTwoFileByFileIstanbulCoverages(
|
|
452
|
-
istanbulCoverageComposed,
|
|
453
|
-
istanbulCoverage,
|
|
454
|
-
)
|
|
455
|
-
: istanbulCoverage
|
|
456
|
-
})
|
|
457
|
-
return istanbulCoverageComposed
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
const launchBrowserUsingPlaywright = async ({
|
|
461
|
-
signal,
|
|
462
|
-
browserName,
|
|
463
|
-
stopOnExit,
|
|
464
|
-
playwrightLaunchOptions,
|
|
465
|
-
}) => {
|
|
466
|
-
const launchBrowserOperation = Abort.startOperation()
|
|
467
|
-
launchBrowserOperation.addAbortSignal(signal)
|
|
468
|
-
const playwright = await importPlaywright({ browserName })
|
|
469
|
-
if (stopOnExit) {
|
|
470
|
-
launchBrowserOperation.addAbortSource((abort) => {
|
|
471
|
-
return raceProcessTeardownEvents(
|
|
472
|
-
{
|
|
473
|
-
SIGHUP: true,
|
|
474
|
-
SIGTERM: true,
|
|
475
|
-
SIGINT: true,
|
|
476
|
-
beforeExit: true,
|
|
477
|
-
exit: true,
|
|
478
|
-
},
|
|
479
|
-
abort,
|
|
480
|
-
)
|
|
481
|
-
})
|
|
482
|
-
}
|
|
483
|
-
const browserClass = playwright[browserName]
|
|
484
|
-
try {
|
|
485
|
-
const browser = await browserClass.launch({
|
|
486
|
-
...playwrightLaunchOptions,
|
|
487
|
-
// let's handle them to close properly browser + remove listener
|
|
488
|
-
// instead of relying on playwright to do so
|
|
489
|
-
handleSIGINT: false,
|
|
490
|
-
handleSIGTERM: false,
|
|
491
|
-
handleSIGHUP: false,
|
|
492
|
-
})
|
|
493
|
-
launchBrowserOperation.throwIfAborted()
|
|
494
|
-
return browser
|
|
495
|
-
} catch (e) {
|
|
496
|
-
if (launchBrowserOperation.signal.aborted && isTargetClosedError(e)) {
|
|
497
|
-
// rethrow the abort error
|
|
498
|
-
launchBrowserOperation.throwIfAborted()
|
|
499
|
-
}
|
|
500
|
-
throw e
|
|
501
|
-
} finally {
|
|
502
|
-
await launchBrowserOperation.end()
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
const importPlaywright = async ({ browserName }) => {
|
|
507
|
-
try {
|
|
508
|
-
const namespace = await import("playwright")
|
|
509
|
-
return namespace
|
|
510
|
-
} catch (e) {
|
|
511
|
-
if (e.code === "ERR_MODULE_NOT_FOUND") {
|
|
512
|
-
throw new Error(
|
|
513
|
-
createDetailedMessage(
|
|
514
|
-
`"playwright" not found. You need playwright in your dependencies to use "${browserName}"`,
|
|
515
|
-
{
|
|
516
|
-
suggestion: `npm install --save-dev playwright`,
|
|
517
|
-
},
|
|
518
|
-
),
|
|
519
|
-
{ cause: e },
|
|
520
|
-
)
|
|
521
|
-
}
|
|
522
|
-
throw e
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
const isTargetClosedError = (error) => {
|
|
527
|
-
if (error.message.match(/Protocol error \(.*?\): Target closed/)) {
|
|
528
|
-
return true
|
|
529
|
-
}
|
|
530
|
-
if (error.message.match(/Protocol error \(.*?\): Browser.*?closed/)) {
|
|
531
|
-
return true
|
|
532
|
-
}
|
|
533
|
-
return error.message.includes("browserContext.close: Browser closed")
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
const extractTextFromConsoleMessage = (consoleMessage) => {
|
|
537
|
-
return consoleMessage.text()
|
|
538
|
-
// ensure we use a string so that istanbul won't try
|
|
539
|
-
// to put any coverage statement inside it
|
|
540
|
-
// ideally we should use uneval no ?
|
|
541
|
-
// eslint-disable-next-line no-new-func
|
|
542
|
-
// const functionEvaluatedBrowserSide = new Function(
|
|
543
|
-
// "value",
|
|
544
|
-
// `if (value instanceof Error) {
|
|
545
|
-
// return value.stack
|
|
546
|
-
// }
|
|
547
|
-
// return value`,
|
|
548
|
-
// )
|
|
549
|
-
// const argValues = await Promise.all(
|
|
550
|
-
// message.args().map(async (arg) => {
|
|
551
|
-
// const jsHandle = arg
|
|
552
|
-
// try {
|
|
553
|
-
// return await jsHandle.executionContext().evaluate(functionEvaluatedBrowserSide, jsHandle)
|
|
554
|
-
// } catch (e) {
|
|
555
|
-
// return String(jsHandle)
|
|
556
|
-
// }
|
|
557
|
-
// }),
|
|
558
|
-
// )
|
|
559
|
-
// const text = argValues.reduce((previous, value, index) => {
|
|
560
|
-
// let string
|
|
561
|
-
// if (typeof value === "object") string = JSON.stringify(value, null, " ")
|
|
562
|
-
// else string = String(value)
|
|
563
|
-
// if (index === 0) return `${previous}${string}`
|
|
564
|
-
// return `${previous} ${string}`
|
|
565
|
-
// }, "")
|
|
566
|
-
// return text
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
const registerEvent = ({ object, eventType, callback }) => {
|
|
570
|
-
object.on(eventType, callback)
|
|
571
|
-
return () => {
|
|
572
|
-
object.removeListener(eventType, callback)
|
|
573
|
-
}
|
|
574
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { URL_META } from "@jsenv/url-meta"
|
|
2
|
-
import { applyBabelPlugins } from "@jsenv/ast"
|
|
3
|
-
import { SOURCEMAP, generateSourcemapDataUrl } from "@jsenv/sourcemap"
|
|
4
|
-
|
|
5
|
-
import { WEB_URL_CONVERTER } from "../../../web_url_converter.js"
|
|
6
|
-
import { babelPluginInstrument } from "../../../test/coverage/babel_plugin_instrument.js"
|
|
7
|
-
|
|
8
|
-
export const initIstanbulMiddleware = async (
|
|
9
|
-
page,
|
|
10
|
-
{ webServer, rootDirectoryUrl, coverageConfig },
|
|
11
|
-
) => {
|
|
12
|
-
const associations = URL_META.resolveAssociations(
|
|
13
|
-
{ cover: coverageConfig },
|
|
14
|
-
rootDirectoryUrl,
|
|
15
|
-
)
|
|
16
|
-
await page.route("**", async (route) => {
|
|
17
|
-
const request = route.request()
|
|
18
|
-
const url = request.url() // transform into a local url
|
|
19
|
-
const fileUrl = WEB_URL_CONVERTER.asFileUrl(url, webServer)
|
|
20
|
-
const needsInstrumentation = URL_META.applyAssociations({
|
|
21
|
-
url: fileUrl,
|
|
22
|
-
associations,
|
|
23
|
-
}).cover
|
|
24
|
-
if (!needsInstrumentation) {
|
|
25
|
-
route.fallback()
|
|
26
|
-
return
|
|
27
|
-
}
|
|
28
|
-
const response = await route.fetch()
|
|
29
|
-
const originalBody = await response.text()
|
|
30
|
-
try {
|
|
31
|
-
const result = await applyBabelPlugins({
|
|
32
|
-
babelPlugins: [babelPluginInstrument],
|
|
33
|
-
urlInfo: {
|
|
34
|
-
originalUrl: fileUrl,
|
|
35
|
-
// jsenv server could send info to know it's a js module or js classic
|
|
36
|
-
// but in the end it's not super important
|
|
37
|
-
// - it's ok to parse js classic as js module considering it's only for istanbul instrumentation
|
|
38
|
-
type: "js_module",
|
|
39
|
-
content: originalBody,
|
|
40
|
-
},
|
|
41
|
-
})
|
|
42
|
-
let code = result.code
|
|
43
|
-
code = SOURCEMAP.writeComment({
|
|
44
|
-
contentType: "text/javascript",
|
|
45
|
-
content: code,
|
|
46
|
-
specifier: generateSourcemapDataUrl(result.map),
|
|
47
|
-
})
|
|
48
|
-
route.fulfill({
|
|
49
|
-
response,
|
|
50
|
-
body: code,
|
|
51
|
-
headers: {
|
|
52
|
-
...response.headers(),
|
|
53
|
-
"content-length": Buffer.byteLength(code),
|
|
54
|
-
},
|
|
55
|
-
})
|
|
56
|
-
} catch (e) {
|
|
57
|
-
if (e.code === "PARSE_ERROR") {
|
|
58
|
-
route.fulfill({ response })
|
|
59
|
-
} else {
|
|
60
|
-
console.error(e)
|
|
61
|
-
route.fulfill({ response })
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
})
|
|
65
|
-
}
|