@jsenv/core 24.3.2 → 24.4.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 (42) hide show
  1. package/dist/browser_runtime/asset-manifest.json +3 -0
  2. package/dist/browser_runtime/{browser_runtime-fbd309a1.js → browser_runtime-015d0fc5.js} +94 -1
  3. package/dist/browser_runtime/{browser_runtime-fbd309a1.js.map → browser_runtime-015d0fc5.js.map} +11 -3
  4. package/dist/build_manifest.js +5 -5
  5. package/dist/compile_proxy/asset-manifest.json +4 -0
  6. package/dist/compile_proxy/assets/{s.js-749702e8.map → s.js-55849eca.map} +14 -4
  7. package/dist/compile_proxy/{compile_proxy-405777e6.html → compile_proxy-2eabd1f7.html} +99 -4
  8. package/dist/compile_proxy/{compile_proxy.html__inline__20-39c0801c.js.map → compile_proxy.html__inline__20-672ba17c.js.map} +0 -0
  9. package/dist/event_source_client/asset-manifest.json +3 -0
  10. package/dist/redirector/asset-manifest.json +4 -0
  11. package/dist/{toolbar/assets/s.js-749702e8.map → redirector/assets/s.js-55849eca.map} +14 -4
  12. package/dist/redirector/{redirector-237cd168.html → redirector-3029c4d3.html} +99 -4
  13. package/dist/redirector/{redirector.html__inline__15-33acb0b9.js.map → redirector.html__inline__15-4d453af0.js.map} +0 -0
  14. package/dist/toolbar/asset-manifest.json +13 -0
  15. package/dist/{redirector/assets/s.js-749702e8.map → toolbar/assets/s.js-55849eca.map} +14 -4
  16. package/dist/toolbar/{toolbar-d3d98c2e.html → toolbar-40bcd3a0.html} +104 -10
  17. package/dist/toolbar/{toolbar.main-cab36c15.js.map → toolbar.main-53e1ab2b.js.map} +2 -2
  18. package/dist/toolbar_injector/asset-manifest.json +4 -0
  19. package/dist/toolbar_injector/{toolbar_injector-01f71ce3.js → toolbar_injector-0a9d5d4c.js} +5 -3
  20. package/dist/toolbar_injector/{toolbar_injector-01f71ce3.js.map → toolbar_injector-0a9d5d4c.js.map} +3 -3
  21. package/package.json +10 -18
  22. package/src/executeTestPlan.js +7 -1
  23. package/src/internal/browser_launcher/from_playwright.js +314 -0
  24. package/src/internal/building/buildUsingRollup.js +2 -2
  25. package/src/internal/building/createJsenvRollupPlugin.js +67 -41
  26. package/src/internal/building/css/parseCssRessource.js +4 -1
  27. package/src/internal/building/html/parseHtmlRessource.js +16 -3
  28. package/src/internal/building/js/parseJsRessource.js +2 -0
  29. package/src/internal/building/ressource_builder.js +27 -37
  30. package/src/internal/building/ressource_builder_util.js +10 -137
  31. package/src/internal/building/svg/parseSvgRessource.js +2 -0
  32. package/src/internal/building/url_loader.js +3 -1
  33. package/src/internal/building/webmanifest/parseWebmanifestRessource.js +2 -1
  34. package/src/internal/dev_server/toolbar/toolbar.injector.js +3 -1
  35. package/src/internal/dev_server/toolbar/toolbar.main.js +7 -6
  36. package/src/internal/executing/executeConcurrently.js +15 -9
  37. package/src/internal/executing/executePlan.js +2 -0
  38. package/src/internal/runtime/s.js +83 -1
  39. package/src/launchBrowser.js +33 -501
  40. package/dist/browser_system/browser_system-29eda202.js +0 -5160
  41. package/dist/browser_system/browser_system-29eda202.js.map +0 -1065
  42. package/src/internal/browser_launcher/createSharing.js +0 -70
@@ -1,511 +1,43 @@
1
- // https://github.com/microsoft/playwright/blob/master/docs/api.md
2
-
3
- import { createDetailedMessage } from "@jsenv/logger"
4
- import {
5
- Abort,
6
- createCallbackListNotifiedOnce,
7
- createCallbackList,
8
- raceProcessTeardownEvents,
9
- } from "@jsenv/abort"
10
- import { memoize } from "@jsenv/filesystem"
11
-
12
- import { fetchUrl } from "./internal/fetchUrl.js"
13
- import { validateResponse } from "./internal/response_validation.js"
14
- import { trackPageToNotify } from "./internal/browser_launcher/trackPageToNotify.js"
15
- import { createSharing } from "./internal/browser_launcher/createSharing.js"
16
- import { executeHtmlFile } from "./internal/browser_launcher/executeHtmlFile.js"
1
+ import { createRuntimeFromPlaywright } from "@jsenv/core/src/internal/browser_launcher/from_playwright.js"
17
2
  import {
18
3
  PLAYWRIGHT_CHROMIUM_VERSION,
19
4
  PLAYWRIGHT_FIREFOX_VERSION,
20
5
  PLAYWRIGHT_WEBKIT_VERSION,
21
6
  } from "./playwright_browser_versions.js"
