Basic Auth w Selenium 4

Interesuje Cię ten kurs?

Zapisz się na listę, a wyślę Ci szczegóły i informację jak dołączyć 👇 

Kojarzysz takie okienko w przeglądarce?

Wyskakujące okienko w przeglądarce z Basic Auth

To metoda na przekazanie w przeglądarce danych do logowania zanim jeszcze w ogóle zobaczymy stronę. To jest takie dodatkowe zabezpieczenie jeżeli na przykład nie chcemy, żeby strona była dostępna dla ludzi „z ulicy”. W ten sposób mogą być zabezpieczone całe foldery plików na serwerze (wraz z podfolderami) jak i pojedyncze pliki.

Jak było do tej pory

W Selenium 3 można sobie było z tym poradzić w poniższy sposób:

Ukryta treść

Nie masz dostępu do tego kursu. Wykup dostęp albo zaloguj się, by móc zobaczyć pełną lekcję.

Czyli zamiast przechodzić bezpośrednio na stronę musieliśmy przed adresem wprowadzić nazwa_użytkownika:hasło@ i tak przekazać dane logowania.

Musieliśmy to zrobić za każdym razem gdy jest to koniecznie do przejścia na stronę (bo dana strona jest zabezpieczona). To oznacza, że w zasadzie trzeba to dodawać do URLa strony za każdym razem.

Jak jest w Selenium 4

W Selenium 4 możemy to zrobić raz (np. w @BeforeEach w JUnit czy [SetUp] w NUnit), a dane logowania zostaną wzięte pod uwagę za każdym razem, gdy odwiedzimy stronę w podanej domenie. Czyli nie musimy już za każdym razem wstawiać do URLa strony w Selenium nazwy użytkownika i hasła.

Ponieważ użyte metody różnią się w tym wypadku dla Selenium w Javie i Selenium w C# opiszę to osobno poniżej. Zobaczysz tam przykłady kodu na specjalnie przygotowanej do tego stronie, do której adres, hasło i nazwę użytkownika znajdziesz w kodzie.

Java

W poniższym przykładzie chroniony hasłem jest folder „protected” co oznacza, że chronione hasłem są także pliki znajdujące się w tym folderze, podfoldery i pliki w podfolderach. Krótko mówiąc całe drzewo.

Ukryta treść

Nie masz dostępu do tego kursu. Wykup dostęp albo zaloguj się, by móc zobaczyć pełną lekcję.

By móc na driverze skorzystać z metody „register”, która nam umożliwi ustawienie danych logowania, najpierw musimy rzutować driver na HasAuthentication.

Metoda „register” w parametrze przyjmuje dane logowania. Przekazujemy je korzystając ze statycznej metody „of” klasy „UsernameAndPassword”. Klasa ta z kolei implementuje interfejs „Credentials”.

W ten sposób za każdym razem, gdy w teście będziemy wywoływać metodę get() albo navigate().to() będą równocześnie przekazywane dane logowania.

A gdy chcemy te konkretne dane logowania przekazywać tylko dla określonych adresów URL? Wtedy do dyspozycji mamy jeszcze metodę „register” z dodatkowym parametrem: predykatem.

Ukryta treść

Nie masz dostępu do tego kursu. Wykup dostęp albo zaloguj się, by móc zobaczyć pełną lekcję.

W powyższym przykładzie dodałam także przejście na stronę główną (fakestore.testelka.pl), żeby Ci pokazać, że strony niechronione hasłem również będą w takiej konfiguracji działać. Poniżej znajdziesz kompletny przykład (całą klasę testową), w którym wyrzuciłam obsługę Basic Auth do @BeforeEach.

Ukryta treść

Nie masz dostępu do tego kursu. Wykup dostęp albo zaloguj się, by móc zobaczyć pełną lekcję.

C#

W poniższym przykładzie chroniony hasłem jest folder „protected” co oznacza, że chronione hasłem są także pliki znajdujące się w tym folderze, podfoldery i pliki w podfolderach. Krótko mówiąc całe drzewo.

W C# cała operacja jest trochę trudniejsza w zrozumieniu niż w Javie, ale sobie poradzimy.

