👨‍💻 Kod / Programowanie

Elementy widoczne na stronie czyli viewport w Playwright

Language
date
Dec 8, 2023
slug
playwright-viewport
author
status
Public
tags
Playwright
TypeScript
JavaScript
Automatyzacja
summary
Czym jest Playwright viewport i jak sprawdzać elementy, które się w nim znajdują?
type
Post
thumbnail
playwright-viewport.jpg
updatedAt
Feb 12, 2024 01:28 PM
category
👨‍💻 Kod / Programowanie
W tym wpisie przybliżę Ci praktycznie jak zbadać czy element znajduje się w widoku testowanej strony.
Będziemy testować na stronie: 🔗https://playwright.dev, którą polecam odwiedzić, aby lepiej zrozumieć kontekst tego wpisu i testów, które zrobimy.
Kod przykladów z tego wpisu wykonasz w domyślnej instalacji Playwright Test (TypeScript).

Czym jest viewport?

 
Teoria mówi, że viewport to wycinek strony, który widzimy w danym czasie w oknie przeglądarki.
 
Niezbyt imponujące. Zróbmy praktyczny test aby lepiej to zobrazować.
Pobieramy obserwowany wycinek strony oraz całą stronę:
test("viewport screenshot vs full page", async ({page}) => { await page.goto('https://playwright.dev/'); await page.screenshot({ path: 'screenshots/page/viewport.png' }); await page.screenshot({ path: 'screenshots/page/full.png', fullPage: true }); });
 
Zbieramy dwa zrzuty ekranu, pierwszy zbierze widok z okna przeglądarki a drugi całą stronę.
Efekt jasno nam pokazuje różnicę między viewport (po lewej) a pełnym widokiem strony (po prawej):
notion image
 
Dowiedzmy się więcej o parametrach naszego viewport:
test("the viewport properties", async ({page}) => { const viewport = page.viewportSize(); console.log('Viewport:', viewport); }); // Console output: // Viewport: { width: 1280, height: 720 }
 
Czyli w takiej rozdzielczości działa nasza przeglądarka.
Dlaczego?
Domyślna konfiguracji w Playwright, w pliku playwright.config.ts korzysta z takich ustawień przeglądarki:
{ name: 'chromium', use: { ...devices['Desktop Chrome'], }, },
Ciekawostka - nie musisz umieszczać informacji o używanej przeglądarce w pliku konfiguracyjnym. Zostanie użyta wtedy dokładnie ta wskazana powyżej.
Pełne ustawienia związane z 'Desktop Chrome' znajdziemy się w pliku: node_modules\playwright-core\lib\server\deviceDescriptorsSource.json
"Desktop Chrome": { "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.9 Safari/537.36", "screen": { "width": 1920, "height": 1080 }, "viewport": { "width": 1280, "height": 720 }, "deviceScaleFactor": 1, "isMobile": false, "hasTouch": false, "defaultBrowserType": "chromium" },
Widzimy dokładne wartości dla viewport. Świetnie - już wiemy skąd ona pochodzi!
Możesz jeszcze zaobserwować wartość screen. Tyczy się ona emulowanego urządzenia niż samej przeglądarki i obszaru wyświetlanego, częściej ma ona zastosowanie w widokach mobilnych.
 

Podsumujmy:

Viewport jest to obszar wyświetlany użytkownikowi związany z zawartością strony (a nie przeglądarki i jej elementów).
 

Najprostsza forma weryfikacji elementu w viewport

 
Jeśli chcemy sprawdzić czy nasz element jest w obszarze widocznym dla użytkownika wystarczy skorzystać z asercji:
await expect(locator).toBeInViewport();
 
Przykładem może być weryfikacja poniższego obrazka z testowanej strony:
notion image
test("browsers image is in viewport", async ({page}) => { await page.goto('https://playwright.dev/'); const browsersImage = page.getByAltText('Browsers'); await expect(browsersImage).toBeInViewport(); });
Wynik - obrazek znaleziony i jest na ekranie:
notion image
 
Niby prosta sprawa - ale co to oznacza?
W ten sposób sprawdziliśmy czy cały element jest wyświetlany w przeglądarce.
 

Element częściowo znajdujący się viewport

 
Może się tak zdarzyć, że tylko część elementu znajduje się w naszym widoku.
Przykładem może być element <main> który zawiera nie tylko wspomniany obrazek ale i elementy znajdujące się po za testowanym widokiem:
notion image
 
Zróbmy test na tym elemencie:
test("main element is partially in viewport", async ({page}) => { await page.goto('https://playwright.dev/'); const main = page.locator('main'); await expect(main).toBeInViewport(); });
i bez problemu przejdzie. Hmm czyli to oznacza, że metoda toBeInViewport() domyślnie sprawdza, że wystarczy tylko częściowa obecność elementu w viewport.
 

