Użycie Docker Selenium w pipeline

Powrót do przeszłości

W poprzedniej lekcji dowiedziałeś się jak może wyglądać przykładowy pipeline w Jenkinsie. Jest to jedna z najprostszych możliwych implementacji. Czas na jego rozbudowę.

Aktualnie pipeline wygląda następująco:

pipeline {
    agent any
    stages {
        stage('Build test code') {
            steps {
                sh 'mvn clean install -DskipTests'
            }
        }
        stage('Execute test') {
            steps {
                sh 'mvn test'
            }
        }
        stage('Generate allure report') {
            steps {
                script {
                    allure([
                            includeProperties: false,
                            jdk              : '',
                            properties       : [],
                            reportBuildPolicy: 'ALWAYS',
                            results          : [[path: 'target/allure-results']]
                    ])
                }
            }
        }
    }
}

Analizując pipeline oraz framework, który go obsługuje widzimy, że ma on pewne wady. Do których należą:

  • Testy możemy uruchomić tylko w sposób taki jak zostało to przewidziane w kodzie. Konfiguracja jest zahardkodowana,
  • Do poprawnego uruchomienia i wykonania testów potrzebujemy zewnętrznego Selenium GRIDa,
  • Framework, który go obsługuje wymaga zewnętrznego Selenium GRID lub uruchomienia go w trybie lokalny driverów. Tryb lokalnych driverów powinien służyć tylko i wyłącznie do lokalnego developmentu testów, nie zaś do uruchamiania ich w ramach ciągłej integracji.
  • Raport Allure nie zostanie wygenerowany, jeśli stage „Execute test" nie zostanie wykonany.

Te i wiele innych problemów możemy wymieniać w nieskończoność. Czas zabrać się za jeden z nich jakim jest brak Selenium GRIDa w ramach pipelinu.

Problem zewnętrznego Selenium GRIDa.

Dla bieżącej implementacji uruchomienie testów na Selenium GRID wymaga infrastruktury jak na obrazku poniżej:

selenium grid

Jest to klasyczne podejście w którym mamy:

  • Jenkins -- Serwer CI (Continues Integration) -- który jest osobną maszyną odpowiadającą za hostowanie Jenkinsa tzw. Jenkins Master,
  • Jenkins Agent -- maszyna na której uruchamiany jest kod testów tzw. Jenkins Slave,
  • Selenium Hub -- maszyna z zainstalowanym Selenium Hub
  • Selenium Node -- kolejne maszyny z odpowiednimi przeglądarkami i Selenium GRID w trybie Node.

Takie klasyczne podejście ma szereg problemów, do których możemy zaliczyć:

  • Wiele elementów infrastruktury, które potencjalnie mogą zawieść,
  • Brak kontroli nad infrastrukturą,
  • Ograniczone zasoby,
  • Duży koszt (duża liczba maszyn).

Rozwiązaniem części z powyższych problemów jest Docker Selenium.

Dzięki zastosowaniu dokeryzacji Selenium GRIDa przenosimy wykonanie testów, oraz infrastrukturę Selenium GRIDa z zewnętrznej maszyny, nad którą nie mamy kontroli na agenta Jenkinsowego.

Przejdźmy w takim razie do implementacji.

Docker Selenium

Zanim zaczniemy, mała dygresja. Jeśli nie wiesz czym jest Docker Selenium w ramach kursu dostępny jest artykuł wprowadzający w zagadnienie. Możesz też zapoznać się z dokumentacją twórców.

Czas na jego przykładowe zastosowanie. W naszym przykładzie użyjemy najprostszego możliwego docker-compose.yml, który będzie agregował nam Selenium Hub oraz dwa nody z przeglądarkami Chrome oraz Firefox.

I tak mamy docker-compose.yml:

version: "3"
services:
  selenium-hub:
    image: selenium/hub:3.141.59-yttrium
    container_name: selenium-hub
    ports:
      - "4444:4444"
  chrome:
    image: selenium/node-chrome:3.141.59-yttrium
    volumes:
      - /dev/shm:/dev/shm
    depends_on:
      - selenium-hub
    environment:
      - HUB_HOST=selenium-hub
      - HUB_PORT=4444
  firefox:
    image: selenium/node-firefox:3.141.59-yttrium
    volumes:
      - /dev/shm:/dev/shm
    depends_on:
      - selenium-hub
    environment:
      - HUB_HOST=selenium-hub
      - HUB_PORT=4444