Żeby w ogóle móc obsłużyć Basic Auth będziemy potrzebowali obiektu klasy implementującej interfejs INetwork. Referencję do takiego obiektu możemy uzyskać poprzez właściwość Network.

Ukryta treść

Nie masz dostępu do tego kursu. Wykup dostęp albo zaloguj się, by móc zobaczyć pełną lekcję.

Taki obiekt pozwala nam na rozpoczęcie monitoringu sieci. Będziemy więc nasłuchiwać co się dzieje w sieci. Potrzebujemy tego do tego, żeby móc wyłapać, że na danej stronie wymagana jest autentykacja i że strona znajduje się na wskazanej przez nas domenie (o tym za chwilę).

Ukryta treść

Nie masz dostępu do tego kursu. Wykup dostęp albo zaloguj się, by móc zobaczyć pełną lekcję.

Asynchroniczność

Wydaje się póki co proste. Ale po zajrzeniu głębiej czym jest metoda StartMonitoring(), co robi i co zwraca musimy trochę zmienić to, co już napisaliśmy. Metoda ta jest zaimplementowana w klasie NetworkManager i wygląda tak:

Ukryta treść

Nie masz dostępu do tego kursu. Wykup dostęp albo zaloguj się, by móc zobaczyć pełną lekcję.

I teraz po kolei. Najpierw czym jest to „async”. Ten modyfikator mówi, że dana metoda jest asynchroniczna. Jeżeli chcesz dokładnie zrozumieć czym jest metoda asynchroniczna, to odsyłam tutaj. Znajdziesz tam fajny przykład z przygotowywaniem śniadania. W dużym skrócie chodzi o to jakbyśmy wykonywali śniadanie synchronicznie, to każdą z czynności wykonywalibyśmy po kolei i przez to blokowali wątek.

Ja mam na przykład w domu taki ekspres do kawy, w którym najpierw go trzeba włączyć, następnie poczekać chwilę (chyba aż się nagrzeje). Trwa to na oko z 20 sekund. Następnie muszę przekręcić jedną wajchę, kawa zacznie się lać do kubka i po 30 sekundach jest gotowa. Jeżeli na śniadanie planuję jajecznicę, to potrzebuję także nagrzać patelnię i roztopić masło zanim wbiję jajka. I jeżeli robiłabym te czynności synchronicznie w ujęciu o jakim tutaj mówię, to wyglądałoby to tak:

  1. Włączam ekspres i gapię się na lampkę dopóki nie przestanie mrugać. W tym czasie nic innego nie widzę ani nie słyszę i nie wykonuję żadnej innej czynności.
  2. Gdy lampa będzie się świecić światłem ciągłym, przekręcam wajchę i czekam. Znowu tylko się gapię i czekam i nie mogę podjąć innej czynności.
  3. Gdy kawa jest gotowa rozgrzewam masło na patelni. I nie ma, że w międzyczasie wyjmę jajka z lodówki, albo zacznę już pić kawę. Gapię się w masło dopóki się nie roztopi.
  4. Wbijam jajka.

Itd.

Czyli jednowątkowa Ela w ujęciu synchronicznym robiłaby śniadanie dużo dłużej niż gdyby robiła to asynchronicznie. Asynchronicznie wyglądało by to np. tak:

  1. Włączam ekspres.
  2. W czasie kiedy ekspres się nagrzewa wyciągam jajka i masło z lodówki.
  3. Ekspres jest gotowy, przełączam wajchę.
  4. W czasie kiedy do kubka wlewa się kawa, zaczynam rozgrzewać masło na patelni.
  5. Kawa jest gotowa, wyłączam ekspres i wbijam jajka na patelnię.

Do tej pory w Selenium działaliśmy synchronicznie, więc to co się tutaj dzieje może być trochę nieintuicyjne. Myślę, że po tym obrazowym przykładzie dużo łatwiej zrozumieć o co biega z tą całą asynchronicznością.

Wracając do asynchronicznej metody StartMonitoring(): jest ona asynchroniczna, bo zawiera w sobie inne asynchroniczne metody (konkretnie trzy). To są te metody, przed którymi znajduje się słówko await (zaraz powiem do czego to słówko). Metody asynchroniczne, to są niezłe świrusy, bo one się po prostu odpalą w momencie wywołania ale ich działanie może się zakończyć dużo później. I inne metody nie poczekają na ich zakończenie.

Dodajmy dodatkową linijkę do naszego kodu:

Ukryta treść

Nie masz dostępu do tego kursu. Wykup dostęp albo zaloguj się, by móc zobaczyć pełną lekcję.

Za pomocą metody StartMonitoring() rozpoczniemy nasłuchiwanie, ale ponieważ metoda ta działa asynchronicznie, możliwe jest że przejdziemy do kolejnej instrukcji (GoToUrl()) zanim rzeczywiście to nasłuchiwanie zadziała. Musimy najpierw poczekać, aż to zadanie się wykona i dopiero przejść na podaną stronę. I właśnie do tego służy słówko await. Musimy je także dodać w naszym teście.

Po dodaniu słówka await zostaniemy poinformowani, że ten operator może być użyty tylko w asynchronicznych metodach. Oznacza to, że nasza metoda testowa także musi dostać modyfikator async. Dodatkowo, po odpaleniu testu dostaniemy informację, że asynchroniczne metody testowe nie mogą nic nie zwracać (void) dlatego ustawimy typ na Task. Jeżeli użyjemy podpowiedzi w Visual Studio, to zostanie zmieniona także nazwa metody – zgodnie z konwencją nazewniczą zostanie dodane na końcu słówko Async. Osobiście chyba bym sobie to darowała w nazwach testów, wolałabym żeby nazwy testów były spójne. Niemniej podrzucam pod spodem to, co mi zaproponowano w podpowiedziach.

Ukryta treść

Nie masz dostępu do tego kursu. Wykup dostęp albo zaloguj się, by móc zobaczyć pełną lekcję.

Użytkownik, hasło i URI

Teraz musimy jakoś przekazać nazwę użytkownika i hasło, którym chcemy się logować. Dla mojej przykładowej strony nazwa użytkownika to: harrypotter, a hasło: Alohomora. Metoda, która pozwoli nam na przekazanie danych logowania to AddAuthenticationHandler(). Metoda ta przyjmuje w parametrze obiekt typu NetworkAuthenticationHandler. Obiekty tej klasy z kolei mają właściwość Credentials i to tej właściwości użyjemy dla nazwy użytkownika i hasła.

Ukryta treść

Nie masz dostępu do tego kursu. Wykup dostęp albo zaloguj się, by móc zobaczyć pełną lekcję.

Teraz możemy przekazać te informacje przed rozpoczęciem monitoringu.

Ukryta treść

Nie masz dostępu do tego kursu. Wykup dostęp albo zaloguj się, by móc zobaczyć pełną lekcję.

Ale to nie wszystko: musimy jeszcze przekazać predykat dotyczący adresu strony. Chodzi o to, żeby te dane logowania były używane tylko tam, gdzie potrzeba. My to ustawimy po prostu dla domeny fakestore.testelka.pl. Dodam tylko, że nawet jeżeli na stronie nie mamy Basic Auth a przekażemy hasło i nazwę użytkownika to nic się nie stanie, strona zostanie wyświetlona poprawnie. Bardziej chodzi o to, że dla różnych podstron mogą być różni użytkownicy z nadanym odpowiednim dostępem i wtedy rzeczywiście to filtrowanie się przyda.

Ukryta treść

Nie masz dostępu do tego kursu. Wykup dostęp albo zaloguj się, by móc zobaczyć pełną lekcję.

I to jest już działający przykład, ale wygląda mało zachęcająco. Na szczęście całość można zapisać w bardziej czytelny na sposób.

Ukryta treść

Nie masz dostępu do tego kursu. Wykup dostęp albo zaloguj się, by móc zobaczyć pełną lekcję.

Raczej będziemy chcieli jednak, żeby wszystko co związane z Basic Auth wylądowało gdzieś „wyżej”, czyli aplikowało do wszystkich testów w klasie (no chyba, że rzeczywiście potrzebujemy tego tylko w jednym teście). Dodatkowo oprócz StartMonitoring() pasuje też po wszystkim dodać StopMonitoring(). Wtedy będzie to wyglądało jak poniżej (w NUnit).

Ukryta treść

Nie masz dostępu do tego kursu. Wykup dostęp albo zaloguj się, by móc zobaczyć pełną lekcję.