Testiranje softvera · Poglavlje 13 · Sedmica 13

Testiranje web aplikacija

Dio 1 – Web i prvi automatski test

Dio 2 – Lokatori, čekanje i provjere

Dio 3 – Organizacija, preglednici i pristupačnost

Praksa – Playwright i stranica DeliveryApp

Materijale priredio Erkan Islamović

erkan.islamovic@eubd.edu.ba · erkan.islamovic@gmail.com

Šta učimo ovog semestra

Petnaest sedmica: svaka ima tri časa teorije i tri časa praktične nastave. Danas: poglavlje 13 (Sedmica 13, označeno). Isti primjer kroz knjigu: DeliveryApp, narudžba N-1001.

Sed.PoglavljeTeorija (3 časa)Praksa (3 časa)
1Zašto testiramoUvodne priče; greška, defekt, otkaz; sedam principa; DeliveryAppTabela očekivanih cijena rukom
2Proces i nivoiTest proces; nivoi i V-model; vrste; statičko testiranjeRecenzija zahtjeva DeliveryApp
3Manuelno testiranjeTest slučaj; izvještaj o defektu; istraživačko testiranjeTest slučajevi za web stranicu
4Automatizovano testiranjeŠta automatizovati; piramida testova; prvi testPrvi pytest
5Jedinično testiranjeAAA; fixture, parametri, izuzeci; TDDTestovi za dostavu i popust
6Bijela kutijaGraf toka; pokrivenost; ciklomatska složenostcoverage.py do 100 % grana
7Tok podatakaDefinicija i upotreba; anomalije; statička analiza, mutacijeruff, mypy, ručna mutacija
8Crna kutijaEkvivalencija i granice; tabela odlučivanja; stanjaLov na pet grešaka

Šta učimo ovog semestra

Sed.PoglavljeTeorija (3 časa)Praksa (3 časa)
9Model i integracijaModel; strategije integracije; APITestClient za API
10Sistemsko testiranjeSistemsko; performanse i sigurnost; prihvatno i BDDLocust, Gherkin
11OO testiranjeStanje objekta; nasljeđivanje; dvojniciNarudzba, unittest.mock
12Paralelne aplikacijeTrka podataka; zastoj; nestabilni testoviNiti, 1000 ponavljanja
13Web aplikacijeWeb i DOM; Playwright; Page Object, pristupačnostPlaywright za DeliveryApp
14Upravljanje testiranjemTest plan i rizik; metrike; CI/CDGitHub Actions
15Alati, AI, projekatPregled alata; AI u testiranju; ISTQBOdbrana projekta
N-1001 je 24,50 € · od 30,00 € dostava je besplatna

Literatura

  1. J. Popović: Priručnik za test inženjere, CET i Računarski fakultet, Beograd, 2023.
  2. Rakić-Skoković: Priručnik za testiranje softvera, Fakultet tehničkih nauka, Novi Sad, 2013.
  3. G. J. Myers: The Art of Software Testing, 2. izdanje, John Wiley & Sons, 2004.
  4. A. P. Mathur: Foundations of Software Testing, Addison-Wesley Professional, 2008.
Priča za početak · Sedmica 13

Priča za početak

Priča za početak

U utorak, 15. novembra 2022., počela je pretprodaja karata za veliku turneju pjevačice Taylor Swift u SAD-u, preko sajta Ticketmaster. Pravo na pretprodaju imali su samo unaprijed registrovani obožavatelji, koji su dobili kod. Sistem je bio pripremljen za veliku gužvu, ali ne za ono što je stiglo: obožavatelji, ali i ogroman broj botova (programa koji automatski kupuju karte da bi ih kasnije preprodali skuplje). Prema izjavi same firme, sistem je tog dana primio 3,5 milijardi zahtjeva, oko četiri puta više nego u bilo kojem ranijem vrhuncu.

Stranica se zaglavljivala, redovi čekanja su stajali satima, korpe su se praznile u posljednjem koraku, a mnogi su dobijali poruke o grešci baš kad su karte bile u korpi. Opšta prodaja, planirana za nekoliko dana kasnije, otkazana je, jer nije ostalo dovoljno karata. Slučaj je završio na saslušanju u američkom Senatu u januaru 2023. Za nas je ova priča zanimljiva jer pokazuje koliko toga mora raditi zajedno da bi jedan klik na dugme „Kupi” uspio: preglednik, stranica, JavaScript, mreža, server, red čekanja, baza i zaštita od botova. Web aplikacija je mjesto na kojem se sve to susreće s korisnikom, i zato je testiranje weba posebna vještina.

Slika 13.1 – Ticketmaster, 15. 11. 2022: oko četiri puta više zahtjeva nego u ranijem vrhuncu
Slika 13.1 – Ticketmaster, 15. 11. 2022: oko četiri puta više zahtjeva nego u ranijem vrhuncu

Zašto ovo poglavlje

U poglavlju 3 testirali smo web stranicu DeliveryApp ručno: test slučajevi TS-KOR-01 … TS-KOR-06, istraživanje, izvještaji o defektu, i našli greške UI-01 i UI-02. U poglavlju 4 vidjeli smo da testovi kroz korisnički interfejs stoje na vrhu piramide: malo ih je, sporiji su, ali provjeravaju ono što korisnik zaista vidi. Sada te ručne testove automatizujemo alatom Playwright. Prvo ukratko kako radi web i šta se na njemu testira. Zatim Playwright: kako pronaći dugme (lokatori), kako sačekati da se nešto pojavi i kako provjeriti rezultat. Na kraju obrazac Page Object, testiranje u više preglednika i na telefonu, i provjere pristupačnosti.

