Postani tester

11 najčešćih problema sa Playwright: Greške u konfiguraciji i loše prakse

11. mart 2026.·Nenad Cvetković

1. Struktura direktorijuma i imenovanje testova

1.1 Nepravilna struktura test direktorijuma

1.1.1 Podrazumevana očekivanja Playwright-a (direktorijumi tests ili specs)

Playwright Test runner dolazi sa jasno definisanim konvencijama koje se očekuju prilikom organizacije test datoteka. Kada se inicijalizuje novi Playwright projekat putem komande npm init playwright@latest, alat automatski kreira direktorijum pod nazivom tests u kome se očekuje da budu smešteni svi test fajlovi (NareshIT) . Ova konvencija nije proizvoljna - ona je duboko ugrađena u arhitekturu test runner-a i omogućava efikasno otkrivanje i izvršavanje testova bez dodatne konfiguracije. Alternativno, Playwright prepoznaje i direktorijum specs kao validnu lokaciju za testove.

Mnogi razvojni timovi, posebno oni koji prelaze sa drugih testnih framework-a poput Jest-a ili Cypress-a, čine grešku što odmah pokušavaju da prilagode ovu strukturu svojim postojećim navikama. Na primer, tim može odlučiti da smesti testove u direktorijum e2e-tests, automation, qa-tests ili bilo koji drugi proizvoljan naziv. Bez odgovarajuće rekonfiguracije, Playwright jednostavno neće moći da locira test datoteke, rezultirajući potpunim neuspehom izvršavanja test suite-a (Testdino) .

Važno je razumeti da Playwright ne vrši rekurzivnu pretragu celog projektnog direktorijuma po default-u. Umesto toga, fokusira se isključivo na putanju specificiranu kroz testDir opciju u konfiguracionoj datoteci. Ovo ponašanje se razlikuje od nekih drugih test framework-a koji mogu imati agresivnije strategije otkrivanja testova, što dodatno naglašava važnost eksplicitne konfiguracije.

1.1.2 Posledice neažuriranja testDir u konfiguraciji

Kada se testDir opcija ne pravilno konfiguriše, posledice su odmah vidljive i frustrirajuće. Playwright će pri pokretanju komande npx playwright test izvestiti da nije pronašao nijedan test, često uz poruku "No Tests Found" koja ne pruža dovoljno konteksta za brzo dijagnostikovanje problema (Testdino) . Ova greška može uzrokovati značajno gubitak vremena tokom debagovanja, posebno ako razvojni tim nije upoznat sa internim mehanizmima Playwright-ovog test runner-a.

U praksi, ovaj problem se manifestuje na sledeći način: razvojni tim kreira novi fajl login.test.js u direktorijumu e2e/tests/, pokreće komandu za izvršavanje testova, i dobija izveštaj da nije pronađen nijedan test. Prva reakcija je često provera sadržaja fajla - da li su importi ispravni, da li je sintaksa testa tačna, da li su sve zagrade zatvorene. Tek nakon značajnog vremena utrošenog na debagovanje samog koda, dolazi se do zaključka da problem leži u konfiguraciji.

Još jedan aspekt ovog problema je ponašanje u različitim operativnim sistemima. Na Windows platformi, putanje sa obrnutim kosa crtama (\) mogu uzrokovati dodatne komplikacije kada se koriste u kombinaciji sa regularnim izrazima u testMatch konfiguraciji. Preporučena praksa je korišćenje pravih kosa crta (/) koje su univerzalno kompatibilne, ili pak korišćenje path.join() i path.resolve() metoda iz Node.js standardne biblioteke za programsko konstruisanje putanja.

1.1.3 Greška "No Tests Found" kao rezultat pogrešne putanje

Greška "No Tests Found" predstavlja fundamentalni indikator da Playwright test runner ne može da locira nijedan fajl koji odgovara kriterijumima za testove. Ova greška se ne odnosi isključivo na probleme sa testDir - ona može biti rezultat kombinacije više faktora, uključujući i neispravno testMatch podešavanje (NareshIT) .

Detaljna analiza ove greške otkriva da Playwright prvo primenjuje testDir filter da bi ograničio pretragu na određeni direktorijum, a zatim primenjuje testMatch filter da bi identifikovao koje fajlove unutar tog direktorijuma treba tretirati kao testove. Ako testDir pokazuje na nepostojeći direktorijum ili na direktorijum koji ne sadrži odgovarajuće fajlove, drugi filter nema šta da obradi. Rezultat je ista greška kao da su svi fajlovi eksplicitno isključeni.

Za razvojne timove koji rade na velikim projektima sa monorepo strukturom, ovaj problem može biti posebno izražen. U takvim okruženjima, testovi za različite pakete ili module mogu biti rasprostranjeni na više lokacija, a centralizovana konfiguracija može postati kompleksna. Rešenje u takvim slučajevima čini korišćenje više konfiguracionih fajlova ili dinamičko određivanje testDir na osnovu trenutnog radnog direktorijuma.

1.2 Nepravilno imenovanje datoteka sa testovima

1.2.1 Očekivani sufiksi (.spec.js, .test.js, .spec.ts, .test.ts)

Pored strukture direktorijuma, Playwright postavlja stroga očekivanja i u pogledu imenovanja samih test datoteka. Podrazumevano, test runner prepoznaje datoteke koje se završavaju sufiksima .spec.js, .test.js, .spec.ts ili .test.ts (NareshIT) . Ova konvencija proizilazi iz šire ekosistemske prakse u JavaScript/TypeScript zajednici, gde su .spec (specifikacija) i .test (test) standardni sufiksi za identifikaciju test datoteka.

Problem nastaje kada timovi koriste alternativne šeme imenovanja - login-tests.js, checkout_scenarios.ts, user-flow.e2e.js ili jednostavno tests.js bez odgovarajućeg sufiksa. U takvim slučajevima, Playwright će potpuno ignorisati ove datoteke prilikom skeniranja za testovima, čak i ako one sadrže validne testne funkcije definisane pomoću test() API-ja (testRigor) . Ovo ponašanje može biti posebno zbunjujuće za korisnike koji dolaze iz ekosistema gde imenovanje datoteka nije striktno vezano za prepoznavanje testova.

