Powrót do: Praktyczne wprowadzenie do testów automatycznych z Playwright
Zestaw testów i przypadki negatywne
Prezentacja
Dodatkowe materiały
Link do testowanej stronyPlik 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:
- 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 }) => { }); - 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.
- Zmiana nazwy pustego testu w pliku login.spec.ts:
test('login with incorrect credentials with incorrect username', async ({ page }) => { }); - Manualnie wykonujemy test na niepoprawne logowanie, gdy podamy zbyt krótki ID użytkownika. Zwróć uwagę na komunikaty o błędach pod polem ID.
- 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. - 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(); - 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(); - 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.
- 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 }); });
- 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:
- 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'); }); - 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.
- 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'); }); - 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.
- 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.
Cały kod
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');
});
});


Cześć, dlaczego w terminalu vsc podczas dodania drugiego testu wyświetla się informacja: “Running 2 tests using 2 workers”, a przy dodaniu trzeciego testu jest informacja: “Running 3 tests using 3 workers” ?
Plik jest zapisany tylko w jednym miejscu w folderze ‘tests’ i jest otwarty tylko jeden edytor
Hej,
Dzięki za pytanie! To, co widzisz w terminalu, to domyślne zachowanie Playwright Test Runnera (test runnera, którego używasz w VS Code).
Playwright Test sam zarządza testami i domyślnie uruchamia je równolegle.
Wykorzystuje w tym celu “workers”, czyli to po prostu osobny proces, który zajmuje się wykonywaniem Twoich testów (możesz myśleć o nim jak o pomocniku albo robotniku, który dostaje zadanie (test) do wykonania)
Dlaczego widzisz na konsoli
Running X tests using X workers?Playwright Test uruchamia każdy test równolegle w osobnym procesie zwanym workerem.
Domyślna liczba workers zależy od liczby logicznych procesorów CPU w Twoim systemie (moze to być np 4), ale jeśli liczba testów jest mniejsza niż workers, to Playwright dopasowuje ją do liczby testów.
Dlatego:
przy 2 testach -> uruchamia 2 workers -> czyli 2 testy sa uruchomiane w tym samym czasie
przy 3 testach -> uruchamia 3 workers -> czyli 3 testy sa uruchomiane w tym samym czasie
A jeśli miałabyś np 6 testów, to Playwright wykorzystałby maksymalną liczbę workerów – czyli 4. A to znaczyłoby ze uruchomi 4 testy równolegle 🙂
Dzięki za wyjaśnienie! Ja to odczytałam dosłownie: “Uruchomiono 3 testy używane przez 3 użytkowników ” więc się zastanawiałam, czy przypadkiem nie uruchamiam tego jakoś tle. Ale skoro to normalne działanie systemu, to już jestem spokojna. Dzięki!
Cześć! Z jakiego powodu playwright, pomimo zmiany nazwy testu nadal wyświetla błąd o duplikacji nazwy? Gdy zamknę VSC i otworzę na nowo, błąd się nie pojawia, tak jakby playwright nie otrzymuje informacji o naprawie błędu – jak mogę to naprawić?
Hej,
Rozumiem, że tak samo jak na nagraniu korzystasz z wtyczki do VS Code, prawda? 🙂
Jesli tak, to wtyczka ma “cache”, który nie zawsze jest od razu odświeżany.
W takim przypadku masz 2 opcje.
Albo zrestartować VS Code (możesz to szybko zrobić korzystając ze skrótu: CTRL + SHITP + P i wpisując “Reload Window”)
Albo poprzez wejście do wtyczki i odświeżenie testów – https://con.jaktestowac.pl/wp-content/uploads/PW/1/S01/vs-code-refresh.png 🙂
Daj prosze znać czy ta druga opcja też pomogła 🙂
Tak, robię wszystko po kolei, zgodnie z Waszymi wskazówkami.
Przetestowałam Twoje porady – obie zadziałały – dzięki! 🙂
To świetnie! 😀
Czasem przy zmianach w testach (dodanie nowych, lub zmiana istniejących) trzeba się wspomóc takim manualnym odświeżeniem 🙂
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:)
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 🙂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
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 🙂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
Cała przyjemność po mojej stronie 🙂
Playwright oferuje wiele przydatnych i wbudowanych funkcji, gdzie w Selenium wiele z tych konceptów trzeba było samemu implementować 🙂
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”
);
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ć 😉
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!