What is a pseudo-element?
There may be times when, while writing UI web automated tests, you will come across some elements that look like this:
These are called pseudo-elements, and they are CSS keywords added to the element’s selector which allow you to style only specific parts of that element. For example, the “::after” keyword adds some text value after the selected element and can apply a specific styling only to this text. Other pseudo-elements you might encounter are:
- ::before, which works similarly to after, except it applies to the text added before the element
- ::first-line, which applies the style to the first line in the element (usually a paragraph element)
- ::placeholder, which means a placeholder text in an input or textarea element
- ::selection, which applies the styling to the part of the document that the user highlighted (selected)
- and the list goes on.
You can read more about how pseud-elements work and how they can be used in CSS on Mozilla’s developer website.
How to work with pseudo-elements in Selenium?
Now comes the tricky part. If we need to interact with a pseudo-element, Selenium WebDriver does not offer us the option to do so.
Let’s say we have an element with this HTML:
<button type="submit" class="okButton"> "Submit" </button>
and the CSS:
.okButton:after { content: 'Content displayed after the button.'; }
and our test requires us to verify the content displayed in the ::after block. Since this is not a regular element, we cannot identify it using the regular Selenium locators we are all familiar with.
For example, if we do this (the code samples are in C# but apply to other programming languages as well):
var element = _driver.FindElement(By.CssSelector(".okButton")); Console.WriteLine(element.Text);
Selenium will not return to us the text content inside the before pseud-element.
Trying to locate the ::after pseudo-element by using a locator like “.okButton::after” or “.okButton:after” you will get a NoSuchElementException and still come up empty-handed.
So what’s the solution? Why, JavaScript, of course đ Because JavaScript is a front-end programming language, it enables us to go deeper in the HTML and CSS code and allows us to get the content from pseudo-elements in Selenium. So the code we need will be:
String script = "return window.getComputedStyle(document.querySelector('.okButton'),':after').getPropertyValue('content')"; IJavaScriptExecutor js = (IJavaScriptExecutor)_driver; String content = (String) js.ExecuteScript(script); Assert.AreEqual("Content displayed after the button.", content);
The JavaScript executor will run a script that takes the content inside the :after pseudo-element. We can then save this content to a string variable and compare it to the expected value and validate our test.
Conclusion
While Selenium itself does not allow interacting with pseudo-elements, we can use the JavaScript executor in our code and obtain the values we need to include in our tests.