Važno je napomenuti da Playwright podržava i druge jezike i odgovarajuće sufikse: .spec.mjs, .test.mjs za ES module, .spec.cjs, .test.cjs za CommonJS module, kao i .spec.tsx i .test.tsx za React komponente testirane kroz Playwright. Međutim, korišćenje nestandardnih sufiksa poput _test.js, .e2e.js, ili .playwright.js zahteva eksplicitnu konfiguraciju testMatch opcije, što uvodi dodatnu složenost.

1.2.2 Konfiguracija testMatch uzoraka u playwright.config.js

Za situacije gde postojeći naming convention ne odgovara Playwright-ovim podrazumevanim očekivanjima, konfiguraciona opcija testMatch pruža fleksibilnost za prilagođavanje. Ova opcija prihvata glob uzorke ili regularne izraze koji određuju koje datoteke će biti tretirane kao testovi. Podrazumevana vrednost testMatch je **/*.@(spec|test).?(c|m)[jt]s?(x), što pokriva sve standardne varijante imenovanja.

Tipična greška je korišćenje preširokog uzorka koji uključuje i datoteke koje nisu testovi, ili preuskog uzorka koji isključuje validne testove. Na primer:

// POGREŠNO - preširok uzorak
testMatch: '**/*.js'  // Uključuje SVE .js datoteke, uključujući utils i helpers

// POGREŠNO - preuzak uzorak
testMatch: '**/tests/*.spec.js'  // Ne uključuje testove u poddirektorijumima

// ISPRAVNO - precizan uzorak
testMatch: [
  '**/tests/**/*.spec.{js,ts}',
  '**/tests/**/*.test.{js,ts}',
  '!**/tests/**/utils/**'  // Isključi helper direktorijum
]

1.2.3 Preklapanje između testDir i testMatch pravila

Kompleksnost se povećava kada se razmotri interakcija između testDir i testMatch pravila. Ove dve opcije rade u kombinaciji: testDir definiše početnu tačku pretrage, dok testMatch filtrira rezultate unutar te tačke (testRigor) . Nepravilna kombinacija ovih dva parametra može rezultirati situacijama gde su test datoteke fizički prisutne na sistemu, ali ih Playwright jednostavno "ne vidi".

Na primer, ako je testDir postavljen na ./e2e a testMatch na tests/**/*.spec.js, Playwright će tražiti datoteke u e2e/tests/**/*.spec.js. Ako se testovi zapravo nalaze direktno u e2e/ bez tests/ poddirektorijuma, neće biti pronađeni. Slično, ako je datoteka u ./e2e/login.js bez .test sufiksa, biće ignorisana zbog testMatch filtera.

ScenariotestDirtestMatchRezultat
Standardna struktura./testsPodrazumevano✓ Testovi pronađeni
Nestandardni direktorijum./e2e (nevažeći)Podrazumevano✗ "No Tests Found"
Nestandardni sufiks./tests**/*.e2e.jsZavisi od imenovanja fajlova
Kombinovani problem./e2etests/**/*.spec.js✗ Testovi izvan putanje

Table 1: Interakcija između testDir i testMatch opcija

2. Greške u konfiguracionoj datoteci playwright.config.js / playwright.config.ts

2.1 Sintaksne greške i nepravilna struktura

2.1.1 Pogrešno postavljanje opcija na nivou use umesto globalnog nivoa

Jedna od najčešćih i najteže uočljivih grešaka u Playwright konfiguraciji jeste pogrešno postavljanje opcija na nivou use bloka umesto na globalnom nivou, ili obrnuto. Playwright jasno razlikuje između test runner opcija koje su globalne (npr. timeout, retries, workers, fullyParallel) i test opcije koje se nalaze unutar use bloka (npr. baseURL, headless, viewport, screenshot, trace). Ova distinkcija je kritična jer pogrešno postavljanje može dovesti do toga da se opcije jednostavno ignorišu, bez bilo kakve upozorenja.

Globalne opcije kontrolišu ponašanje samog test runner-a: kako se testovi raspoređuju, koliko dugo smeju da traju, koliko puta se ponavljaju u slučaju neuspeha, i kako se izveštava o rezultatima. Opcije unutar use bloka, s druge strane, definišu podrazumevane vrednosti za svaki novi browser kontekst koji se kreira tokom testova. One utiču na to kako browser ponaša - da li radi u headless režimu, koje dimenzije ekrana ima, koji je korisnički agent, i slično.

2.1.2 Primer: timeout i retries u use bloku umesto kao globalne opcije

Konkretan primer ove greške dokumentovan je u zajedničkim resursima, gde je korisnik imao sledeću problematičnu konfiguraciju (Stack Overflow) :

// POGREŠNO: timeout i retries u use bloku
const config = {
  use: {
    timeout: 45000,  // Ovo NEĆE raditi kao očekivano
    retries: 2,      // Ovo takođe neće raditi
    headless: true,
  },
};

U ovom primeru, timeout i retries su pogrešno smešteni unutar use objekta. Kao rezultat, testovi će se izvršavati sa podrazumevanim globalnim timeout-om od 30 sekundi, dok korisnik veruje da je produžio vremensko ograničenje. Slično, retries opcija neće uticati na ponašanje test runner-a prilikom ponovnog pokušaja neuspešnih testova.

Ispravna konfiguracija zahteva pomeranje ovih opcija na globalni nivo:

// ISPRAVNO: timeout i retries na globalnom nivou
const config = {
  timeout: 45000,    // Globalno vremensko ograničenje za testove
  retries: 2,        // Globalni broj ponovnih pokušaja
  use: {
    headless: true,  // Opcije specifične za browser kontekst
  },
};

2.1.3 Nepravilan povratni tip u globalSetup funkcijama

Playwright podržava globalSetup i globalTeardown funkcije koje se izvršavaju pre i posle celokupnog test suite-a. Ove funkcije se često koriste za inicijalizaciju testnih podataka, pokretanje pomoćnih servisa ili globalnu autentifikaciju. Međutim, postoje specifični zahtevi za povratni tip ovih funkcija koje se često zanemaruju.

globalSetup funkcija može vratiti funkciju koja će biti korišćena kao globalTeardown, ili undefined ako nema potrebe za čišćenjem. Ako funkcija vraća objekat ili bilo koju drugu vrednost, Playwright će pokušati da je tretira kao teardown funkciju, što može dovesti do neočekivanih grešaka. Slično, ako globalSetup baci izuzetak, celokupan testni ciklus će biti prekinut pre nego što bilo koji test bude izvršen.

