Formularz rejestracyjny jest jednym z kluczowych obszarów na każdej biznesowej stronie internetowej. Dlatego też bardzo często na rozmowie kwalifikacyjnej na stanowisko testera dostaje się za zadanie przetestować formularz. Pokażę dzisiaj jak przy użyciu Selenium można zautomatyzować takie podstawowe zadania jak wypełnianie pól tekstowych czy klikanie w buttony.

Spis treści

Czym w ogóle jest Selenium?

Selenium jest zbiorem narzędzi służących do automatyzacji aplikacji webowych. W jego skład wchodzą: Selenium IDE, Selenium Webdriver oraz Selenium Grid.
Selenium IDE jest rozszerzeniem do Chrome i Firefoxa służącym do nagrywania naszych akcji na stronie, czyli coś w rodzaju tworzenia makra. Jest to narzędzie skierowane przede wszystkim do osób, które nie znają żadnego języka oprogramowania, a chciałaby zautomatyzować jakieś proste zadania wykonywane na stronie internetowej.
Selenium Webdriver korzysta z API udostępnianych przez dostawców przeglądarek do sterowania przeglądarką i uruchamiania testów. Symuluje obsługę przeglądarki, tak jakby robił to prawdziwy użytkownik.
Selenium Grid jest następnym krokiem, gdy już stworzyliśmy nasz przypadek testowy przy pomocy Selenium Webdriver, ponieważ umożliwia uruchamianie przypadków testowych na różnych komputerach na różnych platformach.

Selenium wspiera popularne języki programistyczne jak Python, Java/Kotlin, C#, Ruby i JavaScript. Zwłaszcza w trzech pierwszych językach znajdziesz najwięcej tutoriali. Selenium zapewnia narzędzia do przeprowadzania testów na różnych przeglądarkach i wielu systemach operacyjnych na różnych komputerach. Dzięki dodatkowym frameworkom jak np. Allure możemy w łatwy sposób wygenerować raport z testu, z kolei Pytest umożliwia nam wykonywanie wiele testów w tym samym czasie.

Uruchomienie i zamykanie przeglądarki

Instalacja Selenium jest banalna, więc nie ma co się rozpisywać, bo wystarczy:
pip install selenium
Albo wyszukać paczkę przez PyCharma.

Selenium do otworzenia strony potrzebuje drivera. Dla Chrome będzie to ChromeDriver, dla Mozilli Geckodriver, dla Opery OperaDriver itp. Po ściągnięciu i wypakowaniu drivera, można zacząć działać.

from selenium import webdriver

driver = webdriver.Chrome('/home/user/drivers/chromedriver.exe')

Jeśli przy podawaniu ścieżki do drivera przekopiujesz ją bez zmieniania slashów ‚\’ na ‚/’, to nie zapomnij dodać litery r przed cudzysłowem.

Ja osobiście używam innego sposobu, czyli Webdriver Managera:
pip install webdriver_manager
W Pycharmie znajdziesz pod nazwą webdriver-manager.
Webdriver Manager wspiera drivery dla Chrome, Firefoxa, Opery i Internet Explorera. Dzięki tej bibliotece nie musimy ręcznie aktualizować drivery, ponieważ pobierze i zainstaluje za nas. Trzeba tylko pamiętać o zaktualizowaniu przeglądarki do najnowszej wersji. Inaczej skrypt się nie uruchomi.
Czasami może też się pojawić taki błąd:

PermissionError: [Errno 13] Permission denied: 'C:\\Users\\Emilia\\.wdm\\drivers\\chromedriver\\81.0.4044.69\\win32\\chromedriver.exe'
Unpack archive C:\Users\Emilia\.wdm\drivers\chromedriver\81.0.4044.69\win32\chromedriver.zip

Wystarczy wtedy uruchomić ponownie komputer.
Jeśli ktoś woli tak jak ja używać Webdriver Managera, to wcześnieszy kod może zastąpić poniższym:

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

driver = webdriver.Chrome(ChromeDriverManager().install())

Do uruchomienia przeglądarki służy metoda get():

driver.get("adres strony")

Następnie możemy ustawić rozmiar strony (ale nie musimy):

driver.set_window_size(width, height) # określony rozmiar
driver.maximize_window() # maksymalny rozmiar