Riječi ovog poglavlja (1/2)

  • Preglednik (browser) – program koji prikazuje web stranice: Chrome, Firefox, Safari, Edge.
  • HTML, CSS, JavaScript – sadržaj stranice, njen izgled i njeno ponašanje.
  • DOM (Document Object Model) – stranica kako je preglednik vidi: stablo elemenata koje JavaScript stalno mijenja.
  • Playwright – alat za automatsko upravljanje preglednikom: otvara stranicu, klikće, kuca i provjerava.
  • Lokator – opis kako pronaći element na stranici, npr. „dugme s imenom Naruči”.
  • Uloga (role) – šta element jeste za korisnika i čitač ekrana: dugme, polje, naslov, link.

Riječi ovog poglavlja (2/2)

  • Automatsko čekanje (auto-waiting) – Playwright sam sačeka da element bude vidljiv i spreman prije radnje ili provjere.
  • Page Object – klasa koja predstavlja stranicu i njene radnje, da testovi ne bi zavisili od detalja HTML-a.
  • Responzivnost – stranica se prilagođava ekranu: računar, tablet, telefon.
  • Pristupačnost (accessibility, a11y) – stranicu mogu koristiti i ljudi s invaliditetom: čitačem ekrana, samo tastaturom, uz uvećanje.
  • Trag (trace) – snimak izvršavanja testa korak po korak, sa slikama ekrana, za istraživanje pada.

Ciljevi poglavlja

Nakon poglavlja možete:

objasniti kako preglednik, stranica i server sarađuju; nabrojati šta se na web aplikaciji testira; instalirati Playwright i pokrenuti test stranice DeliveryApp; izabrati dobar lokator i objasniti zašto su uloga i oznaka bolji od CSS putanje; objasniti automatsko čekanje i zašto se ne koristi sleep; napisati provjere expect za tekst, vidljivost i stanje dugmeta; organizovati testove obrascem Page Object; pokrenuti testove u više preglednika i na ekranu telefona; napisati osnovne testove pristupačnosti; istražiti pad testa pomoću snimka ekrana i traga.

Plan poglavlja – Sedmica 13: tri časa teorije i tri časa praktične nastave

ČasSadržajNa času
Teorija 113.1–13.3 Kako radi web; šta testiramo; prvi Playwright testRučni TS-KOR-01 postaje automatski
Teorija 213.4–13.6 Lokatori; čekanje i provjere; istraživanje padaZašto sleep(2) nije rješenje
Teorija 313.7–13.9 Page Object; preglednici i telefon; pristupačnostNaručivanje samo tastaturom
Dio 1 · Sedmica 13

Dio 1 – Web i prvi automatski test

13.1 Kako radi web

Kad kupac otvori stranicu DeliveryApp, dešava se lanac koraka:

  1. preglednik pošalje HTTP zahtjev serveru (poglavlje 9);
  2. server vrati HTML (sadržaj: naslovi, dugmad, polja), CSS (izgled: boje, raspored) i JavaScript (ponašanje: šta se desi kad se klikne);
  3. preglednik od HTML-a napravi DOM, stablo elemenata, i nacrta ga na ekranu;
  4. kad kupac klikne „+” pored Margarite, JavaScript promijeni DOM: doda stavku u korpu i preračuna cijenu, bez novog učitavanja stranice;
  5. kad klikne „Naruči”, JavaScript pošalje zahtjev API-ju i prikaže odgovor.

Za testera, iz toga slijede tri važne stvari:

13.1 Kako radi web

  • Stranica se stalno mijenja. Cijena se ne pojavi odmah, nego kad JavaScript završi račun ili kad stigne odgovor servera. Test koji provjeri prerano vidi staru vrijednost.
  • Isti kod, različiti preglednici. Chrome, Firefox i Safari tumače HTML, CSS i JavaScript skoro isto, ali „skoro” je dovoljno za grešku.
  • Pravila se provjeravaju dva puta. Web stranica DeliveryApp računa cijenu sama, da kupac odmah vidi iznos, a server je računa ponovo (poglavlje 9), jer ne vjeruje klijentu. Obje kopije pravila moraju se slagati, i obje treba testirati.
Slika 13.2 – Web stranica DeliveryApp s narudžbom N-1001
Slika 13.2 – Web stranica DeliveryApp s narudžbom N-1001

13.1 Kako radi web

Stranica iz primjeri/deliveryapp/web/index.html je mala, ali ima sve što nam treba: jelovnik s dugmadima „−” i „+”, korpu, polja za udaljenost i kod, pregled cijene, dugme „Naruči” i, poslije narudžbe, dugmad za promjenu stanja. Sa ?v=0 na kraju adrese učitava prvu verziju s greškama D-01 … D-05, UI-01 i UI-02 (poglavlje 3).

Ukratko – 13.1 Kako radi web

  • Preglednik dobija HTML, CSS i JavaScript, pravi DOM i crta stranicu.
  • JavaScript stalno mijenja DOM, pa se rezultat na ekranu ne pojavljuje odmah.
  • Isti kod se u različitim preglednicima može ponašati malo drugačije.
  • Stranica DeliveryApp računa cijenu i sama i preko servera, pa se obje kopije pravila testiraju.

13.2 Šta se testira na webu

Web test nije samo „da li dugme radi”. Kontrolna lista, od funkcija ka kvalitetu:

13.2 Šta se testira na webu