// ISPRAVNO: globalSetup vraća teardown funkciju
async function globalSetup() {
  await setupDatabase();

  return async () => {
    await teardownDatabase();
  };
}

export default globalSetup;

2.2 Ignorisanje konfiguracije kroz direktnu inicijalizaciju browsera

2.2.1 Korišćenje firefox.launch() umesto Playwright Test API-ja

Osnovni playwright paket omogućava direktno pokretanje browsera putem poziva poput chromium.launch(), firefox.launch() ili webkit.launch(). Dok je ovaj pristup validan za skripte za automatizaciju koje nisu testovi, njegovo korišćenje unutar testnih datoteka koje bi trebalo da koriste @playwright/test runner dovodi do potpunog zaobilaženja konfiguracione datoteke (Stack Overflow) .

Kada programer ručno pokreće browser, sve postavke definisane u playwright.config.js - uključujući baseURL, viewport, headless režim, screenshot i video konfiguraciju, trace opcije, kao i sve projektno-specifične postavke - postaju neprimjenjive. Test će se izvršiti u potpuno izolovanim okruženju koje ne odražava nameravano ponašanje definisano u konfiguraciji.

// POGREŠNO: Direktna inicijalizacija ignorise konfiguraciju
import { firefox } from 'playwright';
import { test } from '@playwright/test';

test('test not using configuration', async () => {
  const browser = await firefox.launch();  // Ignoriše sve iz config-a
  const context = await browser.newContext();
  const page = await browser.newPage();
  // ... test kod
  await browser.close();
});

2.2.2 Zaobilazenje konfiguracije kroz ručno kreiranje browser konteksta

Sličan problem nastaje kada se unutar testova ručno kreira browser kontekst umesto korišćenja fixture-a koji pruža @playwright/test. Playwright Test runner automatski upravlja životnim ciklusom browsera, konteksta i stranica, pružajući izolaciju između testova i primenjujući konfigurisane postavke.

// POGREŠNO: Ručno kreiranje konteksta
test('manual context', async ({ browser }) => {
  const context = await browser.newContext({
    viewport: { width: 800, height: 600 }, // Override konfiguracije
  });
  const page = await context.newPage();
  // Konfiguracija iz playwright.config.js je ignorisana
});

// ISPRAVNO: Korišćenje fixture-a
test('using fixture', async ({ page }) => {
  // page je automatski kreiran sa primenjenim konfiguracijama
  await page.goto('/');
});

2.2.3 Razlika između playwright i @playwright/test paketa

Fundamentalno razumevanje razlike između ova dva paketa je ključno za ispravnu upotrebu Playwright-a:

Aspektplaywright paket@playwright/test paket
NamenaBrowser automatizacija niskog nivoaEnd-to-end testiranje sa test runner-om
Glavni izvozichromium, firefox, webkittest, expect, devices
KonfiguracijaNema ugrađenu konfiguracijuPotpuna podrška za playwright.config.js
FixturesNemaBogat sistem fixture-a
Paralelno izvršavanjeRučno implementiratiUgrađena podrška sa worker-ima
IzveštavanjeRučno implementiratiHTML, JSON, JUnit reporteri
RetriesNemaKonfigurabilni

Table 2: Poređenje playwright i @playwright/test paketa

Kada se koristi @playwright/test, testne datoteke treba da uvoz funkcije test i expect iz tog paketa, a ne iz osnovnog playwright paketa. Ovo osigurava da se sve prednosti test runner-a - uključujući automatsku primenu konfiguracije, paralelno izvršavanje, praćenje i izveštavanje - iskoriste u punoj meri.

3. Hardkodiranje vrednosti specifičnih za okruženje

3.1 Ugradnja URL-ova, kredencijala i putanja direktno u kod

3.1.1 Problemi sa prenosivostju između razvojnog i produkcionog okruženja

