Podstawowe selektory w Selenium opisałam już tutaj. Omówiłam wtedy sześć prostszych, ale też bardziej ograniczonych metod na tworzenie obiektu elementu html, a były to:
- By.ClassName(“selector”)
- By.Id(“selector”)
- By.Name(“selector”)
- By.LinkText(“selector”)
- By.PartialLinkText(“selector”)
- By.TagName(“selector”)
Jeżeli nie znasz tych metod, rzuć okiem do postu z pierwszą częścią. Pomoże Ci to zrozumieć dlaczego nie do wszystkiego się nadają, a mi łatwiej będzie pokazać, dlaczego zamiast nich używam czegoś innego.
W tej części poruszę dwie metody, z których korzystam najczęściej, a będą to:
- By.CssSelector(“selector”)
- By.XpathSelector(“selector”)
W pierwszej części wspominałam, że opisane wcześniej selektory mają ograniczone możliwości i mogą nam nie wystarczyć nam w realnych projektach. Natomiast wychodzę z założenia, że wszystko jest dla ludzi a narzędzi trzeba używać z głową. Jeżeli więc w Twoim przypadku podstawowe selektory są wystarczające, to armata na muchę nam nie potrzebna. W tym wpisie podam kilka przykładów, w których armata jednak potrzebna będzie.
Spis treści
Szukanie przez kombinację klas
Weźmy na przykład poniższy dokument.
<div class="miecz stalowy">...</div> <div class="miecz srebrny">...</div> <div class="srebrny bazyliszek">...</div>
Chcemy zaznaczyć element o dwóch klasach: miecz oraz srebrny. Żadna z klas nie czyni elementu unikatowym, dopiero ich kombinacja sprawia, że możliwa jest lokalizacja obiektu. Z tym przykładem sobie poradzimy używając poprzednich metod, ale kod będzie dłuższy i mniej elegancki. Musimy to zrobić na dwa razy: najpierw znaleźć wszystkie elementy z klasą miecz, a potem wśród nich znaleźć element z klasą srebrny. Albo na odwrót. Będzie to wyglądało tak:
_driver.FindElements(By.Class("miecz")).FindElement(By.Class("srebrny"));
A tak by to mogło wyglądać przy użyciu selektorów CSS i XPath:
//CssSelector _driver.FindElement(By.CssSelector("[class='miecz srebrny']")); //XPath _driver.FindElement(By.CssXPath("//div[@class='miecz srebrny']"));
Jest trochę czytelniej: widzimy od razu, że szukamy tylko jednego elementu oraz że ma on dwie klasy.
Szukanie przez specyficzne atrybuty
W poniższym przykładzie musimy się posłużyć atrybutem „title”.
<div title="miecz stalowy">...</div> <div title="miecz srebrny">...</div> <div title="srebrny bazyliszek">...</div>
Żadna z metod przedstawionych w części pierwszej, nie potrafi zlokalizować obiektu po takim atrybucie. Selektory CSS i XPath ogarną to na przykład tak:
//CssSelector _driver.FindElement(By.CssSelector("[title='miecz srebrny']")); //XPath _driver.FindElement(By.CssXPath("//div[@title='miecz srebrny']"));
Szukanie poprzez rodzica
No i to jest dopiero zabawa. Spójrz na poniższy przykład:
<tbody> <tr title="ene"> <td>Ene</td> </tr> <tr title="due"> <td>Due</td> </tr> <tr title="rike"> <td>Rike</td> </tr> </tbody>
Rozważmy taki scenariusz: załóżmy, że piszesz test i chcesz zaznaczyć komórkę w drugim wierszu (znacznik <tr> oznacza wiersz tabeli, a <td> komórkę) ale nie możesz tego zrobić za pomocą tekstu, bo ten się generuje dynamicznie i nie będzie cały czas taki sam. W takiej sytuacji możemy się odwołać do rodzica i za jego pomocą zlokalizować wskazany obiekt.
//CssSelector _driver.FindElement(By.CssSelector("[title='due']>td")); //XPath _driver.FindElement(By.CssXPath("//tr[@title='due']/td"));
Gdyby nie atrybut „title”, który nie jest obsługiwany przez selektory inne niż CSS i XPath, takie wyszukanie byłoby możliwe za pomocą omawianych wcześniej metod. Gdyby na przykład wiersze miały unikalne klasy albo id, moglibyśmy ponownie zastosować konstrukcję, w której najpierw szukamy wszystkich wierszy o danej wartości klas lub id, a potem w tym podzbiorze szukamy komórki.
Szukanie po tekście
Zostańmy przy tym przykładzie co w poprzednim punkcie, ale teraz rozważmy następujący scenariusz: dane w komórkach nie są generowane dynamicznie, więc możemy użyć tekstu pomiędzy znacznikami. Skorzystanie z tekstu jest możliwe już tylko w XPath.
//XPath _driver.FindElement(By.CssXPath("//td[text()='Due']"));
Inne przewagi selektorów CSS i XPath
Oprócz wymienionych przykładów użycia, w których musimy się posłużyć atrybutem niedostępnym dla metod opisanych w pierwszej części cyklu o selektorach w Selenium, warto także wspomnieć o kilku innych przewagach CSS i XPatha.
- Elementy mogą być lokalizowane w odniesieniu nie tylko do swoich rodziców ale także dowolnego przodka oraz dzieci i rodzeństwa (występują pewne różnice między XPathem a selektorami CSS).
- Elementy mogą być lokalizowane na podstawie nie tylko wartości atrybutu, ale także jego fragmentu. Oznacza to, że można znaleźć element, który w atrybucie zawiera jakiś ciąg znaków albo rozpoczyna się od jakiegoś ciągu znaków.
- Można łączyć lokalizatory, tzn. że można za jednym zamachem wyszukać kilka różnych elementów o różnych wartościach atrybutów robiąc z tego jeden selektor.
Mam nadzieję, że pomogłam Ci zrozumieć najważniejsze przewagi tych dwóch selektorów nad pozostałymi. Jeżeli nie – napisz, czego jeszcze według Ciebie tutaj brakuje. Jeżeli chcesz zacząć używać selektorów CSS i XPatha albo po prostu jesteś strasznym testerskim nerdem, zapraszam do kolejnych wpisów traktujących o każdym z tych selektorów z osobna (selektory CSS tu a XPath tu). Dowiesz się z nich w jaki sposób budować podstawowe ale też całkiem pokręcone selektory, żeby znaleźć to, czego będziesz potrzebować do testów. Oba tematy są obszerne więc teraz jest odpowiedni moment żeby przygotować sobie żarcie albo zrobić kawę 🙂
Cześć,
mam pytanie odnośnie porównania już samych lokatorów CSS i Xpath. W jednym z kursów które przerabiam jest wskazane że lokatory CSS są szybsze - jakie jest Twoje zdanie w tym temacie?
Kuba Rosiński to nawet sprawdzał empirycznie, zajrzyj do komentarzy tutaj: https://www.facebook.com/groups/TestowanieOprogramowania/permalink/2018548571501044/
Różnice jakieś tam są ale wg. mnie zupełnie pomijalne. Jeżeli martwisz się szybkością wykonywania testów, to lepiej skupić się na odpowiednim zaprojektowaniu scenariuszy testowych. Wywalanie jednego niepotrzebnego kroku z kilku testów albo wycięcie jednego redundantnego testu da lepsze efekty niż przepisywanie lokatorów np. na selektory CSS.
Hej,
przede wszystkim dzięki za tworzone przez Ciebie materiały!
Sprawdź proszę czy nie masz błędu w snippecie z ene, due, rike (z twojego css/xpatha wynika, że powinno być w title "due", a nie "rue").
pozdrawiam!
Kay
Lol, tak 😀 Poprawione, dzięki! I dzięki za miłe słowa 🙂