ŠtaPitanjeDeliveryApp
funkcionalnostdaje li stranica tačan rezultat?N-1001 pokazuje 24,50 €
validacija unosaodbija li loš unos s jasnom porukom?11 km → „izvan zone dostave”, dugme Naruči onemogućeno
stanja i tokprate li dugmad i poruke pravila?otkazivanje u pripremi odbijeno (PP-6)
pregledniciradi li isto u Chrome, Firefox, Safari?isti testovi u tri preglednika
responzivnostradi li na telefonu?dugme Naruči vidljivo na ekranu 390 × 844
pristupačnostmože li se koristiti tastaturom i čitačem ekrana?dugmad imaju ime, polja imaju oznaku
performansekoliko brzo se učita i reaguje?alat Lighthouse u Chromeu
sigurnostmože li se ubaciti tuđi kod?ime kupca <script>… iz poglavlja 10

13.2 Šta se testira na webu

Ručni testovi iz poglavlja 3 i automatski iz ovog poglavlja dopunjuju se. Automatski test ponavlja provjeru tačnih vrijednosti hiljadu puta bez umora. Ali samo čovjek primijeti da je dugme ružno, da je poruka zbunjujuća ili da je polje za kod skriveno ispod dugmeta.

Ukratko – 13.2 Šta se testira na webu

  • Na webu se testiraju funkcionalnost, validacija unosa, tok stanja, preglednici, responzivnost, pristupačnost, performanse i sigurnost.
  • Automatski testovi neumorno provjeravaju tačne vrijednosti i ponašanje.
  • Ručni i istraživački testovi primjećuju ono što automat ne vidi: izgled, zbunjujuće poruke, nezgodan raspored.
  • Obje vrste testova se dopunjuju.

13.3 Prvi Playwright test

Playwright je alat koji upravlja pravim preglednikom: otvori stranicu, klikne, upiše, i provjeri šta piše. Napravila ga je firma Microsoft, besplatan je i radi s Chromiumom (osnova Chromea i Edgea), Firefoxom i WebKitom (osnova Safarija). Instalacija:

pip install pytest-playwright
playwright install chromium

Druga naredba preuzme preglednik koji Playwright koristi (nekoliko stotina MB, jednom).

Ručni test slučaj TS-KOR-01 iz poglavlja 3 („N-1001: 2 × Margarita, 1 × Sok, 4,2 km → 24,50 €”) postaje automatski test u tests_web/test_web.py:

13.3 Prvi Playwright test

STRANICA = (pathlib.Path(__file__).parent.parent / "web" / "index.html").resolve().as_uri()


@pytest.fixture
def deliveryapp(page: Page):
    page.goto(STRANICA)
    return page


def dodaj(page, naziv, puta=1):
    for _ in range(puta):
        page.get_by_role("button", name="Dodaj " + naziv).click()


def test_n1001_ukupno(deliveryapp):
    dodaj(deliveryapp, "Pizza Margarita", 2)
    dodaj(deliveryapp, "Sok")
    deliveryapp.get_by_test_id("udaljenost").fill("4.2")
    expect(deliveryapp.get_by_test_id("dostava")).to_have_text("3,00 €")
    expect(deliveryapp.get_by_test_id("ukupno")).to_have_text("24,50 €")

13.3 Prvi Playwright test

Fixture page daje pytest-playwright: novu, praznu karticu preglednika za svaki test. Stranica se otvara direktno iz fajla, bez servera. Ostalo se čita skoro kao ručni test slučaj: dodaj dvije Margarite i sok, upiši 4,2 km, očekuj dostavu 3,00 € i ukupno 24,50 €. Isti obrazac pripremi–izvrši–provjeri kao u poglavlju 5.

pytest tests_web
...............                                                          [100%]
15 passed in 3.17s

Preglednik se po defaultu ne vidi (radi „bez glave”, headless), zato je brz. Da biste gledali šta test radi, dodajte --headed --slowmo 500: preglednik se otvori, a svaki korak traje pola sekunde.

Nad prvom verzijom (DeliveryApp=v0, stranica s ?v=0):

13.3 Prvi Playwright test

FAILED tests_web/test_web.py::test_n1001_ukupno[chromium] - AssertionError: L...
FAILED tests_web/test_web.py::test_kod_malim_slovima[chromium] - AssertionErr...
FAILED tests_web/test_web.py::test_izvan_zone_poruka[chromium] - AssertionErr...
FAILED tests_web/test_web.py::test_kolicina_ne_moze_biti_negativna[chromium]
FAILED tests_web/test_web.py::test_otkazivanje_u_pripremi[chromium] - Asserti...
...
9 failed, 6 passed in 48.46s

Pet testova iz test_web.py hvata D-02, D-03, UI-01, UI-02 i D-04, a četiri iz test_web_po.py (13.7) još D-01 na tačno 30,00 €. Primijetite i vrijeme: 48 sekundi umjesto 3. Svaka pala provjera čeka do 5 sekundi da se tačna vrijednost možda ipak pojavi (13.5), pa tek onda prijavi pad.

Na času

Pokrenite playwright codegen s adresom stranice DeliveryApp. Otvore se preglednik i prozor u kojem Playwright zapisuje kod dok vi klikćete. Dodajte dvije Margarite i pogledajte kakve lokatore je izabrao. Snimljen kod je dobar početak, ali ga uvijek treba urediti: dodati provjere (expect) i ukloniti suvišne korake.