22
7
 
23
- const chromiumSharing = createSharing()
24
- export const chromiumRuntime = {
25
- name: "chromium",
26
- version: PLAYWRIGHT_CHROMIUM_VERSION,
27
- }
28
- chromiumRuntime.launch = async ({
29
- signal = new AbortController().signal,
30
- browserServerLogLevel,
31
- chromiumExecutablePath,
32
-
33
- projectDirectoryUrl,
34
- compileServerOrigin,
35
- compileServerId,
36
- outDirectoryRelativeUrl,
37
-
38
- collectPerformance,
39
- measurePerformance,
40
- collectCoverage,
41
- coverageIgnorePredicate,
42
- coverageForceIstanbul,
43
-
44
- headless = true,
45
- // about debug check https://github.com/microsoft/playwright/blob/master/docs/api.md#browsertypelaunchserveroptions
46
- debug = false,
47
- debugPort = 0,
48
- stopOnExit = true,
49
- share = false,
50
- }) => {
51
- const launchBrowserOperation = Abort.startOperation()
52
- launchBrowserOperation.addAbortSignal(signal)
53
-
54
- const sharingToken = share
55
- ? chromiumSharing.getSharingToken({
56
- chromiumExecutablePath,
57
- headless,
58
- debug,
59
- debugPort,
60
- })
61
- : chromiumSharing.getUniqueSharingToken()
62
- if (!sharingToken.isUsed()) {
63
- const { chromium } = await importPlaywright({ browserName: "chromium" })
64
- const launchOperation = launchBrowser("chromium", {
65
- browserClass: chromium,
66
- launchBrowserOperation,
67
- options: {
68
- headless,
69
- executablePath: chromiumExecutablePath,
70
- ...(debug ? { devtools: true } : {}),
71
- args: [
72
- // https://github.com/GoogleChrome/puppeteer/issues/1834
73
- // https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md#tips
74
- // "--disable-dev-shm-usage",
75
- ...(debug ? [`--remote-debugging-port=${debugPort}`] : []),
76
- ],
77
- },
78
- stopOnExit,
79
- })
80
- sharingToken.setSharedValue(launchOperation)
81
- }
82
-
83
- const [browserPromise, stopUsingBrowser] = sharingToken.useSharedValue()
84
- launchBrowserOperation.addEndCallback(stopUsingBrowser)
85
- const browser = await browserPromise
86
-
87
- if (debug) {
88
- // https://github.com/puppeteer/puppeteer/blob/v2.0.0/docs/api.md#browserwsendpoint
89
- // https://chromedevtools.github.io/devtools-protocol/#how-do-i-access-the-browser-target
90
- const webSocketEndpoint = browser.wsEndpoint()
91
- const webSocketUrl = new URL(webSocketEndpoint)
92
- const browserEndpoint = `http://${webSocketUrl.host}/json/version`
93
- const browserResponse = await fetchUrl(browserEndpoint, {
94
- signal,
95
- ignoreHttpsError: true,
96
- })
97
- const { isValid, message, details } = await validateResponse(
98
- browserResponse,
99
- )
100
- if (!isValid) {
101
- throw new Error(createDetailedMessage(message, details))
8
+ export const chromiumRuntime = createRuntimeFromPlaywright({
9
+ browserName: "chromium",
10
+ browserVersion: PLAYWRIGHT_CHROMIUM_VERSION,
11
+ coveragePlaywrightAPIAvailable: true,
12
+ })
13
+ export const chromiumTabRuntime = chromiumRuntime.tab
14
+
15
+ export const firefoxRuntime = createRuntimeFromPlaywright({
16
+ browserName: "firefox",
17
+ browserVersion: PLAYWRIGHT_FIREFOX_VERSION,
18
+ })
19
+ export const firefoxTabRuntime = firefoxRuntime.tab
20
+
21
+ export const webkitRuntime = createRuntimeFromPlaywright({
22
+ browserName: "webkit",
23
+ browserVersion: PLAYWRIGHT_WEBKIT_VERSION,
24
+ ignoreErrorHook: (error) => {
25
+ // we catch error during execution but safari throw unhandled rejection
26
+ // in a non-deterministic way.
27
+ // I suppose it's due to some race condition to decide if the promise is catched or not
28
+ // for now we'll ignore unhandled rejection on wekbkit
29
+ if (error.name === "Unhandled Promise Rejection") {
30
+ return true
102
31
  }
103
-
104
- const browserResponseObject = JSON.parse(browserResponse.body)
105
- const { webSocketDebuggerUrl } = browserResponseObject
106
- console.log(`Debugger listening on ${webSocketDebuggerUrl}`)
107
- }
108
-
109
- const browserHooks = browserToRuntimeHooks(browser, {
110
- runtime: chromiumRuntime,
111
- browserServerLogLevel,
112
-
113
- projectDirectoryUrl,
114
- compileServerOrigin,
115
- compileServerId,
116
- outDirectoryRelativeUrl,
117
-
118
- collectPerformance,
119
- measurePerformance,
120
- collectCoverage,
121
- coverageIgnorePredicate,
122
- coverageForceIstanbul,
123
- coveragePlaywrightAPIAvailable: true,
124
- })
125
-
126
- return {
127
- browser,
128
- ...browserHooks,
129
- }
130
- }
131
- export const chromiumTabRuntime = {
132
- ...chromiumRuntime,
133
- launch: (params) =>
134
- chromiumRuntime.launch({
135
- shared: true,
136
- ...params,
137
- }),
138
- }
139
-
140
- const firefoxSharing = createSharing()
141
- export const firefoxRuntime = {
142
- name: "firefox",
143
- version: PLAYWRIGHT_FIREFOX_VERSION,
144
- }
145
- firefoxRuntime.launch = async ({
146
- signal = new AbortController().signal,
147
- firefoxExecutablePath,
148
- browserServerLogLevel,
149
-
150
- projectDirectoryUrl,
151
- compileServerOrigin,
152
- outDirectoryRelativeUrl,
153
-
154
- collectPerformance,
155
- measurePerformance,
156
- collectCoverage,
157
- coverageIgnorePredicate,
158
- coverageForceIstanbul,
159
-
160
- headless = true,
161
- stopOnExit = true,
162
- share = false,
163
- }) => {
164
- const launchBrowserOperation = Abort.startOperation()
165
- launchBrowserOperation.addAbortSignal(signal)
166
-
167
- const sharingToken = share
168
- ? firefoxSharing.getSharingToken({ firefoxExecutablePath, headless })
169
- : firefoxSharing.getUniqueSharingToken()
170
- if (!sharingToken.isUsed()) {
171
- const { firefox } = await importPlaywright({ browserName: "firefox" })
172
- const launchOperation = launchBrowser("firefox", {
173
- browserClass: firefox,
174
-
175
- launchBrowserOperation,
176
- options: {
177
- headless,
178
- executablePath: firefoxExecutablePath,
179
- },
180
- stopOnExit,
181
- })
182
- sharingToken.setSharedValue(launchOperation)
183
- }
184
-
185
- const [browserPromise, stopUsingBrowser] = sharingToken.useSharedValue()
186
- launchBrowserOperation.addEndCallback(stopUsingBrowser)
187
- const browser = await browserPromise
188
-
189
- const browserHooks = browserToRuntimeHooks(browser, {
190
- runtime: firefoxRuntime,
191
- launchBrowserOperation,
192
- browserServerLogLevel,
193
-
194
- projectDirectoryUrl,
195
- compileServerOrigin,
196
- outDirectoryRelativeUrl,
197
-
198
- collectPerformance,
199
- measurePerformance,
200
- collectCoverage,
201
- coverageIgnorePredicate,
202
- coverageForceIstanbul,
203
- })
204
-
205
- return {
206
- browser,
207
- ...browserHooks,
208
- }
209
- }
210
- export const firefoxTabRuntime = {
211
- ...firefoxRuntime,
212
- launch: (params) =>
213
- firefoxRuntime.launch({
214
- shared: true,
215
- ...params,
216
- }),
217
- }
218
-
219
- const webkitSharing = createSharing()
220
- export const webkitRuntime = {
221
- name: "webkit",
222
- version: PLAYWRIGHT_WEBKIT_VERSION,
223
- }
224
- webkitRuntime.launch = async ({
225
- signal = new AbortController().signal,
226
- browserServerLogLevel,
227
- webkitExecutablePath,
228
-
229
- projectDirectoryUrl,
230
- compileServerOrigin,
231
- outDirectoryRelativeUrl,
232
-
233
- collectPerformance,
234
- measurePerformance,
235
- collectCoverage,
236
- coverageIgnorePredicate,
237
- coverageForceIstanbul,
238
-
239
- headless = true,
240
- stopOnExit = true,
241
- share = false,
242
- }) => {
243
- const launchBrowserOperation = Abort.startOperation()
244
- launchBrowserOperation.addAbortSignal(signal)
245
-
246
- const sharingToken = share
247
- ? webkitSharing.getSharingToken({ webkitExecutablePath, headless })
248
- : webkitSharing.getUniqueSharingToken()
249
-
250
- if (!sharingToken.isUsed()) {
251
- const { webkit } = await await importPlaywright({ browserName: "webkit" })
252
- const launchOperation = launchBrowser("webkit", {
253
- browserClass: webkit,
254
- launchBrowserOperation,
255
- options: {
256
- headless,
257
- executablePath: webkitExecutablePath,
258
- },
259
- stopOnExit,
260
- })
261
- sharingToken.setSharedValue(launchOperation)
262
- }
263
-
264
- const [browserPromise, stopUsingBrowser] = sharingToken.useSharedValue()
265
- launchBrowserOperation.addEndCallback(stopUsingBrowser)
266
- const browser = await browserPromise
267
-
268
- const browserHooks = browserToRuntimeHooks(browser, {
269
- runtime: webkitRuntime,
270
- launchBrowserOperation,
271
- browserServerLogLevel,
272
-
273
- projectDirectoryUrl,
274
- compileServerOrigin,
275
- outDirectoryRelativeUrl,
276
-
277
- collectPerformance,
278
- measurePerformance,
279
- collectCoverage,
280
- coverageIgnorePredicate,
281
- coverageForceIstanbul,
282
- ignoreErrorHook: (error) => {
283
- // we catch error during execution but safari throw unhandled rejection
284
- // in a non-deterministic way.
285
- // I suppose it's due to some race condition to decide if the promise is catched or not
286
- // for now we'll ignore unhandled rejection on wekbkit
287
- if (error.name === "Unhandled Promise Rejection") {
288
- return true
289
- }
290
- return false
291
- },
292
- transformErrorHook: (error) => {
293
- // Force error stack to contain the error message
294
- // because it's not the case on webkit
295
- error.stack = `${error.message}
32
+ return false
33
+ },
34
+ transformErrorHook: (error) => {
35
+ // Force error stack to contain the error message
36
+ // because it's not the case on webkit
37
+ error.stack = `${error.message}
296
38
  at ${error.stack}`
297
39
 
298
- return error
299
- },
300
- })
301
-
302
- return {
303
- browser,
304
- ...browserHooks,
305
- }
306
- }
307
- export const webkitTabRuntime = {
308
- ...webkitRuntime,
309
- launch: (params) =>
310
- webkitRuntime.launch({
311
- shared: true,
312
- ...params,
313
- }),
314
- }
315
-
316
- const launchBrowser = async (
317
- browserName,
318
- { launchBrowserOperation, browserClass, options, stopOnExit },
319
- ) => {
320
- if (stopOnExit) {
321
- launchBrowserOperation.addAbortSource((abort) => {
322
- return raceProcessTeardownEvents(
323
- {
324
- SIGHUP: true,
325
- SIGTERM: true,
326
- SIGINT: true,
327
- beforeExit: true,
328
- exit: true,
329
- },
330
- abort,
331
- )
332
- })
333
- }
334
-
335
- try {
336
- const browser = await browserClass.launch({
337
- ...options,
338
- // let's handle them to close properly browser + remove listener
339
- // instead of relying on playwright to do so
340
- handleSIGINT: false,
341
- handleSIGTERM: false,
342
- handleSIGHUP: false,
343
- })
344
- launchBrowserOperation.throwIfAborted()
345
- return browser
346
- } catch (e) {
347
- if (launchBrowserOperation.signal.aborted && isTargetClosedError(e)) {
348
- // rethrow the abort error
349
- launchBrowserOperation.throwIfAborted()
350
- }
351
- throw e
352
- } finally {
353
- await launchBrowserOperation.end()
354
- }
355
- }
356
-
357
- const importPlaywright = async ({ browserName }) => {
358
- try {
359
- const namespace = await import("playwright")
360
- return namespace
361
- } catch (e) {
362
- if (e.code === "ERR_MODULE_NOT_FOUND") {
363
- throw new Error(
364
- createDetailedMessage(
365
- `"playwright" not found. You need playwright in your dependencies when using "${browserName}Runtime"`,
366
- {
367
- suggestion: `npm install --save-dev playwright`,
368
- },
369
- ),
370
- { cause: e },
371
- )
372
- }
373
- throw e
374
- }
375
- }
376
-
377
- const stopBrowser = async (browser) => {
378
- const disconnected = browser.isConnected()
379
- ? new Promise((resolve) => {
380
- const disconnectedCallback = () => {
381
- browser.removeListener("disconnected", disconnectedCallback)
382
- resolve()
383
- }
384
- browser.on("disconnected", disconnectedCallback)
385
- })
386
- : Promise.resolve()
387
-
388
- // for some reason without this 100ms timeout
389
- // browser.close() never resolves (playwright does not like something)
390
- await new Promise((resolve) => setTimeout(resolve, 100))
391
-
392
- await browser.close()
393
- await disconnected
394
- }
395
-
396
- const browserToRuntimeHooks = (
397
- browser,
398
- {
399
- runtime,
400
- projectDirectoryUrl,
401
- compileServerOrigin,
402
- compileServerId,
403
- outDirectoryRelativeUrl,
404
-
405
- collectPerformance,
406
- measurePerformance,
407
- collectCoverage,
408
- coverageIgnorePredicate,
409
- coverageForceIstanbul,
410
- coveragePlaywrightAPIAvailable = false,
411
- ignoreErrorHook = () => false,
412
- transformErrorHook = (error) => error,
40
+ return error
413
41
  },
414
- ) => {
415
- const stopCallbackList = createCallbackListNotifiedOnce()
416
- const stoppedCallbackList = createCallbackListNotifiedOnce()
417
- const stop = memoize(async (reason) => {
418
- await stopCallbackList.notify({ reason })
419
- stoppedCallbackList.notify({ reason })
420
- return { graceful: false }
421
- })
422
-
423
- // https://github.com/GoogleChrome/puppeteer/blob/v1.4.0/docs/api.md#event-disconnected
424
- browser.on("disconnected", () => {
425
- stop()
426
- })
427
-
428
- stopCallbackList.add(async () => {
429
- await stopBrowser(browser)
430
- })
431
-
432
- const errorCallbackList = createCallbackList()
433
-
434
- const outputCallbackList = createCallbackList()
435
-
436
- const execute = async ({
437
- signal,
438
- fileRelativeUrl,
439
- ignoreHTTPSErrors = true, // we mostly use self signed certificates during tests
440
- }) => {
441
- const executeOperation = Abort.startOperation()
442
- executeOperation.addAbortSignal(signal)
443
- executeOperation.throwIfAborted()
444
- // open a tab to execute to the file
445
- const browserContext = await browser.newContext({ ignoreHTTPSErrors })
446
- executeOperation.throwIfAborted()
447
- const page = await browserContext.newPage()
448
- executeOperation.addEndCallback(async () => {
449
- try {
450
- await browserContext.close()
451
- } catch (e) {
452
- if (isTargetClosedError(e)) {
453
- return
454
- }
455
- throw e
456
- }
457
- })
458
- // track tab error and console
459
- const stopTrackingToNotify = trackPageToNotify(page, {
460
- onError: (error) => {
461
- error = transformErrorHook(error)
462
- if (!ignoreErrorHook(error)) {
463
- errorCallbackList.notify(error)
464
- }
465
- },
466
- onConsole: outputCallbackList.notify,
467
- })
468
- stoppedCallbackList.add(stopTrackingToNotify)
469
-
470
- const result = await executeHtmlFile(fileRelativeUrl, {
471
- runtime,
472
- executeOperation,
473
-
474
- projectDirectoryUrl,
475
- compileServerOrigin,
476
- compileServerId,
477
- outDirectoryRelativeUrl,
478
-
479
- page,
480
- measurePerformance,
481
- collectPerformance,
482
- collectCoverage,
483
- coverageForceIstanbul,
484
- coveragePlaywrightAPIAvailable,
485
- coverageIgnorePredicate,
486
- transformErrorHook,
487
- })
488
- return result
489
- }
490
-
491
- return {
492
- stoppedCallbackList,
493
- errorCallbackList,
494
- outputCallbackList,
495
- execute,
496
- stop,
497
- }
498
- }
499
-
500
- const isTargetClosedError = (error) => {
501
- if (error.message.match(/Protocol error \(.*?\): Target closed/)) {
502
- return true
503
- }
504
- if (error.message.match(/Protocol error \(.*?\): Browser.*?closed/)) {
505
- return true
506
- }
507
- if (error.message.includes("browserContext.close: Browser closed")) {
508
- return true
509
- }
510
- return false
511
- }
42
+ })
43
+ export const webkitTabRuntime = webkitRuntime.tab