Rozmiar okna nie ma wpływu na wykonywanie akcji na elementach, ponieważ Selenium lokalizuje elementy według kodu strony.

Zamykanie strony:

driver.quit() #wszystkie okna zostaną zamknięte
driver.close()  #zamyka bieżące okno

Lokalizowanie elementów

Do zlokalizowania elementu na stronie służy metoda find_element_by_ i tutaj musisz wpisać selektor, za pomocą którego szukasz. Można szukać za pomocą atrybutów takich jak ‚name’, ‚id’, ‚class’; tagów czyli tag_name; selektorów css; XPatha; tekstu wewnątrz linku i tutaj mamy do wyboru link_text, gdzie trzeba wpisać cały tekst między znacznikami <a></a> albo partial_link,gdzie wystarczy tylko jakiś fragment.

Jest jeszcze analogiczna technika finds_element_by, która zwraca listę elementów o podanym selektorze.

Trochę akcji

O to kilka podstawowych czynności, które możemy wykonać na naszych elementach:

  • Kliknięcie na element – .click()
  • Wprowadzenie wartości do pola tekstowego – .send_keys(„tekst”)
  • Wyczyszczenie pola tekstowego – .clear()
  • Pobieranie tekstu z elementu – .text
  • Utworzenie screenshota – driver.save_screenshot(„nazwa”)
  • Symulowanie naciśnięcia klawisza – zaimportowanie Keys
from selenium.webdriver.common.keys import Keys
element.send_keys(Keys.Enter)

To pora zajrzeć w „bebechy” jakiejś strony. Wybrałam jedno z dem, które służą do nauki automatyzacji. Strona z przykładowym formularzem rejestracyjnym http://demo.automationtesting.in/Register.html:

Kiedy już wejdziemy na stronę, Aby szybko przejść do kodu szukanego elementu kliknij na niego prawym przyciskiem myszy oraz wybierz opcje „Zbadaj element”. Otworzą nam się ‚Narzędzia dla deweloperów’. Jest to bardzo przydatne narzędzie także dla testerów. W konsoli możesz w szybki sposób sprawdzić responsywność strony czy znaleźć kody odpowiedzi HTTP, które się pojawiły podczas ładowania strony.
Postaram się użyć różnych metod do znalezienia elementów. Jednak osobiście najczęściej używam XPatha. Tak w skrócie XPath to język ścieżek xml. Jeśli chciałbyś się go nauczyć, co naprawdę nie jest takie trudne! To polecam takie strony jak: https://topswagcode.com/xpath/ . Nauka w formie gry, nawet całkiem wciągające 🙂

Możesz też skorzystać ze ściągi na tej stronie: https://devhints.io/xpath. Opcją dla leniwych jest kopiowanie ścieżki z kodu strony. Jeśli masz już znaleziony fragment kodu szukanego elementu to wystarczy kliknąć prawym przyciskiem myszy, wybrać Copy> następnie którąś z opcji np. Copy XPath.

Spróbuj najpierw samemu zlokalizować elementy.
Tak wygląda cały mój kod:

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

#Otwieranie okna przeglądarki
driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get("http://demo.automationtesting.in/Register.html")

#Rozmiar okna
driver.maximize_window()

#Lokalizatory
input_first_name = driver.find_element_by_xpath("//input[@placeholder='First Name']")
input_last_name = driver.find_element_by_xpath("//input[@placeholder='Last Name']")
textarea_address = driver.find_element_by_tag_name("textarea")
input_email = driver.find_element_by_xpath("//input[@ng-model='EmailAdress']")
input_phone = driver.find_element_by_xpath("//input[@type='tel']")
radiobox_gender = driver.find_element_by_xpath("//input[@name='radiooptions' and @value='FeMale']")
checkbox_hobby = driver.find_element_by_id("checkbox2")
multiselect_language = driver.find_element_by_id("msdd") # wymaga wcześniejszego kliknięcia, zanim Selenium będzie mógł kliknąć w dany język
language = driver.find_element_by_xpath("//a[contains(text(),'Polish')]")
select_skills = driver.find_element_by_xpath("//select[@id='Skills']/option[@value='Python']")
select_country = driver.find_element_by_xpath("//select[@id='countries']/option[@value='Poland']")
select_country2 = driver.find_element_by_xpath("//select[@id='country']/option[@value='United States of America']")
select_birth_year = driver.find_element_by_xpath("//select[@id='yearbox']/option[@value='1995']")
select_birth_month = driver.find_element_by_xpath("//select[@ng-model='monthbox']/option[@value='January']")
select_birth_day = driver.find_element_by_xpath("//select[@id='daybox']/option[@value='15']")
input_pwd = driver.find_element_by_xpath("//input[@id='firstpassword']")
input_confirm_pwd = driver.find_element_by_xpath("//input[@id='secondpassword']")
upload_photo = driver.find_element_by_id('imagesrc')
button_submit = driver.find_element_by_id('submitbtn')

