Native Automation support for Shadow DOM — with WebDriverIO and Cypress {Chapter 3}
The last stage of the Shadow DOM battle is yet to win — so be ready to handle it natively. After going through the previous chapters {chpater#1 Anatomy of Shadow DOM and chpater#2 W3C Webdriver support for Shadow DOM} of this series, now we have strong fundamentals about Shadow DOM. So let’s win the last stage and conquer the Shadow DOM by using few open-source frameworks.
For Shadow DOM, Which frameworks we need to choose if we are starting automation from scratch?
If your Test Automation team is well known to JavScript then we can opt for any one of the following Node JS based frameworks, because both support Shadow DOM natively.
- WebdriverIO {wrapper over W3C Webdriver} framework v5.5.0+
- Cypress framework v5.2.0+
WebDriverIO framework over Shadow DOM
WebdriverIO v5.5.0 introduced built-in support for shadow DOM via two new commands, shadow$ and shadow$$:
- shadow$ — Access a single element inside a given element’s shadowRoot
- shadow$$ — Access more than one elements inside a given element’s shadowRoot
In our test application, we have multi-level shadow roots so we need to chain $ command and shadow$ commands as deeply as needed. First of all, with the help of the $ command, we will reach out to the Shadow Host element i.e. id=todo-app, then by using shadow$ commands, we will reach out to Shadow Root elements i.e. id=adds-item, and then id=enter-text-area. For more clarity, have a look at the below script and screenshot:
browser.$(‘#todo-app’).shadow$(‘#adds-item’).shadow$(‘#enter-text-area’);
In our script, we will take two actions on Shadow DOM elements:
- Enter some text inside the element ‘enter-text-area’
- Click ‘btn-enter’ element
// WebDriverIO JS code snippet - GitHub Repoget inputTaskName () { return browser.$(‘#todo-app’).shadow$(‘#adds-item’).shadow$(‘#enter-text-area’); }get enterButton () { return browser.$(‘#todo-app’).shadow$(‘#adds-item’).shadow$(‘.btn-enter’); }enterTodayTaskName (todayTaskName) {
this.inputTaskName.setValue(todayTaskName);
this.enterButton.click();
}
Cypress framework over Shadow DOM
Cypress v5.2.0 introduced built-in support for shadow DOM via command shadow(selector), that traverse into the Shadow DOM to find the element:
- shadow() — Traverse into the shadow DOM of an element
In our test application, we have multi-level shadow roots so we need to chain the shadow() method as deeply as needed. First of all, with the help of get() method, we will reach out to the Shadow Host element i.e. id=todo-app, then by using shadow() method, we will reach out to Shadow Root elements i.e. id=adds-item, and then id=enter-text-area. For more clarity, have a look at the below code and screenshot:
cy
.get(‘#todo-app’)
.shadow().find(‘#adds-item’)
.shadow().find(‘#enter-text-area’);
// Cypress JS code snippet - GitHub Repodescribe(‘Example to demonstrate the handling of Shadow Dom in Cypress’, () => {
before(() => {
cy.visit(‘http://localhost:3000/')
})it(‘Input a text in the plan box and add it to todays list’, () => {
cy.get(‘#todo-app’)
.shadow().find(‘#adds-item’)
.shadow().find(‘#enter-text-area’)
.type(‘Shadow DOM’) cy.get(‘#todo-app’)
.shadow().find(‘#adds-item’)
.shadow().find(‘.btn-enter’)
.click()
})
})
📍📍 Special case — What if Shadow DOM resides inside iFrame? Handling would be still the same but Webdriver needs to switch context before taking any action on iFrame’s Shadow DOM elements.
Key Takeaways
- Aware of JS-based frameworks that natively support Shadow DOM.
- Got to know the way of native handling of Shadow DOM by using WebDriverIO.
- Better known in-built of handling Shadow DOM by using WebDriverIO.
- Understood — handling of Shadow DOM, if they reside inside the iFrame.
So it’s time to bring down the curtain — the Shadow DOM automation series ending here. Let’s get your hands dirty with Shadow DOM and its elements!!
For further discussion or any doubts — please comment below and start open collaboration over Shadow DOM 👍👍👍👍