Rozwiązanie: Kolejny test pulpitu

TIP: Ta lekcja jest częścią rozwijanego Programu Testy Automatyczne z Playwright 🎭

Dodatkowe materiały

Link do testowanej strony
TIP: Cały kod z tej i innych lekcji znajdziesz w naszym repozytorium.

Twoim zadaniem było przygotowanie testu automatycznego dla operacji doładowania telefonu na stronie Pulpit. Poniżej znajdziesz porady jak podejść do tego zadania oraz jego rozwiązanie 😉

Nagrywanie testu

Aby nagrać test za pomocą codegen użyj polecenia:

npx playwright codegen [adres]

czyli np:

npx playwright codegen https://demo-bank.vercel.app/

Uruchomienie jednego testu

Podczas pisania nowego testu warto często go uruchamiać, aby sprawdzić, czy podążamy w dobrą stronę 😉 Aby skupić się tylko na tym, co piszemy, warto uruchamiać tylko jeden testy

Aby to zrobić, skorzystaj z konstrukcji only() np.:

test.only('successful mobile top-up', async ({ page }) => {

Przerywanie działającego procesu w konsoli

Kliknij w terminalu, w którym proces node.js nadaj jest uruchomiony, a następnie użyj skrótu CTRL + C, aby przerwać działający proces.

Komentowanie wiele linii

Zaznacz wiele linii i użyj skrótu CTRL + /

Duplikacja danej linii

Ustaw kursor na linii, którą chcesz zduplikować, a następnie naciśnij ALT + SHIFT +

Selektory i wyszukiwanie elementów na stronie

Aby wyszukać elementy w przeglądarce za pomocą selektorów CSS otwórz narzędzia developerskie (DevTools). Następnie otwórz konsolę i użyj następującej konstrukcji:

$$(‘selektor CSS’)

Wyszukiwaniu elementów w przeglądarce omawiamy w naszych lekcjach bonusowych:

Cały kod

Zawartość pliku pulpit.spec.ts z rozwiązaniem zadania w postaci testu successful mobile top-up:

import { test, expect } from '@playwright/test';


test.describe('Pulpit tests', () => {
    
    test('quick payment with correct data', async ({ page }) => {
      await page.goto('https://demo-bank.vercel.app/');
      await page.getByTestId('login-input').fill('testerLO');
      await page.getByTestId('password-input').fill('password');
      await page.getByTestId('login-button').click();
      
      await page.locator('#widget_1_transfer_receiver').selectOption('2');
      await page.locator('#widget_1_transfer_amount').fill('150');
      await page.locator('#widget_1_transfer_title').fill('pizza');


      await page.getByRole('button', { name: 'wykonaj' }).click();
      await page.getByTestId('close-button').click();


      await expect(page.locator('#show_messages')).toHaveText('Przelew wykonany! Chuck Demobankowy - 150,00PLN - pizza')
    });


    test('successful mobile top-up', async ({ page }) => {
        await page.goto('https://demo-bank.vercel.app/');
        await page.getByTestId('login-input').fill('testerLO');
        await page.getByTestId('password-input').fill('password');
        await page.getByTestId('login-button').click();


        await page.locator('#widget_1_topup_receiver').selectOption('503 xxx xxx');
        await page.locator('#widget_1_topup_amount').fill('50');
        await page.locator('#uniform-widget_1_topup_agreement span').click();
        await page.getByRole('button', { name: 'doładuj telefon' }).click();
        await page.getByTestId('close-button').click();
       
        await expect(page.locator('#show_messages')).toHaveText('Doładowanie wykonane! 50,00PLN na numer 503 xxx xxx')
      });
});

12 komentarzy

  1. Hej mam pytanie o tego checkboxa, przyznam, że zamiast używać codegen do nagrania testu to spróbowałem po prostu z devtoolsami i szybko poszło, ale kod na końcu się różnił od tego co podaliście, ale wszystko działa. Sięgnąłem też do dokumentacji playwrighta i zauważyłem, że są tam sugerowane lokatory elementów i raczej odradza się używanie CSS i Xpath jeśli nie jest to konieczne, ze względu na trudność w utrzymaniu testów (cssy i xpathy łatwo ulegają zmianom). Jednak ja złapałem element #widget_1_topup_agreement zamiast uniform-widget_1_topup_agreement span, kierowałem się przy tym myśleniem, że mimo wszystko to Id, odwołuje się bezpośrednio do checkboxa (który jest inputem), a uniform-widget_1_topup_agreement span odwołuje się do jakiegoś elementu opakowującego/trzymającego w sobie ten input. Założyłem, że prędzej ten div może ulec zmianie niż sam input, który może co najwyżej zostać przeniesiony. Czy tutaj istnieje jakieś jednoznaczne stwierdzenie, które z tych rozwiązań jest lepsze czy “to zależy”?

    U mnie:

    await page.locator('#widget_1_topup_agreement').click();
    

    W podanym rozwiązaniu przez jaktestowac.pl:

     await page.locator('#uniform-widget_1_topup_agreement span').click();
    

    Druga rzecz, kiedy po zrobieniu zadania, spróbowałem zrobić je jeszcze raz z codegen zauważyłem, że na sam koniec kiedy zamykam ekran informujący o tym, że doładowanie zakończyło się powodzeniem, playwright inspektor czasem zapisuje kliknięcie buttona OK jako getByRole a czasem jako page.getByTestId, czy oba te rozwiązania są równie dobre?

    Avatar Franciszek Klocek
    1. Ogólnie Twoje rozwiązanie również wygląda poprawnie 🙂
      Również myślę, że Twoje przemyślenia nt zmienności elementów są poprawne – czyli, że lepiej odnieść się do konkretnego elementu przez jego ID, niż po typie elementu 🙂 I też sugerowałbym odnosić się do ID, które jest najbliżej interesującego nas elementu.

      To zależy odnosiłoby się do projektów, w których elementy nie mają ID i musimy wybierać “mniejsze zło” 😉

      Działanie codegen może się zmieniać między wersjami Playwrighta… i jak widać również w zależności od uruchomienia😅 Obecnie nie wiem dokładnie na jakiej podstawie są generowane i wybierane lokatory w codegen, jednak obie opcje mogą być poprawne 🙂
      Tutaj zachęcałbym również do przyjrzenia się czy dałoby radę zrobić to lepiej/inaczej – np. po ID. Bo codegen nie zawsze działa optymalnie 🙂

      Krzysiek Kijas Krzysiek Kijas
  2. Super lekcja, dzięki! 🙂 Jednak zauważyłem coś dziwnego: po wybraniu nr tel 504 xxx xxx zamiast pola input mamy listę rozwijaną z kwotami do wyboru.
    Mimo to, jeśli wpiszę w teście

    await page.locator('#widget_1_topup_amount').selectOption('100');
    

    i puszczę test, to Playwright wskazuje mi w tym miejscu błąd:

    Error: locator.selectOption: Error: Element is not a  element
    

    No i jeszcze dziwniejsze jest to, że test dla numeru 504 xxx xxx przechodzi, jeśli zamiast metody selectOption dam metodę fill:

    await page.locator('#widget_1_topup_amount').fill('50');
    

    Trzeba będzie sprawdzić, co się dzieje w API 🙂

    Avatar Slawomir Nowodworski
    1. Hej 😀
      Dzięki wielkie! 🙇‍♂️
      selectOption nie zadziała na page.locator('#widget_1_topup_amount'), bo jest to obiekt typu input (a nie select/drop down) 😉 Select byłby odpowiedni dla elementu page.locator('#widget_1_topup_receiver') 🙂

      Krzysiek Kijas Krzysiek Kijas
      1. Krzysiek, cały wic polega na tym, że dla numeru 504 xxx xxx (tylko dla tego numeru) zamiast pola input mamy listę rozwijaną z kwotami doładowania do wyboru. Przynajmniej u mnie tak to działa. Zaręczam, że nie gmerałem w kodzie w devtoolsach 🙂 Tym dziwniejsze jest to, że ten numer nie przechodzi testu, jeśli wybierzemu lokator selectOption. Prawda testu i prawda ekranu. 😀
        504 xxx xxx

        wybierz telefon do doładowania

        500 xxx xxx

        502 xxx xxx
        503 xxx xxx
        504 xxx xxx

        Avatar Slawomir Nowodworski
        1. Faktycznie 😀 Sprawdziłem dla innych numerów – i akurat nie sprawdziłem 504 xxx xxx.
          W sumie w realnym projekcie -> idealne na zgłoszenie buga 😀
          W naszym przypadku – pozostaje nam pominąć ten przypadek 😉

          Widać w tej apcje mamy więcej bugów niż zakładaliśmy i niż jesteśmy świadomi 😀

          Krzysiek Kijas Krzysiek Kijas
  3. Oprócz “braku wiadomości” test szybkiego przelewu czasami nie przechodzi, gdy kwota w wiadomości jest podawana bez wartości dziesiętnych.

    Expected string: “Przelew wykonany! Chuck Demobankowy – 150,00PLN – pizza”
    Received string: “Przelew wykonany! Chuck Demobankowy – 150PLN – pizza”

    Pewnie treść wiadomości powinna być doprecyzowana w specyfikacji, a sytuacja stworzona w celach dydaktycznych.

    Avatar Adam
    1. W pewnych przypadkach testy mogą kończyć się niepowodzeniem, gdzie powody mogą być różne – począwszy od połączenia internetowego, prędkości testu, czy z winy samej aplikacji. W tym przypadku możemy ten błąd zignorować, a w projekcie warto przedyskutować go z innymi QA lub developerami.

      Również takie niestabilne testy w testowej aplikacji pozwalają też pobawić się z ustawieniami w Playwrighcie – np w pliku config jest parametr retries, który pozwala ponawiać testy, które zakończyły się niepowodzeniem.

      Domyślnie wartość ustawiona jest na 0, czyli każdy test ma tylko jedną szanse, ale przy niestabilnych testach możemy poeksperymentować z wartością retries.
      Przy czym – warto tu się zastanowić czy takie ponawianie testów jest dobrym rozwiązaniem w naszym kontekście (czyli projekcie) i jaki jest faktyczny powód tej niestabilności testów. Bo ustawiając retries bez analizy problemy możemy bardzo łatwo przeoczyć faktyczny błąd w aplikacji 😉

      Więcej o tym powiemy w przyszłych materiałach – również o wadach, zaleta oraz zagrożeniach 🙂

      Krzysiek Kijas Krzysiek Kijas
    1. Idealnie! 😀

      A tak na serio – była w tym głębsza myśl 😉
      Aplikacja została specjalnie tak zaprojektowana, aby oddać różne (czasem specyficzne) wymagania klienta oraz kilka innych niedogodności… Dzięki temu symulujemy prosty projekt, w którym musimy się dostosować, ale momentami nie jesteśmy pewni czy znaleziona rzeczy to bug czy feature 😉

      Krzysiek Kijas Krzysiek Kijas

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *