Modul 5: Avtomatik gözləmə və flaky testlər
Veb-first assertion-ların avtomatik olaraq necə yenidən cəhd etdiyini artıq bilirsiniz. İndi isə etibarlılığın digər tərəfinə baxaq: Playwright hər hansı bir əməliyyatı icra etməzdən əvvəl nə edir — və qalan hər waitForTimeout çağırışını həqiqətən işləyən bir şeylə necə əvəz etmək olar.
🎬 Video tezliklə əlavə olunacaq
Playwright hər əməliyyatdan əvvəl avtomatik necə gözləyir
Bölmə: “Playwright hər əməliyyatdan əvvəl avtomatik necə gözləyir”Hər Playwright əməliyyatı — click(), fill(), hover(), press(), selectOption(), check(), uncheck() — həqiqətən icra etməzdən əvvəl bir sıra actionability yoxlamaları keçirir. Bu yoxlamalar avtomatik baş verir; siz onları yazmırsınız.
Yoxlamalar bunlardır:
| Yoxlama | Mənası |
|---|---|
| Attached | Element DOM-da mövcuddur |
| Visible | Element gizlənməyib (display:none, visibility:hidden, opacity:0, sıfır ölçü) |
| Stable | Element iki ardıcıl animasiya çərçivəsi boyunca eyni sərhəd qutusunu saxlayır (hərəkəti/animasiyası dayanıb) |
| Receives events | Heç bir element hədəfi örtmür (overlay, modal və ya tooltip yoxdur) |
| Enabled | Element disabled deyil |
Playwright hamısı keçənə — ya da əməliyyat vaxt aşımı bitənə (defolt: 30 saniyə) qədər dövrə üzərindən ~50 ms-dən bir bütün beş şərti yoxlayır.
// Playwright düymə attached, visible, stable, hadisə qəbul edir// VƏ enabled olana qədər gözləyir — sonra click edir.await page.getByRole('button', { name: 'Sifariş ver' }).click();
// Bunları özünüz yazmanıza gərək yoxdur:// await page.waitForSelector('button', { state: 'visible' }); // artıqdır// await page.waitForTimeout(500); // anti-patternBu praktikada nə demək olar:
- Düymə əvvəlcə yükləmə overlay-ının arxasındadırsa,
click()overlay-ın yox olmasını gözləyir. - Düymə
disabledbaşlayır və forma doldurulduqdan sonra aktiv olursa,click()gözləyir. - Element hazırda animasiya edirsə (sürüşərək girən, silinərək görünən),
click()sabitləşməsini gözləyir.
Buna görə Playwright ilə açıq gözləmələrin əksəriyyəti lazımsızdır.
Yadda saxla: hər əməliyyat işə düşməzdən əvvəl attached + visible + stable + receives-events + enabled gözləyir — əməliyyatdan əvvəl nadir hallarda açıq gözləmə lazım olur.
waitForTimeout həmişə anti-pattern-dir
Bölmə: “waitForTimeout həmişə anti-pattern-dir”page.waitForTimeout(N) tam olaraq bir şey edir: testi N millisaniyə dayandırır. Heç bir şərti yoxlamır. Tətbiqin hazır olduğunu bilmir. Həmişə yanlışdır.
// ANTİ-PATTERN — heç vaxt belə etməyinawait page.click('#submit');await page.waitForTimeout(3000); // səhifənin 3 saniyədə yüklənəcəyini ümid edirconst text = await page.locator('h1').textContent();expect(text).toContain('Təsdiqləndi');
// DÜZGÜN — faktiki şərti gözləyirawait page.click('#submit');await expect(page.locator('h1')).toContainText('Təsdiqləndi');waitForTimeout testləri nə üçün flaky edir:
- Sizin maşınınız o qədər sürətli ola bilər ki, 3000 ms kifayətdir. CI serveri 4× daha yavaşdır. Test CI-də uğursuz olur.
- Tətbiq növbəti buraxılışda sürətlənir. 3000 ms yuxumanız indi hər icrada 2 saniyə israf edir.
- Bir reqressiya nəticəsində tətbiq yavaşlayır. Yuxumanız indi çox qısadır. Test qırmızıya çevrilir.
waitForTimeout testinizi hardware sürətinə bağlayır. Veb-first assertion-lar və ağıllı gözləmə API-ləri testinizi tətbiq davranışına bağlayır. İkincisi heç vaxt yanlış səbəblərdən qırılmır.
waitForTimeout-un yeganə qəbul edilə bilən istifadəsi debug zamanıdır — brauzerın nə etdiyini görmək üçün testi müvəqqəti olaraq yavaşlatmaq. Commit etməzdən əvvəl onu silin.
// Debug zamanı müvəqqəti olaraq tamamdırawait page.waitForTimeout(5000); // COMMIT ETMƏZDƏN ƏVVƏL SİLİN
// Şərh xatırladıcınızdır. Həqiqətən silin.Yadda saxla: sabit yuxuma heç nəyi yoxlamır və testi hardware sürətinə bağlayır — onu faktiki şərti gözləməklə əvəz et.
expect avtomatik yenidən cəhdi — xatırlatma
Bölmə: “expect avtomatik yenidən cəhdi — xatırlatma”Modul 4-dən: expect(locator) assertion-ları avtomatik yenidən cəhd edir. Bu burada aktualdır çünki geliştiricilerin waitForTimeout-a əl atmasının ən yaygın səbəbi yenidən cəhd etməyən assertion istifadə etmələridir.
// Yenidən cəhd etmir — bir dəfə yoxlayır, yavaş səhifələrdə uğursuz olurconst text = await page.locator('.status').textContent();expect(text).toBe('Hazır');
// Avtomatik yenidən cəhd edir — şərt keçənə ya da vaxt aşımı bitənə qədər yenidən cəhd edirawait expect(page.locator('.status')).toHaveText('Hazır');Mətn, say, URL ya da görünürlük vəziyyətini yoxlamadan əvvəl waitForTimeout yazdığınızı görürsünüzsə — yoxlamanı veb-first ekvivalenti ilə əvəz edin. Yuxuma avtomatik yox olur.
Yadda saxla: əksər waitForTimeout-lar yenidən cəhd etməyən assertion səbəbindən var — veb-first expect(locator) qoy, yuxuma yox olur.
waitForURL
Bölmə: “waitForURL”page.waitForURL() brauzerın hazırkı URL-inin gözlənilən dəyərlə uyğunlaşmasını gözləyir. String, glob şablonu ya da müntəzəm ifadə qəbul edir.
// Dəqiq URL gözləyinawait page.waitForURL('https://example.com/dashboard');
// Glob şablon gözləyinawait page.waitForURL('**/orders/**');
// Regex — dinamik ID-lər üçün faydalıdırawait page.waitForURL(/\/orders\/\d+/);Kritik şablon: tetikle, sonra gözlə. Əvvəlcə URL-i gözləməyin — naviqasiya artıq baş vermiş ola bilər. waitForURL çağırışı onu tetikleyen əməliyyatı izləməlidir.
await page.getByRole('button', { name: 'Sifariş ver' }).click();await page.waitForURL(/\/orders\/\d+/);// URL artıq /orders/1042 kimi bir şeydirwaitForURL vs expect(page).toHaveURL():
Hər ikisi işləyir. Fərq niyyətdədir:
waitForURLaçıq bir gözləmədir: “Naviqasiyanın baş verməsini gözləyirəm.”expect(page).toHaveURL()bir assertion-dır: “Naviqasiyanın baş verdiyini yoxlayıram.”
Praktikada demək olar ki, eynidir — toHaveURL da yenidən cəhd edir. Test assertion-larında toHaveURL, birbaşa assertion etmədiyiniz köməkçi metodlarda ya da page object-lərdə waitForURL üstün tutun.
// Testdə — assertion formasını istifadə edinawait checkoutPage.placeOrder();await expect(page).toHaveURL(/\/orders\/\d+/);
// Page object köməkçisində — gözləmə formasını istifadə edinasync placeOrder() { await this.placeOrderBtn.click(); await this.page.waitForURL(/\/orders\/\d+/);}Yadda saxla: əvvəl tetiklə, sonra gözlə; testlərdə toHaveURL, köməkçilərdə və page object-lərdə waitForURL üstün tut.
waitForResponse
Bölmə: “waitForResponse”page.waitForResponse() brauzer tərəfindən müəyyən bir HTTP cavabının qəbul edilməsini gözləyir. Bir əməliyyat şəbəkə sorğusunu tetiklediyinde istifadə edin və davam etməzdən əvvəl cavabı yoxlamanız lazımdır.
Kritik şablon: Promise.all.
waitForResponse-u əməliyyatdan sonra çağırırsınızsa, cavabı qaçıra bilərsiniz — dinləyiciniz qeydiyyata alınmazdan əvvəl tamamlanmış ola bilər. Həmişə Promise.all istifadə edərək əməliyyatı tetiklemeden əvvəl dinləyicini başladın:
// YANLIŞ — cavab dinləyicidən əvvəl gələ bilərawait page.click('.daha-yüklə');const response = await page.waitForResponse('**/api/products');
// DÜZGÜN — dinləyici click-dən əvvəl qeydiyyata alınırconst [response] = await Promise.all([ page.waitForResponse('**/api/products'), page.click('.daha-yüklə'),]);expect(response.ok()).toBeTruthy();Uyğunlaşdırma şablonları: URL string, glob ya da cavab obyektini qəbul edən funksiyanla uyğunlaşdıra bilərsiniz.
// Glob ilə uyğunlaşdırconst [response] = await Promise.all([ page.waitForResponse('**/api/products**'), page.click('.məhsulları-yüklə'),]);
// Funksiya ilə uyğunlaşdır — status kodu yoxlamaları üçün faydalıdırconst [response] = await Promise.all([ page.waitForResponse( (resp) => resp.url().includes('/api/products') && resp.status() === 200 ), page.click('.məhsulları-yüklə'),]);
// Cavab gövdəsini yoxlayınconst body = await response.json();expect(body.products).toHaveLength(10);waitForResponse nə vaxt istifadə edilər:
- “Daha yüklə”yə kliklədikdən sonra — yeni elementləri iddia etməzdən əvvəl API cavabını gözləyin
- Forma göndərdikdən sonra — təsdiq mesajını iddia etməzdən əvvəl POST cavabını gözləyin
- Şəbəkə xətası işləmini sınaqdan keçirərkən — 4xx ya da 5xx cavabını gözləyin
Yadda saxla: dinləyicini əməliyyatdan əvvəl Promise.all ilə qeydiyyata al, yoxsa cavab sən dinləməyə başlamazdan əvvəl gələ bilər.
waitForLoadState
Bölmə: “waitForLoadState”page.waitForLoadState() səhifənin müəyyən bir yüklənmə vəziyyətinə çatmasını gözləyir. Üç vəziyyət var:
| Vəziyyət | Nə vaxt işə düşür |
|---|---|
'load' | load hadisəsi işə düşdü (bütün resurslar endirildi) |
'domcontentloaded' | DOMContentLoaded hadisəsi işə düşdü (HTML ayrıştırıldı, şəkillər hələ yox) |
'networkidle' | 500 ms boyunca şəbəkə sorğusu yoxdur |
// Səhifənin tam yüklənməsini gözləyinawait page.goto('/dashboard');await page.waitForLoadState('load'); // adətən artıqdır — goto() artıq gözləyir
// DOM-un ayrıştırılmasını gözləyin ('load'-dan daha sürətli)await page.waitForLoadState('domcontentloaded');
// Şəbəkənin sabitləşməsini gözləyinawait page.waitForLoadState('networkidle');Vacib: page.goto() defolt olaraq artıq 'load'-u gözləyir, buna görə goto()-dan sonra waitForLoadState('load') çağırmaq demək olar ki, həmişə artıqdır.
Yadda saxla: goto() artıq load-u gözləyir — vəziyyətə yalnız konkret olaraq domcontentloaded və ya (nadir hallarda) networkidle lazım olanda müraciət et.
networkidle-ın çatışmazlıqları
Bölmə: “networkidle-ın çatışmazlıqları”networkidle ən təhlükəsiz seçim kimi görünür — “hər şey bitənə qədər gözlə.” Praktikada ciddi problemləri var:
Problem 1: Heç vaxt işə düşməyə bilər. Müasir SPA-lar fasiləsiz olaraq arxa planda sorğular edir — analitika pingi, heartbeat polling, WebSocket yenidən qoşulmaları. Tətbiq sorğu göndərməyə davam edərsə, networkidle sonsuz gözləyir (vaxt aşımına qədər).
Problem 2: Yavaşdır. Sakit səhifələrdə belə, networkidle həmişə son sorğudan sonra minimum 500 ms gözləyir. Bunu yüzlərlə testdə artırın.
Problem 3: Yanlış şeyi gözləyir. Adətən müəyyən bir cavabla maraqlanırsınız, “bütün şəbəkə fəaliyyəti” ilə deyil. Başqa bir arxa planda çalışan sorğudan gələn cavab doğru anda networkidle-ı açsa, həqiqətən maraqlandığınız cavab gəlməzdən əvvəl baş verə bilər.
// KÖVRƏK — şəbəkə sakinləşdikdə işə düşür, datanız hazır olduqda deyilawait page.click('.məhsulları-yüklə');await page.waitForLoadState('networkidle');await expect(page.locator('.product-card')).toHaveCount(10);
// MÖHKƏM — müəyyən cavab gəldikdə işə düşürconst [response] = await Promise.all([ page.waitForResponse('**/api/products'), page.click('.məhsulları-yüklə'),]);await expect(page.locator('.product-card')).toHaveCount(10);Playwright-in öz sənədləri networkidle-ı tövsiyə edilməyən kimi qeyd edir — məhz bu səbəblərdən. Köhnə nümunələrdə və ya təlimatlarda görsən, onu ən yaxşı təcrübə deyil, kod iyi kimi qəbul et.
networkidle-ın qəbul edilə bilən olduğu zaman:
- Arxa planda sorğu olmayan sadə statik səhifə yüklənməsi
- SPA marşrutlaması olmayan köhnəlmiş tətbiqlərdə testlər
- Daha yaxşı siqnal olmadıqda son çarə kimi — hətta o zaman belə, nə üçün olduğunu izah edən şərh əlavə edin
Yadda saxla: maraqlandığın konkret cavabı gözlə, bütün şəbəkənin sakitləşməsini deyil — SPA-da networkidle heç vaxt gəlməyə bilər.
Flaky testləri diaqnostika etmək
Bölmə: “Flaky testləri diaqnostika etmək”Test heç bir kod dəyişikliyi olmadan bəzən keçdikdə, bəzən isə uğursuz olduqda flaky-dir. Flakiness demək olar ki, həmişə kök səbəbə malikdir — onu tapın.
Addım 1: Yuxumaları yoxlayın
Bölmə: “Addım 1: Yuxumaları yoxlayın”Ən yaygın səbəb. Test faylında waitForTimeout axtarın. Hər nümunəni uyğun veb-first alternativlə əvəz edin.
// Əvvəlawait page.click('#submit');await page.waitForTimeout(2000);const text = await page.locator('.result').textContent();
// Sonraawait page.click('#submit');await expect(page.locator('.result')).toHaveText(/uğur/i);Addım 2: Yenidən cəhd etməyən assertion-ları yoxlayın
Bölmə: “Addım 2: Yenidən cəhd etməyən assertion-ları yoxlayın”Lokatorlar əvəzinə await-lənmiş dəyərlərdən qurulan assertion-ları axtarın.
// Flaky — bir dəfə qiymətləndirirconst visible = await page.locator('.banner').isVisible();expect(visible).toBe(true);
// Sabit — avtomatik yenidən cəhd edirawait expect(page.locator('.banner')).toBeVisible();Addım 3: Qorunmamış URL ya da cavab yoxlamalarını tapın
Bölmə: “Addım 3: Qorunmamış URL ya da cavab yoxlamalarını tapın”// Flaky — page.url() sinxrondur, yenidən cəhd yoxdurexpect(page.url()).toContain('/dashboard');
// Sabit — avtomatik yenidən cəhd edirawait expect(page).toHaveURL('/dashboard');Addım 4: waitForResponse-da yarış şərtlərini yoxlayın
Bölmə: “Addım 4: waitForResponse-da yarış şərtlərini yoxlayın”Ən incə səbəb. waitForResponse tetikleyen əməliyyatdan sonra çağırılırsa, cavabı qaçıra bilər.
// Flaky — cavab dinləyicidən əvvəl gəlmiş ola bilərawait page.click('.axtarış');const resp = await page.waitForResponse('**/api/search');
// Sabit — tetiklemeden əvvəl dinləyici qeydiyyata alınırconst [resp] = await Promise.all([ page.waitForResponse('**/api/search'), page.click('.axtarış'),]);Addım 5: Click-lərdə { force: true } yoxlayın
Bölmə: “Addım 5: Click-lərdə { force: true } yoxlayın”click({ force: true }) bütün beş actionability yoxlamasını atlayır. Elementi örtülü, deaktiv ya da gizli olsa belə tıklamağa məcbur edir. Bu real problemləri gizlədir.
// Kod iyi — bu element nə üçün normal tıklana bilmir?await page.locator('.submit-btn').click({ force: true });
// Düzəliş: tıklamanı bloklayan şeyi tapın və idarə edinawait expect(page.locator('.modal')).not.toBeVisible(); // modalın bağlanmasını gözləyinawait page.locator('.submit-btn').click();Flaky test diaqnostika cədvəli
Bölmə: “Flaky test diaqnostika cədvəli”| Simptom | Kök səbəb | Düzəliş |
|---|---|---|
| Yerli keçir, CI-də uğursuz olur | waitForTimeout sürətli maşına uyğunlaşdırılıb | Veb-first assertion ilə əvəz edin |
| Eyni maşında ~20% uğursuz olur | Yenidən cəhd etməyən assertion, yarış şərti | Yenidən cəhd etməyən yoxlamanı tapın |
| Yalnız testlər paralel çalışdıqda uğursuz olur | Paylaşılan vəziyyət, test sıralama asılılığı | Test datanı izolyasiya edin |
| Heç bir test dəyişikliyi olmadan deploy-dan sonra uğursuz olur | Lokator çox kövrəkdir | Rol əsaslı ya da data-testid lokatorlarına keçin |
console.log əlavə etdiyinizdə keçir | Əlavə mikrotask tick-i ilə üzə çıxan yarış şərti | Düzgün await ya da Promise.all əlavə edin |
| Həmişə eyni addımda uğursuz olur | Real bug, flakiness deyil | Tətbiqi ya da assertion məntiqi düzəldin |
Yadda saxla: flakiness-in kök səbəbi var — yuxuma əlavə etmək əvəzinə yoxlama siyahısını keç (yuxumalar, yenidən cəhd etməyən assertion-lar, sinxron URL yoxlamaları, çatışmayan Promise.all, { force: true }).
Xüsusi əməliyyat vaxt aşımları
Bölmə: “Xüsusi əməliyyat vaxt aşımları”Defolt olaraq, hər əməliyyat actionability yoxlamaları üçün 30 saniyəyə qədər gözləyir. Bunu qlobal olaraq ya da əməliyyat-başına dəyişdirə bilərsiniz.
// Əməliyyat-başına vaxt aşımı (millisaniyə)await page.getByRole('button', { name: 'Yavaş əməliyyat' }).click({ timeout: 60_000 });
// playwright.config.js-də qlobal əməliyyat vaxt aşımıimport { defineConfig } from '@playwright/test';
export default defineConfig({ use: { actionTimeout: 10_000, // bütün əməliyyatlar üçün 10 saniyə },});Bir şeyin sürətli olması lazım olduğunu bildiyiniz zaman vaxt aşımını azaldın. Düymə tıklaması 2 saniyə içində naviqasiyaya səbəb olmalıdırsa, amma 30 saniyelik vaxt aşımınız varsa, real reqressiya test uğursuz olmazdan əvvəl 30 saniyə aşkar edilməyə bilər.
Yadda saxla: sürətli olmalı şeylərdə vaxt aşımını azalt ki, real reqressiya 30 s asılı qalmaqdansa tez uğursuz olsun.
Ağıllı gözləmə yaddaş vərəqi
Bölmə: “Ağıllı gözləmə yaddaş vərəqi”| Nəyi gözləmək istəyirəm… | İstifadə et |
|---|---|
| Element / mətn / say şərti | veb-first expect(locator)… (default seçimin) |
| Naviqasiya və ya yönləndirmə | expect(page).toHaveURL(…) (test) · page.waitForURL(…) (köməkçi) |
| Konkret şəbəkə cavabı | Promise.all([page.waitForResponse(…), əməliyyat]) |
| DOM ayrıştırılıb (şəkillər yox) | page.waitForLoadState('domcontentloaded') |
| Bütün şəbəkə sakitləşsin (son çarə) | page.waitForLoadState('networkidle') |
| Sabit gecikmə | ❌ heç vaxt waitForTimeout — yalnız debug üçün |
Tapşırıqlar
Bölmə: “Tapşırıqlar”Bu tapşırıqlar http://localhost:3000-də yerli olaraq işləyən TestMarket Lab istifadə edir.
Tapşırıq 1: Sabit gözləmələri veb-first assertion-larla əvəz edin
Bölmə: “Tapşırıq 1: Sabit gözləmələri veb-first assertion-larla əvəz edin”Bu testi refaktor edin — hər waitForTimeout-u düzgün veb-first alternativlə əvəz edin:
// ƏVVƏL (flaky — hər yerdə sabit yuxular)import { test, expect } from '@playwright/test';
test('məhsul axtarışı', async ({ page }) => { await page.goto('/products'); await page.waitForTimeout(1500);
await page.fill('#search', 'Wireless'); await page.waitForTimeout(800);
await page.click('#apply-filters'); await page.waitForTimeout(3000);
const count = await page.locator('.product-card').count(); expect(count).toBeGreaterThan(0);
await page.waitForTimeout(500); expect(page.url()).toContain('search=Wireless');});| Əvəz edin | Bunla |
|---|---|
waitForTimeout(1500) | Silin — fill() artıq element üçün avtomatik gözləyir |
waitForTimeout(800) | Silin — click() artıq avtomatik gözləyir |
waitForTimeout(3000) + count() | expect(locator).not.toHaveCount(0) |
waitForTimeout(500) + page.url() | expect(page).toHaveURL(/[?&]search=Wireless/) |
// SONRA (veb-first — sabit yuxular yoxdur)import { test, expect } from '@playwright/test';
test('məhsul axtarışı', async ({ page }) => { await page.goto('/products'); await page.locator('#search').fill('Wireless'); await page.locator('#apply-filters').click();
await expect(page.locator('.product-card')).not.toHaveCount(0); await expect(page).toHaveURL(/[?&]search=Wireless/);});Tapşırıq 2: Flaky naviqasiya testini düzəldin
Bölmə: “Tapşırıq 2: Flaky naviqasiya testini düzəldin”Orijinal iki səbəbdən flaky-dir: URL-i sinxron yoxlayır (yenidən cəhd yoxdur) sabit yuxudan sonra, və quraşdırması natamamdır — /checkout daxil olmuş, səbətində element olan istifadəçi tələb edir, ona görə sadə goto('/checkout') sadəcə login səhifəsinə qayıdır.
// ƏVVƏL (flaky — və checkout-a heç çatmır)await page.goto('/checkout');await fillCheckoutForm(page);await page.click('#place-order');await page.waitForTimeout(2000);expect(page.url()).toMatch(/\/orders\/\d+/); // sinxron — yenidən cəhd yoxdurÖz-özünə yetərli, veb-first yenidən yazılış:
// SONRAimport { test, expect } from '@playwright/test';
test.describe('Ödəniş yönləndirməsi', () => { test.beforeEach(async ({ page }) => { await page.goto('/auth/login'); await page.locator('#password').fill('customer123'); await page.getByTestId('login-submit').click();
await page.goto('/products'); await page.getByTestId('add-to-cart').first().click(); await page.goto('/checkout'); });
test('sifariş vermək sifariş səhifəsinə yönləndirir', async ({ page }) => { await page.locator('#shipping_name').fill('Jane Doe'); await page.locator('#shipping_address').fill('123 Main Street'); await page.locator('#shipping_city').fill('Portland'); await page.locator('#shipping_zip').fill('97201');
// Click avtomatik gözləyir; toHaveURL yönləndirmə gələnə qədər yenidən cəhd edir await page.getByTestId('place-order').click(); await expect(page).toHaveURL(/\/orders\/\d+/); });});Tapşırıqlar:
toHaveURL-u köhnəexpect(page.url()).toMatch(/\/orders\/\d+/)ilə əvəz edin və bir neçə dəfə işlədin — flaky edən məhz sinxron yoxlama idi.- Page-object köməkçisində bunun əvəzinə
await page.waitForURL(/\/orders\/\d+/)yazardınız — hər ikisi gözləyir; assertion forması sadəcə həm də yoxlama rolunu oynayır.
Tapşırıq 3: Avtomatik gözləmə və waitForResponse
Bölmə: “Tapşırıq 3: Avtomatik gözləmə və waitForResponse”TestMarket Lab məhsullar səhifəsini ?delay=NNNN query parametri (millisaniyə) ilə qəsdən yavaşlada bilər — avtomatik gözləməni bir dənə də yuxu olmadan görmək üçün ideal yol. Sonra cavabı Promise.all şablonu ilə tut.
import { test, expect } from '@playwright/test';
test.describe('Real tətbiqi gözləmək', () => {
test('veb-first assertion yavaş səhifəni gözləyir — yuxu lazım deyil', async ({ page }) => { // ?delay=2000 serverin cavabı 2s saxlamasına səbəb olur await page.goto('/products?delay=2000');
// waitForTimeout yoxdur: assertion sadəcə kartlar render olana qədər gözləyir await expect(page.locator('.product-card')).not.toHaveCount(0); });
test('cavabı Promise.all ilə tut', async ({ page }) => { // Dinləyici onu tetikleyen naviqasiyadan ƏVVƏL qeydiyyata alınır const [response] = await Promise.all([ page.waitForResponse( (resp) => resp.url().includes('/products') && resp.request().method() === 'GET' ), page.goto('/products?search=Wireless'), ]);
expect(response.ok()).toBeTruthy(); await expect(page.locator('.product-card')).not.toHaveCount(0); });});Tapşırıqlar:
- Birinci testi
?delay=4000-ə qaldırın — yenəwaitForTimeoutolmadan keçir; Playwright sadəcə daha çox gözləyir. waitForResponse-ugoto-dan sonraya keçirin (Promise.all-dan kənara) — sürətli cavabda dinləyici onu qaçıra bilər və test asılı qalır. Buna görə əvvəl qeydiyyata alırsan.
Özünü yoxlama sualları
Bölmə: “Özünü yoxlama sualları”- Playwright hər əməliyyatdan əvvəl hansı beş actionability yoxlamasını aparır?
waitForTimeoutyerli keçdikdə belə CI-də testləri flaky niyə edir?waitForResponseüçünPromise.allşablonu nədir və nə üçün zəruridir?waitForURLiləexpect(page).toHaveURL()arasındakı fərq nədir?networkidlenə üçün SPA-lar üçün etibarsızdır?click({ force: true })olan bir test görürsünüz. Bu sizə test haqqında nə deyir?- Yerli keçən amma CI-də 20% uğursuz olan bir testi necə diaqnostika edərdiniz?
- Defolt əməliyyat vaxt aşımı nədir və onu əməliyyat-başına necə dəyişdirirsiniz?
Əsas nəticələr
Bölmə: “Əsas nəticələr”- Avtomatik gözləmə daxildir. Hər Playwright əməliyyatı elementin attached, visible, stable, bloklanmamış və enabled olmasını gözləyir. Əməliyyatlardan əvvəl açıq gözləmə yazmağa nadir hallarda ehtiyac var.
waitForTimeouthəmişə yanlışdır. Heç bir şərti yoxlamır. Hər yuxumanı veb-first assertion ya da ağıllı gözləmə API-si ilə əvəz edin.waitForResponseüçünPromise.all. Tetikleyen əməliyyatdan əvvəl dinləyicini qeydiyyata alın — heç vaxt sonra deyil.- SPA-larda
networkidle-dan çəkinin. Heç vaxt gəlməyə bilən sükutu gözləyir. Bunun əvəzinə müəyyən bir URL ya da cavabı gözləyin. - Flakiness-in kök səbəbi var. Diaqnostika yoxlama siyahısı üzərindən işləyin: yuxumalar, yenidən cəhd etməyən assertion-lar, sinxron URL yoxlamaları, çatışmayan
Promise.allya da{ force: true }.