npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

wdio-webcomponents

v1.1.0

Published

WebdriverIO plugin to handle shadow roots and DOMs

Downloads

51

Readme

wdio-webcomponents

wdio-webcomponents is a webdriver.io plugin which makes webdriver compatible with Open Shadow Roots.

Shadow DOMs are a great solution to encapsulate your components from the rest of your application, but it prevents your components from easily being e2e tested. Normal Selenium commands fail, due to the element actually not beind in the main document.

With the rise of Shadow DOM in webcomponent applications, we need a solution to test the components using Webdriver(Selenium). This plugin is that solution!

When this plugin is enabled, every Webdriver command will work with Shadow DOMS.

Installation

Install the npm lib:

npm install wdio-webcomponents --save-dev

Then add the plugin to your wdio.conf under plugins.

{
    plugins: {
        'wdio-webcomponents': {}
    }
}

How to use

You can use it just like you normally use webdriver. However, there are some pitfalls:

  • You can only use CSS selectors.
  • The selector should contain every Shadow Host on the way to the element. (Read down for explanation)
  • Visibility is checked recursively (Read down for explanation)

For examples on how to use it, the internal test suite contains a lot of examples. These examples 'test' the Polymer example shop.

You can find the test-suite at https://github.com/Morlack/wdio-webcomponents/blob/master/test/wdio/specs/main.spec.js

Visibility checks

One of the things that are hard to solve with Selenium and Shadow DOM is checking the visiblity of a selected element.

This is because Selenium checks whether the element is visible or not by checking styling and attributes on the element and it's parents. If the element, or one of it's parents, are hidden (such as when display is set to none) the element is considered invisible. This becomes a problem when Selenium can't check outside the Shadow DOM, since the Shadow DOM can be located inside an element.

You can find the code where Selenium checks visibility here: https://github.com/SeleniumHQ/selenium/blob/master/javascript/atoms/dom.js#L437 (This is the Javascript version).

Because of the we have to check whether all shadow hosts on the way are visibile. This is built in and you don't have to do anything for it.

However, there are some cases where part of the visibility check should be skipped. For example when your element is located inside an invisible element (element itself is absolute with width and height, but it's parent has a height of 0 and thus it's invisible). In this case you can add :skip-visible to the element. For example, the selector 'could' become: my-app my-dialog-wrapper:skip-visible my-element. In this case, only the my-app and my-element will be checked for visibility.

Shadow Host inclusion

A Shadow host is an element which has at least a Shadow DOM, and might have a light DOM. The Light DOM is content added through slot/content tags. The Actual HTML of a component having both might look like this:

<my-awesome-element>
    #shadow-root
        <div class="shadow">This is a shadow DOM element!</div>
        <slot></slot>
    <!-- End shadow root -->

    <p class="light">This is a light DOM element!</p>
</my-awesome-element>

When considering the markup above, the shadow and light dom elements are queried differently. To query either of them, use the following selectors:

Querying Shadow DOM

Shadow selector: my-awesome-element .shadow

Resulting JS: document.querySelector('my-awesome-element).shadowRoot.querySelector('.shadow')

The resulting JS shows how the plugin works internally. This is because you can only query elements in a Shadow DOM from the shadowRoot of the host element.

Querying light DOM

Light selector: my-awesome-element::.light

Resulting JS: document.querySelector('my-awesome-element .light')

Since we do not need to descend into a shadowRoot, but my-awesome-element has one, we want to prevent descending. The :: syntax is here to provide this; When concatenating selectors using :: they will be executed in the same querySelector call.

Note that when there are nested shadowRoots, you need to include the parent Shadow Hosts. Example:

<my-awesome-element>
    #shadow-root
        <my-awesome-nested-element>
            #shadow-root
                <p class="shadow">This is a Shadow DOM element</p>
                <slot></slot>
            <!-- End nested shadow root -->
            
            <p class="nested-light">This is another light DOM element!</p>
        </my-awesome-nested-element>
    <!-- End top-level shadow root -->

    <p class="light">This is a light DOM element!</p>
</my-awesome-element>

In the above case, to retrieve the .nested-light element, you will need to use my-awesome-element my-awesome-nested-element::.nested-light selector.

Internal workings

The plugin works by replacing the browser.element and browser.elements commands with another implementation. All other webdriver commands use these two functions, so overriding these two fixes all other commands.

It uses a Javascript function, sent to the browser, to find the correct element/elements in or outside of a Shadow DOM. The implementation is based on ChadKillingsworth's code, that can be found here: https://gist.github.com/ChadKillingsworth/d4cb3d30b9d7fbc3fd0af93c2a133a53

The code in this plugin has been modified to support more use cases, non-shadowroots and multiple element selection. You can find it in src/finders/findElement.js.