Plik docker-compose.yml umieszczamy w głównym katalogu repozytorium.

docker compose

Kolejnym krokiem będzie zmiana w ramach pliku configuration.propertiesna następujące wartości:

is.remote.run=true
grid.url=http://localhost:4444/wd/hub

Wartość localhostbieżę się stąd, że Selenium GRID będzie się znajdować na tej samej maszynie co testy, w ramach kontenera dockerowego.

Mając gotowy docker-compose.yml możemy przejść do modyfikacji Jenkinsfile . Dzieki zastosowaniu podejścia infrastructure as a code wszystko znajduję się w repozytorium. Nie musimy modyfikować pipelinu utworzonego w ramach lekcji.

Dla przypomnienia aby uruchomić kontenery zdefiniowane w docker-compose.yml wywołujemy komendę:

docker-compose up -d

W celu ich wyłączenia kontenerów:

docker-compose down

Przechodząc do implementacji Jenkinsfilemamy:

pipeline {
    agent any
    stages {
        stage('Build test code') {
            steps {
                sh 'mvn clean install -DskipTests' // Budowanie testów
            }
        }
        stage('Run selenium grid') {
            steps {
                sh 'docker-compose up -d' // Uruchiomienie Docker Selenium
            }
        }
        stage('Execute test') {
            steps {
                sh 'mvn test' // Uruchomienie testów
                sh 'docker-compose down' // Wyłączenie Docker Selenium, wyłączenie kontenerów
            }
        }
    }
    post {
        always {
            script { // Wygenerowanie raportu Allurowego
                allure([
                        includeProperties: false,
                        jdk              : '',
                        properties       : [],
                        reportBuildPolicy: 'ALWAYS',
                        results          : [[path: 'target/allure-results']]
                ])
            }
        }
    }
}

Dodatkowo w porównaniu do poprzedniego pipelina, przenieśliśmy skrypt odpowiadający za generowanie raportu Allurowego do sekcji post . Sekcja post jest to sekcja, która wykona się zawsze po przejściu całego planu, niezależnie od wyniku.

Kurs Selenium

Uwaga: Do poprawnego uruchomienia powyższego pipelinu na maszynie agenta powinien być zainstalowany docker!

Jeśli teraz uruchomimy zmodyfikowany pipeline, zobaczymy:

[Pipeline] }
[Pipeline] // stage
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Build test code)
[Pipeline] sh
+ mvn clean install -DskipTests
[INFO] Scanning for projects...
[INFO] 
[INFO] ----------------< pl.javastart.courses:selenium-intro >-----------------
[INFO] Building selenium-intro 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ selenium-intro ---
[INFO] Deleting D:\Program Files (x86)\Jenkins\workspace\Test\target
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ selenium-intro ---
[WARNING] Using platform encoding (Cp1250 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 3 resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.7.0:compile (default-compile) @ selenium-intro ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ selenium-intro ---
[WARNING] Using platform encoding (Cp1250 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.7.0:testCompile (default-testCompile) @ selenium-intro ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 26 source files to D:\Program Files (x86)\Jenkins\workspace\Test\target\test-classes
[INFO] 
[INFO] --- maven-surefire-plugin:2.21.0:test (default-test) @ selenium-intro ---
[INFO] Tests are skipped.
[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ selenium-intro ---
[INFO] Building jar: D:\Program Files (x86)\Jenkins\workspace\Test\target\selenium-intro-1.0-SNAPSHOT.jar
[INFO] 
[INFO] --- maven-install-plugin:2.4:install (default-install) @ selenium-intro ---
[INFO] Installing D:\Program Files (x86)\Jenkins\workspace\Test\target\selenium-intro-1.0-SNAPSHOT.jar to C:\Windows\system32\config\systemprofile\.m2\repository\pl\javastart\courses\selenium-intro\1.0-SNAPSHOT\selenium-intro-1.0-SNAPSHOT.jar
[INFO] Installing D:\Program Files (x86)\Jenkins\workspace\Test\pom.xml to C:\Windows\system32\config\systemprofile\.m2\repository\pl\javastart\courses\selenium-intro\1.0-SNAPSHOT\selenium-intro-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.722 s
[INFO] Finished at: 2020-01-12T10:11:24+01:00
[INFO] ------------------------------------------------------------------------
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Run selenium grid)
[Pipeline] sh
+ docker-compose up -d
Creating network "test_default" with the default driver
Pulling selenium-hub (selenium/hub:3.141.59-yttrium)...
3.141.59-yttrium: Pulling from selenium/hub
Digest: sha256:6f6bdd8d5ce5cd8d7be42ded88bc3dbbdf7a60ec32c908eb26dd31b37f69589a
Status: Downloaded newer image for selenium/hub:3.141.59-yttrium
Pulling chrome (selenium/node-chrome:3.141.59-yttrium)...
3.141.59-yttrium: Pulling from selenium/node-chrome
Digest: sha256:5e37ffdeae0864dd7f0df63adafcc9428766d79976a645853bc1e20d7487ff4f
Status: Downloaded newer image for selenium/node-chrome:3.141.59-yttrium
Pulling firefox (selenium/node-firefox:3.141.59-yttrium)...
3.141.59-yttrium: Pulling from selenium/node-firefox
Digest: sha256:3a92810aca49182944c72e15c68dd8561731f25e723983d8702a9234d32163d6
Status: Downloaded newer image for selenium/node-firefox:3.141.59-yttrium
Creating selenium-hub ... 

 [1A [2K
Creating selenium-hub ...  [32mdone [0m
 [1BCreating test_firefox_1 ... 

Creating test_chrome_1  ... 

 [2A [2K
Creating test_firefox_1 ...  [32mdone [0m
 [2B [1A [2K
Creating test_chrome_1  ...  [32mdone [0m
 [1B
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Execute test)
[Pipeline] sh
+ mvn test
[INFO] Scanning for projects...
[INFO] 
[INFO] ----------------< pl.javastart.courses:selenium-intro >-----------------
[INFO] Building selenium-intro 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ selenium-intro ---
[WARNING] Using platform encoding (Cp1250 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 3 resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.7.0:compile (default-compile) @ selenium-intro ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ selenium-intro ---
[WARNING] Using platform encoding (Cp1250 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.7.0:testCompile (default-testCompile) @ selenium-intro ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-surefire-plugin:2.21.0:test (default-test) @ selenium-intro ---
[INFO] 
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running TestSuite
[INFO ] 2020-01-12 10:12:34.795 [TestNG-tests-2] configuration.PropertiesLoader - Trying to load properties with file name: configuration.properties
[INFO ] 2020-01-12 10:12:34.795 [TestNG-tests-1] configuration.PropertiesLoader - Trying to load properties with file name: configuration.properties
[INFO ] 2020-01-12 10:12:34.803 [TestNG-tests-2] configuration.PropertiesLoader - Successfully loaded properties for file: configuration.properties
[INFO ] 2020-01-12 10:12:34.803 [TestNG-tests-1] configuration.PropertiesLoader - Successfully loaded properties for file: configuration.properties
sty 12, 2020 10:12:35 AM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: W3C
[INFO ] 2020-01-12 10:12:35.982 [TestNG-tests-2] driver.listeners.DriverEventListener - Trying to navigate to http://przyklady.javastart.pl/jpetstore/
[INFO ] 2020-01-12 10:12:36.114 [TestNG-tests-2] driver.listeners.DriverEventListener - Navigated to http://przyklady.javastart.pl/jpetstore/
[INFO ] 2020-01-12 10:12:36.209 [TestNG-tests-2] utils.testng.listeners.TestListener - Starting test: asUserLoginUsingValidLoginAndPassword
[INFO ] 2020-01-12 10:12:36.234 [TestNG-tests-2] driver.listeners.DriverEventListener - Trying to navigate to http://przyklady.javastart.pl/jpetstore/actions/Account.action?signonForm=
[INFO ] 2020-01-12 10:12:36.376 [TestNG-tests-2] driver.listeners.DriverEventListener - Navigated to http://przyklady.javastart.pl/jpetstore/actions/Account.action?signonForm=
[INFO ] 2020-01-12 10:12:36.407 [TestNG-tests-2] driver.listeners.DriverEventListener - Trying to find element with locator By.name: username
[INFO ] 2020-01-12 10:12:36.429 [TestNG-tests-2] driver.listeners.DriverEventListener - Found element with locator By.name: username
[INFO ] 2020-01-12 10:12:36.484 [TestNG-tests-2] driver.listeners.DriverEventListener - Trying to find element with locator By.name: username
[INFO ] 2020-01-12 10:12:36.500 [TestNG-tests-2] driver.listeners.DriverEventListener - Found element with locator By.name: username
[INFO ] 2020-01-12 10:12:36.514 [TestNG-tests-2] driver.listeners.DriverEventListener - Trying to type into element: input text [j2ee]
[INFO ] 2020-01-12 10:12:36.586 [TestNG-tests-2] driver.listeners.DriverEventListener - Typed into element: input text [j2ee]
[INFO ] 2020-01-12 10:12:36.588 [TestNG-tests-2] page.objects.LoginPage - Typed into User Name Field j2ee
[INFO ] 2020-01-12 10:12:36.588 [TestNG-tests-2] driver.listeners.DriverEventListener - Trying to find element with locator By.name: password
[INFO ] 2020-01-12 10:12:36.611 [TestNG-tests-2] driver.listeners.DriverEventListener - Found element with locator By.name: password
[INFO ] 2020-01-12 10:12:36.621 [TestNG-tests-2] driver.listeners.DriverEventListener - Trying to enter empty string or clear element: input
[INFO ] 2020-01-12 10:12:36.663 [TestNG-tests-2] driver.listeners.DriverEventListener - Entered empty string or cleared element: input
[INFO ] 2020-01-12 10:12:36.664 [TestNG-tests-2] driver.listeners.DriverEventListener - Trying to find element with locator By.name: password
[INFO ] 2020-01-12 10:12:36.681 [TestNG-tests-2] driver.listeners.DriverEventListener - Found element with locator By.name: password
[INFO ] 2020-01-12 10:12:36.695 [TestNG-tests-2] driver.listeners.DriverEventListener - Trying to type into element: input text [j2ee]
[INFO ] 2020-01-12 10:12:36.788 [TestNG-tests-2] driver.listeners.DriverEventListener - Typed into element: input text [j2ee]
[INFO ] 2020-01-12 10:12:36.788 [TestNG-tests-2] page.objects.LoginPage - Typed into Password Field j2ee
[INFO ] 2020-01-12 10:12:36.788 [TestNG-tests-2] driver.listeners.DriverEventListener - Trying to find element with locator By.name: signon
[INFO ] 2020-01-12 10:12:36.822 [TestNG-tests-2] driver.listeners.DriverEventListener - Found element with locator By.name: signon
[INFO ] 2020-01-12 10:12:36.838 [TestNG-tests-2] driver.listeners.DriverEventListener - Trying to click on element with tag name: input
[INFO ] 2020-01-12 10:12:37.026 [TestNG-tests-2] driver.listeners.DriverEventListener - Clicked on element
[INFO ] 2020-01-12 10:12:37.026 [TestNG-tests-2] page.objects.LoginPage - Clicked on Login Button
[INFO ] 2020-01-12 10:12:37.027 [TestNG-tests-2] page.objects.FooterPage - Checking if dog banner is displayed
[INFO ] 2020-01-12 10:12:37.027 [TestNG-tests-2] driver.listeners.DriverEventListener - Trying to find element with locator By.cssSelector: #Banner img[src*='dog']
[INFO ] 2020-01-12 10:12:37.052 [TestNG-tests-2] driver.listeners.DriverEventListener - Found element with locator By.cssSelector: #Banner img[src*='dog']
[INFO ] 2020-01-12 10:12:37.119 [TestNG-tests-2] generic.assertions.AssertWebElement - Checking if element is displayed
[INFO ] 2020-01-12 10:12:37.119 [TestNG-tests-2] driver.listeners.DriverEventListener - Trying to find element with locator By.cssSelector: #Banner img[src*='dog']
[INFO ] 2020-01-12 10:12:37.150 [TestNG-tests-2] driver.listeners.DriverEventListener - Found element with locator By.cssSelector: #Banner img[src*='dog']
[INFO ] 2020-01-12 10:12:37.172 [TestNG-tests-2] generic.assertions.AssertWebElement - WebElement was displayed!
[INFO ] 2020-01-12 10:12:37.174 [TestNG-tests-2] utils.testng.listeners.TestListener - Test asUserLoginUsingValidLoginAndPassword passed successfully
sty 12, 2020 10:12:37 AM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: W3C
[INFO ] 2020-01-12 10:12:37.410 [TestNG-tests-1] driver.listeners.DriverEventListener - Trying to navigate to http://przyklady.javastart.pl/jpetstore/
[INFO ] 2020-01-12 10:12:37.557 [TestNG-tests-1] driver.listeners.DriverEventListener - Navigated to http://przyklady.javastart.pl/jpetstore/
[INFO ] 2020-01-12 10:12:37.561 [TestNG-tests-1] utils.testng.listeners.TestListener - Starting test: asUserTryToLogInWithIncorrectLoginAndPassword
[INFO ] 2020-01-12 10:12:37.564 [TestNG-tests-1] driver.listeners.DriverEventListener - Trying to navigate to http://przyklady.javastart.pl/jpetstore/actions/Account.action?signonForm=
[INFO ] 2020-01-12 10:12:37.734 [TestNG-tests-1] driver.listeners.DriverEventListener - Navigated to http://przyklady.javastart.pl/jpetstore/actions/Account.action?signonForm=
[INFO ] 2020-01-12 10:12:37.734 [TestNG-tests-1] driver.listeners.DriverEventListener - Trying to find element with locator By.name: username
[INFO ] 2020-01-12 10:12:37.750 [TestNG-tests-1] driver.listeners.DriverEventListener - Found element with locator By.name: username
[INFO ] 2020-01-12 10:12:37.780 [TestNG-tests-1] driver.listeners.DriverEventListener - Trying to find element with locator By.name: username
[INFO ] 2020-01-12 10:12:37.793 [TestNG-tests-1] driver.listeners.DriverEventListener - Found element with locator By.name: username
[INFO ] 2020-01-12 10:12:37.802 [TestNG-tests-1] driver.listeners.DriverEventListener - Trying to type into element: input text [NotExistingLogin]
[INFO ] 2020-01-12 10:12:37.832 [TestNG-tests-1] driver.listeners.DriverEventListener - Typed into element: input text [NotExistingLogin]
[INFO ] 2020-01-12 10:12:37.832 [TestNG-tests-1] page.objects.LoginPage - Typed into User Name Field NotExistingLogin
[INFO ] 2020-01-12 10:12:37.832 [TestNG-tests-1] driver.listeners.DriverEventListener - Trying to find element with locator By.name: password
[INFO ] 2020-01-12 10:12:37.846 [TestNG-tests-1] driver.listeners.DriverEventListener - Found element with locator By.name: password
[INFO ] 2020-01-12 10:12:37.853 [TestNG-tests-1] driver.listeners.DriverEventListener - Trying to enter empty string or clear element: input
[INFO ] 2020-01-12 10:12:37.885 [TestNG-tests-1] driver.listeners.DriverEventListener - Entered empty string or cleared element: input
[INFO ] 2020-01-12 10:12:37.885 [TestNG-tests-1] driver.listeners.DriverEventListener - Trying to find element with locator By.name: password
[INFO ] 2020-01-12 10:12:37.897 [TestNG-tests-1] driver.listeners.DriverEventListener - Found element with locator By.name: password
[INFO ] 2020-01-12 10:12:37.904 [TestNG-tests-1] driver.listeners.DriverEventListener - Trying to type into element: input text [NotProperPassword]
[INFO ] 2020-01-12 10:12:37.936 [TestNG-tests-1] driver.listeners.DriverEventListener - Typed into element: input text [NotProperPassword]
[INFO ] 2020-01-12 10:12:37.936 [TestNG-tests-1] page.objects.LoginPage - Typed into Password Field NotProperPassword
[INFO ] 2020-01-12 10:12:37.936 [TestNG-tests-1] driver.listeners.DriverEventListener - Trying to find element with locator By.name: signon
[INFO ] 2020-01-12 10:12:37.949 [TestNG-tests-1] driver.listeners.DriverEventListener - Found element with locator By.name: signon
[INFO ] 2020-01-12 10:12:37.955 [TestNG-tests-1] driver.listeners.DriverEventListener - Trying to click on element with tag name: input
[INFO ] 2020-01-12 10:12:38.028 [TestNG-tests-1] driver.listeners.DriverEventListener - Clicked on element
[INFO ] 2020-01-12 10:12:38.028 [TestNG-tests-1] page.objects.LoginPage - Clicked on Login Button
[INFO ] 2020-01-12 10:12:38.028 [TestNG-tests-1] page.objects.LoginPage - Checking if warning message Invalid username or password. Signon failed. is displayed
[INFO ] 2020-01-12 10:12:38.029 [TestNG-tests-1] driver.listeners.DriverEventListener - Trying to find element with locator By.cssSelector: #Content ul[class='messages'] li
[INFO ] 2020-01-12 10:12:38.040 [TestNG-tests-1] driver.listeners.DriverEventListener - Found element with locator By.cssSelector: #Content ul[class='messages'] li
[INFO ] 2020-01-12 10:12:38.075 [TestNG-tests-1] generic.assertions.AssertWebElement - Checking if element is displayed
[INFO ] 2020-01-12 10:12:38.075 [TestNG-tests-1] driver.listeners.DriverEventListener - Trying to find element with locator By.cssSelector: #Content ul[class='messages'] li
[INFO ] 2020-01-12 10:12:38.087 [TestNG-tests-1] driver.listeners.DriverEventListener - Found element with locator By.cssSelector: #Content ul[class='messages'] li
[INFO ] 2020-01-12 10:12:38.110 [TestNG-tests-1] generic.assertions.AssertWebElement - WebElement was displayed!
[INFO ] 2020-01-12 10:12:38.110 [TestNG-tests-1] generic.assertions.AssertWebElement - Checking if WebElement has text: Invalid username or password. Signon failed.
[INFO ] 2020-01-12 10:12:38.110 [TestNG-tests-1] driver.listeners.DriverEventListener - Trying to find element with locator By.cssSelector: #Content ul[class='messages'] li
[INFO ] 2020-01-12 10:12:38.120 [TestNG-tests-1] driver.listeners.DriverEventListener - Found element with locator By.cssSelector: #Content ul[class='messages'] li
[INFO ] 2020-01-12 10:12:38.120 [TestNG-tests-1] driver.listeners.DriverEventListener - Trying to get text for WebElement
[INFO ] 2020-01-12 10:12:38.131 [TestNG-tests-1] driver.listeners.DriverEventListener - Taken text of WebElement. Text wast Invalid username or password. Signon failed.
[INFO ] 2020-01-12 10:12:38.132 [TestNG-tests-1] generic.assertions.AssertWebElement - WebElement had expected text!
[INFO ] 2020-01-12 10:12:38.132 [TestNG-tests-1] utils.testng.listeners.TestListener - Test asUserTryToLogInWithIncorrectLoginAndPassword passed successfully
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.339 s - in TestSuite
[INFO] 
[INFO] Results:
[INFO] 
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  7.196 s
[INFO] Finished at: 2020-01-12T10:12:39+01:00
[INFO] ------------------------------------------------------------------------
[Pipeline] sh
+ docker-compose down
Stopping test_firefox_1 ... 

Stopping test_chrome_1  ... 

Stopping selenium-hub   ... 

 [3B [1A [2K
Stopping selenium-hub   ...  [32mdone [0m
 [1BRemoving test_firefox_1 ... 

Removing test_chrome_1  ... 

Removing selenium-hub   ... 

 [1A [2K
Removing selenium-hub   ...  [32mdone [0m
 [1B [3A [2K
Removing test_firefox_1 ...  [32mdone [0m
 [3B [2A [2K
Removing test_chrome_1  ...  [32mdone [0m
 [2BRemoving network test_default
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Declarative: Post Actions)
[Pipeline] script
[Pipeline] {
[Pipeline] allure
[Test] $ "D:\Program Files (x86)\Jenkins\tools\ru.yandex.qatools.allure.jenkins.tools.AllureCommandlineInstallation\allure\bin\allure.bat" generate "D:\Program Files (x86)\Jenkins\workspace\Test\target\allure-results" -c -o "D:\Program Files (x86)\Jenkins\workspace\Test\allure-report"
Report successfully generated to D:\Program Files (x86)\Jenkins\workspace\Test\allure-report
Allure report was successfully generated.
Creating artifact for the build.
Artifact was added to the build.
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

Podsumowanie

Dzięki zastosowaniu Docker Selenium mamy możliwość:

  • Łatwego skalowania ilością Nodów Selenium i ich konfiguracją w ramach docker-compose.yml
  • Pełną kontrolą na infrastrukturą Selenium GRID,
  • Wykonanie na jednej maszynie, co zmniejsza koszt, zwiększa stabilność, ułatwia debugowanie.

Potrzebujesz więcej informacji?

Artykuł powstał na bazie kursu Automatyzacja testów z wykorzystaniem Selenium.

O Autorze

Nazywam się Mateusz Ciołek i od 2011 roku zajmuję się testowaniem oprogramowania ze specjalizacją w automatyzacji testów.

Dyskusja i komentarze

Masz pytania do tego wpisu? Może chcesz się podzielić spostrzeżeniami? Zapraszamy dyskusji na naszej grupie na Facebooku.