#Akcje
input_first_name.send_keys('Emilia')
input_last_name.send_keys('Jagła')
textarea_address.send_keys('Jakiś adres')
input_email.send_keys('mail@mail.pl')
input_phone.send_keys('9999999999') #Zauważ, że w kodzie html jest podane pattern="^\d{10}$" , to znaczy, że pole musi zawierać 10 cyfr
radiobox_gender.click()
checkbox_hobby.click()
multiselect_language.click()
language.click()
select_skills.click()
select_country.click()
select_country2.click()
select_birth_year.click()
select_birth_month.click()
select_birth_day.click()
input_pwd.send_keys('Sekretnehaslo1')
input_confirm_pwd.send_keys('Sekretnehaslo1')
upload_photo.send_keys(r"C:\Users\Emilia\PycharmProjects\SeleniumProject\nic.txt") # trzeba podać absolutną ścieżkę pliku
button_submit.click()
driver.save_screenshot("screenshot1.png")

W swoim folderze powinieneś mieć teraz taki plik png:

Wszystkie lokalizatory przypisałam do zmiennych. Jednak nie musisz tego robić, jeśli nie chcesz. Zadziała też samo driver.find_element_by_xpath("//input[@placeholder='First Name']").send_keys("jakiś tekst") itd. dla innych elementów . Nie mniej musisz wiedzieć, że podczas automatyzacji testów stosuje się często Page Object Model, który w skrócie polega na tym, że cały kod pakujesz do klas i osobnych plików. W osobnej klasie powinny być lokalizatory, które następnie importuje się do danego testu. Na przykład jeśli testujesz wyszukiwarkę jakiegoś sklepu internetowego, to robisz osobno klasę na stronę, gdzie lokalizowałeś input do wpisania wyszukiwanego przedmiotu i osobno na wyniki wyszukiwań. Jedna strona = jeden obiekt. Przechowywanie lokalizatorów w osobnym pliku pomaga później przy konserwacji testów. Jak się coś zmienia na stronie, to trzeba często zmienić także lokalizator.

Błędy

Niestety życie nie jest proste i podczas pracy z Selenium często występują błedy, np.
selenium.common.exceptions.ElementNotInteractableException albo
selenium.common.exceptions.NoSuchElementException:

Najczęstszą przyczyną jest źle zlokalizowany element albo Selenium znalazł, więcej niż jeden element o podanej lokalizacji. Można to sprawdzić za pomocą funkcji len(). Na przykład: print(len(driver.find_elements_by_xpath(lokalizator))
Jeśli wcześniej wyszukiwało jakiś element, a potem nagle wyskoczył błąd, może to oznaczać, że jakiś element nie zdążył się załadować. Można wtedy rozważyć użycie metody implicitly_wait(czas w sekundach) albo po prostu time.sleep z modułu time. A gdy nic nie pomaga, a jesteśmy pewni, że lokalizator jest dobry, to można użyć print(driver.page_source) i wtedy zobaczymy, jaki kod widzi Selenium. Może się okazać, że Selenium po prostu nie widzi szukanego elementu.

Podsumowanie

Używanie Selenium nie wymaga jakichś nadzwyczajnych umiejętności programowania. Wystarczy podstawowa znajomość HTML i Pythona. To co przedstawiłam, jest dopiero wstępem do Selenium. Jeśli ktoś myśli o pracy jako tester automatyczny to warto poczytać Page Object Model (jeśli wciąż masz problemy z programowaniem obiektowym to zajrzyj koniecznie tutaj). Warto też poczytać o pytest, asercjach, dekoratorach.