Hardkodiranje vrednosti koje variraju između različitih okruženja predstavlja jednu od najrasprostranjenijih loših praksi u test automatizaciji. Najčešći primeri uključuju direktno ugrađivanje URL-ova aplikacije (https://staging.example.com), API ključeva (sk_test_abc123), kredencijala (username: 'testuser'), i sistemskih putanja (/home/user/projects/) direktno u test kod ili konfiguracionu datoteku (AppSignal Blog) .

Primarni problem sa hardkodiranim vrednostima je neprenosivost. Test koji sadrži await page.goto('http://localhost:3000/login') će funkcionisati isključivo u lokalnom razvojnom okruženju gde aplikacija zaista radi na tom portu. Kada isti test bude izvršen u CI okruženju gde je aplikacija dostupna na drugoj adresi, ili u staging okruženju sa HTTPS protokolom, test će neizbežno pasti (AppSignal Blog) . Ova fragilnost forsira programere da ručno modifikuju kod prilikom svakog prelaska između okruženja, što je ne samo neefikasno već i izvor potencijalnih grešaka.

3.1.2 Otežano održavanje pri promeni infrastrukture

Hardkodirane vrednosti stvaraju tehnički dug koji se akumulira eksponencijalno sa rastom projekta. Kada infrastruktura evoluira - na primer, migracija sa monolitne na mikroservisnu arhitekturu, promena domena, ili uvođenje CDN-a - svaka hardkodirana vrednost mora biti ručno pronađena i ažurirana. U velikom test suite-u, ovaj proces može biti podložan greškama i značajno usporiti deployment (AppSignal Blog) .

Playwright pruža elegantno rešenje za ovaj problem kroz kombinaciju environment varijabli i baseURL konfiguracije:

// playwright.config.js
export default defineConfig({
  use: {
    baseURL: process.env.BASE_URL || 'http://localhost:3000',
  },
});

// Test datoteka
test('user can login', async ({ page }) => {
  await page.goto('/login'); // Koristi baseURL iz konfiguracije
});

3.2 Nepravilno upravljanje testnim podacima

3.2.1 Statički podaci umesto dinamičke generacije

Korišćenje istih statičkih podataka u više testova ili u više izvršavanja istog testa može dovesti do konflikata i nepredvidivih rezultata. Na primer, ako test kreira korisnika sa fiksnim email adresom test@example.com, drugo izvršavanje istog testa će pokušati da kreira istog korisnika, što će rezultirati greškom o duplikatu (firm86.com) . Ovo ponašanje čini testove zavisnim od redosleda izvršavanja i stanja baze podataka, direktno suprotno principu izolacije testova.

Dinamička generacija podataka korišćenjem biblioteka poput faker ili jednostavnih tehnika kao što su timestamp-ovi i slučajni stringovi rešava ovaj problem:

import { faker } from '@faker-js/faker';

test('user registration', async ({ page }) => {
  const email = faker.internet.email(); // Jedinstven za svaki pokret
  await page.fill('[name="email"]', email);
  // ...
});

3.2.2 Deljenje stanja između testova kroz globalne promenljive

Globalne promenljive predstavljaju anti-pattern u test automatizaciji koji podriva izolaciju i reproducibilnost testova. Kada testovi dele stanje kroz globalne objekte - bilo da se radi o korisničkim sesijama, ID-evima kreiranih entiteta, ili privremenim podacima - ponašanje jednog testa može uticati na ponašanje drugog (BrowserStack) . Ovo kreše temeljni princip da svaki test treba da bude nezavisan i da proizvodi isti rezultat bez obzira na redosled izvršavanja ili prisustvo drugih testova.

U Playwright kontekstu, globalne promenljive su posebno opasne zbog paralelnog izvršavanja testova. Kada se testovi izvršavaju istovremeno u različitim worker procesima, pristup istoj globalnoj promenljivoj može dovesti do race condition-a i nepredvidivih rezultata. @playwright/test pruža fixture-e kao alternativu - mehanizam koji omogućava definisanje zavisnosti koje se automatski kreiraju za svaki test i čiste nakon njegovog završetka, osiguravajući potpunu izolaciju.

3.2.3 Nedostatak mehanizama za čišćenje podataka nakon testova

Svaki test koji kreira podatke - bilo da se radi o korisnicima, porudžbinama, fajlovima, ili bilo kojim drugim entitetima - ima odgovornost da očisti te podatke nakon završetka. Propust u ovoj oblasti dovodi do akumulacije "mrtvih" podataka u testnom okruženju, što usporava testove, troši resurse, i može dovesti do konflikata sa budućim testovima (firm86.com) .

Playwright pruža test.afterEach() i test.afterAll() hook-ove za implementaciju čišćenja, ali njihovo korišćenje zahteva disciplinu i planiranje. Napredniji pristup uključuje korišćenje API-ja za direktno brisanje podataka, što je značajno brže od UI-baziranog čišćenja i manje podložno greškama.

4. Zanemarivanje prilagođavanja za CI/CD okruženje

4.1 Nepravilna konfiguracija paralelnog izvršavanja

4.1.1 Previše radnika (workers) u resursno ograničenim CI okruženjima

Playwright podrazumevano pokreće testove sa optimalnim brojem worker procesa baziranim na dostupnim CPU jezgrima. U lokalnom okruženju sa moćnom mašinom, ovo obično funkcioniše dobro. Međutim, CI okruženja često imaju značajno ograničenije resurse - manje CPU jezgara, manje RAM memorije, i sporije disk operacije (Autify) . U takvim scenarijima, podrazumevani broj worker-a može biti previše, rezultirajući prekomernom konkurencijom za resurse i degradacijom performansi.

Konkretno, ako CI agent ima 2 CPU jezgra a Playwright pokušava da pokrene 4 worker-a, svaki worker će dobijati nedovoljno procesorskog vremena, što dovodi do sporijeg izvršavanja testova i povećane verovatnoće timeout grešaka. U ekstremnim slučajevima, prekomerna potrošnja memorije može dovesti do ubijanja procesa od strane operativnog sistema, rezultirajući kriptičnim greškama koje su teške za dijagnostikovanje.

4.1.2 Nedostatak uslovljavanja broja radnika prema okruženju (process.env.CI)

Idealna konfiguracija treba da se razlikuje između lokalnog razvojnog okruženja i CI okruženja. Lokalno, veći broj worker-a ubrzava iteraciju, dok u CI-ju, manji broj osigurava stabilnost. Playwright ne pruža automatsku detekciju CI okruženja za ovu svrhu, pa je na programerima da implementiraju uslovnu logiku (Autify) :

export default defineConfig({
  workers: process.env.CI ? 2 : undefined, // Ograniči u CI-ju, automatski lokalno
});

4.1.3 Konflikti pri istovremenom pristupu resursima

Kada se testovi izvršavaju paralelno, svaki worker proces radi nezavisno. Ako testovi pristupaju deljenim resursima - bazi podataka, fajl sistemu, eksternim API-jima sa rate limit-om, ili čak istom korisničkom nalogu - mogu nastati konflikti koje je teško predvideti i reprodukovati (firm86.com) . Ovi konflikti manifestuju se kao flaky testovi koji prolaze kada se izvršavaju izolovano ali padaju u paralelnom izvršavanju.

Rešenje zahteva pažljivo dizajniranje testova da budu potpuno nezavisni. Ovo može uključivati: korišćenje različitih korisničkih naloga za svaki test, izolaciju baze podataka (npr. kroz jedinstvene šeme ili prefikse tabela), mock-ovanje eksternih servisa, ili serijalizaciju testova koji moraju pristupati istom resursu.

4.2 Neadekvatna podešavanja režima rada

4.2.1 Korišćenje headless: false u CI okruženju

Headless režim (headless: false) pokreće browser sa vidljivim korisničkim interfejsom, što je neophodno za lokalno debagovanje ali potpuno neprikladno za CI okruženje. U CI-ju, headed režim zahteva display server (X11 na Linux-u), što dodaje složenost konfiguraciji i troši značajne resurse. Više od toga, headed režim je značajno sporiji od headless režima jer uključuje renderovanje vizuelnih elemenata koje nisu neophodni za funkcionalnost testova (LinkedIn) .

Nepravilna konfiguracija koja rezultira headed režimom u CI-ju može dovesti do grešaka poput "Unable to open X display" ili jednostavno zauzimati neprihvatljivo dugo vreme za izvršavanje. Preporučena praksa je eksplicitno uslovljavanje:

export default defineConfig({
  use: {
    headless: !!process.env.CI, // headless u CI, headed lokalno
  },
});

4.2.2 Nedostatak slowMo ili drugih debugging opcija za lokalni razvoj

Suprotno od CI scenarija, lokalni razvoj značajno benefitira od opcija koje usporavaju izvršavanje i omogućavaju vizuelno praćenje testova. Opcija slowMo (slow motion) dodaje fiksnu pauzu između svake akcije, čineći lako pratiti šta se dešava na ekranu (Autify) . Slično, headless: false omogućava direktno posmatranje browsera tokom testa.

Konfiguracija koja ne pruža lako uključivanje/isključivanje ovih opcija otežava debagovanje. Preporučeni pristup je da se slowMo i headless konfigurišu kroz environment varijable ili CLI parametre, omogućavajući programerima da brzo pređu iz "brzog" režima za regresiono testiranje u "spori" režim za debagovanje bez modifikacije koda.

4.2.3 Nepravilna konfiguracija fullyParallel za zavisne testove

Playwright podrazumevano izvršava testove unutar iste datoteke sekvencijalno, ali omogućava paralelno izvršavanje kroz fullyParallel: true opciju. Ova opcija može značajno ubrzati izvršavanje, ali je nebezbedna za testove koji imaju implicitne zavisnosti (Playwright) .

Na primer, ako test A kreira korisnika a test B koristi tog korisnika za porudžbinu, paralelno izvršavanje će dovesti do toga da test B pokuša da koristi nepostojećeg korisnika. Playwright pruža test.describe.serial() za eksplicitno označavanje zavisnih grupa testova, ali ova anotacija se mora koristiti pažljivo i konzistentno.

5. Neispravna konfiguracija vremenskih ograničenja (timeout)

5.1 Globalno preniska vremenska ograničenja

5.1.1 Podrazumevanih 30 sekundi nedovoljno za sporije CI okruženje

Playwright postavlja podrazumevana vremenska ograničenja koja su prilagođena tipičnim scenarijima: 30 sekundi za testove, 5 sekundi za expect asertacije, i 30 sekundi za navigacije i akcije. Međutim, ova ograničenja nisu univerzalno primenljiva i često zahtevaju prilagođavanje (Autify) .

CI okruženja su često sporija od lokalnih mašina zbog deljenih resursa, manje CPU snage, i mrežne latencije do testnih instanci aplikacije. Test koji prolazi lokalno za 10 sekundi može trajati 45 sekundi u CI-ju, rezultirajući TimeoutError bez ikakve promene u kodu (Autify) . Ovo ponašanje je posebno frustrirajuće jer stvara iluziju regresije kada je u pitanju samo sporije okruženje.

Globalno povećanje timeout vrednosti u konfiguraciji je često neophodno za stabilan CI:

export default defineConfig({
  timeout: 60000, // 60 sekundi umesto podrazumevanih 30
  expect: {
    timeout: 10000, // 10 sekundi za asertacije
  },
});

5.1.2 Razlika između timeout (test) i expect timeout-a

Playwright razlikuje više nivoa timeout-a koji kontrolišu različite aspekte izvršavanja testova. Globalni timeout određuje maksimalno vreme koje bilo koji pojedinačni test može da traje pre nego što bude prekinut sa TimeoutError. expect.timeout kontroliše koliko dugo će asertacije čekati da uslov bude ispunjen. actionTimeout i navigationTimeout definišu vremenska ograničenja za specifične operacije.

Nepoznavanje ove hijerarhije može dovesti do zabune. Na primer, povećanje expect.timeout na 30 sekundi neće pomoći ako je globalni timeout i dalje 30 sekundi - test će i dalje biti prekinut nakon 30 sekundi ukupnog trajanja. Ispravno balansiranje ovih parametara zahteva razumevanje karakteristika testiranog sistema i okruženja izvršavanja.

5.2 Nedostatak prilagođavanja timeout-a specifičnim testovima

5.2.1 Korišćenje test.slow() za dugotrajne operacije

Ne svi testovi su jednaki - neki uključuju složene operacije kao što su upload velikih fajlova, generisanje izveštaja, ili obrada velikih količina podataka. Playwright pruža test.slow() metodu koja automatski trostruko povećava timeout za specifični test, omogućavajući mu duže vreme izvršavanja bez globalne promene konfiguracije:

test.slow('complex report generation', async ({ page }) => {
  // Ovaj test ima 3x duži timeout (90s sa podrazumevanih 30s)
  await page.goto('/reports');
  await page.setInputFiles('#file', 'large-dataset.csv');
  await page.click('#generate');
  await expect(page.locator('.report-ready')).toBeVisible();
});

5.2.2 Lokalno override timeout-a umesto globalne konfiguracije

Za precizniju kontrolu, test.setTimeout() omogućava eksplicitno definisanje timeout-a u milisekundama za pojedinačni test. Ova metoda je korisna kada test.slow() nije dovoljno fleksibilan, ili kada je potrebno postaviti specifično vreme koje nije multiplikator podrazumevane vrednosti:

test('bulk data import', async ({ page }) => {
  test.setTimeout(300000); // 5 minuta specifično za ovaj test
  // ... test kod
});

5.2.3 Posledice: lažno pozitivni padovi testova usled sporijeg učitavanja

Nepravilno konfigurisani timeout-ovi dovode do lažno pozitivnih padova testova - situacija gde test funkcionalno radi ispravno, ali ne uspeva zbog previše agresivnog vremenskog ograničenja. Ovo može dovesti do gubitka poverenja u test suite, gde timovi počinju da ignoriraju padove testova pretpostavljajući da su "samo timeout problemi", što može maskirati prave regresije u aplikaciji.

Preporučena strategija uključuje postavljanje konzervativnog globalnog timeout-a (npr. 60 sekundi) koji pokriva većinu slučajeva, sa specifičnim override-ima za testove koji su poznato duži. Monitoring stvarnog vremena izvršavanja testova u ciljnom okruženju i iterativno prilagođavanje parametara osigurava optimalan balans između brzine detekcije problema i tolerancije na normalnu varijabilnost performansi.

6. Greške u konfiguraciji cross-browser testiranja kroz projects

6.1 Nepravilno definisanje projekata za različite pregledače

6.1.1 Dupliranje konfiguracije umesto korišćenja nasleđivanja

Playwright-ov projects mehanizam predstavlja moćan način za organizovanje testova po različitim konfiguracijama - pregledačima, uređajima, ili okruženjima. Međutim, nepravilno korišćenje ovog mehanizma može dovesti do neefikasnosti i grešaka. Dupliranje konfiguracije umesto korišćenja mehanizma nasleđivanja je čest anti-pattern:

// POGREŠNO - masivno dupliranje
export default defineConfig({
  projects: [
    {
      name: 'chromium',
      use: {
        browserName: 'chromium',
        headless: true,
        viewport: { width: 1280, height: 720 },
        screenshot: 'only-on-failure',
        trace: 'on-first-retry',
        // ... još 20 linija konfiguracije
      },
    },
    {
      name: 'firefox',
      use: {
        browserName: 'firefox',
        // Identična konfiguracija kopirana
      },
    },
  ],
});

// ISPRAVNO - korišćenje nasleđivanja
const baseConfig = {
  headless: true,
  viewport: { width: 1280, height: 720 },
  screenshot: 'only-on-failure',
  trace: 'on-first-retry',
};

export default defineConfig({
  projects: [
    { name: 'chromium', use: { ...baseConfig, browserName: 'chromium' } },
    { name: 'firefox', use: { ...baseConfig, browserName: 'firefox' } },
  ],
});

6.1.2 Pogrešno postavljanje testMatch na nivou projekta

Kada je testMatch definisan na nivou projekta, on filtrira koje test datoteke će biti izvršene u tom projektu. Međutim, ova opcija interaguje sa globalnim testDir i testMatch na način koji može biti neočekivan. Konkretno, projektni testMatch se primenjuje relativno u odnosu na projektnu konfiguraciju, a ne u odnosu na globalni testDir (Stack Overflow) .

Ovo može dovesti do situacije gde se testovi koji bi trebalo da budu izvršeni u projektu jednostavno ne pronalaze, bez jasne indikacije zašto. Preporučena praksa je eksplicitna provera pokrivenosti testova po projektima i jasno dokumentovanje konvencija za testMatch uzorke.

6.2 Problemi sa webServer konfiguracijom unutar projekata

6.2.1 Greške u pokretanju lokalnog servera unutar projektnih definicija

webServer opcija omogućava Playwright-u da automatski pokrene lokalni razvojni server pre izvršavanja testova. Međutim, korišćenje ove opcije unutar projektnih definicija može dovesti do neočekivanog ponašanja. U dokumentovanom slučaju, webServer konfigurisan unutar projekta ne deli iste garantije o redosledu pokretanja kao globalni webServer, što može rezultirati time da testovi pokušavaju da pristupe aplikaciji pre nego što je server spreman (Stack Overflow) .

6.2.2 Konflikti portova i nedostatak reuseExistingServer logike

Kada se više projekata izvršava istovremeno ili se testovi pokreću paralelno sa drugim servisima, mogu nastati konflikti portova. Opcija reuseExistingServer omogućava Playwright-u da koristi već pokrenuti server ako je dostupan, što je korisno kada se projekti izvršavaju sekvencijalno:

export default defineConfig({
  webServer: {
    command: 'npm run dev',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI, // Lokalno: koristi postojeći, CI: uvek novi
  },
});

7. Neispravna obrada environment varijabli i sigurnosnih podataka

7.1 Nedostatak ili nepravilno učitavanje .env datoteka

7.1.1 Zaboravljeno učitavanje varijabli pre pokretanja testova

Environment varijable predstavljaju standardni mehanizam za eksternalizaciju konfiguracije, ali njihovo nepravilno korišćenje u Playwright kontekstu može dovesti do frustrirajućih problema. Playwright sam po sebi ne učitava .env datoteke automatski - to je odgovornost programera da eksplicitno učita ove datoteke, tipično korišćenjem biblioteke poput dotenv na početku konfiguracione datoteke (Stack Overflow) :

import dotenv from 'dotenv';
import path from 'path';

dotenv.config({ path: path.resolve(__dirname, '.env') });

export default defineConfig({
  use: {
    baseURL: process.env.BASE_URL,
  },
});

7.1.2 Razlike u ponašanju između lokalnog i CI okruženja

Lokalno razvojno okruženje tipično koristi .env datoteke koje se učitavaju kroz biblioteke poput dotenv, dok CI/CD okruženja tipično injektuju varijable direktno u okruženje procesa (BrowserStack) . Nepravilna konfiguracija ovog mehanizma može dovesti do situacije gde testovi funkcioniraju lokalno, ali propadaju u CI zbog nedostupačnosti varijabli. Eksplicitna validacija prisustva kritičnih varijabli na početku izvršavanja predstavlja odbrambenu meru koja brzo identifikuje ovaj problem.

7.2 Nebezbedno čuvanje tajni u konfiguraciji

7.2.1 Ugradnja API ključeva i lozinki direktno u playwright.config.js

Hardkodiranje osetljivih podataka direktno u konfiguracionu datoteku ili test kod predstavlja ozbiljan sigurnosni rizik. Ove vrednosti se čuvaju u plain text formatu i postaju deo git istorije, dostupne svakome ko ima pristup repozitorijumu. Čak i u privatnim repozitorijumima, ova praksa krši princip najmanjih privilegija i otežava rotaciju kredencijala (NareshIT) .

7.2.2 Nedostatak korišćenja CI/CD mehanizama za upravljanje tajnama

Moderni CI sistemi pružaju sofisticirane mehanizme za bezbedno skladištenje i injektovanje tajni - GitHub Actions ima secrets, GitLab CI ima masked variables, Azure DevOps ima secret variables. Korišćenje ovih mehanizama osigurava da se tajne nikada ne pojavljuju u logovima ili kodu (BrowserStack) :

# GitHub Actions primer
- name: Run Playwright tests
  env:
    API_KEY: ${{ secrets.API_KEY }}
    TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}
  run: npx playwright test

