Zestaw testów i przypadki negatywne

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

Prezentacja

Zestaw testów i przypadki negatywne

Dodatkowe materiały

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

Plik README.md z najważniejszymi poleceniami

Aby ułatwić sobie pracę dodamy do naszego projektu plik README.md. Jest to standardowy plik z dokumentacją, który wypełniamy posługując się specjalną składnią zwaną markdown.

Plik ten dodajemy w głównym katalogu naszego projektu tzn. klikając prawym klawiszem myszki w pustej przestrzeni pod listą plików w naszym projekcie.

Użyj opcji New File… i stwórz plik z nazwą README.md.

W nim też można zawrzeć wszystkie istotne informacje. My proponujemy takie:

# Test Automation training form jaktestowac.pl


## Links
- course https://jaktestowac.pl/course/playwright-wprowadzenie/
- test site
https://demo-bank.vercel.app/  
If link broken check first lesson for update:
https://jaktestowac.pl/lesson/pw1s01l01/


## Commands
- check `NodeJS` version    
`node -v`
- new project with Playwright:  
`npm init playwright@latest`
- record tests for given site  
`npx playwright codegen https://demo-bank.vercel.app/`
- run tests without browser GUI:  
`npx playwright test`
- run test with browser GUI:  
`npx playwright test --headed`
- viewing report  
`npx playwright show-report`


## Playwright Config modifications
- config file `playwright.config.ts`
- disabling browsers, i.e. Firefox:
    ```json
    // {
    //   name: 'firefox',
    //   use: {
    //     ...devices['Desktop Firefox'],
    //   },
    // },
    ```

Zapisuj tu istotne dla Ciebie informacje, dzięki temu szybko wykonasz polecenia bez wychodzenia z projektu 😉

Podstawowa składnia pliku README.md

  • Nagłówki – użyj # i odstęp. Wraz z ilością znaków # zmienia się wielkość nagłówka.
  • Listy – użyj - i odstęp.
    TIP: Łamanie linii w listach uzyskasz za pomocą podwójnej spacji oraz Enter na końcu wiersza listy.
  • Kod i wyróżnienia – użyj ` czyli znak backtick na początku i końcu kodu.
  • Wielolinijkowy kod – użyj ``` czyli znak backtick x 3 na początku i końcu kodu, który zawiera wiele linii.

Co na początku warto wiedzieć o VS Code?

  • Preview – podgląd pliku README.md (znajdziesz w prawym górnym rogu),
  • Autosave – auto zapisywanie plików, które można ustawić w menu: File | Auto Save,
  • Timeline – czyli historia danego pliku. Można ją podejrzeć klikając prawym klawiszem myszy na pliku (po lewej stronie w explorer) a następnie wybraniu opcji Timeline z menu kontekstowego.

Refaktoryzacja nazw

Zmieniamy nazwy testów i związanych z nimi plików, tak aby były bardziej czytelne.

Zmieniamy nazwę pliku z example.spec.ts na login.spec.ts.

Zmieniamy nazwę testu z:

  test('test', async ({ page }) => {


  });

na

  test('login with correct credentials', async ({ page }) => {


  });

Test na niepoprawne logowanie ze zbyt krótkim ID użytkownika

