Challenge: Setup a locator that can be used to identify the ‘View all’ link on the Events card on the Ministry of Testing website.
Comment below with your answer. I’ll be posting my own response next week.

Link to the Ministry of Testing website: https://www.ministryoftesting.com/

At the end of this article is some sample code which you can use to help you check your locator works.

Response To Last Weeks Challenge

Last weeks locator challenge: Worlds Worst Website

So, sorry about last weeks challenge. That was a tough one. Well done those who attempted it. I asked you to setup a locator using XPath or CSS Selector that can be used to identify the tip on the worlds worst website without using the index or position number.

I wanted a locator that is less likely to break if additional text was added to the page. I try to avoid using index or position numbers of elements if possible as it makes it harder to identify what the element is, and can break easily when the website is modified. Sometimes we have no choice, but I wanted to encourage those participating in this challenge to find alternative ideas for identifying the element.

Well done Velan and Emile Zwiggelaar for providing correct examples.

XPaths:

My chosen XPath was the following.

"//strong[text()='TIP:']/parent::p/following-sibling::p"

The first part "//strong[text()='TIP:'] will identiy the TIP header text. This is a child element of a paragraph element, which has the p. The next section of the xpath /parent::p identified the parent element of the TIP text.

The actual tip message is a sibling element of the Tip parent paragraph element. So, to identify the tip message I used /following-sibling::p to identify the sibling element of the tip paragraph text.

Image showing elements of website with text and arrows showing how we first identify the Tip text element, then its parent element and then the sibling element.

The only downside of this solution is that it will identify all paragraph sibling elements of the tip paragraph, not just a single element. If only wanting to identify a single element, then the first element that meets the criteria should be identified. However, the following sibling which includes the Next text would also meet the criteria of my xpath.

Emile Zwiggelaar came up with a brilliant alternative which uniquely identifies the tip message:

"//p[strong[text()='TIP:']]//following::p[not(a) and not(script)]"

This approach identified paragraph elements which contain the TIP text, and then identifies elements following this which do not contain a or script elements.

CSS Selectors:

At the time of setting this challenge, I’d not been able to create a CSS Selector that could identify the tip message. However, Emile Zwiggelaar did provide a brilliant example that I feel met the difficult and complicated criteria I set which was not to use the index and position number.

"div[style^='background-color: white']>p:first-of-type+p"

This is similar to the method used in the XPath except, instead of first identifying the TIP text, the white area which contains the tip is identified. It then looks for the paragraph following the first paragraph. This avoids using the position number, and also reduce the risk if another paragraph was added further up the page.

Final Thoughts

This weeks challenge was such a tough one, so I’d like to say well done to anyone who dared attempt it. In normal circumstances, if you needed to identify an element without any IDs then you can always ask the developers to add them in for you. As fun as it was to find alternatives that allow us to identify awkward elements, it is a lot more efficient to just include unique IDs in the first place.

Useful Resources

Two ‘games’ that will help you learn how to write XPaths and CSS Selectors.

Cheat Sheets

Sample Code

Here is some sample code which you can use to test your locator. If you need any help, feel free to contact me either on my blog, or via LinkedIn.

For this code to work, you’ll need to install the following NuGet packages:

  • Selenium.WebDriver
  • Selenium.WebDriver.ChromeDriver
  • NUnit
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Interactions;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading;

namespace LocatorChallenge
{
    public class Program
    {
        public static void Main(string[] args)
        {
                IWebDriver Driver = new ChromeDriver(Environment.CurrentDirectory);
                Driver.Navigate().GoToUrl("https://www.ministryoftesting.com/");
                Driver.Manage().Window.Maximize();

                //ReadOnlyCollection<IWebElement> element= Driver.FindElement(By.CssSelector(""));
                ReadOnlyCollection<IWebElement> element = Driver.FindElements(By.XPath(""));
                Console.WriteLine(element[0].Text);

                Assert.AreEqual(1, element.Count);
        }
    }
}