Modul 4: İddialar
Səhifə ilə qarşılıqlı əlaqə qurmağı öyrəndiniz. İndi isə hər testin digər yarısından — tətbiqin həqiqətən istədiyinizi etdiyini yoxlamaqdan — danışaq. Bu modul Playwright-in tam expect() API-sini əhatə edir və assertion-ları düzgün yazmanın bütöv bir flakey test kateqoriyasını niyə aradan qaldırdığını izah edir.
🎬 Video tezliklə əlavə olunacaq
Veb-first assertion-lar
Bölmə: “Veb-first assertion-lar”Playwright assertion-ları veb-first-dir: bir dəfə qiymətləndirib uğur ya uğursuzluq bildirmir. DOM-u sıx bir dövrə üzərindən (təxminən hər 50 ms-də bir) sorğulayır və assertion keçənə — ya da vaxt aşımı bitənə qədər yenidən cəhd edir.
Bu tək dizayn qərarı sayəsində assertion-dan əvvəl demək olar ki, heç vaxt açıq gözləmə yazmağa ehtiyac qalmır.
// Element görünənə qədər (ya da vaxt aşımı bitənə qədər) avtomatik yenidən cəhd edirawait expect(page.locator('.success-banner')).toBeVisible();
// YANLIŞ — bir dəfə qiymətləndirir, yenidən cəhd yoxdur, yavaş səhifələrdə uğursuz olurconst visible = await page.locator('.success-banner').isVisible();expect(visible).toBe(true);Qızıl qayda: expect()-ə həmişə bir Locator verin, artıq gözlənilmiş dəyər deyil. Birinci forma avtomatik yenidən cəhd edir. İkincisi etmir.
| Şablon | Avtomatik yenidən cəhd? | Bunu istifadə et |
|---|---|---|
expect(locator).toBeVisible() | Bəli | Həmişə |
expect(await locator.isVisible()).toBe(true) | Xeyr | Heç vaxt |
expect(locator).toHaveText('...') | Bəli | Həmişə |
expect(await locator.textContent()).toBe('...') | Xeyr | Heç vaxt |
Yadda saxla: expect()-ə Locator ver — o, sorğulayıb yenidən cəhd edir; artıq gözlənilmiş boolean bir dəfə yoxlanılır və yenidən cəhd edə bilmir.
toBeVisible
Bölmə: “toBeVisible”toBeVisible() element DOM-da olduqda və görünür olduqda — display: none, visibility: hidden, opacity: 0 ilə gizlənmədikdə və ya görüntü sahəsindən kənarda olmadıqda keçir.
// Elementin görünür olduğunu iddia edinawait expect(page.locator('.welcome-message')).toBeVisible();
// Yükləmə fırlacının yox olduğunu iddia edinawait expect(page.locator('.spinner')).not.toBeVisible();
// Click etdikdən sonra modalın göstərildiyini iddia edinawait page.getByRole('button', { name: 'Open Modal' }).click();await expect(page.locator('.modal')).toBeVisible();toBeVisible vs toBeAttached:
toBeVisible— element DOM-dadır və ekranda görünürtoBeAttached— element gizli olsa belə DOM-dadır
React bir komponenti render etdiyini amma gizli ola biləcəyini iddia etmək istədiyinizdə toBeAttached istifadə edin. İstifadəçinin həqiqətən görə biləcəyi hər şey üçün toBeVisible istifadə edin.
// Varlıq vacibdir amma görünürlük vacib deyilawait expect(page.locator('[data-testid="lazy-component"]')).toBeAttached();
// İstifadəçi onu görə bilməlidirawait expect(page.locator('.notification')).toBeVisible();Yadda saxla: toBeVisible = DOM-da və ekranda; toBeAttached = gizli olsa belə DOM-da.
toHaveText vs toContainText
Bölmə: “toHaveText vs toContainText”Bu, assertion çaşqınlığının ən yaygın mənbəyidir. Yanlışını seçmək real debug vaxtına mal olur.
toHaveText — dəqiq uyğunluq
Bölmə: “toHaveText — dəqiq uyğunluq”toHaveText elementin tam mətn məzmununun gözlənilən stringlə dəqiq uyğunlaşdığını iddia edir (boş yerləri kəsdikdən sonra).
// Yalnız tam mətn "Order Confirmed" olduqda keçirawait expect(page.locator('h1')).toHaveText('Order Confirmed');
// Regex ilə — tam uyğunluq tələb olunurawait expect(page.locator('.status-badge')).toHaveText(/Processing/);Sizi aldatdığı hal: Element " Order Confirmed " (əlavə boş yerlə) saxlayırsa, Playwright boş yeri normallaşdırır, buna görə yenə keçir. Amma element "Your Order Confirmed" saxlayırsa, uğursuz olur.
toContainText — alt string uyğunluğu
Bölmə: “toContainText — alt string uyğunluğu”toContainText elementin mətninin gözlənilən stringi içindəki hər hansı bir yerdə ehtiva etdiyini iddia edir.
// Mətn "Order" içeriyorsa keçirawait expect(page.locator('h1')).toContainText('Order');
// Dinamik məzmun üçün çox faydalıdır — ID-lər, tarixlər, istifadəçi adlarıawait expect(page.locator('.confirmation')).toContainText('order #');
// Alt string semantikası ilə regexawait expect(page.locator('.message')).toContainText(/\d+ items/);Aralarında seçim
Bölmə: “Aralarında seçim”// toHaveText — dəqiq stringi siz idarə edirsinizawait expect(page.locator('.cart-empty')).toHaveText('Your cart is empty');
// toContainText — string dinamikdir ya da başqa mətnlə əhatə olunubawait expect(page.locator('h1')).toContainText('Order'); // "Order #12345" ilə uyğunlaşır
// Dinamik URL-lər üçün regex ilə toHaveURLawait expect(page).toHaveURL(/\/orders\/\d+/);Əsas qayda: Dəqiq mətn hər hansı bir dinamik şey (ID-lər, zaman damgaları, istifadəçi adları) ehtiva edirsə toContainText-ə müraciət edin. Stringi tamamilə siz idarə edirsizsə toHaveText istifadə edin.
Yadda saxla: toHaveText = dəqiq (boş yer normallaşdırılır), toContainText = alt string — dinamik hər şey üçün toContainText-i default seç.
toHaveValue
Bölmə: “toHaveValue”toHaveValue form sahəsinin — <input>, <textarea> ya da <select>-in — hazırkı dəyərini iddia edir.
// Mətn daxiletməsinin dəyərini iddia edinawait expect(page.locator('#email')).toHaveValue('customer@test.io');
// Textarea-nı iddia edinawait expect(page.locator('#description')).toHaveValue('Test product description');
// Select dropdown-ının hazırkı seçimini iddia edinawait expect(page.locator('#category')).toHaveValue('electronics');
// Qismən dəyər uyğunluğu üçün regex istifadə edinawait expect(page.locator('#search')).toHaveValue(/widget/i);Yaygın şablon — doldurun, sonra yoxlayın:
await page.locator('#shipping_name').fill('Jane Doe');await expect(page.locator('#shipping_name')).toHaveValue('Jane Doe');
await page.locator('#category').selectOption('electronics');await expect(page.locator('#category')).toHaveValue('electronics');Qeyd: toHaveValue DOM-un value xassəsini oxuyur, görünən mətni deyil. <select> üçün option-ın etiket mətni deyil, value atributunu qaytarır.
Yadda saxla: toHaveValue sahənin DOM value-sunu oxuyur; <select> üçün bu, etiket deyil, option-ın value-sudur.
toHaveAttribute
Bölmə: “toHaveAttribute”toHaveAttribute bir elementin müəyyən bir dəyərə sahib xüsusi bir atribut daşıdığını iddia edir.
// href atributunu iddia edinawait expect(page.getByRole('link', { name: 'Terms' })).toHaveAttribute( 'href', '/terms');
// Data atributunu iddia edinawait expect(page.locator('.product-card').first()).toHaveAttribute( 'data-product-id', '42');
// Əlçatanlıq testi üçün aria atributlarını iddia edinawait expect(page.getByRole('button', { name: 'Submit' })).toHaveAttribute( 'aria-disabled', 'true');
// Qismən atribut dəyərləri üçün regex istifadə edinawait expect(page.locator('img.hero')).toHaveAttribute('src', /\/images\//);İpucu: toHaveAttribute xüsusən disabled, aria-label, data-testid, type və href dəyərlərini iddia etmək üçün faydalıdır.
// Daxiletmədəki type atributunu iddia edinawait expect(page.locator('#password')).toHaveAttribute('type', 'password');
// "Parolu göstər" toggle-dan sonraawait page.locator('#show-password').click();await expect(page.locator('#password')).toHaveAttribute('type', 'text');Yadda saxla: toHaveAttribute(ad, dəyər) bir atributu yoxlayır — qismən uyğunluq üçün regex ver.
toHaveCount
Bölmə: “toHaveCount”toHaveCount bir lokatorla uyğunlaşan elementlərin sayını iddia edir. Bütün veb-first assertion-lar kimi, say uyğunlaşana ya da vaxt aşımı bitənə qədər yenidən cəhd edir.
// Siyahıda tam olaraq 3 element olduğunu iddia edinawait expect(page.locator('.cart-item')).toHaveCount(3);
// Cədvəlin tam olaraq 5 sətrə sahib olduğunu iddia edinawait expect(page.locator('.product-table tbody tr')).toHaveCount(5);
// Elementlərin silindiğini iddia edin — say 0-a çatana qədər yenidən cəhd edirawait expect(page.locator('.cart-item')).toHaveCount(0);toHaveCount(0) güclüdür. Hazırda 3 element varsa və toHaveCount(0) iddia edirsizsə, Playwright hamısı yox olana qədər yoxlamanı yenidən cəhd edəcək. Bu, silmə axınlarını test etmənin düzgün yoludur.
// 3 element əlavə edin, sonra hamısını silin, sonra təmiz vəziyyəti iddia edinawait expect(page.locator('.cart-item')).toHaveCount(3);
await page.locator('.remove-all-btn').click();
// Bütün elementlər DOM-dan silinənə qədər yenidən cəhd edirawait expect(page.locator('.cart-item')).toHaveCount(0);await expect(page.locator('.empty-cart-message')).toBeVisible();toHaveCount vs manual say:
// OTOMATİK YENİDƏN CƏHD EDIR — elementlər asinxron olaraq göründüyündə bunu istifadə edinawait expect(page.locator('.search-result')).toHaveCount(5);
// OTOMATİK YENİDƏN CƏHD ETMİR — yalnız sinxron anlıq görüntülər üçün istifadə edinconst count = await page.locator('.search-result').count();expect(count).toBeGreaterThan(0);Yadda saxla: toHaveCount(n) say dəqiq n olana qədər yenidən cəhd edir; toHaveCount(0) “hamısı getdi”-ni iddia etmənin təmiz yoludur.
toBeEnabled və toBeDisabled
Bölmə: “toBeEnabled və toBeDisabled”Bu assertion-lar form kontrolunun interaktiv olub olmadığını yoxlayır. Otomatik yenidən cəhd edirlər — məcburi sahələr doldurulduqdan sonra göndər düyməsinin aktiv hala gəldiyini iddia etmək üçün faydalıdır.
// Göndər düyməsinin aktiv olduğunu iddia edinawait expect(page.locator('button[type="submit"]')).toBeEnabled();
// Form boş olduqda göndər düyməsinin deaktiv olduğunu iddia edinawait expect(page.locator('button[type="submit"]')).toBeDisabled();Şablon — yalnız forma düzgün olduqda aktivləşən düymə:
Bəzi tətbiqlər bütün məcburi sahələr doldurulana qədər göndər düyməsini deaktiv saxlayır. Bu assertion-lar avtomatik yenidən cəhd etdiyi üçün keçidi manual gözləmə olmadan iddia edə bilərsiniz:
// Forma düzgün olana qədər düyməsini deaktiv saxlayan signup formasındaawait expect(page.locator('#signup-btn')).toBeDisabled();
await page.getByLabel('Email').fill('new@user.io');await page.getByLabel('Password').fill('secret123');await page.getByLabel('Confirm Password').fill('secret123');
// Playwright düymə aktivə keçənə qədər yenidən cəhd edirawait expect(page.locator('#signup-btn')).toBeEnabled();toBeEnabled vs not.toBeDisabled: Ekvivalentdirlər. Test ssenarinizdə daha natural oxunanı seçin.
// Bu iki sətir eyni şeyi iddia edirawait expect(page.locator('#submit')).toBeEnabled();await expect(page.locator('#submit')).not.toBeDisabled();Yadda saxla: toBeEnabled/toBeDisabled avtomatik yenidən cəhd edir, ona görə kontrolun vəziyyət dəyişməsini gözləyir; toBeEnabled ≡ not.toBeDisabled.
Mənfi assertion-lar
Bölmə: “Mənfi assertion-lar”İstənilən Playwright assertion-ı .not ilə inkar edilə bilər. İnkar edilmiş assertion da otomatik yenidən cəhd edir — şərt yanlış olana qədər gözləyir.
// Bir element artıq görünməyənə qədər gözləyin (məsələn, yükləmə fırlacı)await expect(page.locator('.loading-spinner')).not.toBeVisible();
// Admin olmayan istifadəçilərin admin kontrollarını görə bilmədiyini iddia edinawait expect(page.locator('#admin-panel')).not.toBeVisible();
// URL-in admin bölməsinə getmədiyini iddia edinawait expect(page).not.toHaveURL('/admin');
// Mətni olmadığını iddia edinawait expect(page.locator('.status')).not.toHaveText('Error');
// Sahənin təmizləndiyini iddia edinawait expect(page.locator('#search')).not.toHaveValue('old query');Giriş kontrolu üçün mənfi assertion-lar:
test('admin olmayan istifadəçi admin bölməsindən yönləndirilir', async ({ page }) => { // Normal müştəri (admin deyil) kimi daxil olun await page.goto('/admin');
// Səhifənin yönləndirildiyini iddia edin — URL /admin ehtiva etməməlidir await expect(page).not.toHaveURL(/\/admin/);
// Admin panel başlığının görünmədiyini iddia edin await expect(page.locator('h1')).not.toHaveText('Admin Dashboard');
// Bunun əvəzinə xəta xəbərdarlığının görünür olduğunu iddia edin await expect(page.locator('.alert.alert-error')).toBeVisible();});Yadda saxla: .not da yenidən cəhd edir — şərt yanlış olana qədər gözləyir (fırlacın yox olması, sahənin təmizlənməsi).
Soft assertion-lar
Bölmə: “Soft assertion-lar”Defolt olaraq uğursuz bir assertion testi dərhal dayandırır. Soft assertion-lar fərqlidir — soft assertion uğursuz olsa belə test davam edir. Bütün uğursuzluqlar toplanır və testin sonunda birlikdə bildirilir.
// Soft assertion-lar — bunlar uğursuz olsa belə test davam edirawait expect.soft(page.locator('.widget-revenue')).toBeVisible();await expect.soft(page.locator('.widget-orders')).toBeVisible();await expect.soft(page.locator('.widget-users')).toBeVisible();await expect.soft(page.locator('.widget-products')).toBeVisible();
// Testin sonunda Playwright bütün uğursuzluqları bir anda bildirir// yuxarıdakılardan biri uğursuz olsa beləSoft assertion-lar nə vaxt istifadə edilər:
- Panel smoke testləri — 10+ vidgeti yoxlamaq və yalnız birincini deyil, bütün uğursuzları görmək istəyirsiniz
- Vizual tamlıq yoxlamaları — bir səhifənin bütün bölümlərinin düzgün render olunduğunu yoxlamaq
- Paralel forma validasiyası — eyni anda bir neçə sahəni yoxlamaq
test('admin panel smoke testi', async ({ page }) => { // (admin kimi daxil olunub) await page.goto('/admin');
// Hər stat kartını yoxlayın — bütün çatışmayanları bir anda bildirin await expect.soft(page.getByRole('heading', { name: 'Total Products' })).toBeVisible(); await expect.soft(page.getByRole('heading', { name: 'Total Users' })).toBeVisible(); await expect.soft(page.getByRole('heading', { name: 'Total Orders' })).toBeVisible(); await expect.soft(page.getByRole('heading', { name: 'Recent Orders' })).toBeVisible();
// İsteğe bağlı: soft uğursuzluqların toplanmadığını iddia edin expect(test.info().errors).toHaveLength(0);});Diqqət: Soft assertion-lar güclüdür, amma onlardan səhv istifadə etmək asandır. Bir testin 15 soft assertion-ı varsa və 10-u uğursuz olarsa, bildiriş çox qarışıq olur. Onları test strukturu haqqında düşünməmənin bir yolu kimi deyil, smoke yoxlamaları üçün qəsdən istifadə edin.
Yadda saxla: expect.soft(...) uğursuzluğu qeyd edib davam edir — smoke yoxlamaları üçün, kritik yol axını üçün yox.
Xüsusi expect vaxt aşımları
Bölmə: “Xüsusi expect vaxt aşımları”Defolt olaraq, hər veb-first assertion uğursuz olmazdan əvvəl 5 saniyə gözləyir. Bunu hər assertion üçün ayrıca ya da qlobal olaraq dəyişdirə bilərsiniz.
Assertion-başına vaxt aşımı
Bölmə: “Assertion-başına vaxt aşımı”// Bu xüsusi assertion üçün 10 saniyəyə qədər gözləyinawait expect(page.locator('.slow-component')).toBeVisible({ timeout: 10_000 });
// Qısa vaxt aşımı — element tez görünmürsə sürətlə uğursuz olunawait expect(page.locator('.instant-feedback')).toBeVisible({ timeout: 1_000 });
// İstənilən assertion-da xüsusi vaxt aşımıawait expect(page.locator('.report-table')).toHaveCount(50, { timeout: 15_000 });playwright.config.js-də qlobal vaxt aşımı
Bölmə: “playwright.config.js-də qlobal vaxt aşımı”import { defineConfig } from '@playwright/test';
export default defineConfig({ expect: { timeout: 10_000, // bütün assertion-lar üçün 10 saniyə },});Xüsusi vaxt aşımı nə vaxt istifadə edilər:
- Məlum yavaş əməliyyatlar (hesabat yaratma, fayl emalı, email çatdırılması)
- Yerli geliştirme mühitindən əhəmiyyətli dərəcədə daha yavaş olan CI mühitləri
- Başlatmaq üçün vaxt tələb edən üçüncü tərəf vidgetləri
Xüsusi vaxt aşımı nə vaxt istifadə edilməməlidir: yavaş ya da flakey bir tətbiq üçün plaster kimi. Hər yerə timeout: 30_000 əlavə edirsinizsə, doğru düzəliş testi deyil, tətbiqin profilini çıxarmaqdır.
Yadda saxla: { timeout } ilə hər assertion üçün və ya expect.timeout ilə qlobal olaraq dəyiş — həqiqətən yavaş əməliyyatlar üçün, flakey tətbiqi gizlətmək üçün yox.
Assertion yaddaş vərəqi
Bölmə: “Assertion yaddaş vərəqi”| Nəyi iddia etmək istəyirəm… | İstifadə et |
|---|---|
| Element görünür / gizli | toBeVisible() · not.toBeVisible() |
| Element DOM-da (bəlkə gizli) | toBeAttached() |
| Dəqiq mətn | toHaveText('…') |
| Mətnin alt stringi | toContainText('…') |
| Form sahəsinin dəyəri | toHaveValue('…') |
| Atributun dəyəri | toHaveAttribute('ad', '…') |
| Neçə element uyğun gəlir | toHaveCount(n) (0 daxil) |
| Kontrol interaktivdir | toBeEnabled() · toBeDisabled() |
| Checkbox / radio vəziyyəti | toBeChecked() (Modul 3-ə bax) |
| Hazırkı səhifə URL-i | toHaveURL('…' və ya /regex/) |
| Səhifədəki bütün uğursuzluqları topla | expect.soft(…) |
| Yavaş element üçün daha çox gözlə | …({ timeout: 10_000 }) |
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: Səbət vəziyyətini iddia edin
Bölmə: “Tapşırıq 1: Səbət vəziyyətini iddia edin”tests/starter/mod4/cart-assertions.spec.js yaradın. beforeEach daxil olur; sonra hər test veb-first assertion-larla bir səbət vəziyyətini iddia edir.
import { test, expect } from '@playwright/test';
test.describe('Səbət assertion-ları', () => { test.beforeEach(async ({ page }) => { await page.goto('/auth/login'); await page.locator('#email').fill('customer@test.io'); await page.locator('#password').fill('customer123'); await page.getByTestId('login-submit').click(); await expect(page.locator('.alert.alert-success')).toBeVisible(); });
test('elementləri olan səbət sətirlər, cəm və ödəniş keçidi göstərir', async ({ page }) => { await page.goto('/products'); await page.getByTestId('add-to-cart').first().click(); await page.goto('/cart');
await expect(page.locator('.cart-table .table-row')).not.toHaveCount(0); await expect(page.locator('.total-row h3')).toBeVisible(); await expect(page.getByRole('link', { name: 'Proceed to Checkout' })).toBeVisible(); });
test('boş səbət boş vəziyyət mesajını göstərir', async ({ page }) => { // Təzə brauzer konteksti boş (sessiya əhatəli) səbətlə başlayır await page.goto('/cart');
await expect(page.getByText('Your cart is empty')).toBeVisible(); await expect(page.locator('.cart-table .table-row')).toHaveCount(0); await expect(page.locator('.total-row h3')).not.toBeVisible(); });});Tapşırıqlar:
- Birinci testdə
not.toHaveCount(0)-utoHaveCount(5)-ə dəyişin və assertion-ın uğursuz olmazdan əvvəl tam vaxt aşımı boyunca yenidən cəhd etməsinə baxın. add-to-cartsətrini silin — indinot.toHaveCount(0)uğursuz olur, çünki səbət boşdur.
Tapşırıq 2: Ödəniş təsdiqi assertion-ları
Bölmə: “Tapşırıq 2: Ödəniş təsdiqi assertion-ları”tests/starter/mod4/checkout-assertions.spec.js yaradın. beforeEach daxil olur, məhsul əlavə edir və ödənişi açır.
import { test, expect } from '@playwright/test';
test.describe('Ödəniş assertion-ları', () => { test.beforeEach(async ({ page }) => { await page.goto('/auth/login'); await page.locator('#email').fill('customer@test.io'); 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 təsdiq səhifəsinə aparır', 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'); await page.getByTestId('place-order').click();
// Dinamik sifariş URL-i — regex ilə uyğunlaşdır await expect(page).toHaveURL(/\/orders\/\d+/); // Başlıq "Order Confirmation" oxuyur — alt string uyğunluğu await expect(page.locator('h1')).toContainText('Order'); await expect(page.locator('.alert.alert-success')).toBeVisible(); });
test('boş forma HTML5 validasiyası ilə bloklanır', async ({ page }) => { // Məcburi sahələr göndərməni client tərəfdə dayandırır — səhifə naviqasiya etmir await page.getByTestId('place-order').click(); await expect(page).toHaveURL(/\/checkout/); });});Tapşırıqlar:
toContainText('Order')-utoHaveText('Order')ilə dəyişin — dəqiq uyğunluq uğursuz olur (real mətn “Order Confirmation”-dır); geri qaytarın.- Boş forma testində yalnız
#shipping_name-i doldurun, sonra göndərin — növbəti çatışmayan məcburi sahə yenə naviqasiyanı bloklayır.
Tapşırıq 3: Admin assertion-ları — cədvəl + giriş kontrolu
Bölmə: “Tapşırıq 3: Admin assertion-ları — cədvəl + giriş kontrolu”tests/starter/mod4/admin-assertions.spec.js yaradın. Bir test admin kimi daxil olur; digəri müştərinin bloklandığını sübut edir.
import { test, expect } from '@playwright/test';
test.describe('Admin assertion-ları', () => {
test('admin məhsullar səhifəsi sətirlər və New Product düyməsi göstərir', async ({ page }) => { await page.goto('/auth/login'); await page.locator('#email').fill('admin@test.io'); await page.locator('#password').fill('admin123'); await page.getByTestId('login-submit').click();
await page.goto('/admin/products'); await expect(page.locator('.table-row')).not.toHaveCount(0); await expect(page.getByRole('link', { name: 'New Product' })).toBeVisible(); });
test('müştəri /admin-dən xəta ilə yönləndirilir', async ({ page }) => { await page.goto('/auth/login'); await page.locator('#email').fill('customer@test.io'); await page.locator('#password').fill('customer123'); await page.getByTestId('login-submit').click();
await page.goto('/admin');
// /admin-dən yönləndirilir (tətbiq admin olmayanları ana səhifəyə göndərir)... await expect(page).not.toHaveURL(/\/admin/); // ...və giriş-rədd flash-ı həmin təyinat səhifəsində render olunur await expect(page.locator('.alert.alert-error')).toContainText('Access denied'); });});Tapşırıqlar:
- İkinci testdə müştəri kimlik məlumatlarını admin-inkilərlə dəyişin — yönləndirmə assertion-ı indi uğursuz olur, çünki admin həqiqətən
/admin-ə çatır. - Birinci testə
await expect(page.locator('.alert.alert-error')).not.toBeVisible();əlavə edin ki, düzgün admin yüklənməsində xəta görünmədiyini təsdiqləyəsiniz.
Tapşırıq 4: Sabit gözləmələri assertion-larla əvəz edin
Bölmə: “Tapşırıq 4: Sabit gözləmələri assertion-larla əvəz edin”Bu flakey testi refaktor edin — hər waitForTimeout-u düzgün veb-first assertion-la əvəz edin:
// ƏVVƏL (flakey — hər yerdə sabit yuxular)import { test, expect } from '@playwright/test';
test('flakey axtarış testi', async ({ page }) => { await page.goto('/products'); await page.waitForTimeout(2000); await page.fill('#search', 'Wireless'); await page.waitForTimeout(1000); await page.click('#apply-filters'); await page.waitForTimeout(3000); const count = await page.locator('.product-card').count(); expect(count).toBeGreaterThan(0); await page.waitForTimeout(1000); expect(page.url()).toContain('search=Wireless');});| Yuxu | Əvəz et |
|---|---|
waitForTimeout(2000) | Silin — fill() artıq avtomatik gözləyir |
waitForTimeout(1000) | Silin — click() artıq avtomatik gözləyir |
waitForTimeout(3000) + manual say | expect(locator).not.toHaveCount(0) |
waitForTimeout(1000) + page.url() | expect(page).toHaveURL(/[?&]search=Wireless/) |
// SONRA (veb-first — sabit yuxular yoxdur)import { test, expect } from '@playwright/test';
test('etibarlı axtarış testi', 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 5: Soft assertion-lar — bütün vidgetləri bir anda yoxlayın
Bölmə: “Tapşırıq 5: Soft assertion-lar — bütün vidgetləri bir anda yoxlayın”tests/starter/mod4/soft-assertions.spec.js yaradın. Bu tamamilə öz-özünə yetərlidir — page.evaluate ilə mock panel inject edir, ona görə istənilən səhifədə işləyir.
import { test, expect } from '@playwright/test';
test('soft assertion-larla panel smoke yoxlaması', async ({ page }) => { await page.goto('/products');
// Dörd stat vidgeti olan mock panel inject edin await page.evaluate(() => { const panel = document.createElement('div'); panel.id = 'dashboard'; panel.innerHTML = ` <div data-testid="widget-revenue">Revenue: $12,400</div> <div data-testid="widget-orders">Orders: 87</div> <div data-testid="widget-users">Users: 1,203</div> <div data-testid="widget-products">Products: 56</div>`; document.body.appendChild(panel); });
// Soft assertion-lar: əvvəlki biri uğursuz olsa belə hər vidget yoxlanılır, // və bütün uğursuzluqlar testin sonunda birlikdə bildirilir. await expect.soft(page.getByTestId('widget-revenue')).toBeVisible(); await expect.soft(page.getByTestId('widget-orders')).toBeVisible(); await expect.soft(page.getByTestId('widget-users')).toBeVisible(); await expect.soft(page.getByTestId('widget-products')).toBeVisible();
// İsteğe bağlı qapı: hər hansı soft assertion uğursuz olubsa testi uğursuz et expect(test.info().errors).toHaveLength(0);});Tapşırıqlar:
- İnject edilmiş HTML-dən
widget-userssətrini silin (assertion-ını saxlayın) və yenidən işlədin — test yenə hər dörd vidgeti yoxlayır, sonra bir uğursuzluğu sonda bildirir, ona toxunub dayanmır. - Hər dörd
expect.soft-u sadəexpect-ə dəyişin, vidget hələ də çatışmırkən — indi test ilk uğursuzluqda dayanır və qalanını heç vaxt yoxlamır. Bu fərq soft assertion-ların bütün məğzidir.
Özünü yoxlama sualları
Bölmə: “Özünü yoxlama sualları”- Nə üçün
expect(locator).toBeVisible()avtomatik yenidən cəhd edir, ammaexpect(await locator.isVisible()).toBe(true)etmir? toHaveTextvstoContainText-i nə vaxt istifadə edərdiniz? Hər biri üçün bir nümunə verin.- Hazırda 5 uyğun element varsa
toHaveCount(0)nə edir? - Adi assertion ilə soft assertion (
expect.soft) arasındakı fərq nədir? - Assertion-başına vaxt aşımını necə təyin edirsiniz? Qlobal defoltunu necə?
- Nə üçün
toBeEnabledforma validasiya testləri üçün faydalıdır? toHaveAttribute('href', '/terms')nəyi iddia edir?- Nə üçün
expect(page.url()).toContain('/admin')expect(page).toHaveURL('/admin')-dən daha pisdir?
Əsas nəticələr
Bölmə: “Əsas nəticələr”Hər testə apardığınız dörd qayda:
expect()-ə həmişəLocatorverin — gözlənilmiş dəyər deyil.expect(locator).toBeVisible()yenidən cəhd edir;expect(await locator.isVisible()).toBe(true)etmir.- Dinamik məzmun üçün
toContainText, dəqiq stringlər üçüntoHaveText— şübhə etdikdətoContainText-i üstün tutun toHaveCountelement siyahılarında yenidən cəhd edir — elementlər asinxron olaraq göründüyündəcount()-dan əvəz istifadə edin- Smoke testləri üçün soft assertion-lar, axın testləri üçün hard assertion-lar — səhifə səviyyəsindəki yoxlamada bütün uğursuzluqları toplayın; kritik yol testlərində sürətlə uğursuz olun
Modul 5 avtomatik gözləməni əhatə edir — Playwright-in daxili əməliyyat yoxlamalarının açıq gözləmələri necə aradan qaldırdığını və onlar kifayət etmədikdə nə edəcəyinizi öyrənəcəksiniz.