Strona główna > Nawigacja w górę w selektorach CSS: pseudoklasa :has()

Nawigacja w górę w selektorach CSS: pseudoklasa :has()

Dla osób, które są tu chwilę dłużej, nie jest zaskoczeniem, że wolę selektory CSS od XPatha. Są one dla mnie prostsze i bardziej intuicyjne w użyciu. Jednak zawsze, gdy o tym mówię, słyszę pytania, że jak to, a co z wyszukiwaniem po tekście? A nawigacja w górę?

Cóż, wyszukiwanie po tekście w ogóle nie jest dobrym pomysłem, a co do nawigacji w górę – w selektorach CSS mamy już dostępne rozwiązanie.

O co chodzi z tą nawigacją w górę

W testach Selenium, kiedy chcemy zlokalizować element, czasami potrzebujemy użyć nawigacji w górę, co oznacza znalezienie elementu na podstawie jego potomka. Aby przedstawić realny przykład, posłużę się stroną fakestore.testelka.pl, czyli moim testowym sklepem. Gdy dodamy dwa produkty do koszyka i do niego przejdziemy, zobaczymy coś takiego:

Produkty dodane do koszyka na stronie fakestore.testelka.pl

Załóżmy, że chcemy zmienić ilość drugiego produktu w koszyku. W tym celu potrzebujemy dokładnie go zidentyfikować, aby zmiana ilości dotyczyła konkretnie produktu “Windusrfing w Karpathos”, a nie losowego produktu na drugiej pozycji. Dzięki temu, nasz test będzie odporny na ewentualne zmiany kolejności produktów w koszyku.

Jest jednak pewien problem – w tym przypadku nie jest łatwo zlokalizować input służący do zmiany ilości. Nie ma tam żadnego id, które jednoznacznie wskazywałoby produkt. Takie id istnieje, ale wyłącznie pod przyciskiem do usuwania produktu z koszyka (ten krzyżyk po lewej stronie produktu). Gdybyśmy chcieli skorzystać z tej informacji, żeby namierzyć odpowiedni input do zmiany ilości, w przypadku XPatha musielibyśmy to zrobić tak:

  1. Namierzyć przycisk “x” do usuwania produktu korzystając z id produktu:
    .//a[@data-product_id=50]
  2. Przejść z tego elementu “do góry”, czyli do wspólnego przodka tego elementu i inputa, którego szukamy:
    /ancestor::tr
  3. Następnie, z tego przodka, przejść do poszukiwanego inputa:
    //input

Gotowy XPath wygląda tak:

.//a[@data-product_id=50]/ancestor::tr//input

Nawigacja w górę w selektorach CSS: pseudoklasa :has()

Możemy osiągnąć to samo selektorem CSS używając pseudoklasy :has(). Pozwala ona na wybranie elementu, który zawiera w sobie inny określony element. Dla powyższego przykładu procedura będzie wyglądała następująco:

  1. Najpierw należy namierzyć wiersz, który zawiera przycisk “x” o określonym id produktu:
    tr:has(a[data-product_id=”50″])
  2. Następnie można już przejść do inputa z tego wiersza:
    input

Cały selektor wygląda tak:

tr:has(a[data-product_id="50"]) input

Ograniczenia pseudoklasy :has()

Póki co nie wszystkie przeglądarki obsługują pseudoklasę :has(). Jak możecie zobaczyć na poniższym zrzucie ekranu, pseudoklasa jest obsługiwana od określonych wersji przeglądarek:

Kompatybilność funkcji has() z konkretnymi przeglądarkami

Zauważcie, że w przypadku przeglądarki Firefox trzeba samodzielnie włączyć tę opcję, aby móc korzystać z pseudoklasy :has(). Możecie to zrobić wchodząc na stronę about:config i wyszukując tam frazę layout.css.has-selector.enabled:

Włączanie pseudoklasy :has() w Firefoxie

Następnie wystarczy, że klikniecie na przełącznik po prawej, by zmienić wartość false na true.

Pseudoklasa :has() – łatwiejszy sposób na wyszukiwanie elementów

Pseudoklasa :has() może skutecznie ułatwić nam życie przy tworzeniu kolejnych selektorów do testów. Chociaż nie wszystkie przeglądarki obsługują tę pseudokladę, to warto pamiętać o jej istnieniu i stosować, gdy jest to możliwe. Na pewno będzie to prostsze niż budowanie niektórych XPathów. 😜

Dajcie znać, czy mieliście już okazję korzystać z :has() lub z innych selektorów pseudoklas. A może interesuje Was case study na temat innej pseudoklasy? Cóż – wszystko da się załatwić. 😎