7.2.3 Rizik od eksponiranja osetljivih podataka u logovima i izveštajima

Čak i kada se tajne pravilno čuvaju u environment varijablama, one mogu biti nenamerno logovane u slučaju grešaka ili detaljnog debagovanja. Preporučljiva praksa uključuje implementaciju mehanizama za maskiranje osetljivih podataka u izveštajima, kao i pažljivo razmatranje šta se uključuje u error poruke i stack trace-ove (NareshIT) .

8. Problemi sa izolacijom testova i upravljanjem browser kontekstima

8.1 Nedostatak pravilnog korišćenja browser konteksta za izolaciju

8.1.1 Deljenje istog konteksta između testova umesto kreiranja novog

Playwright je dizajniran sa izolacijom testova kao fundamentalnim principom - svaki test bi trebalo da bude nezavisan i da ne zavisi od stanja koje je ostavio prethodni test. Međutim, programeri ponekad krše ovaj princip deljenjem istog browser konteksta između više testova, bilo eksplicitno kroz ručno upravljanje, bilo implicitno kroz nepravilnu upotrebu fixture-ova (firm86.com) .

Browser kontekst enkapsulira stanje browsera uključujući kolačiće, localStorage, sessionStorage, i keš, što znači da akcije jednog testa mogu uticati na ponašanje narednih testova ako se deli isti kontekst. Ovo dovodi do "flaky" testova čije ponašanje varira između izvršavanja.