Kroki:

  1. Przygotowanie pustego testu w pliku login.spec.ts o takiej samej nazwie co wcześniej istniejący test:
      test('login with correct credentials', async ({ page }) => {
    
    
      });
    
    
  2. Sprawdzamy wynik po uruchomieniu wszystkich testów:
    npx playwright test
    

    Na konsoli powinniśmy otrzymać błąd:

    Running 2 tests using 2 workers
    ========================================
     duplicate test titles are not allowed.
     - title: successful login with correct credentials
       - login.spec.ts:3
       - login.spec.ts:15
    ========================================
    
    
      2 skipped
    

    Oznacza to, że nie możemy posiadać testów o takiej samej nazwie.

  3. Zmiana nazwy pustego testu w pliku login.spec.ts:
      test('login with incorrect credentials with incorrect username', async ({ page }) => {
    
    
      });
    
    
  4. Manualnie wykonujemy test na niepoprawne logowanie, gdy podamy zbyt krótki ID użytkownika. Zwróć uwagę na komunikaty o błędach pod polem ID.
  5. Kopiujemy kod część kodu z poprzedniego testu:
        await page.goto('https://demo-bank.vercel.app/');
        await page.getByTestId('login-input').click();
        await page.getByTestId('login-input').fill('tester');
        await page.getByTestId('password-input').click();
    
    TIP:Aby poprawnie sformatować edytowany kod, użyj opcji autoformatowania.
    Wywołaj ją w oknie edycji kodu prawym klawiszem myszki. Wybierz opcję Format Document.
  6. Nagrywamy test za pomocą polecenia:
    npx playwright codegen https://demo-bank.vercel.app/
    

    a następnie kopiujemy element z tekstem błędu do testu w pliku login.spec.ts

    await page.getByTestId('error-login-id').click();
    
  7. Kopiujemy kod część kodu z poprzedniego testu:
        await page.goto('https://demo-bank.vercel.app/');
        await page.getByTestId('login-input').click();
        await page.getByTestId('login-input').fill('tester');
        await page.getByTestId('password-input').click();
    
  8. Dodajemy asercję i wykorzystujemy element z tekstem błędu:
        await expect(page.getByTestId('error-login-id')).toHaveText('');
    
    
    

    Uruchamiamy testy i kończy się on niepowodzeniem, ale możemy łatwo skopiować tekst błędu, którego oczekujemy.

    TIP:Tworzymy testy dla istniejącej strony i obecnie nie porównujemy jej z dokumentacją (gdyż taką tutaj nie dysponujemy).

    Pamiętaj, aby tworzyć asercje w projekcie w oparciu o dostępną dokumentację i wymagania.

  9. Sprawdzamy wynik po uruchomieniu wszystkich testów:
    npx playwright test
    

    Na konsoli powinniśmy otrzymać następujący wynik:

    Running 2 tests using 2 workers
    
      2 passed (9s)
    

    Oznacza to, że nasze testy zakończyły się sukcesem.

Describe w testach

  • test.describe grupuje nasze testy w logiczną całość,
  • przykład wykorzystania test.describe:
    import { test, expect } from '@playwright/test';
    
    
    test.describe('User login to Demobank', () => {
     
      test('successful login with correct credentials', async ({ page }) => {
        // kod testu
      });
    
    
      test('unsuccessful login with too short username', async ({ page }) => {
        // kod testu
      });
    
    
    });
    
    
TIP: Zapamiętaj👨‍🏫

  • nazewnictwo testów to kwestia umowna,
  • nazwy testów podlegają tej samej ewolucji co kod – w razie potrzeby, zawsze możecie zmienić sposób nazywania testów,
  • wypracuj ze swoim zespołem standard, a następnie go przestrzegajcie.

Piszemy test na niepoprawne logowanie ze zbyt krótkim hasłem użytkownika

