Selenium 39. Zadanie: czekanie na warunki

Czas przećwiczyć to, co przerobiliśmy wspólnie w kilku ostatnich filmach. Przed Tobą zadanie, w którym użyjesz klasy WebDriverWait.

Na początku filmu tłumaczę polecenie, a następnie rozwiązanie. Będzie moment żeby zatrzymać film na czas wykonania zadania – dam znać w filmie kiedy.

Podpowiedź

Najlepiej jeżeli od początku ustawisz wielkość okna przeglądarki na 1295×760 za pomocą poniższej metody umieszczonej w setupie testu (metodzie z adnotacją @BeforeEach):

driver.manage().window().setSize(new Dimension(1295, 760));

Przy innych wielkościach test może zachowywać się trochę inaczej. Po więcej szczegółów sprawdź sekcję komentarzy pod tą lekcją.

Polecenie do zadania

Ukryta treść

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

Rozwiązanie

Lepiej nie podglądać przed rozwiązaniem zadania ⚠️

Ukryta treść

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

Wsparcie merytoryczne

Nie masz aktywnego członkostwa. Wykup dostęp albo Zaloguj się, by móc zadawać pytania.

  1. Hej 🙂
    Gdy próbuję odpalić test usuwania dodanego kuponu, to często rzuca mi na przemian błędami, że albo button do usuwania kuponu nie jest klikalny, albo że właśnie liczba elementów div.blockUI nie jest większa od 0.
    Jak obsłużyć sytuację, w której elementy div.blockUI pojawią się i znikną jeszcze zanim nasz test zacznie je zliczać? Bo mam wrażenie, że to szybkość działania testu albo łącza internetowego może być przyczyną tego problemu. Ale może jednak coś innego, na co jeszcze nie wpadłem 😛
    Wydaje mi się, że mam identyczną składnię kodu jak ta przedstawiona w filmie, nie znalazłem żadnych różnic.

    Odpowiedz
      • Cześć, ja mam właśnie taki problem, tj. rzuca mi ElementClickInterceptedException przy czekaniu na elementToBeClickable ;D. Ale nie zawsze, generalnie mam problem z ogarnięciem stabilności tych testów. Często też wywala się waitForProcessingEnd, bo nie może doczekać się aż liczba elementów .processing będzie > 0, tak jakby ładowanie kończyło się jeszcze zanim selenium policzy je poraz pierwszy.
        (skopiowałem Twój kod)

        Odpowiedz
  2. Hej 🙂 Dzięki za kod, myślę że to dobry pomysł, byśmy mogli mieć do niego wgląd, w razie potrzeby 🙂 Udało mi się chyba znaleźć przyczynę błędów. W filmiku poradziłaś, żeby wysokość okna była większa od 760, ale wydaje mi się, że dokładniej rzecz biorąc, kluczem jest zachowanie odpowiedniej proporcji między wysokością a szerokością okna. Bo w moim przypadku, testy przy rozmiarach okna 1295x760 i 1295x800 działały prawidłowo, ale już przy ustawieniu 1295x900 albo 1295x960 test na usuwanie kuponu się wysypywał 🙂

    Odpowiedz
  3. Hej! W sprawie tego podwójnego wpisywania kuponu i czekania aż 'kręciołek' zniknie.
    Tobie wyskoczył komunikat błędu z elementem i klasą, które mogłaś wykorzystać, ale mi cały czas wyskakuje komunikat: stale element reference: element is not attached to the page document , z którego nic wyciągnąć się nie da. Co w takiej sytuacji?

    Odpowiedz
  4. Hej, mam podobny kłopot do tego który ma Magdalena, lecz u mnie pojawia się on wcześniej - w odniesieniu do pola tekstowego do wpisania kuponu. Na zmianę (nie wiem dlaczego) rzuca mi następującymi wyjątkami:

    1) org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document, albo
    2) org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"input[name='coupon_code']"} (Session info: chrome=83.0.4103.61)

    Mój kod:

    package DriverMethods;
    import org.junit.jupiter.api.AfterEach;
    import org.junit.jupiter.api.Assertions;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    import org.openqa.selenium.*;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.support.ui.ExpectedConditions;
    import org.openqa.selenium.support.ui.WebDriverWait;
    import java.util.concurrent.TimeUnit; 
    
    public class WaitsExcercise {
        WebDriver driver;
        WebDriverWait wait; 
    
        By cookieConsentBar = By.cssSelector("a[class*='dismiss-link']");
        By windSurfingGroup = By.cssSelector("a[href*='windsurfing']");
        By productEgipt = By.xpath(".//h2[text()='Egipt – El Gouna']");
        By addToCartButton = By.cssSelector("button[name='add-to-cart']");
        By goToCartButton = By.cssSelector("a.cart-contents");
        By addCoupon = By.cssSelector("button[name='apply_coupon']");
        String validCoupon = "10procent";
        String invalidCoupon = "invalidCoupon"; 
    
        @BeforeEach
        public void driverSetup() {
            System.setProperty("webdriver.chrome.driver", "src/main/resources/chromedriver.exe");
            driver = new ChromeDriver();
            driver.manage().window().setSize(new Dimension(1295, 760));
            driver.manage().window().setPosition(new Point(10, 40));
            driver.manage().timeouts().pageLoadTimeout(50, TimeUnit.SECONDS);
            driver.navigate().to("https://fakestore.testelka.pl/"); 
    
            wait = new WebDriverWait(driver, 10); 
    
            driver.findElement(cookieConsentBar).click();
            driver.findElement(windSurfingGroup).click();
            driver.findElement(productEgipt).click();
            driver.findElement(addToCartButton).click();
            driver.findElement(goToCartButton).click();
        }
    
        @AfterEach
        public void driverQuit() {
            driver.close();
            driver.quit();
        } 
    
        @Test
        public void validCouponTest() {
            applyCoupon(validCoupon);
        }
    
        private void applyCoupon(String coupon) {
            By couponCodeField = By.cssSelector("input[name='coupon_code']");
            By applyCouponButton = By.cssSelector("button[name='apply_coupon']");
            driver.findElement(couponCodeField).sendKeys(coupon);
            driver.findElement(applyCouponButton).click();
        }
    }
    

    Natomiast gdy odpalam ten sam kod w debug'u krok po kroku, wtedy poprawnie znajduje couponCodeField i działa.
    Próbowałem skorzystać z Twojej rady by wrzucić to w pętle i po wykonaniu kodu wciąż rzuca którymś z wyjątków (w przypadku unable to locate element wrzucałem mu wtedy w pętli catch (NoSuchElementException e)).

    Poniżej screen ukazujący jak to wygląda w debug'u:
    https://snipboard.io/ExvDL7.jpg
    Na chwilę udało mi się to zmitygować wrzucając do metody applyCoupon thread.sleep, ale po paru godzinach przestało działać i jestem w punkcie wyjścia, dalej rzuca tymi samymi wyjątkami.

    Wszystkie opisane powyżej sytuacje również powtarzają się gdy odpalam Twój kod.

    Mam jeszcze 2 pytania:

    1) W odpowiedzi do komentarza Magdy napisałaś w odniesieniu do org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document, że trzeba wyciągnąć z konsoli informacje o elemencie którego to dotyczy. Czy masz na myśli przeszukanie internal calls, jak na screenie poniżej? Jeżeli tak, tu tej informacji nie ma :(. Przyczynę ustaliłem dopiero gdy odpalałem kod w debug'u krok po kroku i obserwowałem działanie chrome'a. Później dopiero IntelliJ zaczął rzucać wyjątkiem NoSuchElementException gdzie już wskazany jest css, który według niego nie mógł zostać znaleziony.

    2) Gdy uruchomię kod w debug'u tak jak na screenie pierwszym, wtedy tylko za pierwszym razem kod wykonywany jest krok po kroku tak jak bym chciał. Każdym następnym razem jak odpale debug validCouponTest() wówczas cały kod wykonuje się tak jakbym zrobił run test. Co robię źle?

    Odpowiedz
  5. Hej, w @BeforeEach "wait = new WebDriverWait(driver, 10);" Intellij pokazuje jako "Depracated".
    Czy możemy zastosować coś innego w tym miejcu żeby kod z zadania zadziałał?

    Odpowiedz
  6. Hej!
    Kiedy odpalam test z nieprawidłowym kuponem, test nie przechodzi i wyskakuje taki błąd:

    "org.openqa.selenium.TimeoutException: Expected condition failed: waiting for visibility of element located by By.cssSelector: div[role='alert'] (tried for 15 second(s) with 500 milliseconds interval".

    Co ciekawe, test z prawidłowym kuponem przechodzi normalnie. Mimo wszystko próbowałam wydłużyć czas oczekiwania, ale bezskutecznie. Na podglądzie, wszystko wydaje się działać dobrze, wpisuje błędny kupon, potwierdza, wyskakuje informacja.. a test jest oblany.

    Przekopiowałam nawet Twoj fragment niezdanego testu ( skoro przy prawidłowym jest okej, to reszta kodu musi być okej) a mimo to nie przechodzi.

    Odpowiedz
  7. Hej, no nie wymyślę co jest nie tak. Co tutaj jest źle, że test pozytywny przechodzi, a negatywny nie? Wyskakuje mi taki błąd:
    org.openqa.selenium.TimeoutException: Expected condition failed: waiting for visibility of element located by By.cssSelector: div[role='alert'] (tried for 10 second(s) with 500 milliseconds interval).
    A przy teście z prawidłowym kuponem, wszystko gra.

    import org.junit.jupiter.api.Assertions;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    import org.openqa.selenium.By;
    import org.openqa.selenium.Dimension;
    import org.openqa.selenium.Point;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.support.ui.ExpectedConditions;
    import org.openqa.selenium.support.ui.WebDriverWait;
    import java.util.concurrent.TimeUnit;
    
    public class ZadaniePatki2 {
    
        WebDriver driver;
        WebDriverWait wait;
        By cookieConsentBar = By.cssSelector("a[class*='dismiss-link']");
        By product = By.cssSelector("li.post-61");
        By acceptInfo = By.cssSelector("a[class='woocommerce-store-notice__dismiss-link']");
        By addToCart = By.cssSelector("button[name='add-to-cart']");
        By cartContent = By.cssSelector("a[class='cart-contents']>span.count");
        By couponArea = By.cssSelector("input[id='coupon_code']");
        By couponConfirmButton = By.cssSelector("button[name='apply_coupon']");
        String correctCoupon = "10procent";
        String incorrectCoupon = "test";
    
    
    
      @BeforeEach
        public void driverSetup() {
            System.setProperty("webdriver.chrome.driver", "src/main/resources/chromedriver.exe");
            driver = new ChromeDriver();
    
          driver.manage().window().setSize(new Dimension(1295, 760));
          driver.manage().window().setPosition(new Point(10,40));
          driver.manage().timeouts().pageLoadTimeout(15, TimeUnit.SECONDS);
          driver.navigate().to("https://fakestore.testelka.pl/product-category/yoga-i-pilates/");
          wait = new WebDriverWait(driver,10);
    
         // driver.findElement(cookieConsentBar).click();
          driver.findElement(acceptInfo).click();
          driver.findElement(product).click();
          driver.findElement(addToCart).click();
          driver.findElement(cartContent).click();
    
    
        }
    
        @Test
        public void correctCoupon(){
          applyCoupon(correctCoupon);
          Assertions.assertEquals("Kupon został pomyślnie użyty.",getAlertText(),"Alert message was not what expected");
        }
    
        @Test
        public void incorrectCouponTest(){
            applyCoupon(incorrectCoupon);
            Assertions.assertEquals("Kupon \"" + incorrectCoupon + "\" nie istnieje!", getAlertText(), "Alert message was not what expected.");
        }
    
        private void applyCoupon(String coupon){
          driver.findElement(couponArea).sendKeys(coupon);
            driver.findElement(couponConfirmButton).click();
        }
        private String getAlertText(){
          By alert = By.cssSelector("div[role='alert']");
          return wait.until(ExpectedConditions.visibilityOfElementLocated(alert)).getText();
        }}
       
    

    Gdzie tam jest babol 😀

    Odpowiedz