8.1.2 Posledice: kontaminacija stanja i flaky testovi

Kontaminacija stanja između testova je jedan od najčešćih uzroka flaky testova - testova koji ponekad prolaze, a ponekad padaju, bez ikakvih promena u kodu. Ovo ponašanje je izuzetno teško dijagnostikovati jer se manifestuje intermitentno i često ne može reproducirati lokalno. Preporučena praksa je potpuna delegacija upravljanja kontekstom na Playwright-ov test runner, korišćenjem ugrađenih page i context fixture-ova koji automatski osiguravaju izolaciju.

8.2 Neispravno zatvaranje resursa (context leaks)

8.2.1 Propusti u afterEach ili afterAll hook-ovima

Svaki test koji kreira dodatne resurse - bilo da se radi o dodatnim browser kontekstima, stranicama, ili eksternim konekcijama - mora imati odgovarajući mehanizam za njihovo oslobađanje. Propusti u afterEach ili afterAll hook-ovima dovode do "curenja" resursa, gde otvoreni browser procesi ostaju aktivni i troše sistemske resurse nakon završetka testova (NareshIT) .

8.2.2 Visoka potrošnja memorije pri dugotrajnim test suitama

Curenje konteksta manifestuje se praktično kao visoka potrošnja memorije pri dugotrajnim test suitama. Svaki otvoreni browser kontekst zauzima značajnu količinu RAM memorije, a moderni operativni sistemi imaju ograničenja na broj istovremenih procesa i otvorenih fajl deskriptora. Simptomi uključuju postepeno usporavanje izvršavanja testova, nasumične greške pri kreiranju novih konteksta, i eventualni pad test runner-a (NareshIT) .