Kroki:

  1. Możemy użyć wcześniejszy test – kopiujemy go w pliku login.spec.ts i zmieniamy mu nazwę na:
      test('unsuccessful login with too short password', async ({ page }) => {
        await page.goto('https://demo-bank.vercel.app/');
        await page.getByTestId('login-input').click();
        await page.getByTestId('login-input').fill('testerLO');
        await page.getByTestId('password-input').click();
        await page.getByTestId('password-input').fill('1234');
    
    
        await expect(page.getByTestId('error-login-id')).toHaveText('identyfikator ma min. 8 znaków');
      });
    
    
  2. Następnie nagrywamy test tak aby wywołać informacje o błędzie
    Tutaj kliknięcie w przycisk Zapisz nie zadziała.
    Należy kliknąć w dowolne inne miejsce np:

        await page.locator('#login_password_container label').click(); 
    

    Nagraj również kliknięcie w tekst błędu aby poznać kod lokatora.

  3. Uzupełniamy test w VSC. Zwróć uwagę na asercję z poprawnymi danymi:
      test.only('unsuccessful login with to short password', async ({ page }) => {
        await page.goto('https://demo-bank.vercel.app/');
        await page.getByTestId('login-input').click();
        await page.getByTestId('login-input').fill('testerLO');
        await page.getByTestId('password-input').click();
        await page.getByTestId('password-input').fill('1234');
        await page.locator('#login_password_container label').click(); 
    
    
        await expect(page.getByTestId('error-login-password')).toHaveText('hasło ma min. 8 znaków');
      });
    
    
  4. Zamiast kliknięcia w losowy element, zastosujemy funkcję blur() na polu password. Ta funkcja służy do opuszczenia pola, na którym w danej chwili jesteśmy:
    await page.getByTestId('password-input').blur();
    

    W ten sposób wywołujemy informacje o błędzie.

  5. Sprawdzamy wynik po uruchomieniu wszystkich testów:
    npx playwright test
    

    Na konsoli powinniśmy otrzymać następujący wynik:

    Running 3 tests using 3 workers
    
      3 passed (8s)
    

Uruchamianie pojedynczego testu

