@browserless/goto 13.0.9 → 13.1.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 CHANGED
@@ -71,6 +71,7 @@ const { response, device, error } = await goto(page, {
71
71
  | `javascript` | `boolean` | `true` | Enable/disable JavaScript |
72
72
  | `animations` | `boolean` | `false` | Enable CSS animations |
73
73
  | `colorScheme` | `string` | — | `'light'` or `'dark'` preference |
74
+ | `flattenShadowDOM` | `boolean` | `false` (`true` for `html()`) | Serialize open shadow DOM into HTML (mutates the page DOM; closed shadow roots are skipped) |
74
75
  | `mediaType` | `string` | — | CSS media type (`'screen'`, `'print'`) |
75
76
  | `timezone` | `string` | — | Timezone to emulate |
76
77
  | `authenticate` | `object` | — | HTTP authentication credentials |
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@browserless/goto",
3
3
  "description": "Navigate to web pages with built-in ad blocking, device emulation, and optimized loading for faster automation.",
4
4
  "homepage": "https://browserless.js.org/#/?id=gotopage-options",
5
- "version": "13.0.9",
5
+ "version": "13.1.0",
6
6
  "main": "src/index.js",
7
7
  "author": {
8
8
  "email": "hello@microlink.io",
@@ -42,7 +42,7 @@
42
42
  "tough-cookie": "~6.0.1"
43
43
  },
44
44
  "devDependencies": {
45
- "@browserless/test": "13.0.9",
45
+ "@browserless/test": "13.1.0",
46
46
  "ava": "5",
47
47
  "p-wait-for": "3"
48
48
  },
@@ -66,5 +66,5 @@
66
66
  "timeout": "2m",
67
67
  "workerThreads": false
68
68
  },
69
- "gitHead": "b4a515a809d6d7d33828e901d18d32e805e26d55"
69
+ "gitHead": "5f117c60ca3a4bea5d8905a41abccedd10a99fc7"
70
70
  }
package/src/index.js CHANGED
@@ -251,6 +251,7 @@ module.exports = ({ defaultDevice = 'Macbook Pro 13', timeout: globalTimeout, ..
251
251
  authenticate,
252
252
  click,
253
253
  colorScheme,
254
+ flattenShadowDOM = false,
254
255
  headers: rawHeaders = {},
255
256
  html,
256
257
  javascript = true,
@@ -481,7 +482,7 @@ module.exports = ({ defaultDevice = 'Macbook Pro 13', timeout: globalTimeout, ..
481
482
  return Promise.race([page.goto(url, { waitUntil, ...args }), promise])
482
483
  })()
483
484
 
484
- const { value: response, reason: error } = await run({
485
+ let { value: response, reason: error } = await run({
485
486
  fn: navigationPromise,
486
487
  timeout: gotoTimeout,
487
488
  debug: { fn: html ? 'html' : 'url', waitUntil }
@@ -547,6 +548,65 @@ module.exports = ({ defaultDevice = 'Macbook Pro 13', timeout: globalTimeout, ..
547
548
  await waitUntilAuto(page, { response, timeout: actionTimeout * 2 })
548
549
  }
549
550
 
551
+ if (flattenShadowDOM) {
552
+ const { isRejected, reason: flattenError } = await run({
553
+ fn: page.evaluate(() => {
554
+ ;(function flatten (root) {
555
+ const replaceSlot = (slot, nodes) => {
556
+ const parent = slot.parentNode
557
+ if (!parent) return
558
+ for (const node of nodes) parent.insertBefore(node, slot)
559
+ slot.remove()
560
+ }
561
+
562
+ const flattenNode = node => {
563
+ if (node.nodeType !== window.Node.ELEMENT_NODE) return
564
+ if (node.shadowRoot) flattenElement(node)
565
+ flattenChildren(node)
566
+ }
567
+
568
+ const flattenChildren = root => {
569
+ for (const el of root.querySelectorAll('*')) {
570
+ if (el.shadowRoot) flattenElement(el)
571
+ if (el.localName !== 'slot') continue
572
+
573
+ const slot = el
574
+ const nodes = slot.assignedNodes({ flatten: true })
575
+ if (nodes.length > 0) {
576
+ const clones = nodes.map(node => {
577
+ flattenNode(node)
578
+ return node.cloneNode(true)
579
+ })
580
+
581
+ replaceSlot(slot, clones)
582
+ } else {
583
+ const fallback = [...slot.childNodes]
584
+ fallback.forEach(flattenNode)
585
+ if (fallback.length > 0) {
586
+ replaceSlot(
587
+ slot,
588
+ fallback.map(n => n.cloneNode(true))
589
+ )
590
+ } else slot.remove()
591
+ }
592
+ }
593
+ }
594
+
595
+ const flattenElement = el => {
596
+ flattenChildren(el.shadowRoot)
597
+ el.innerHTML = el.shadowRoot.innerHTML
598
+ }
599
+
600
+ flattenChildren(root)
601
+ })(document.body)
602
+ }),
603
+ timeout: actionTimeout,
604
+ debug: 'flattenShadowDOM'
605
+ })
606
+
607
+ if (isRejected) error = error || flattenError || new Error('flattenShadowDOM failed')
608
+ }
609
+
550
610
  return { response, device, error }
551
611
  } finally {
552
612
  if (abortTypesHandler) page.off('request', abortTypesHandler)