8.2.3 Nasumični padovi testova usled istrošenih resursa

U ekstremnim slučajevima, curenje resursa dovodi do nasumičnih padova testova sa kriptičnim greškama koje ne ukazuju direktno na uzrok. Dijagnostika ovog problema zahteva monitoring resursa tokom izvršavanja testova i pažljivu analizu obrazaca neuspeha. Preventivne mere uključuju rigoroznu upotrebu try/finally blokova za garantovano zatvaranje resursa, kao i korišćenje Playwright-ovih ugrađenih mehanizama za automatsko upravljanje životnim ciklusom.

9. Zanemarivanje ugrađenih mehanizama za pouzdanost

9.1 Nekorišćenje ili nepravilna konfiguracija ponovnih pokušaja (retries)

9.1.1 Podrazumevano isključeni retries umesto prilagođene konfiguracije

Playwright-ov mehanizam za ponovne pokušaje (retries) predstavlja moćan alat za borbu protiv flaky testova, ali je ovaj mehanizam podrazumevano isključen. Ovo znači da svaki pad testa odmah rezultira neuspehom celog test run-a, čak i ako je pad uzrokovan privremenim faktorima kao što su mrežna latencija ili kratak trenutak nestabilnosti aplikacije.

Konfiguracija retries-a treba da bude pažljivo razmotrena - premalo retries-a znači da će flaky testovi često prouzrokovati lažne alarme, dok previše retries-a može maskirati prave probleme u testovima ili aplikaciji:

export default defineConfig({
  retries: process.env.CI ? 2 : 0, // CI: 2 retries, lokalno: bez retries-a
});

9.1.2 Previše retries koji maskiraju prave probleme u testovima

Ako se test konzistentno prolazi tek nakon više pokušaja, to je jasan indikator da test ili aplikacija ima fundamentalan problem koji treba adresirati, a ne maskirati kroz ponovne pokušaje (LinkedIn) . Monitoring stope uspeha ponovnih pokušaja predstavlja važnu metriku koja može identifikovati testove koji zahtevaju pažnju. Idealno, stopa ponovnih pokušaja treba da bude blizu nule, sa povremenim, nasumičnim neuspezima koji se rešavaju ponovnim pokušajem.

9.2 Nedostatak praćenja i evidencije za debagovanje

9.2.1 Neuključeno trace: 'on-first-retry' za analizu padova

Playwright pruža izuzetno moćne alate za dijagnostiku problema kroz tracing mehanizam, ali je ovaj mehanizam podrazumevano isključen zbog performansi i prostora na disku. Neuključivanje trace: 'on-first-retry' znači da kada test padne u CI-ju, tim ima ograničene informacije za dijagnozu problema. Trace datoteke sadrže detaljan, korak-po-korak uvid u izvršavanje testa, uključujući DOM stanje, mrežne zahteve, i izvršene akcije, što je neprocenjivo za razumevanje uzroka neuspeha.

9.2.2 Nedostatak konfiguracije screenshot-a i video snimaka pri neuspehu

Slično tome, screenshot-ovi i video snimci prilikom neuspeha pružaju vizuelni uvid u stanje aplikacije u trenutku pada. Ovi artefakti su relativno jeftini u poređenju sa vremenom potrebnim za reprodukciju i debagovanje problema, pa je preporučljivo konfigurisati njihovo automatsko generisanje:

export default defineConfig({
  use: {
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
    trace: 'on-first-retry',
  },
});

9.2.3 Propusti u korišćenju outputDir za organizaciju artefakata

