Mundarija (33)
- Bu darsda
- 1. Nega bu kerak?
- 2. Playwright nima
- 3. Boshlash: npm init playwright
- 3.1 Loyiha ochish
- 3.2 Brauzerlar qayerdan keladi
- 4. Birinchi test: vazifa qo'shish
- 5. Lokatorlar
- 5.1 Oila va ustuvorlik
- 5.2 Strict mode: bitta lokator — bitta element
- 5.3 Toraytirish
- 6. Auto-wait va web-first assertion
- 6.1 Auto-wait: bosishdan oldin tekshiruv
- 6.2 Web-first assertion
- 6.3 Tuzoq: isVisible() — bir martalik surat
- 6.4 expect.poll — sahifadan tashqaridagi qiymat
- 7. webServer: test oldidan ilovani ishga tushirish
- 8. Soxta API: page.route bilan birinchi tanishuv
- 9. Kanon testlaridan uch usul
- 10. UI mode, debug, codegen va hisobot
- 11. Vazifalar qadami: Playwright e2e (holat 09)
- 11.1 O'rnatish va fayllar
- 11.2 Birinchi o'tishdagi xatolar
- 11.3 Natija va commit
- 12. Ko'p uchraydigan xatolar
- 13. Mashqlar
- 1-mashq (oson): bo'sh joylarni to'ldiring
- 2-mashq (o'rta): Bobur va buyruqlar oynasi
- 3-mashq (qiyin): o'chirish oqimi
- 4-mashq: Vazifalar qadami
- 14. Real ishda
- Xulosa
- Manbalar
Playwright I: e2e testlar asoslari — lokatorlar, auto-wait, web-first assertion va webServer
Qisqacha: Playwright — butun ilovani haqiqiy brauzerda (Chromium, Firefox, WebKit) foydalanuvchi kabi ishlatadigan test vositasi. Test
@playwright/testdan:test("…", async ({ page }) => { await page.goto("/"); … }). Elementlar lokator bilan topiladi —page.getByRole("button", { name: "Saqlash" }); Playwright bosishdan oldin element ko'rinishi, harakatsiz va yoqilgan bo'lishini o'zi kutadi (auto-wait). Tekshiruvawait expect(lokator).toBeVisible()— 5 soniyagacha qayta uriniladi (web-first assertion).webServersozlamasi testdan oldin ilovani o'zi build qilib ishga tushiradi.
Bu darsda
npm init playwrightbilan loyiha ochib, yaratilgan fayllarni o'qiysiz.- Lokatorlar, strict mode va
exactbilan elementni aniq topasiz. - Auto-wait va web-first assertion qanday ishlashini,
isVisible()nega tuzoq ekanini tushuntirasiz. webServerbilan production build ustida test yozasiz;page.routebilan soxta API bilan tanishasiz.- UI mode,
--debug, codegen va HTML hisobot nima uchun kerakligini bilasiz.
Oldin bilishingiz kerak: Nega test yozamiz, RTL I: so'rovlar, Vitest Browser Mode, Vite build va preview.
1. Nega bu kerak?
O'tgan darsda komponentni haqiqiy Chrome'da sinadik. Lekin u baribir bitta komponent edi, test o'zi chizgan. Foydalanuvchi esa komponentni ko'rmaydi — u butun ilovani ochadi. Ilova esa ko'p qavat: Vite build, router, tarjimalar, service worker, CSS, server bilan aloqa.
Bu qavatlar orasidagi xatoni komponent testi ko'rmaydi. Router noto'g'ri yo'naltirsa, build'da fayl yo'qolsa, ruscha sahifada havola buzilsa — faqat foydalanuvchi biladi. Coverage hisobotida sahifalar 0 % edi — aynan shu bo'shliq.
17-qismdan beri vazifalar ni har qadamda biz — kurs mualliflari — o'z skriptlarimiz bilan brauzerda tekshirib keldik ("brauzer tekshiruvi 159"). Endi bu ish loyihaning o'zida bo'ladi: siz yozasiz, siz yurgizasiz.
E2E test (Nega test yozamiz darsida tanishgan edik) — ilovani boshidan oxirigacha, foydalanuvchi yo'li bo'yicha sinash. O'xshatish: restoran inspektori oshxonadagi har pichoqni emas, mehmon sifatida kelib, buyurtma berib, ovqatni yeb ko'radi.
2. Playwright nima
Playwright — Microsoft chiqargan brauzer boshqarish vositasi (playwright.dev). Ikki qismi bor:
playwright— kutubxona: brauzerni ochish, sahifaga o'tish, bosish. Browser Mode aynan shunga tayangan edi.@playwright/test— test vositasi (test runner):test,expect, parallel ishlash, hisobot, qayta urinish.
Uchta brauzer dvigateli bilan ishlaydi: Chromium (Chrome va Edge asosi), Firefox va WebKit (Safari asosi). Brauzer mosligi darsida aytgan edik: Playwright ularni o'zi bilan olib keladi. Bitta test uchala dvigatelda ishlashi mumkin.
Har test yangi brauzer konteksti (browser context) da boshlanadi. Kontekst — inkognito oynaga o'xshaydi: o'z cookie'lari, localStorage i, keshi. Bitta test qoldirgan narsa keyingisiga o'tmaydi.
flowchart TB
R["npx playwright test"] --> W["webServer: build + preview"]
R --> P1["ishchi 1"]
R --> P2["ishchi 2"]
P1 --> C1["kontekst → sahifa → test A"]
P2 --> C2["kontekst → sahifa → test B"]
C1 --> W
C2 --> WRasmga qarang: test vositasi avval ilovani ishga tushiradi, keyin testlarni bir nechta ishchi (worker) ga — parallel jarayonlarga — bo'lib beradi. Har test o'z toza kontekstida ilovaga ulanadi.
3. Boshlash: npm init playwright
3.1 Loyiha ochish
Playwright'ning rasmiy boshlovchisi savollar beradi (TypeScript yoki JS, test papkasi, GitHub Actions). Biz javoblarni bayroq bilan berdik va brauzer yuklashni o'chirdik — bo'sh papkada:
npm init playwright@latest -- --quiet --lang=ts --browser=chromium --no-browsers --ghaGetting started with writing end-to-end tests with Playwright:
Initializing project in '.'
Installing Playwright Test (npm install --save-dev @playwright/test)…
added 3 packages, and audited 4 packages in 2s
found 0 vulnerabilities
Installing Types (npm install --save-dev @types/node)…
…
Writing playwright.config.ts.
Writing .github\workflows\playwright.yml.
Writing tests\example.spec.ts.
Writing package.json.
✔ Success! Created a Playwright Test project at C:\Users\…\init-pwChiqish oxirida foydali buyruqlar ro'yxati bor (npx playwright test, --ui, --debug, codegen) — ularni pastda ko'ramiz. Yaratilgan fayllar:
| Fayl | Nima |
|---|---|
playwright.config.ts |
sozlama: test papkasi, brauzerlar, hisobot |
tests/example.spec.ts |
namuna test (playwright.dev saytini ochadi) |
.github/workflows/playwright.yml |
CI fayli — Playwright II da o'zimiznikini yozamiz |
package.json |
@playwright/test qo'shildi |
2026-10-20 holatiga @playwright/test ning eng yangi versiyasi 1.64.1 (14-oktabr). Kanon esa 1.64.0 da (semver: patch farqi). Shablon yozgan workflow actions/checkout@v4 ishlatadi — bu eski versiya. GitHub Actions darsida @v7 ni ishlatgan edik. Shablon har doim ham eng yangisini yozmaydi — tekshiring.
3.2 Brauzerlar qayerdan keladi
npx playwright install Playwright'ning shu versiyasiga moslangan brauzerlarni yuklaydi. Nima yuklanishini --dry-run ko'rsatadi (qisqartirilgan):
Chrome for Testing 156.0.8078.4 (playwright chromium v1248)
Install location: C:\Users\…\AppData\Local\ms-playwright\chromium-1248
Chrome Headless Shell 156.0.8078.4 (playwright chromium-headless-shell v1248)
Install location: C:\Users\…\AppData\Local\ms-playwright\chromium_headless_shell-1248
Firefox 157.0 (playwright firefox v1555)
…
WebKit 27.2 (playwright webkit v2370)
…Brauzerlar loyiha ichiga emas, foydalanuvchi papkasidagi umumiy keshga (ms-playwright) tushadi. Kanon esa Browser Mode dagi kabi hech narsa yuklamadi — channel: "chrome" bilan kompyuterdagi Google Chrome ishlatiladi.
4. Birinchi test: vazifa qo'shish
Kanondagi e2e/asosiy.spec.ts ning birinchi testi:
test("qo'shish: Enter — qator paydo bo'ladi, POST ketadi", async ({
page,
}) => {
const server = await soxtaApi(page);
await page.goto("/");
const maydon = page.getByRole("textbox", { name: "Yangi vazifa" });
await maydon.fill("Choy damlash");
await maydon.press("Enter");
await expect(
page.getByRole("checkbox", { name: "Choy damlash" }),
).toBeVisible();
await expect(maydon).toHaveValue("");
await expect(maydon).toBeFocused();
// expect.poll — oddiy qiymatni (bu yerda — server holati)
// kutadi
await expect.poll(() => server.sorovlar).toContain("POST");
expect(server.tanalar).toContain('POST {"matn":"Choy damlash"}');
});Qatorma-qator:
testvaexpect—@playwright/testdan (Vitest'dan emas, lekin juda o'xshash).async ({ page })— test funksiyasi argument sifatida tayyorpageoladi: yangi kontekstdagi bo'sh sahifa. Bunday tayyor narsalar fixture deyiladi — Playwright II da o'zimiznikini yozamiz.soxtaApi(page)— server o'rnida soxta API («Soxta API» bo'limida).page.goto("/")— sahifani ochish. To'liq manzil emas:baseURLkonfiguratsiyada.fill("Choy damlash")— maydonni tozalab, matn yozadi.press("Enter")— klaviatura tugmasi.await expect(...).toBeVisible()— yangi qator chiqqanini kutib tekshiradi.toHaveValue(""),toBeFocused()— maydon tozalandi va fokus unda qoldi: Bobur keyingi vazifani darhol yoza oladi.
Butun to'plamni yurgizamiz (biz yurgizdik, holat 09):
npx playwright testQatorlar tartibiga va boshidagi raqamlarga qarang — ular nega 3, 4, 1, 5, 2 bo'lib ketdi?
Running 5 tests using 5 workers
ok 3 [chrome] › e2e\asosiy.spec.ts:36:1 › tahrir: forma → PATCH, vazifa sahifasiga qaytadi (2.0s)
ok 4 [chrome] › e2e\asosiy.spec.ts:18:1 › qo'shish: Enter — qator paydo bo'ladi, POST ketadi (2.1s)
ok 1 [chrome] › e2e\asosiy.spec.ts:55:1 › oflayn: o'zgarish navbatda, internet qaytganda yuboriladi (2.1s)
ok 5 [chrome] › e2e\asosiy.spec.ts:104:1 › eksport: «Faylga yuklab olish» — JSON fayl, ichida ro'yxat (2.3s)
ok 2 [chrome] › e2e\asosiy.spec.ts:87:1 › til: /ru/ — ruscha; sozlamalarda English — /en/sozlamalar (2.7s)
5 passed (11.4s)[chrome] — loyiha (project) nomi. Testlar e'lon tartibida emas, tugash tartibida chiqadi: 5 ta ishchi ularni bir vaqtda yurgizdi. Raqam (ok 3) — test tartib raqami. Sizda vaqtlar boshqacha bo'ladi.
5. Lokatorlar
5.1 Oila va ustuvorlik
Playwright lokatorlari Browser Mode dagilar kabi "qidiruv yo'riqnomasi": qidiruv harakat paytida bo'ladi. Ustuvorlik RTL dagidek:
| Lokator | Qachon |
|---|---|
getByRole("button", { name }) |
deyarli hamma narsa — birinchi tanlov |
getByLabel("Ismingiz") |
forma maydoni (RTL'da getByLabelText) |
getByPlaceholder, getByText |
label yoki rol bo'lmasa |
getByAltText, getByTitle |
rasm, title |
getByTestId("…") |
oxirgi chora (data-testid) |
locator("#aloqa") |
CSS selektor — kanon faqat id li xabar hududlari uchun |
Farq bitta: Playwright rol va nomni W3C ARIA qoidalari bo'yicha ekran o'quvchi ko'rganidek hisoblaydi (hujjatda: "foydalanuvchi va yordamchi texnologiya sahifani qanday qabul qilsa"). Ekran o'quvchidan yashirin elementlar (display: none, aria-hidden="true") sukut bo'yicha o'tkazib yuboriladi. Bir nozik farq: Browser Mode lokatori inert orqa fondagi tugmani ham "topgan" edi — u yerda tekshiruvni fokus orqali qildik.
5.2 Strict mode: bitta lokator — bitta element
Harakat yoki tekshiruv paytida lokator aniq bitta elementga mos kelishi shart. Ikkitasi topilsa — xato. Bu strict mode (qat'iy rejim). Biz statistika sahifasida sarlavhani qidirdik:
await page.goto("/statistika");
await expect(
page.getByRole("heading", { name: "Statistika" }),
).toBeVisible(); Error: expect(locator).toBeVisible() failed
Locator: getByRole('heading', { name: 'Statistika' })
Expected: visible
Error: strict mode violation: getByRole('heading', { name: 'Statistika' }) resolved to 2 elements:
1) <h2 tabindex="-1">Statistika</h2> aka getByRole('heading', { name: 'Statistika', exact: true })
2) <h2 id="_r_4_">…</h2> aka getByRole('heading', { name: 'Batafsil statistika' })Tarjima: "qat'iy rejim buzildi: lokator 2 ta elementga mos keldi". Nega «Batafsil statistika» ham? name sukut bo'yicha qism bo'yicha va katta-kichik harfga qaramay solishtiriladi: "statistika" so'zi ikkala nomda ham bor. Xabarning o'zi yechim taklif qiladi — aka dan keyin har element uchun aniq lokator. Birinchisiga exact: true qo'shilgan: endi nom to'liq mos kelishi kerak.
Kanon birinchi o'tishda aynan shu xatoga uchradi — kirish testida sarlavha { level: 2, name: "Statistika", exact: true } shundan.
Nega xato yaxshi? Strict mode bo'lmasa, Playwright birinchisini bosardi — balki noto'g'risini. Test "o'tardi", lekin boshqa narsani tekshirardi.
5.3 Toraytirish
Element bir guruh ichida bo'lsa — lokatorni lokator ichidan chaqiring (within ning Playwright ko'rinishi):
const dialog = page.getByRole("dialog", {
name: "Vazifa o'chirilsinmi?",
});
await dialog.getByRole("button", { name: "Bekor qilish" }).click();
// Ro'yxatdan "Non olish" bor qatorni topib, ichidagi tugma
await page
.getByRole("listitem")
.filter({ hasText: "Non olish" })
.getByRole("button", { name: /O'chirish/ })
.click();filter({ hasText }) — faqat shu matnni o'z ichiga olgan elementlar. first(), nth(2) ham bor, lekin ehtiyot bo'ling: tartib o'zgarsa, test boshqa elementni bosadi.
Tekshirib ko'ring: Sahifada «Saqlash» va «Saqlash va chiqish» tugmalari bor.
page.getByRole("button", { name: "Saqlash" }).click()nima qiladi?
Javob
Strict mode xatosi: nom qism bo'yicha solishtiriladi, ikkala tugma ham mos keladi. Playwright tavakkal bosmaydi. Tuzatish — { name: "Saqlash", exact: true } yoki tugmalarni ajratadigan konteyner ichidan qidirish.
6. Auto-wait va web-first assertion
6.1 Auto-wait: bosishdan oldin tekshiruv
click() darhol bosmaydi. Playwright avval harakatga tayyorlikni (actionability) tekshiradi va hammasi bajarilguncha kutadi:
| Tekshiruv | Ma'nosi |
|---|---|
| Visible | ko'rinadi (o'lchami bor, visibility: hidden emas) |
| Stable | harakatlanmayapti (animatsiya tugagan) |
| Receives Events | bosish nuqtasida aynan shu element turadi — ustini toast yoki boshqa oyna yopmagan |
| Enabled | disabled emas |
Jadval Playwright hujjatidan ("Actionability", click uchun to'rt tekshiruv). fill boshqacha to'plamni tekshiradi: Visible, Enabled va Editable (tahrirlanadi, readonly emas). Bundan oldin esa strict mode qoidasi ishlaydi: lokator aniq bitta elementga mos kelishi kerak. Shuning uchun e2e testlarda sleep(500) yozilmaydi — animatsiya tugashini Playwright o'zi kutadi.
O'xshatish: ehtiyotkor haydovchi. Svetofor yashil bo'ldi, piyoda o'tib bo'ldi, oldindagi mashina qo'zg'aldi — shundan keyin yuradi. Soat bo'yicha "3 soniyadan keyin yuraman" demaydi.
6.2 Web-first assertion
await expect(lokator).toBeVisible() — web-first assertion (sahifaga mos tekshiruv): shart bajarilguncha qayta tekshiradi, sukut bo'yicha 5 soniya. Element umuman chiqmasa:
Error: expect(locator).toBeVisible() failed
Locator: getByRole('button', { name: 'Yuborish' })
Expected: visible
Timeout: 5000ms
Error: element(s) not found
Call log:
- Expect "toBeVisible" getByRole('button', { name: 'Yuborish' }) with timeout 5000ms
- waiting for getByRole('button', { name: 'Yuborish' })Tarjima: "5 000 ms ichida element topilmadi". Call log — Playwright nima qilganining kundaligi. Butun test uchun alohida chegara bor — sukut bo'yicha 30 s.
flowchart LR
A["expect(lokator).toBeVisible()"] --> B{"shart bajarildimi?"}
B -- ha --> C["✓ davom"]
B -- "yo'q" --> D{"5 s o'tdimi?"}
D -- "yo'q" --> E["biroz kut"] --> B
D -- ha --> F["× Timeout: 5000ms"]6.3 Tuzoq: isVisible() — bir martalik surat
locator.isVisible() qayta urinmaydi — u shu lahzadagi holatni qaytaradi. Biz oflayn testida shunday yozib ko'rdik: internet qaytgach, navbat xabari yo'qolishi kerak:
await context.setOffline(false);
expect(await page.locator("#navbat").isVisible()).toBe(false); Error: expect(received).toBe(expected) // Object.is equality
Expected: false
Received: true| Qadam | #navbat xabari |
isVisible() |
await expect(...).toBeHidden() |
|---|---|---|---|
setOffline(false) |
hali ko'rinadi | darhol true → test yiqildi |
kutishni boshladi |
| ilova navbatni yubordi | yo'qoldi | — (allaqachon tugagan) | shart bajarildi → davom |
Ilova navbatni yuborib ulgurmagan edi — xabar hali ko'rinib turardi. Kanon to'g'ri yozgan: await expect(page.locator("#navbat")).toBeHidden() — yo'qolguncha kutadi. Bunday "ba'zan o'tadi, ba'zan yo'q" test — flaky test, u Test strategiyasi darsining asosiy mavzusi.
G'oyani natija oynasida ko'ramiz. Bu yerda Playwright yo'q, lekin farq o'sha: "bir martalik surat" va "qayta urinish". «Ishga tushir» ni bosing:
import { render, screen } from "@testing-library/react";
import { useEffect, useState } from "react";
import { expect, test, vi } from "vitest";
function SaveStatus() {
const [saved, setSaved] = useState(false);
useEffect(() => {
const id = setTimeout(() => setSaved(true), 300);
return () => clearTimeout(id);
}, []);
return <p role="status">{saved ? "Saqlandi" : "Saqlanmoqda…"}</p>;
}
test("bir martalik surat — shoshildi", () => {
render(<SaveStatus />);
const text = screen.getByRole("status").textContent;
expect(text).toBe("Saqlandi");
});
test("qayta urinish — kutdi", async () => {
render(<SaveStatus />);
await vi.waitFor(() =>
expect(screen.getByRole("status")).toHaveTextContent("Saqlandi"),
);
});Konsolda:
× bir martalik surat — shoshildi
→ expected 'Saqlanmoqda…' to be 'Saqlandi' // Object.is equality
✓ qayta urinish — kutdi
Testlar: 1 yiqildi, 1 o'tdi (jami 2)Birinchi test holatni bir marta o'qidi — 300 ms hali o'tmagan edi. Ikkinchisi vi.waitFor bilan qayta-qayta tekshirdi. Playwright'ning await expect(lokator)… — aynan ikkinchisi, faqat waitFor siz.
6.4 expect.poll — sahifadan tashqaridagi qiymat
Web-first assertion lokator bilan ishlaydi. Soxta serverga so'rov ketganini tekshirish kerak bo'lsa-chi? U sahifada emas, test kodidagi massivda. Buning uchun — expect.poll(() => qiymat): funksiyani qayta-qayta chaqirib, natijani tekshiradi. Kanonda: await expect.poll(() => server.sorovlar).toContain("POST").
Tekshirib ko'ring: Nega
await page.waitForTimeout(1000)(1 soniya kutish) yomon yechim,await expect(lokator).toBeHidden()esa yaxshi?
Javob
Qat'iy kutish ikki tomondan yomon: tez kompyuterda 1 s behuda yo'qotiladi, sekin CI'da esa 1 s yetmay, test tasodifan yiqiladi. Web-first assertion shart bajarilgan zahoti davom etadi va 5 s gacha sabr qiladi — ham tez, ham barqaror.
7. webServer: test oldidan ilovani ishga tushirish
Kanonning playwright.config.ts i (holat 09, izohlar qisqartirilgan):
import { defineConfig, devices } from "@playwright/test";
const CI = process.env["CI"] !== undefined;
const PORT = 4173;
export default defineConfig({
testDir: "e2e",
fullyParallel: true,
// CI'da test.only qolib ketsa — yiqiladi
forbidOnly: CI,
reporter: [["list"], ["html", { open: "never" }]],
use: {
baseURL: `http://localhost:${PORT}`,
// Ilovaning sw.js i so'rovlarni o'zi oladi —
// page.route ularni ko'rmaydi
serviceWorkers: "block",
// Tizimdagi Chrome
channel: "chrome",
},
projects: [
{
name: "chrome",
use: { ...devices["Desktop Chrome"] },
},
],
webServer: {
command: `npm run build && npm run preview -- --port ${PORT} --strictPort`,
url: `http://localhost:${PORT}`,
reuseExistingServer: !CI,
timeout: 180_000,
},
});| Kalit | Nima qiladi |
|---|---|
testDir |
testlar e2e/ da (Vitest'nikidan alohida) |
fullyParallel |
bitta fayl ichidagi testlar ham parallel |
forbidOnly |
CI'da test.only — xato (Vitest I dagi only tuzog'i) |
reporter |
terminalda list, yana playwright-report/ da HTML |
baseURL |
page.goto("/") shu manzilga qo'shiladi |
serviceWorkers: "block" |
ilovaning SW'i o'chiriladi |
devices["Desktop Chrome"] |
oyna o'lchami, user agent — tayyor to'plam |
webServer.command |
testdan oldin: build va preview |
reuseExistingServer |
lokalda ishlab turgan server bo'lsa — o'shani oladi |
Uch qarorga diqqat qiling:
- Production build ustida.
npm run devemas,build && preview: foydalanuvchi oladigan aynan o'sha fayllar. Dev serverda bo'lmagan xato (masalan, kod bo'lish yoki minifikatsiya) shu yerda chiqadi. serviceWorkers: "block". Ilovaning service worker i so'rovni o'zi ushlasa,page.routeularni ko'rmaydi. SW'ning o'zi alohida sinaladi.channelyuqoriuseda. Kanon tuzog'i (o'lchandi):channelfaqat bitta loyihada yozilsa, boshqa loyiha Playwright'ning o'z brauzerini qidiradi va yiqiladi:Executable doesn't exist at …\ms-playwright\chromium_headless_shell-1248\… npx playwright install.
8. Soxta API: page.route bilan birinchi tanishuv
E2E testga haqiqiy server kerakmi? Kanon uni ishlatmaydi: internetga bog'liq test sekin va beqaror bo'ladi, server ma'lumoti esa testlar orasida aralashib ketadi. O'rniga — brauzer tarmoq qatlamida soxta server. Ilova kodi buni bilmaydi: u oddiy fetch qiladi.
await page.route("**/api/mashq/vazifalar/**", async (route) => {
const sorov = route.request();
const metod = sorov.method();
// … so'rovni yozib qo'yamiz (s.sorovlar, s.tanalar)
if (metod === "GET") {
return route.fulfill({
json: { versiya: s.versiya, vazifalar: s.vazifalar },
});
}
// … POST qo'shadi, PATCH o'zgartiradi, DELETE o'chiradi
});page.route(naqsh, handler)— shu manzilga ketadigan har so'rovni ushlaydi.**— "istalgan qism".route.fulfill({ json })— serverga bormasdan javob qaytaradi.- Xulq MSW dagi soxta server bilan bir xil: holatli (POST qo'shgani keyingi GET'da ko'rinadi).
Xatolar, uzilish, sekin server — Playwright II da.
9. Kanon testlaridan uch usul
Oflayn. context.setOffline(true) — butun kontekst uchun internetni uzadi (Oflayn ishlash):
await context.setOffline(true);
await expect(page.locator("#aloqa")).toHaveText(
"Internet yo'q. Ro'yxat — shu brauzerdagi nusxa.",
);Keyin vazifa qo'shiladi, navbat xabari chiqadi, POST ketmaydi. setOffline(false) — navbat yuboriladi. Bu oqimni jsdom'da sinab bo'lmaydi.
Til. /ru/ ochiladi, html ning lang atributi tekshiriladi, sozlamalarda English tanlanadi — manzil /en/sozlamalar. i18n butun yo'l bo'yicha ishlashi shu tarzda ko'rinadi.
Yuklab olish. Hodisani bosishdan oldin kutishni boshlash kerak:
const yuklash = page.waitForEvent("download");
await page
.getByRole("button", { name: "Faylga yuklab olish" })
.click();
const fayl = await yuklash;
expect(fayl.suggestedFilename()).toMatch(/\.json$/);Avval click, keyin waitForEvent yozilsa, hodisa bosish paytida sodir bo'lib, kutuvchi uni o'tkazib yuborishi mumkin. Promise'ni saqlab, keyin await — shu muammoning yechimi.
10. UI mode, debug, codegen va hisobot
Test yiqilsa yoki yangi test yozish kerak bo'lsa, Playwright'da to'rt asbob bor:
| Buyruq | Nima qiladi |
|---|---|
npx playwright test --ui |
UI mode: testlar ro'yxati, har qadam vaqt chizig'ida, DOM surati, kuzatuv rejimi |
npx playwright test --debug |
Inspector: qadamma-qadam, har harakatdan oldin to'xtaydi |
npx playwright codegen localhost:4173 |
codegen: siz bosasiz, u test kodini yozadi |
npx playwright show-report |
HTML hisobot: yiqilgan test, xato, rasm |
- UI mode — test yozishda eng qulayi. Har qadamni bosib, o'sha paytdagi sahifani ko'rasiz.
--debugva kod ichidagiawait page.pause()— test o'sha joyda to'xtaydi, brauzer oynasi ochiq qoladi.- codegen — tayyor lokatorlarni (
getByRole…) taklif qiladi. Uning kodi — qoralama: tekshiruvlarni (expect) va tushunarli nomlarni o'zingiz qo'shasiz. --headed— brauzer oynasini ko'rsatib yurgizish.
Bu oynalar grafik interfeys — ularni o'z kompyuteringizda oching. Yana bir-ikki foydali bayroq:
npx playwright test --listListing tests:
[chrome] › asosiy.spec.ts:18:1 › qo'shish: Enter — qator paydo bo'ladi, POST ketadi
[chrome] › asosiy.spec.ts:36:1 › tahrir: forma → PATCH, vazifa sahifasiga qaytadi
…-g "oflayn" — faqat nomida shu so'z bor testlar; e2e/asosiy.spec.ts:55 — bitta test qatori bo'yicha; --project=chrome — bitta loyiha; --repeat-each=5 — har testni 5 marta (beqarorlikni tutish uchun).
Har yiqilgan test uchun test-results/<test>/error-context.md ham yoziladi: xato matni va sahifaning a11y surati — yordamchi vosita (yoki hamkasb) xatoni tez tushunishi uchun.
11. Vazifalar qadami: Playwright e2e (holat 09)
11.1 O'rnatish va fayllar
git switch -c test/e2e
npm i -D -E @playwright/test@1.64.0Kanon: +1 paket, 40 KB — playwright Browser Mode da kelgan edi. Brauzer yuklanmadi.
| Fayl | Nima |
|---|---|
playwright.config.ts |
«webServer» bo'limidagi sozlama |
e2e/soxta-api.ts |
page.route bilan holatli soxta server |
e2e/asosiy.spec.ts |
5 test: qo'shish, tahrir, oflayn, til, eksport |
tsconfig.e2e.json |
e2e/ va config uchun: Node + DOM |
package.json |
"test:e2e": "playwright test" |
Har testda avval kirish formasi to'ldiriladi (test.beforeEach) — ilova kirmagan foydalanuvchini /kirish ga yo'naltiradi. Bu sekin; Playwright II da bir marta kirib, holatni saqlaymiz.
tsconfig.e2e.json nega kerak? E2E testlar Node'da ishlaydi, lekin Playwright turlari DOM'ga tayanadi — Browser Mode dagi TS2304 muammosining o'zi. tsconfig.json ning references iga qo'shildi: npm run tip testlarni ham tekshiradi.
playwright-report/, test-results/, e2e/.auth/ — .gitignore, ESLint va Prettier e'tiboridan chiqarildi.
11.2 Birinchi o'tishdagi xatolar
Kanon testlarni birinchi yurgizganda ikki xato chiqdi — ikkalasi ham test xatosi, ilova to'g'ri edi:
- statistika sarlavhasi — strict mode («Strict mode» bo'limidagi xabar) →
exact: true; - til tanlovi ro'yxat sahifasida emas, sozlamalarda ekan → test sozlamalar havolasini bosadi.
knip ham bitta narsani topdi: soxta-api.ts dagi ishlatilmagan BOSHLANGICH eksporti — olib tashlandi.
11.3 Natija va commit
- E2E: 5 test, 12.1 s devor soati (shundan build + preview ~2 s; testlar 10.2 s, 6 ishchi).
- Vitest 348, brauzer 6 — o'zgarmadi. Coverage 62.72 % — o'zgarmadi: e2e testlar
test:qamrovga kirmaydi. - Ilova JS — 206.7 KB gzip, o'zgarmadi. Lint,
format:check,tip, knip — toza.
git add -A
git commitCommit (kanon): test: Playwright e2e — qo'shish, tahrir, oflayn navbat, til, eksport (production build ustida).
12. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
strict mode violation … resolved to 2 elements |
nom qism bo'yicha mos | exact: true yoki konteyner ichidan qidirish |
Timeout: 5000ms … element(s) not found |
nom yoki sahifa boshqa | Call log, UI mode, error-context.md |
| ba'zan o'tadi, ba'zan yo'q | isVisible(), waitForTimeout |
web-first assertion: await expect(...) |
Executable doesn't exist … npx playwright install |
brauzer yuklanmagan | npx playwright install yoki channel: "chrome" |
Process from config.webServer was not able to start |
build yiqildi (masalan tip xatosi) | npm run build ni alohida yurgizing |
page.route so'rovni ko'rmaydi |
ilovaning SW'i ushlagan | serviceWorkers: "block" |
| yuklab olish kutilmaydi | waitForEvent bosishdan keyin |
avval Promise, keyin click |
13. Mashqlar
Mashqlar kurs/mashqlar/22/09-playwright-e2e/ da. Testlarni vazifalar loyihangizning e2e/ papkasiga qo'yib, npx playwright test bilan yurgizing (natija oynasida Playwright yo'q).
1-mashq (oson): bo'sh joylarni to'ldiring
- Test fayli importi:
import { expect, test } from "" - Nom to'liq mos kelsin:
getByRole("heading", { name: "Statistika", : true }) - Element yo'qolguncha kutish:
await expect(lokator).() - Sahifadan tashqari qiymatni kutish:
await expect.(() => server.sorovlar).toContain("POST") - Interaktiv rejim:
npx playwright test --
Yechim
- @playwright/test — test vositasi (
playwright— faqat kutubxona). - exact — sukut bo'yicha nom qism bo'yicha va katta-kichik harfga qaramay solishtiriladi.
- toBeHidden — web-first: yo'qolguncha 5 s gacha kutadi;
isVisible()esa bir martalik. - poll — funksiyani qayta-qayta chaqiradi.
- ui — UI mode: vaqt chizig'i va DOM suratlari.
2-mashq (o'rta): Bobur va buyruqlar oynasi
Fokus boshqaruvi darsida va'da qilgan edik: Bobur ssenariysini Playwright'da page.keyboard va :focus bilan yozamiz. Test: «Yangi vazifa» maydoniga fokus qo'ying, Control+K bosing — «Buyruqlar» dialogi ko'rinadi va undagi qidiruv maydoni (combobox) fokusda. Escape — dialog yo'qoladi, fokus yana «Yangi vazifa» da. Oxirida page.locator(":focus") ning kirish nomini tekshiring.
Ishora: page.keyboard.press("Control+K"); fokusni tekshirish — toBeFocused(); soxtaApi ni har testda ulang.
Yechim
import { expect, test } from "@playwright/test";
import { soxtaApi } from "./soxta-api.ts";
test("Ctrl+K — buyruqlar oynasi, Escape — fokus qaytadi", async ({
page,
}) => {
await soxtaApi(page);
await page.goto("/");
const maydon = page.getByRole("textbox", { name: "Yangi vazifa" });
await maydon.focus();
await page.keyboard.press("Control+K");
const oyna = page.getByRole("dialog", { name: "Buyruqlar" });
await expect(oyna).toBeVisible();
// page.getByRole("combobox") — 2 ta (sahifadagi <select> ham
// combobox): strict mode xatosi. Oyna ichidan qidiramiz
await expect(oyna.getByRole("combobox")).toBeFocused();
await page.keyboard.press("Escape");
await expect(oyna).toBeHidden();
await expect(maydon).toBeFocused();
// 18-qismdagi usul: fokusdagi element — :focus
await expect(page.locator(":focus")).toHaveAccessibleName(
"Yangi vazifa",
);
});Biz avval page.getByRole("combobox") deb yozdik — test yiqildi: strict mode violation … resolved to 2 elements, ikkinchisi — <select id="saralash"> (aka getByLabel('Tartib')). <select> ning roli ham combobox. Browser Mode da bu muammo yo'q edi: u yerda faqat bitta komponent chizilgan edi. E2E'da butun sahifa bor — lokatorni oyna ichiga toraytirish shart. To'g'ri variant o'tdi (1.6 s).
3-mashq (qiyin): o'chirish oqimi
Bitta testda: «O'chirish: Non olish #bozor» tugmasi → dialog «Vazifa o'chirilsinmi?» → «Bekor qilish» → dialog yo'q, qator joyida, DELETE ketmagan. Keyin yana bosing → «O'chirish» → qator yo'q va soxta serverga DELETE /1 ketdi.
Ishora: dialog ichidagi «O'chirish» tugmasi uchun exact: true (tashqaridagi «O'chirish: …» tugmalari ham mos keladi); server holati — expect.poll.
Yechim
import { expect, test } from "@playwright/test";
import { soxtaApi } from "./soxta-api.ts";
test("o'chirish: bekor qilish va tasdiqlash", async ({ page }) => {
const server = await soxtaApi(page);
await page.goto("/");
const qator = page.getByRole("checkbox", {
name: "Non olish #bozor",
});
const tugma = page.getByRole("button", {
name: "O'chirish: Non olish #bozor",
});
const dialog = page.getByRole("dialog", {
name: "Vazifa o'chirilsinmi?",
});
await tugma.click();
await expect(dialog).toBeVisible();
await dialog.getByRole("button", { name: "Bekor qilish" }).click();
await expect(dialog).toBeHidden();
await expect(qator).toBeVisible();
expect(server.sorovlar).not.toContain("DELETE /1");
await tugma.click();
await dialog
.getByRole("button", { name: "O'chirish", exact: true })
.click();
await expect(qator).toBeHidden();
await expect.poll(() => server.sorovlar).toContain("DELETE /1");
});Biz yurgizdik — o'tdi (1.7 s). Lokatorlar test boshida bir marta yozildi va ikki marta ishlatildi: ular "manzil", element emas. Dialog yopilib qayta ochilganda ham o'sha lokator yangi holatni topadi.
4-mashq: Vazifalar qadami
test/e2e branch'ida «Vazifalar qadami» dagi fayllarni yarating va npm run test:e2e ni yurgizing. Keyin UI mode'ni oching (npx playwright test --ui) va «oflayn» testini qadamma-qadam ko'ring: setOffline(true) dan keyin sahifada nima o'zgaradi?
Yechim
Tekshiruv ro'yxati:
npm run test:e2e— 5 passed; birinchi marta build tufayli sekinroq.- Ilova ishlab turgan bo'lsa (
npm run preview -- --port 4173),reuseExistingServeruni oladi — build qayta qilinmaydi. - «oflayn» testida vaqt chizig'ida «Internet yo'q…» xabari va «Navbatda: 1 ta o'zgarish…» qatori ko'rinadi;
setOffline(false)dan keyin navbat qatori yo'qoladi. npm run tip— toza (tsconfig.e2e.jsontestlarni ham tekshiradi). Bitta testdagetByRolega xato tur bering ({ name: 1 }) —tipushlaydi.
14. Real ishda
- E2E testlar kam, lekin eng muhim yo'llar uchun: kirish, to'lov, buyurtma, ro'yxatdan o'tish. Har tugma uchun e2e yozilmaydi — u trofey ning tepasi.
- Playwright va Cypress — eng ko'p uchraydigan ikki e2e vositasi. Ikkalasining g'oyasi yaqin (lokator, kutish); Playwright bir nechta brauzer dvigateli va parallel ishlash bilan ajralib turadi.
- Production build ustida sinash — real jamoalardagi odatiy talab: "dev serverda ishlaydi" yetmaydi.
- Intervyu savollari: "auto-wait nima?", "nega
waitForTimeoutyomon?", "strict mode nima uchun kerak?", "e2e va komponent testining farqi?".
Xulosa
- Playwright butun ilovani haqiqiy brauzerda sinaydi; har test — yangi toza kontekst,
pagefixture'i bilan. - Lokatorlar RTL ustuvorligida (
getByRolebirinchi); strict mode bir nechta moslikni xato qiladi —exact, toraytirish. - Auto-wait bosishdan oldin tayyorlikni kutadi; web-first assertion 5 s gacha qayta tekshiradi;
isVisible()— bir martalik surat. webServertestdan oldin production build'ni ko'taradi;page.route— soxta API.- UI mode,
--debug, codegen, HTML hisobot — yozish va xato qidirish asboblari. vazifalar: 5 e2e test, 12.1 s, +40 KB; ilova 206.7 KB — o'zgarmadi.
Keyingi dars: Playwright II: auth, tarmoq, trace va CI — bir marta kirib holatni saqlash, server xatolari va uzilishni sinash, trace viewer va GitHub Actions'da testlar.
Manbalar
- Playwright: "Installation", "Writing tests", "Locators", "Actionability", "Assertions", "Test configuration", "Web server" (playwright.dev/docs)
- Playwright: "Timeouts" — expect 5 s, test 30 s (playwright.dev/docs/test-timeouts)
- Playwright: "UI Mode", "Debugging tests", "Test generator" (codegen)
- create-playwright 1.17.139 (
npm init playwright), @playwright/test 1.64.0 / 1.64.1 (npm, 2026-10-07 / 2026-10-14) - Haqiqiy chiqishlar: Playwright 1.64.0, Node 24.21.0, Chrome (channel "chrome", headless), Windows 11 (2026-10-20)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!