Strona główna > Selektory w Selenium – najprostsze metody lokalizowania elementów na stronie

Selektory w Selenium – najprostsze metody lokalizowania elementów na stronie

Selenium dostarcza mechanizmóm do użycia kilku różnych selektorów na zidentyfikowanie elementów na stronie. Takim elementem może być coś, z czym użytkownik może wejść w jakąś interakcję: button, checkbox, pole ale też na przykład link albo coś innego, co w procesie automatyzacji potrzebujemy zlokalizować na stronie. Do lokalizowania elementów w Selenium służą dwie metody:

  • IWebElement FindElement(By by) – do zlokalizowania pojedynczego elementu,
  • ReadOnlyCollection<IWebElement> FindElements(By by) –  do zlokalizowania jednego i więcej elementów.

Metoda FindElement zwraca obiekt implementujący interfejs IWebElement. Jeżeli kilka elementów na stronie będzie reprezentowanych przez ten sam selektor, to się o tym nie dowiemy – WebDriver i tak nam zwróci tylko pierwszy, na który się nadzieje. Dlatego ważne jest, żeby selektory w przypadku tej metody były unikalne dla danego elementu, żeby oszczędzić sobie dodatkowej pracy później, przy utrzymaniu testów.

Metoda FindElements pozbawiona jest tego problemu – zwraca kolekcję elementów reprezentowanych przez podany selektor. Ta metoda ma jeszcze jedną zaletę, która kilkukrotnie przydała mi się w trakcie pisania testów: gdy nie znajdzie żadnych elementów odpowiadających podanemu selektorowi, zwraca pustą listę ale nie sypie wyjątkiem (co robi z kolei FindElement). W innym artykule pokażę, kiedy warto użyć jednak FindElements nawet, jeśli oczekujemy tylko jednego elementu.

Selenium pozwala na zlokalizowanie elementów za pomocą:

  • By.CssSelector(“selector”)
  • By.XpathSelector(“selector”)
  • By.ClassName(“selector”)
  • By.Id(“selector”)
  • By.Name(“selector”)
  • By.LinkText(“selector”)
  • By.PartialLinkText(“selector”)
  • By.TagName(“selector”)

Używam głównie dwóch pierwszych w układzie “gdzie CSS nie może, tam XPatha pośle”, niemniej teraz opiszę całą resztę metod, które są prostsze w zrozumieniu i użyciu i pozwolą lepiej zrozumieć po co nam te CSSy i XPathy do szczęścia potrzebne.

ClassName, Id i Name

Na przykładzie zawsze fajniej – skorzystamy ze strony automationpractice.com. Na stronie głównej chcemy znaleźć ikonkę symbolizującą kartę kredytową używając ClassName, czyli nazwy klasy elementu. Wyszukałam ten element w konsoli przeglądarki (korzystając z wbudowanego w konsolę Chrome narzędzia), jego klasa to “icon-credit-card”, zatem ten element zidentyfikujemy w Selenium używając poniższej konstrukcji:

_driver.FindElement(By.ClassName("icon-credit-card"));

A co jeżeli element jest opisany przez kilka klas? Wtedy lipa. ClassName nie obsługuje takiego przypadku, możemy podać tylko jedną z klas przypisanych do danego elementu (nawet jeżeli ma ich kilka). Chcąc więc zlokalizować “szukajkę” na poniższej stronie musimy wybrać jedną z trzech klas przypisanych do tego elementu klas: btn, btn-default albo button-search. Wybrałam tą ostatnią, bo tylko ona jest unikatowa dla tego elementu.

_driver.FindElement(By.ClassName("button-search"));

W przypadku, gdy chcemy namierzyć kilka elementów na stronie, robimy dokładnie to samo ale używamy metody FindElements(By by). Jeżeli na tej samej stronie, będziemy chcieli zlokalizować wszystkie ikonki słuchawki (których na stronie jest sztuk trzy) to skorzystamy z klasy icon-phone.

_driver.FindElements(By.ClassName("icon-phone"));

Id i Name funkcjonują na tych samych zasadach co ClassName i ich użycie jest podobne. Zatem zlokalizowanie ikonki ciężarówy za pomocą Id sprowadza się do polecenia:

_driver.FindElement(By.Id("icon-truck"));

Formalnie, możemy lokalizować więcej niż jeden element za pomocą id ale wartości atrybutu id są z reguły unikalne dla elementów na stronie, więc poniższe użycie ma trochę mniej sensu:

_driver.FindElements(By.Id("jakieś-nieunikalne-id"));

Wróćmy do szukajki – chcąc ją wyszukać po atrybucie name postępujemy w podobny sposób. Atrybut name dla przycisku służącego do zatwierdzenia szukanej na stronie frazy, ma wartość submit_search, zatem by go namierzyć, należy użyć poniższej konstrukcji: 

_driver.FindElement(By.Name("submit_search"));

Analogicznie, gdy chcemy znaleźć kilka elementów używając tego samego selektora. Załóżmy, że na stronie są dwa przyciski służące do wyszukiwania. Wtedy użyjemy poniższej metody:

_driver.FindElements(By.Name("submit_search"));

TagName

TagName służy do zlokalizowania obiektu za pomocą jego taga html. Przykładem niech będzie tag select służący do tworzenia list rozwijanych. Wyobraźmy sobie taki scenariusz: chcemy przetestować czy opcje na liście rozwijanej są takie, jak oczekujemy. By to sprawdzić możemy namierzyć listę za pomocą taga select, a następnie pobrać tekst. Taka metoda zwróci wszystkie opcje dostępne na liście.

var selectOptions = _driver.FindElement(By.TagName("select")).Text;

Output:
Price: Lowest first
Price: Highest first
Product Name: A to Z
Product Name: Z to A
In stock
Reference: Lowest first
Reference: Highest first

Wszystkie obrazki na stronie znajdziemy używając taga img analogicznie jak w poprzednich przykładach:

_driver.FindElements(By.TagName("img"));

LinkText i PartialLinkText

Sama nazwa obu method: LinkText oraz PartialLinkText, wskazuje na podstawową różnicę pomiędzy nimi. Tekst o jaki nam chodzi to ten znajdujący się pomiędzy tagami. Należy pamiętać, że obie metody zwracają jedynie linki. Nie da rady ich użyć to wyszukiwania innych elementów po tekście. Chcąc zlokalizować link do My orders możemy to zrobić za pomocą LinkText:

_driver.FindElement(By.LinkText("My orders"));

Przy LinkText musimy podać cały tekst jakiego się spodziewamy, a nie jego część, inaczej element nie zostanie znaleziony a test zwróci nam wyjątek. Do wyszukania linka po części tekstu użyjemy PartialLinkText:

_driver.FindElement(By.PartialLinkText("orders"));

A jeżeli interesuje nas wyszukanie kilku linków z tekstem “My ” to zrobimy to jak poniżej:

_driver.FindElements(By.PartialLinkText("My "));

Spacja po “My” ma tutaj znaczenie – jest częścią stringa. Ta metoda zwróci nam link “My orders” ale także pozostałe trzy elementy zawierające wskazany tekst. Możemy również analogicznie użyć LinkText przy wyszukiwaniu większe ilości elementów.

_driver.FindElements(By.LinkText("My orders"));

Czy to wszystko?

Zupełnie nie. Przedstawione selektory są łatwiejsze w użyciu ale mają też ograniczone możliwości, w zasadzie do tych, które zostały przedstawione. Nietrudno sobie wyobrazić przypadek, w którym dwa elementy są rozróżnialne po atrybucie title, którego to nie obsługuje żadna z przedstawionych metod. Albo gdy dla elementu, który nas interesuje, unikalna jest jedynie cała kombinacja klas, jakie ma przypisane, a jak już wiemy By.ClassName nie ogarnia, gdy podamy mu kilka klas. Co wtedy, jak żyć, w co wierzyć? W selektory CSS i XPath. Materiały o obu rozwiązaniach znajdziesz u mnie na blogu. Zacznij od selektorów CSS, które według mnie są trochę bardziej intuicyjne i świetnie Cię przygotują na XPatha. Materiał o selektorach CSS znajdziesz tutaj: Selektory w Selenium – CSS.