Ukratko – 13.3 Prvi Playwright test

  • Playwright upravlja pravim preglednikom (Chromium, Firefox, WebKit) i radi s pytestom preko pytest-playwright.
  • Fixture page daje novu karticu za svaki test.
  • Ručni test slučaj TS-KOR-01 postaje kratak automatski test s istim koracima i očekivanim rezultatom.
  • Nad prvom verzijom 9 od 15 web testova pada i otkriva D-01 … D-04, UI-01 i UI-02.

Provjeri se

  1. Šta je DOM? Stranica kako je preglednik vidi: stablo elemenata koje JavaScript stalno mijenja.
  2. Zašto web stranica DeliveryApp i server oba računaju cijenu? Stranica da kupac odmah vidi iznos, a server jer ne vjeruje broju koji bi poslao klijent.
  3. Šta radi playwright codegen? Otvori preglednik i zapisuje Playwright kod dok korisnik klikće.

Odgovori: tipka R ili klik na zamućeno polje.

Dio 2 · Sedmica 13

Dio 2 – Lokatori, čekanje i provjere

13.4 Lokatori: kako naći dugme

Da bi kliknuo dugme, test ga mora pronaći. Opis kako se element traži zove se lokator. Isti element se može naći na više načina, i razlika je velika (slika 13.3):

Slika 13.3 – Lokatori od najboljeg ka najgorem
Slika 13.3 – Lokatori od najboljeg ka najgorem

13.4 Lokatori: kako naći dugme

  1. Po ulozi (get_by_role): „dugme s imenom Naruči”. Tako element vide korisnik i čitač ekrana za slijepe. Ako se promijeni boja, raspored ili HTML oko dugmeta, test i dalje radi.
  2. Po oznaci (get_by_label): „polje s oznakom Udaljenost (km)”. Najbolje za polja forme.
  3. Po tekstu (get_by_text): „Korpa je prazna.” Dobro za poruke.
  4. Po test oznaci (get_by_test_id): atribut data-testid="ukupno" koji programeri dodaju posebno za testove. Stabilan, ali korisnik ga ne vidi, pa ne provjerava ništa o pristupačnosti.
  5. Po CSS ili XPath putanji: #jelovnik > div:nth-child(2) button. Opisuje strukturu stranice („drugo dugme u drugom redu”) i puca čim neko doda novo jelo ili omot oko dugmeta. Izbjegavati.

U stranici DeliveryApp dugmad „+” i „−” imaju samo znak, ali i opis za čitač ekrana: aria-label="Dodaj Pizza Margarita". Zato test može napisati get_by_role("button", name="Dodaj Pizza Margarita"). Ovdje se dobar test i dobra pristupačnost sreću: ako test ne može naći dugme po imenu, ne može ni slijepi korisnik.

Česta zabluda

„Najsigurnije je dodati data-testid na sve.” Test oznake su stabilne i korisne za elemente koji nemaju smisleno ime (npr. iznos 24,50 € u pregledu). Ali za dugmad i polja je bolje get_by_role i get_by_label: test tada usput provjerava i da element ima ime koje vide korisnik i čitač ekrana.

Ukratko – 13.4 Lokatori: kako naći dugme

  • Lokator opisuje kako se element pronalazi na stranici.
  • Najbolji su lokatori po ulozi i oznaci, jer opisuju element kako ga vidi korisnik.
  • Test oznake (data-testid) su stabilne, ali ne provjeravaju ništa o pristupačnosti.
  • CSS i XPath putanje opisuju strukturu stranice i pucaju pri svakoj izmjeni.

13.5 Automatsko čekanje i provjere

Stranica se mijenja asinhrono: klik na „+” pokrene JavaScript, koji tek poslije promijeni cijenu. Na sporom računaru to može trajati duže. Stari alati su tjerali testera da piše:

page.click("text=+")
time.sleep(2)                                    # nadam se da je dovoljno…
assert page.inner_text("#ukupno") == "24,50 €"

To je recept za nestabilan test (poglavlje 12): na brzom računaru gubi dvije sekunde, na sporom CI serveru ponekad nije dovoljno.

Playwright to rješava na dva mjesta:

  1. Prije radnje (click, fill) sam sačeka da element postoji, da je vidljiv, da nije onemogućen i da se ne pomjera.
  2. Provjere expect ponavljaju provjeru dok ne uspije ili dok ne istekne vrijeme (5 sekundi po defaultu). Ovo su tzv. provjere „za web” (web-first assertions).

13.5 Automatsko čekanje i provjere

expect(page.get_by_test_id("ukupno")).to_have_text("24,50 €")   # čeka dok tekst ne bude 24,50 €
expect(page.get_by_test_id("naruci")).to_be_disabled()           # čeka dok dugme ne bude onemogućeno
expect(page.get_by_test_id("poruka")).to_contain_text("izvan zone")
expect(page.get_by_label("Udaljenost (km)")).to_be_visible()

Najvažnije provjere:

13.5 Automatsko čekanje i provjere

ProvjeraŠta znači
to_have_text("…")tačan tekst elementa
to_contain_text("…")tekst sadrži dati dio
to_be_visible() / to_be_hidden()element se vidi / ne vidi
to_be_enabled() / to_be_disabled()dugme se može / ne može kliknuti
to_have_value("…")vrijednost u polju forme
to_have_count(n)lokator nalazi tačno n elemenata

Razlika između assert i expect je važna: assert page.get_by_test_id("ukupno").inner_text() == "24,50 €" pročita tekst jednom, u tom trenutku, i ne čeka. expect(...) čeka. Za web uvijek expect.

