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'); }); });
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:
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!