Opcija outputDir definiše gde će se čuvati rezultati testova, screenshot-ovi, trace-evi i drugi artefakti. Nepravilna konfiguracija ove opcije može dovesti do haotične strukture rezultata, gde se artefakti mešaju u neorganizovanim direktorijumima ili, još gore, gube između različitih test run-ova. Eksplicitno definisanje outputDir i osiguranje da je on jedinstven za svaki test run (npr. kroz timestamp ili CI build ID) olakšava organizaciju i analizu rezultata.

10. Nepravilno korišćenje Playwright-ovog auto-waiting mehanizma

10.1 Ručno dodavanje fiksnih čekanja (waitForTimeout)

10.1.1 Zamena auto-waiting-a sa setTimeout ili page.waitForTimeout

Jedna od najmoćnijih karakteristika Playwright-a je njegov auto-waiting mehanizam - sposobnost da automatski čeka da elementi budu spremni za interakciju pre nego što izvrši akciju. Međutim, mnogi programeri koji prelaze sa drugih alata ili imaju iskustvo sa manje sofisticiranim framework-ima navikli su da eksplicitno dodaju fiksna čekanja kako bi "osigurali" da je stranica spremna (Autify) .

Ova praksa je ne samo nepotrebna već i štetna. page.waitForTimeout(5000) ili setTimeout u test kodu usporava izvršavanje testova za fiksno vreme bez obzira na to da li je stranica zapravo spremna, i uvođenje flakiness-a - ako se stranica spremi za 100ms, test čeka nepotrebno 4900ms; ako joj treba 5100ms, test pada.

10.1.2 Usporenje izvršavanja i uvođenje flakiness-a

Fiksna čekanja su posebno problematična u CI okruženjima gde su performanse varijabilne. Vreme koje je "dovoljno" lokalno može biti nedovoljno u sporijem CI okruženju, što dovodi do intermitentnih padova. Preporučena praksa je potpuno uklanjanje fiksnih čekanja i oslanjanje na Playwright-ov auto-waiting, koji inteligentno čeka na odgovarajuće uslove za svaku akciju.

10.2 Nepravilno korišćenje eksplicitnih čekanja

10.2.1 waitForSelector umesto locator.waitFor()

Stariji pristupi čekanja kao što je page.waitForSelector() su zamenjeni modernijim locator-based API-jem. locator.waitFor() pruža bolju integraciju sa Playwright-ovim auto-waiting mehanizmom i jasniju semantiku - čeka se na specifičan element, a ne na selektor koji može odgovarati više elemenata ili biti nestabilan.

10.2.2 Nedostatak korišćenja web-first asercija (expect(locator).toBeVisible())

Playwright-ov expect API pruža web-first asertacije koje kombinuju čekanje i proveru u jednoj operaciji. Umesto eksplicitnog čekanja pa zasebne provere, expect(locator).toBeVisible() automatski čeka da element bude vidljiv i zatim proverava taj uslov, sa konfigurabilnim timeout-om (Autify) :

// POGREŠNO - ručno čekanje pa provera
await page.waitForSelector('#submit-button');
const button = await page.$('#submit-button');
expect(await button.isVisible()).toBe(true);

// ISPRAVNO - web-first asercija
await expect(page.locator('#submit-button')).toBeVisible();

11. Konfiguracioni propusti pri integraciji sa spoljnim servisima

11.1 Nepravilno rukovanje mrežnim zahtevima i mock-ovanjem

11.1.1 Zavisnost od nestabilnih eksternih API-ja

Testovi koji direktno zavise od eksternih API-ja - bilo da se radi o third-party servisima, payment gateway-ima, ili eksternim autentifikacionim provajderima - su inherentno flaky. Nestabilnost ovih servisa, rate limiting, ili promene u njihovom API-ju mogu dovesti do padova testova koji nemaju veze sa aplikacijom koja se testira.

11.1.2 Nedostatak page.route() za kontrolu mrežnog saobraćaja

Playwright pruža moćan mehanizam mrežnog interceptovanja kroz page.route() koji omogućava:

  • Mock-ovanje eksternih API odgovora za predvidljivo testiranje
  • Modifikaciju zahteva i odgovora za testiranje edge case-ova
  • Blokiranje neželjenih mrežnih poziva za brže izvršavanje testova

Nekorišćenje ovog mehanizma predstavlja propuštenu priliku za stabilizaciju testova i smanjenje zavisnosti od eksternih faktora.

11.2 Problemi sa autentifikacijom i sesijama

11.2.1 Ponavljanje login procedura umesto korišćenja storageState

Jedan od najčešćih uzroka sporih testova je ponavljanje login procedure u svakom testu koji zahteva autentifikovanog korisnika. Ova praksa ne samo da usporava izvršavanje već i uvodi dodatnu tačku otkaza - ako login forma ima probleme, svi testovi padaju bez obzira na to da li funkcionalnost koju testiraju zaista zavisi od autentifikacije.

Playwright pruža elegantno rešenje kroz storageState mehanizam - mogućnost da se stanje autentifikacije (kolačići, localStorage) sačuva nakon jednog login-a i ponovo iskoristi u narednim testovima:

// global-setup.js
async function globalSetup() {
  const browser = await chromium.launch();
  const page = await browser.newPage();

  await page.goto('/login');
  await page.fill('#username', process.env.TEST_USER);
  await page.fill('#password', process.env.TEST_PASSWORD);
  await page.click('#submit');

  // Sačuvaj stanje autentifikacije
  await page.context().storageState({ path: 'auth.json' });

  await browser.close();
}

// playwright.config.js
export default defineConfig({
  globalSetup: './global-setup.js',
  use: {
    storageState: 'auth.json', // Koristi sačuvano stanje za sve testove
  },
});

11.2.2 Neispravna konfiguracija globalSetup za prethodnu autentifikaciju

Iako globalSetup pruža moćan mehanizam za inicijalizaciju, njegova nepravilna konfiguracija može dovesti do problema. Česte greške uključuju: nepravilno čuvanje storageState fajla, pokušaj korišćenja stanja pre nego što je kreirano, ili zanemarivanje potrebe za periodičnom obnovom stanja kada sesije ističu. Pažljivo planiranje životnog ciklusa autentifikacije i jasno dokumentovanje procesa su ključni za uspešnu implementaciju.

Povezani kursevi