Element w pełni znajdujący się viewport

 
Sprawdźmy teraz czy nasz element znajduje się całkowicie w viewport za pomocą ustawienia {ratio: 1}
1 oznacza 100% elementu musi się znajdować w viewport.
Zróbmy test dla naszego elementu main
test("main element is fully in viewport", async ({page}) => { await page.goto('https://playwright.dev/'); const main = page.locator('main'); await expect(main).toBeInViewport({ratio: 1}); });
Ten test zakończy się takim niepowodzeniem
Locator: locator('main') Expected: in viewport Received: outside viewport Call log: - expect.toBeInViewport with timeout 5000ms - waiting for locator('main') - locator resolved to <main>…</main> - unexpected value "viewport ratio 0.08866515755653381"
Widzimy w ostatniej linii, że zaledwie ~9% elementu znajduje się w obszarze testowanego widoku.
Czyli gdy ustawimy ratio na 0.08 to test powinien przejść:
test("main element is at least 8% in viewport", async ({page}) => { await page.goto('https://playwright.dev/'); const main = page.locator('main'); await expect(main).toBeInViewport({ratio: 0.09}); });
Teraz możesz łatwo pobawić się zmianami ustawiania ratio i tym samym zadbać o to aby test przeszedł zgodnie z wymaganiami.

Element poza viewport

 
Na koniec zostało nam zbadanie elementu poza widokiem.
Zweryfikujmy ten oto obrazek (który, jest widoczny dopiero po skrolowaniu widoku strony):
notion image
Dodamy do naszej asercji zaprzeczenie: .not.toBeInViewport();
test("image element is outside of viewport", async ({page}) => { await page.goto('https://playwright.dev/'); const imageVSCode = page.getByAltText('VS Code'); await expect(imageVSCode).not.toBeInViewport(); });
Test przechodzi! Czyli sprawdzenie element poza viewport działa 😁

Podsumowanie

 
Znając działanie viewport w Playwright z łatwością przetestujesz elementy, które powinny (lub nie), znaleźć się w obszarze prezentowanym użytkownikowi.
 
Tego typu testy są szczególnie ważne w przypadku treści, które np. muszą znaleźć się na pierwszej stronie i użytkownik z niej korzystający powinien mieć z nimi styczność.
W szczególności, gdy chcemy się upewnić, że cały element, np. oferta zakupu, czy baner informacyjny są poprawnie wyświetlane.
 
Zachęcam Ciebie do przekopiowania całego kodu i modyfikacji testów, tak aby nie przechodziły lub sprawdzić procentową widoczność danego elementu. Możesz potestować swoje umiejętności np. na stronie https://unsplash.com gdyż tam często będziesz miał styczność z przyciętymi obrazkami w viewport.

Jeszcze więcej zabawy z viewport?

To nie koniec eksperymentów z viewport, gdyż w kolejnym wpisie poczytasz jak kreatywnie wykorzystać tę wiedzę: 🔗https://playwright.info/playwright-viewport-elements
 

Cały kod

Poniżej znajdziesz cały kod, który rozwijałem w tym wpisie:
import { expect, test } from "@playwright/test"; test("viewport screenshot vs full page", async ({page}) => { await page.goto('https://playwright.dev/'); await page.screenshot({ path: 'screenshots/page/viewport.png' }); await page.screenshot({ path: 'screenshots/page/full.png', fullPage: true }); }); test("the viewport properties", async ({page}) => { const viewport = page.viewportSize(); console.log('Viewport size:', viewport); }); test("browsers image is in viewport", async ({page}) => { await page.goto('https://playwright.dev/'); const browsersImage = page.getByAltText('Browsers'); await expect(browsersImage).toBeInViewport(); }); test("main element is partially in viewport", async ({page}) => { await page.goto('https://playwright.dev/'); const main = page.locator('main'); await expect(main).toBeInViewport(); }); // below test will fail: element is only 8% in viewport test("main element is fully in viewport", async ({page}) => { await page.goto('https://playwright.dev/'); const main = page.locator('main'); await expect(main).toBeInViewport({ratio: 1}); }); test("main element is at least 8% in viewport", async ({page}) => { await page.goto('https://playwright.dev/'); const main = page.locator('main'); await expect(main).toBeInViewport({ratio: 0.09}); }); test("image element is outside of viewport", async ({page}) => { await page.goto('https://playwright.dev/'); const imageVSCode = page.getByAltText('VS Code'); await expect(imageVSCode).not.toBeInViewport(); });