Ukratko – 13.5 Automatsko čekanje i provjere

  • Stranica se mijenja asinhrono, pa test koji provjeri prerano vidi staru vrijednost.
  • time.sleep čini test sporim i nestabilnim.
  • Playwright prije radnje sam čeka da element bude spreman, a expect ponavlja provjeru do 5 sekundi.
  • Za provjere na webu koristi se expect, a ne assert nad jednom pročitanom vrijednošću.

13.6 Kad test padne: poruka, slika, trag

Kad web test padne, prvo pitanje je: šta je bilo na ekranu? Playwright daje tri pomoći.

1. Poruka provjere. Pad testa granice na v0 (3,1 km):

>       expect(self.page.get_by_test_id("dostava")).to_have_text(tekst)
E       AssertionError: Locator expected to have text '3,00 €'
E       Actual value: 2,50 €
E       Call log:
E         - Expect "to_have_text" get_by_test_id("dostava") with timeout 5000ms
E         - waiting for get_by_test_id("dostava")
E           14 × locator resolved to <span id="dostava" data-testid="dostava">2,50 €</span>
E              - unexpected value "2,50 €"

Poruka kaže šta je očekivano, šta je dobijeno, i da je Playwright 14 puta provjerio u 5 sekundi prije nego što je odustao. To je N-1001 na v0: dostava 2,50 € umjesto 3,00 €, greška D-02.

13.6 Kad test padne: poruka, slika, trag

2. Snimak ekrana. pytest tests_web --screenshot only-on-failure sačuva sliku ekrana u trenutku pada, u folder test-results/. Slika je odlična za izvještaj o defektu (poglavlje 3).

3. Trag. pytest tests_web --tracing retain-on-failure za svaki pali test sačuva trag: svaki korak, sliku ekrana prije i poslije, DOM, mrežne zahtjeve i poruke konzole. Otvara se naredbom:

playwright show-trace test-results/<ime-testa>/trace.zip

U pregledniku traga možete ići korak po korak, unazad i unaprijed, kao da gledate snimak utakmice. Trag je posebno koristan za pad u CI-ju, gdje ne možete gledati preglednik uživo.

Ukratko – 13.6 Kad test padne: poruka, slika, trag

  • Poruka expect kaže šta je očekivano, šta je dobijeno i koliko puta je provjereno.
  • Opcija --screenshot only-on-failure čuva sliku ekrana u trenutku pada.
  • Opcija --tracing retain-on-failure čuva trag sa svakim korakom, DOM-om i mrežom.
  • Trag se otvara naredbom playwright show-trace i posebno pomaže kod padova u CI-ju.

Provjeri se

  1. Zašto je get_by_role("button", name="Naruči") bolji od CSS putanje? Opisuje element kako ga vidi korisnik, ne puca kad se promijeni struktura stranice, i usput provjerava da dugme ima ime.
  2. Koja je razlika između assert ... inner_text() == ... i expect(...).to_have_text(...)? assert pročita jednom i ne čeka; expect ponavlja provjeru dok ne uspije ili istekne vrijeme.
  3. Šta sadrži Playwright trag? Svaki korak testa sa slikama ekrana, DOM, mrežne zahtjeve i poruke konzole.

Odgovori: tipka R ili klik na zamućeno polje.

Dio 3 · Sedmica 13

Dio 3 – Organizacija, preglednici i pristupačnost

13.7 Page Object

U test_web.py svaki test sam zna da se dugme zove „Dodaj Pizza Margarita” i da polje ima data-testid="udaljenost". Kad dizajner promijeni natpis na „Dodaj u korpu: Pizza Margarita”, treba mijenjati svaki test. Obrazac Page Object rješava to tako što stranicu predstavi klasom s metodama za radnje kupca. Testovi pozivaju metode, a samo klasa zna HTML.

Slika iz života: daljinski upravljač. Pritisnete „glasnije” i ne zanima vas kakav je čip u televizoru. Ako proizvođač promijeni čip, novi daljinski ima isto dugme „glasnije”.

Fajl tests_web/stranica.py:

13.7 Page Object

class DeliveryAppStranica:
    def __init__(self, page: Page, adresa: str):
        self.page = page
        self.adresa = adresa

    def otvori(self):
        self.page.goto(self.adresa)
        return self

    def dodaj(self, jelo, puta=1):
        for _ in range(puta):
            self.page.get_by_role("button", name=f"Dodaj {jelo}").click()
        return self

    def udaljenost(self, km):
        self.page.get_by_label("Udaljenost (km)").fill(str(km))
        return self

    def ocekuj_dostavu(self, tekst):
        expect(self.page.get_by_test_id("dostava")).to_have_text(tekst)
    ...

13.7 Page Object

Metode vraćaju self, pa se radnje mogu nizati. Testovi u tests_web/test_web_po.py čitaju se kao rečenice:

13.7 Page Object

def test_n1001_kroz_page_object(deliveryapp):
    deliveryapp.dodaj("Pizza Margarita", 2).dodaj("Sok").udaljenost(4.2)
    deliveryapp.ocekuj_dostavu("3,00 €")
    deliveryapp.ocekuj_ukupno("24,50 €")


@pytest.mark.parametrize("korpa, dostava", [
    ([("Pizza Capricciosa", 2), ("Sok", 3)], "3,00 €"),          # 22,00 + 7,50 = 29,50 € (najbliže ispod granice)
    ([("Pizza Margarita", 2), ("Pizza Capricciosa", 1)], "0,00 €"),  # 19,00 + 11,00 = tačno 30,00 € (PP-4)
])
def test_granica_besplatne_dostave(deliveryapp, korpa, dostava):
    for jelo, puta in korpa:
        deliveryapp.dodaj(jelo, puta)
    deliveryapp.udaljenost(5)
    deliveryapp.ocekuj_dostavu(dostava)

13.7 Page Object

Primijetite drugi test. Granica od 30,00 € (poglavlje 8) na stranici se ne može testirati sa 29,99 €, jer su sve cijene u jelovniku višestruke od 0,50 €. Najbliži iznos ispod granice koji kupac može složiti je 29,50 €, a tačno 30,00 € daju dvije Margarite i jedna Capricciosa. Granične vrijednosti uvijek treba prilagoditi onome što korisnik stvarno može unijeti. Ovaj test na v0 pada za 30,00 € (D-01).

Ukratko – 13.7 Page Object

  • Page Object predstavlja stranicu klasom s metodama za radnje korisnika i provjere.
  • Samo klasa zna HTML, pa promjena stranice traži izmjenu na jednom mjestu.
  • Testovi s Page Objectom čitaju se kao rečenice: dodaj, upiši udaljenost, očekuj ukupno.
  • Granične vrijednosti se prilagođavaju onome što korisnik stvarno može unijeti, npr. 29,50 € i 30,00 €.

13.8 Više preglednika i ekran telefona

Isti testovi pokreću se u drugom pregledniku jednom opcijom:

playwright install firefox webkit
pytest tests_web --browser chromium --browser firefox --browser webkit

Svaki test se izvrši tri puta, a ime u izvještaju kaže gdje: test_n1001_ukupno[firefox]. WebKit je osnova Safarija, pa ovako na Windowsu i Linuxu dobijamo dobru aproksimaciju Safarija bez Apple računara.

Više od polovine posjeta na webu danas dolazi s telefona. Test na ekranu telefona pravi poseban kontekst preglednika s malim ekranom i dodirom:

13.8 Više preglednika i ekran telefona

def test_mobilni_ekran(browser):
    """Ista stranica na ekranu telefona (390 × 844): dugme Naruči mora biti vidljivo i upotrebljivo."""
    kontekst = browser.new_context(viewport={"width": 390, "height": 844}, is_mobile=True, has_touch=True)
    page = kontekst.new_page()
    page.goto(ADRESA)
    page.get_by_role("button", name="Dodaj Pizza Margarita").tap()
    naruci = page.get_by_role("button", name="Naruči")
    naruci.scroll_into_view_if_needed()
    expect(naruci).to_be_visible()
    expect(naruci).to_be_enabled()
    kontekst.close()

Umjesto click koristi se tap (dodir prstom). Playwright ima i gotove profile poznatih telefona (playwright.devices["iPhone 13"]), a pytest-playwright opciju --device "iPhone 13".

Emulacija nije isto što i pravi telefon: ekran i dodir se glume, ali procesor, mreža i stvarni Safari na iPhoneu nisu isti. Zato se uz automatske testove u emulaciji, prije izdanja, stranica proba i ručno na bar jednom pravom telefonu.

Ukratko – 13.8 Više preglednika i ekran telefona

  • Opcija --browser pokreće iste testove u Chromiumu, Firefoxu i WebKitu.
  • WebKit omogućava aproksimaciju Safarija na Windowsu i Linuxu.
  • Novi kontekst s malim ekranom i dodirom provjerava stranicu na telefonu.
  • Emulacija ne zamjenjuje ručnu provjeru na bar jednom pravom telefonu.

13.9 Pristupačnost

U poglavlju 10 rekli smo da stranicu treba da mogu koristiti i ljudi s invaliditetom. Standard WCAG ima stotine kriterija, ali tri najvažnija za početak mogu se testirati automatski:

  1. Svako dugme i polje ima ime koje čitač ekrana izgovori. Dugme „+” bez opisa čitač pročita kao „plus, dugme”, i slijepi korisnik ne zna uz koje jelo ide.
  2. Sve se može uraditi tastaturom. Ljudi koji ne mogu koristiti miš kreću se tipkom Tab i aktiviraju Enterom ili razmakom.
  3. Polja imaju vidljivu oznaku (<label>), a ne samo sivi tekst unutar polja koji nestane kad se počne kucati.

Testovi iz test_web_po.py:

13.9 Pristupačnost

def test_samo_tastaturom(page: Page):
    """Pristupačnost: kupac koji ne koristi miš mora moći dodati jelo i vidjeti cijenu."""
    page.goto(ADRESA)
    dugme = page.get_by_role("button", name="Dodaj Pizza Margarita")
    dugme.focus()
    page.keyboard.press("Enter")
    page.keyboard.press("Enter")
    expect(page.get_by_test_id("artikli")).to_have_text("19,00 €")


def test_polja_imaju_vidljive_oznake(page: Page):
    """Pristupačnost: čitač ekrana mora znati šta je koje polje."""
    page.goto(ADRESA)
    expect(page.get_by_label("Udaljenost (km)")).to_be_visible()
    expect(page.get_by_label("Kod popusta")).to_be_visible()
    for dugme in page.get_by_role("button").all():
        assert dugme.get_attribute("aria-label") or dugme.inner_text().strip()

13.9 Pristupačnost

Drugi test prolazi kroz sva dugmad na stranici i provjerava da svako ima ime, bilo kao vidljiv tekst („Naruči”) ili kao opis za čitač ekrana (aria-label). Kad neko sutra doda novo dugme bez imena, test padne.

Za detaljniju provjeru postoje alati kao axe (biblioteka axe-core, koja se može pozvati iz Playwrighta) i Lighthouse u Chromeu (kartica Lighthouse u alatima za programere). Oni provjeravaju i kontrast boja, redoslijed naslova, jezik stranice i desetine drugih pravila. Ali ni oni ne mogu reći da li je stranica zaista upotrebljiva slijepom korisniku: za to je potrebno probati je s čitačem ekrana (NVDA na Windowsu, VoiceOver na Macu i iPhoneu), a najbolje s osobom koja ga svakodnevno koristi.

13.9 Pristupačnost

Iz stvarnog svijeta

Pristupačnost nije samo dobra volja. Evropski akt o pristupačnosti (European Accessibility Act), čija se pravila primjenjuju od juna 2025. godine, traži da mnoge digitalne usluge u EU, među njima i online prodaja, budu pristupačne. Firme koje prodaju u EU, uključujući one iz BiH, moraju to provjeravati.

Ukratko – 13.9 Pristupačnost

  • Tri osnovne provjere pristupačnosti su: svako dugme i polje ima ime, sve radi tastaturom, polja imaju vidljivu oznaku.
  • Playwright testovi mogu provjeriti rad tastaturom i imena svih dugmadi na stranici.
  • Alati axe i Lighthouse provjeravaju desetine pravila, uključujući kontrast boja.
  • Stvarnu upotrebljivost za slijepe potvrđuje tek proba s čitačem ekrana.

Provjeri se

  1. Šta je Page Object i koja je njegova korist? Klasa koja predstavlja stranicu i njene radnje; kad se stranica promijeni, mijenja se samo ta klasa, a ne svi testovi.
  2. Kako se isti testovi pokreću u tri preglednika? Opcijom --browser chromium --browser firefox --browser webkit.
  3. Zašto dugme „+” mora imati aria-label? Da čitač ekrana izgovori šta dugme radi, npr. „Dodaj Pizza Margarita”; tada ga i test može naći po imenu.

Odgovori: tipka R ili klik na zamućeno polje.

Praksa · Sedmica 13

Praktična nastava – Playwright i stranica DeliveryApp

Praktična nastava – Playwright i stranica DeliveryApp

Cilj je automatizovati ručne test slučajeve iz poglavlja 3, organizovati ih obrascem Page Object, pokrenuti ih u više preglednika i na ekranu telefona, i provjeriti pristupačnost. Radi se u parovima. Prije početka: pip install pytest-playwright, pa playwright install chromium firefox webkit.

Korak 1 – Prvi testovi (40 minuta)

  1. U primjeri/deliveryapp pokrenite pytest tests_web nad ispravnom i nad prvom verzijom. Zapišite koji testovi padaju i koju grešku hvata svaki.
  2. Pokrenite jedan test sa --headed --slowmo 500 i gledajte preglednik.
  3. Pokrenite playwright codegen nad stranicom i snimite narudžbu 4 × Capricciosa na 2,5 km (stranica ima samo jelovnik Picerije). Uredite snimljen kod u test s provjerama (expect): artikli 44,00 €, dostava 0,00 € (PP-4), ukupno 44,00 €.

Korak 2 – Ručni testovi postaju automatski (50 minuta)

  1. Uzmite svoje test slučajeve TS-KOR-01 … TS-KOR-06 iz poglavlja 3. Za svaki napišite metodu ili test koristeći DeliveryAppStranica. Ako nekoj radnji fali metoda (npr. ocekuj_poruku), dodajte je u stranica.py.
  2. Za svaki test prvo zapišite očekivani rezultat iz pravila, pa tek onda pokrenite.
  3. Dodajte test za kod " STUDENT10 " s razmacima i za nepoznat kod STUDENT20.

Korak 3 – Kad test padne (30 minuta)

  1. Pokrenite nad v0: pytest tests_web --screenshot only-on-failure --tracing retain-on-failure.
  2. Otvorite trag jednog palog testa naredbom playwright show-trace … i prođite korak po korak. U kojem koraku se prvi put vidi pogrešna vrijednost?
  3. Napišite izvještaj o defektu za UI-02 (negativna količina) sa snimkom ekrana iz test-results/.

Korak 4 – Preglednici, telefon, pristupačnost (60 minuta)

  1. Pokrenite sve web testove u tri preglednika. Da li neki test prolazi u jednom, a pada u drugom? Ako da, istražite zašto.
  2. Pokrenite testove sa --device "iPhone 13". Šta se mijenja?
  3. Napišite test u kojem kupac samo tastaturom napravi cijelu narudžbu: doda dvije Margarite, upiše udaljenost, i klikne Naruči (koristite page.keyboard.press("Tab") i "Enter"). Uspijeva li? Ako ne, zapišite nalaz pristupačnosti.
  4. Otvorite stranicu u Chromeu, alati za programere (F12), kartica Lighthouse, kategorija „Accessibility”. Zapišite ocjenu i tri najvažnije preporuke.
  5. U svojoj kopiji index.html uklonite aria-label s jednog dugmeta. Koji test pada?

Rezultat koji se predaje: fajl rezultati-13.md s tabelom web testova nad obje verzije i greškom koju hvata svaki; prošireni stranica.py i testovi za TS-KOR-01 … TS-KOR-06; izvještaj o defektu UI-02 sa slikom ekrana; rezultati u tri preglednika i na telefonu; test samo tastaturom i nalazi Lighthousea.

Vježbe

Vježbe za studenta

Rješenja su sakrivena – tipka R ili klik na okvir.

Vježba za studenta 1 – lokatori.

Zadatak

Poredajte lokatore od najboljeg ka najgorem i objasnite: a) page.locator("div.pregled > button.glavno"); b) page.get_by_role("button", name="Naruči"); c) page.get_by_test_id("naruci"); d) page.locator("//section[3]/button[1]").

Vježba za studenta 1 – lokatori. – rješenje

Rješenje (R)

b) uloga i ime, kako dugme vidi korisnik i čitač ekrana; c) test oznaka, stabilna ali bez provjere pristupačnosti; a) CSS putanja, puca kad se promijene klase ili omot; d) XPath po rednom broju sekcije i dugmeta, najkrhkiji: puca čim se doda nova sekcija.

Vježba za studenta 2 – čekanje.

Zadatak

Prepravite test tako da ne koristi sleep:

page.get_by_role("button", name="Naruči").click()
time.sleep(3)
assert page.get_by_test_id("stanje").inner_text() == "NOVA"

Vježba za studenta 2 – čekanje. – rješenje

Rješenje (R)
page.get_by_role("button", name="Naruči").click()
expect(page.get_by_test_id("stanje")).to_have_text("NOVA")

expect čeka dok stanje ne bude NOVA (do 5 sekundi), pa je test brz kad je stranica brza i stabilan kad je spora.

Vježba za studenta 3 – Page Object.

Zadatak

Dodajte u DeliveryAppStranica metodu ocekuj_poruku(tekst) i napišite test za 11 km koji je koristi.

Vježba za studenta 3 – Page Object. – rješenje

Rješenje (R)
    def ocekuj_poruku(self, tekst):
        expect(self.page.get_by_test_id("poruka")).to_contain_text(tekst)


def test_izvan_zone(deliveryapp):
    deliveryapp.dodaj("Pizza Margarita", 2).udaljenost(11)
    deliveryapp.ocekuj_poruku("izvan zone")

Na v0 test pada, jer stranica pokazuje „Greška 422” (UI-01).

Vježba za studenta 4 – granice na stranici.

Zadatak

Na stranici se mogu naručiti samo Margarita (9,50 €), Capricciosa (11,00 €) i Sok (2,50 €). Koje korpe biste izabrali za granicu PP-1 (najmanje 5,00 €)?

Vježba za studenta 4 – granice na stranici. – rješenje

Rješenje (R)

Ispod granice: 1 × Sok = 2,50 € (najveći iznos ispod 5,00 € koji se može složiti je 2,50 €, jer su sve cijene višestruke od 0,50 €, a 4,50 € nije moguće). Na granici: 2 × Sok = 5,00 €. Očekivano: 2,50 € odbijeno s porukom o minimalnoj narudžbi; 5,00 € prihvaćeno. Iznos 4,99 € iz poglavlja 8 testira se na nivou API-ja i funkcije, gdje se može unijeti.

Vježba za studenta 5 – pristupačnost.

Zadatak

Dizajner želi da polje za kod popusta nema oznaku, nego samo sivi tekst „npr. STUDENT10” unutar polja, „da bude čistije”. Šta odgovarate i koji test bi to otkrio?

Vježba za studenta 5 – pristupačnost. – rješenje

Rješenje (R)

Sivi tekst (placeholder) nestane čim kupac počne kucati, a mnogi čitači ekrana ga ne čitaju kao oznaku; ljudi s lošijim vidom ga teško vide zbog slabog kontrasta. Polje mora imati pravu oznaku (<label>). Test test_polja_imaju_vidljive_oznake bi pao, jer get_by_label("Kod popusta") ne bi našao polje.

Sažetak u pet rečenica

  1. Ticketmaster je 2022. dobio oko četiri puta više zahtjeva nego ikada ranije, a priča pokazuje koliko dijelova mora raditi zajedno da bi jedan klik na web stranici uspio.
  2. Web stranica je HTML, CSS i JavaScript koji stalno mijenja DOM, a testiraju se funkcionalnost, unos, tok stanja, preglednici, telefon, pristupačnost, performanse i sigurnost.
  3. Playwright upravlja pravim preglednikom, a najbolji lokatori su po ulozi i oznaci, jer opisuju element kako ga vide korisnik i čitač ekrana.
  4. Playwright sam čeka da element bude spreman, provjere expect ponavljaju se do 5 sekundi umjesto nestabilnog sleep, a pad se istražuje porukom, slikom ekrana i tragom.
  5. Page Object čuva detalje stranice na jednom mjestu, isti testovi rade u tri preglednika i na ekranu telefona, a testovi tastature i imena dugmadi provjeravaju osnove pristupačnosti; na prvoj verziji DeliveryApp pada 9 od 15 web testova.

Pitanja za ponavljanje

  1. Šta se desilo s Ticketmasterom 2022. i šta to govori o web aplikacijama?
  2. Kako preglednik prikazuje stranicu? Šta su HTML, CSS, JavaScript i DOM?
  3. Šta se sve testira na web aplikaciji?
  4. Kako se instalira i pokreće Playwright s pytestom?
  5. Šta je lokator? Poredajte vrste lokatora od najboljeg ka najgorem.
  6. Zašto je get_by_role dobar i za pristupačnost?
  7. Zašto je time.sleep loš u web testovima i šta ga zamjenjuje?
  8. Koja je razlika između assert i expect u Playwrightu?
  9. Kako se istražuje pad web testa? Šta je trag?
  10. Šta je Page Object i koja je njegova korist?
  11. Kako je testirana granica od 30,00 € na stranici i zašto ne sa 29,99 €?
  12. Kako se testovi pokreću u više preglednika i na ekranu telefona?
  13. Koje su tri osnovne provjere pristupačnosti i kako se testiraju?
  14. Koliko web testova pada na prvoj verziji i koje greške hvataju?