0

Good morning,

we are having a severe problem with automated web browsing since shadow-root was introduced on the site. Following the online guides I figured out that with the instructions:

you manage to enter the tree first and then the branch. Our problem is that the shadow-root here is heavily nested and I can't get past the first level. this is the code.

<macroponent-f51912f4c700201072b211d4d8c26010 component-id="dsdsds">
 #shadow-root (open)
 <div style="display. contents;">
   <sn-canvas-appshell-root component-id="pxcbgwo-root">
   #shadow-root (open)
   <sn-canvas-appshell-layout component-id="pxcbgwo-root">
    #shadow-root (open)
     <sn-polaris-layout>
     <>
   <iframe title="Main Content" id="gfst_main">
    #document
        .....
        .....
        .....
    <a id="95410f6c1bba215041a2fc49cd4bcb5f">0</a>

      

2 Answers2

0

For an unknown levels of shadowRoot you need to "Walk the DOM" and dive into shadowRoots:

<my-component>
  #shadow-root(open)
  <my-component>
    #shadow-root(open)
    <my-component>
      #shadow-root(open)
      <content>
        <p>..text..</p>
      </content>
    </my-component>
  </my-component>
</my-component>

<script>
customElements.define("my-component", class extends HTMLElement {
  constructor() {
    super().attachShadow({mode:"open"}).innerHTML = `<slot></slot>`;
  }
})

const shadowDive = (
  el,
  selector,
  match = (el, root) => {
    console.warn('match', el, root);
  },
  root = el.shadowRoot || el
) => {
  root.querySelector(selector) && match(root.querySelector(selector), root);
  [...root.querySelectorAll("*")].map(el => shadowDive(el, selector, match));
}
shadowDive(document.body, "content"); // note optional parameters
</script>

It What Shall Not Be Named/Used says to refactor it to:

const shadowDive = (
  el,
  selector,
  match = (el, root) => {
    console.warn('match', el, root);
  },
  root = el.shadowRoot || el
) => {
  const matchEl = root.querySelector(selector);
  if (matchEl) {
    match(matchEl, root);
  }

  Array.from(root.children).forEach(child => {
    shadowDive(child, selector, match);
  });
}

shadowDive(document.body, "content"); // note optional parameters

Danny '365CSI' Engelman
  • 16,526
  • 2
  • 32
  • 49
0

Watir v7.2 introduced some basic shadow DOM support. It behaves similar to iframes in that you need to specifically tell Watir to look in them. Specifically, you need to call the #shadow_root method.

Find the element with a shadow, call #shadow_root, find the nested element having a shadow, call #shadow_root, etc:

browser.element(component_id: 'dsdsds').shadow_root
  .element(component_id: 'pxcbgwo-root').shadow_root
  .element(component_id: 'pxcbgwo-root').shadow_root
  .iframe
  .link.id

(I'm not sure I have the nesting correct for your example, but hopefully this gets the idea across.)

Justin Ko
  • 46,526
  • 5
  • 91
  • 101