Możesz zaraz po obiekcie test dodać opcję only:

  test.only('unsuccessful login with to short password', async ({ page }) => {

Uruchamiając testy w konsoli, zostanie uruchomiony wyłącznie ten test.

TIP: Pamiętaj o usunięciu tej opcji po testach danego testu 😀

Cały kod

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

Zawartość pliku example.spec.ts:

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


test.describe('User login to Demobank', () => {
 
  test('successful login with correct credentials', async ({ page }) => {
    await page.goto('https://demo-bank.vercel.app/');
    await page.getByTestId('login-input').click();
    await page.getByTestId('login-input').fill('testerLO');
    await page.getByTestId('password-input').click();
    await page.getByTestId('password-input').fill('10987654');
    await page.getByTestId('login-button').click();
    await page.getByTestId('user-name').click();


    await expect(page.getByTestId('user-name')).toHaveText('Jan Demobankowy');
  });


  test('unsuccessful login with too short username', async ({ page }) => {
    await page.goto('https://demo-bank.vercel.app/');
    await page.getByTestId('login-input').click();
    await page.getByTestId('login-input').fill('tester');
    await page.getByTestId('password-input').click();
    await page.getByTestId('error-login-id').click();


    await expect(page.getByTestId('error-login-id')).toHaveText('identyfikator ma min. 8 znaków');
  });


  test('unsuccessful login with too short password', async ({ page }) => {
    await page.goto('https://demo-bank.vercel.app/');
    await page.getByTestId('login-input').click();
    await page.getByTestId('login-input').fill('testerLO');
    await page.getByTestId('password-input').click();
    await page.getByTestId('password-input').fill('1234');
    await page.getByTestId('password-input').blur();


    await expect(page.getByTestId('error-login-password')).toHaveText('hasło ma min. 8 znaków');
  });


});

9 komentarzy

  1. Pytanko, jak tworzymy przypadek testowy “unsuccessful login with too short password” to sprawdzamy wyświetlony erorr a czy poprawne byłoby również w tym przypadku dodać kolejną asercje aby sprawdzał czy faktycznie button zaloguj ma byc nieaktywny do kliknięcia czy to juz w nowym przypadku testowym? Nie możemy wykluczyć ze komunikat się pojawi, ale cały czas będziemy mogli zalogować sie na swoje konto:)

    Avatar Grzegorz Gajownik
    1. Bardzo słuszne pytanie 🙂
      Przy automatyzacji w projekcie należałoby się zastanowić – co mamy w wymaganiach i co dokładnie chcemy sprawdzić i jak to zrobić. Tutaj dla uproszczenia bazujemy tylko na wiadomości, jednak w niektórych przypadkach (i w zależności od wymagań) dobrze sprawdzić też inne elementy – np. czy button jest nieaktywny albo czy jesteśmy cały czas na danej stronie.

      W Playwright możemy to zrobić za pomocą expect.soft() – czyli asercji, która nie przerwie od razu testu, gdy wynik będzie negatywny 😉 Tym samym możemy dość szybko i prosto w jednym teście sprawdzić kilka elementów 🙂

      Krzysiek Kijas Krzysiek Kijas
  2. Hej hej,
    Mam pytanie odnośnie asercji w teście – wiem że dobre podejście wymaga zgodnie z kolejnością asercje robić jako ostatnie ale gdybyśmy chcieli zrobić asercję np adresu URL w międzyczasie zaraz po wejściu na stronę to czy jest dopuszczalne zrobienie jej w jednym teście czy raczej rozbić go na malutkie kawałeczki a potem bawić się w testy zależne:
    Przykład:

      test("unsuccessful login with to short password", async ({ page }) => {
        await page.goto("https://demo-bank.vercel.app/");
        // Assertion one
        await expect(page).toHaveURL(/.*.app/);
        await page.getByTestId("login-input").click();
        await page.getByTestId("login-input").fill("login123");
        await page.getByTestId("login-input").focus();
        // Assert two
        await expect(page.getByTestId("login-input")).toHaveValue('login123');
        await page.getByTestId("password-input").click();
        await page.getByTestId("password-input").fill("mypaswo");
        // Blur allows us to leave input field which is used to neg
        await page.getByTestId("password-input").blur();
        // Final Assertion
        await expect(page.getByTestId("error-login-password")).toHaveText(
          "hasło ma min. 8 znaków"
        );
      });
    

    Czy raczej unikać dodawania asercji pomiedzy krokami ??
    Dzięki z góry za odpowiedź.

    Pozdrawiam i spokojności życzę,
    Jakub K

    Avatar Jakub Kruszyński
    1. Hej,
      W takim przypadku najlepiej użyć asercji typu soft czyli await expect.soft(), która w razie błędu nie zatrzyma nam testu 🙂 Dopiero na końcu test zostanie odpowiednio oznaczony jesli taka asercja zakończy się błędem 🙂

      Dzięki await expect.soft() możemy w jednym teście sprawdzić kilka rzeczy – również tych mniej ważnych 🙂

      Krzysiek Kijas Krzysiek Kijas
      1. Hej,
        Super dzięki za Tipa – nie ma to jak dostać go od specjalisty ja nie pomyślałem o miękkiej asercji tutaj – co doświadczenie to doświadczenie – dziękuję pięknie zaz podpowiedź i zwrócenie uwagi że jest w Playwrighcie coś takiego jak miękka asercja – zupełnie wyleciało mi ze łba przez nieużywanie na codzień.

        Pozdrawiam i spokojności życzę,
        Jakub K

        Avatar Jakub Kruszyński
  3. ciekawa sprawa. W moim przypadku weryfikacja komunikatu nie działa, gdy łapiemy element po TestId:

    await expect(page.getByTestId(“error_login_password”)).toHaveText(
    “hasło ma min. 8 znaków”
    );

    ale działa bez problemu, gdy wziąłem locator -> ID

    await expect(page.locator(“#error_login_password”)).toHaveText(
    “hasło ma min. 8 znaków”
    );

    Avatar Michał Dudziak
    1. Hej 😉
      Powodem tutaj jest… literówka 😀

      Nasz obiekt ma postać:
      <div class=”error” data-testid=”error-login-password” id=”error_login_password” style=””>hasło ma min. 8 znaków</div>

      Id ma w sobie _, a data-testid – - 😉
      I powinno zadziałać 😉

      Krzysiek Kijas Krzysiek Kijas
      1. hmm… faktycznie. Co ciekawe, ja to zaczynałem robić poprzez codegen i on mi taki locator wskazał. Ale najważniejsze że już wiadomo gdzie jest błąd. Dzięki!

        Avatar Michał Dudziak

Dodaj komentarz

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