Mundarija (37)
- Bu darsda
- 1. Nega bu kerak?
- 2. Test nima beradi va nima turadi
- 2.1 Test — ishonch
- 2.2 Test ham kod — u ham turadi
- 3. Test qavatlari
- 3.1 Statik tekshiruv: kod ishga tushmasdan
- 3.2 Unit test: bitta funksiya
- 3.3 Integratsiya testi: komponent hamkorlari bilan
- 3.4 E2E test: butun ilova haqiqiy brauzerda
- 3.5 Vizual va a11y testlar
- 3.6 Qavatlarni taqqoslash
- 4. Piramida va trofey
- 4.1 Test piramidasi
- 4.2 Test trofeyi
- 5. Xulqni test qiling, implementatsiyani emas
- 5.1 Qoida
- 5.2 Ikki test — bitta savatcha
- 5.3 Yolg'on qizil: kod yaxshilandi, test yiqildi
- 5.4 Yolg'on yashil: kod buzildi, test o'tdi
- 5.5 Frontendda bu nimani anglatadi
- 6. Nimani test qilish kerak
- 7. Vazifalar qadami: testlar xaritasi (holat 01)
- 7.1 Vazifa
- 7.2 TESTLAR.md
- 7.3 Bo'shliqlar — qism rejasi
- 7.4 Topilma: hech kim ishga tushirmagan test
- 7.5 Commit
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): bo'sh joylarni to'ldiring
- 2-mashq (o'rta): qaysi qavat?
- 3-mashq (qiyin): implementatsiya testini xulq testiga aylantiring
- 4-mashq: vazifalar qadami
- 10. Real ishda
- Xulosa
- Manbalar
Frontend testlash: nega test yozamiz va frontend test turlari
Qisqacha: Test — dasturning o'zini tekshiradigan kod. Frontendda testlar qavatlarga bo'linadi: statik tekshiruv (TypeScript, ESLint), unit (bitta funksiya), integratsiya (komponent hooklari va providerlari bilan), e2e (butun ilova haqiqiy brauzerda), shuningdek vizual va a11y testlar. "Test trofeyi" eng ko'p kuchni integratsiya qavatiga berishni maslahat beradi. Asosiy qoida: kod ichida qanday yozilganini emas, foydalanuvchi ko'radigan xulqni tekshiring.
Bu darsda
- Test qanday muammoni hal qilishini va qancha turadiganini tushuntira olasiz.
- Har test qavatini (statik, unit, integratsiya, e2e, vizual, a11y) misol bilan ajrata olasiz.
- Test piramidasi va test trofeyi farqini, nega frontendda trofey ko'proq ishlatilishini bilasiz.
- "Implementatsiyani emas, xulqni test qil" qoidasini ikki misolda (yolg'on qizil, yolg'on yashil) ko'rasiz.
vazifalardagi mavjud testlarning xaritasini (TESTLAR.md) tuzasiz va unutilgan, yiqiladigan testni topasiz.
Oldin bilishingiz kerak: Birinchi avtomatik test: node:test va assert, ESLint va Prettier, Nega TypeScript, Ro'yxatlarni render qilish va key (birinchi Vitest testlari), Custom hooklar I.
1. Nega bu kerak?
21-qism tugadi. vazifalar endi katta ilova: React, router, server holati, i18n, oflayn navbat, PWA. Har qism oxirida biz uni brauzerda tekshirib keldik — 159, 72, 100, 77 va 81 ta tekshiruvdan iborat ssenariylar bilan. Lekin bu ssenariylar kurs tomonida ishlaydi. Sizning repongizda ular yo'q.
Endi tasavvur qiling: Sardor «Bahor» ilovasida savatcha kodini tozaladi. Ilova ochildi, xato yo'q. U ishni topshirdi. Ertasi kuni Jasur aka qo'ng'iroq qildi: "Chegirma ishlamayapti, 200 000 so'mlik buyurtmada mijoz to'liq narx to'ladi". Sardor buni qanday bilishi mumkin edi? Har o'zgarishdan keyin 30 ta sahifani qo'lda bosib chiqishmi? Bir-ikki kun shunday qiladi, keyin charchaydi.
Yechim — avtomatik test (automated test): dasturning o'zini tekshiradigan kod. Siz bir marta "200 000 so'mda 10 % chegirma bo'lishi kerak" deb yozasiz. Keyin har o'zgarishdan keyin kompyuter buni bir soniyada tekshiradi.
Hayotiy o'xshatish: samolyot uchishdan oldin uchuvchi ro'yxat bo'yicha tekshiradi — yoqilg'i, qanotlar, g'ildiraklar. U har safar "nimani unutdim?" deb o'ylamaydi, ro'yxatga qaraydi. Testlar — ilovangizning shunday ro'yxati. Farqi — ro'yxatni mashina o'qiydi.
Bu qismda biz shu ro'yxatni vazifalar ning ichiga quramiz. Qism davomida testlar ilovada haqiqiy xatolarni ham topadi. Ulardan biri — «Qayta urinish» tugmasi 20-qismning Ikonkalar darsidan beri internet bor paytda ham ko'rinib turgan. Kursning 159 ta brauzer tekshiruvi buni sezmagan, chunki ular tugmaning hidden atributini tekshirgan, ekrandagi rasmni emas. Uni Visual regression testlar darsida skrinshot testi topadi. Har qavat o'z xatosini ushlaydi — bugungi darsning asosiy g'oyasi shu.
2. Test nima beradi va nima turadi
2.1 Test — ishonch
node:test darsida birinchi testlarni yozgan edik: funksiyani chaqirasiz, natijani kutilgan qiymat bilan solishtirasiz. Test aniq bir savolga javob beradi: "shu holatda kod to'g'ri ishlayaptimi?".
Testlar uch narsa beradi:
- O'zgartirishga jasorat. Kodni qayta yozdingiz (refactoring), testlar yashil — demak xulq buzilmagan.
- Regressiyadan himoya. Regressiya (regression) — oldin ishlagan narsaning yangi o'zgarishdan keyin buzilishi. Bir marta topilgan xatoga test yozilsa, u qaytib kelmaydi.
- Tirik hujjat.
test("aynan 200 000 — chegirma bor")o'qigan yangi dasturchi qoidani biladi.
2.2 Test ham kod — u ham turadi
Testning narxi bor, va buni halol aytish kerak:
- Yozish vaqti. Har test — qo'shimcha kod.
- Kutish vaqti. Testlar har safar ishga tushadi.
vazifalarda hozirgi 320 ta test taxminan 9–10 soniya oladi (kanon o'lchovi, keyingi darsda batafsil). - Qo'llab-quvvatlash. Ilova o'zgarsa, testlar ham o'zgaradi. Yomon yozilgan test har kichik o'zgarishda yiqiladi va jonga tegadi.
- Yolg'on xotirjamlik. Hech qachon yiqilmaydigan test hech narsani tekshirmaydi. Buni
node:testdarsidagi "Hech qachon yiqilmagan test" xatosida ko'rgan edik.
Demak savol "test yozamizmi?" emas. Savol — "qaysi testni, qaysi qavatda, qancha?".
Tekshirib ko'ring: Sardor 100 ta test yozdi, hammasi yashil. Ertasi kuni ilovada xato chiqdi. Bu qanday bo'lishi mumkin?
Javob
Testlar faqat o'zlari tekshirgan narsani kafolatlaydi. Ehtimol, xato chiqqan joyga umuman test yo'q edi. Yoki testlar noto'g'ri narsani tekshirgan — masalan, kodning ichki tuzilishini, foydalanuvchi ko'radigan natijani emas («Xulqni test qiling» bo'limida ko'ramiz). Testlar soni ishonch o'lchovi emas — nimani tekshirgani muhim.
3. Test qavatlari
Frontendda xatolar har xil joyda yashaydi: tur xatosi, hisob xatosi, komponentlar ulanishidagi xato, sahifalar orasidagi oqim, CSS. Har biri uchun o'z test turi bor. Ularni pastdan yuqoriga ko'ramiz.
3.1 Statik tekshiruv: kod ishga tushmasdan
Statik tekshiruv (static analysis) — kodni ishga tushirmasdan o'qib, xato qidirish. Bu qavatda TypeScript va ESLint ishlaydi. Ular eng arzon: bir soniyada butun loyihani ko'radi.
Mana JavaScript'dagi yashirin xato — price o'rniga prise yozilgan:
function total(items) {
return items.reduce((sum, item) => sum + item.prise, 0);
}
console.log(total([{ name: "Osh", price: 35000 }])); // NaNXato tashlanmadi. Natija — NaN, va u jimgina ekranga chiqadi. TypeScript esa shu kodni ishga tushirmasdan rad etadi:
interface MenuItem {
name: string;
price: number;
}
function total(items: MenuItem[]): number {
return items.reduce((sum, item) => sum + item.prise, 0);
}Xato:
TS2551: Property 'prise' does not exist on type 'MenuItem'. Did you mean 'price'?Tarjimasi: "MenuItem turida prise xususiyati yo'q. price ni nazarda tutdingizmi?" Bunday xatoga test yozish shart emas — kompilyator uni bepul ushlaydi.
vazifalar da statik qavat allaqachon kuchli: tsc -b (strict va noUncheckedIndexedAccess bilan), typed ESLint (react-hooks, XSS taqiqlari), Prettier, knip va commitlint. Hammasi npm run check ichida.
Statik tekshiruv nimani ko'rmaydi? Mantiqni. summa > 200000 o'rniga summa >= 200000 kerak edi — TypeScript uchun ikkalasi ham to'g'ri kod. Buni faqat ishga tushirib bilamiz.
3.2 Unit test: bitta funksiya
Unit test (birlik testi) — bitta funksiya yoki modulni boshqalardan ajratib tekshirish: kirish → chiqish. Siz ularni node:test darsida yozgansiz. vazifalar da sof mantiq — reducer, qidiruv, saralash, CSV, API klient — shunday testlangan.
Unit testlar tez va aniq. Yiqilsa, qaysi funksiya aybdorligi darhol ko'rinadi. Lekin ular bir narsani ko'rmaydi: bo'laklar bir-biriga to'g'ri ulanganmi. Har g'isht mustahkam bo'lishi mumkin, devor esa qiyshiq.
3.3 Integratsiya testi: komponent hamkorlari bilan
Integratsiya testi (integration test) — bir nechta bo'lakni birga tekshirish. Frontendda bu ko'pincha komponent testi: komponent o'z hooklari, Context'i, router'i va server holati bilan birga chiziladi. Keyin foydalanuvchi kabi ishlatiladi: tugma bosiladi, matn yoziladi, ekranda nima chiqqani tekshiriladi.
Bunday test Node ichida ishlaydi — DOM'ni jsdom beradi (brauzer o'rinbosari). Ro'yxatlarni render qilish darsida birinchi komponent testlarini shunday ulagan edik. To'liq — Vitest I va React Testing Library I (qisqasi RTL) darslarida.
3.4 E2E test: butun ilova haqiqiy brauzerda
E2E test (end-to-end — boshidan oxirigacha) — butun ilovani haqiqiy brauzerda ochib, foydalanuvchi yo'lini bosib chiqish: sahifa ochiladi, vazifa yoziladi, Enter bosiladi, ro'yxatda yangi qator chiqadi. Bu qism oxirida vazifalar da shunday testlar bo'ladi (Playwright I). Ko'rinishi taxminan shunday (hozir o'qish uchun):
test("qo'shish: Enter — qator paydo bo'ladi", async ({ 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();
});Bu test ilovaning hamma qatlamini birga ko'radi: build, router, React, tarmoq so'rovi, CSS. Shuning uchun u eng ko'p ishonch beradi. Narxi esa — tezlik va mo'rtlik. Har test brauzer ochadi. Tarmoq yoki vaqt sababli ba'zan tasodifan yiqiladi — bunday test flaky test (beqaror test) deyiladi, uni Nozik xatolar darsida ko'rgan edik.
3.5 Vizual va a11y testlar
Ikki maxsus qavat bor:
- Vizual test (visual regression test) — sahifa skrinshotini oldingi "oltin" rasm bilan piksel bo'yicha solishtirish. CSS buzilsa, tugma siljisa yoki ko'rinmas bo'lishi kerak bo'lgan narsa ko'rinsa — ushlaydi. «Qayta urinish» tugmasini aynan shu topadi (Visual regression testlar).
- A11y testi (accessibility test) — axe kabi vosita sahifani qoidalar bo'yicha tekshiradi: rasmda
altbormi, tugmaning nomi bormi, kontrast yetarlimi. Klaviatura oqimi (Tab, Enter, Esc) testi ham shu qavatga kiradi (Accessibility testlari). Malika va Bobur uchun bu — ilovadan foydalana olish-olmaslik masalasi.
3.6 Qavatlarni taqqoslash
| Qavat | Nimani ushlaydi | Tezlik | Ishonch |
|---|---|---|---|
| Statik | tur, yozuv, taqiqlangan kod | eng tez | tor |
| Unit | funksiya mantiqi | juda tez | tor |
| Integratsiya | komponent + hooklar + providerlar | tez | keng |
| E2E | butun oqim, build, tarmoq | sekin | eng keng |
| Vizual / a11y | ko'rinish, qulaylik | sekin | maxsus |
"Tez" va "sekin" so'zlari aniq raqamga ega. Quyidagi grafik — vazifalar da shu qism davomida o'lchangan o'rtacha bitta test vaqti. Hisob oddiy: hamma testlar vaqti testlar soniga bo'lingan (issiq ishga tushirish, holat raqami izohda). Ustunlarning balandligiga qarang:
- Unit (node:test)255 test, 1.21 s (holat 00)5 ms
- Komponent (Vitest + jsdom)82 test, ~7–10 s (holat 08)100 ms
- Komponent (haqiqiy Chrome)6 test, 3.84 s (holat 08)640 ms
Manba: O'lchandi: vazifalar kanoni (unit — holat 00, devor soati; komponent — holat 08, Vitest Duration), i5-12500H, Windows 11, Node 24.21.0, Vitest 5.0.4, natijalar/02-vaqt.txt, 08-brauzer.txt va tekshiruv-08.txt, 2026-10-19/20
Unit test komponent testidan taxminan 20 baravar, haqiqiy brauzerdagi komponent testi esa jsdom'dagidan taxminan 6 baravar sekin (≈0.64 s, holat 08). E2E testlar bundan ham og'ir: Playwright I darsidagi 5 ta e2e test 6 ta parallel ishchida 10.2 soniya oladi.
Tekshirib ko'ring: Qaysi qavat quyidagi xatoni ushlaydi? (a)
vazifa.matn.toUpercase()— harf xatosi; (b) filtr tugmasi bosilganda ro'yxat yangilanmaydi; (c) qorong'i temada matn fon bilan bir xil rangda.
Javob
(a) — statik tekshiruv: TypeScript toUpercase metodi yo'qligini ishga tushirmasdan aytadi. (b) — integratsiya (komponent) testi: tugma, holat va ro'yxat birga ishlashi kerak, bitta funksiya testi buni ko'rmaydi. (c) — vizual test yoki a11y testi (axe kontrastni tekshiradi). Bu xato kodda emas, CSS'da, unit test uni hech qachon ko'rmaydi.
4. Piramida va trofey
4.1 Test piramidasi
Testlar nisbati haqida eng mashhur rasm — test piramidasi (test pyramid). Mike Cohn uni "Succeeding with Agile" kitobida (2009) taklif qilgan, Martin Fowler'ning "TestPyramid" maqolasi (2012) uni mashhur qilgan. G'oya oddiy: pastda ko'p tez unit test, o'rtada kamroq integratsiya, tepada juda oz sekin e2e test.
Piramida backend va ko'p mantiqli kod uchun yaxshi ishlaydi. Frontendda esa muammo bor. Komponentlarning ko'pchiligida murakkab mantiq yo'q — ular ma'lumotni olib, ekranga chizadi va tugmalarga javob beradi. Xatolar asosan ulanishda: noto'g'ri prop, unutilgan provider, ishlamagan hodisa. Bularni unit test ko'rmaydi.
4.2 Test trofeyi
Testing Library muallifi Kent C. Dodds boshqa shakl taklif qildi — test trofeyi (testing trophy). U Guillermo Rauch'ning (2016) gapiga tayanadi: "Write tests. Not too many. Mostly integration." — "Test yozing. Juda ko'p emas. Asosan integratsiya."
Trofeyni pastdan yuqoriga o'qing. Har qavat yonida — u nima berishi:
flowchart BT
S["Statik: TS, ESLint<br/>poydevor, bepul"] --> U["Unit<br/>sof mantiq"]
U --> I["Integratsiya<br/>ENG KATTA QISM"]
I --> E["E2E<br/>asosiy oqimlar"]Rasmga qarang: trofeyning eng keng qismi — o'rtada, integratsiyada. Poydevor — statik tekshiruv, u deyarli bepul ishonch beradi. E2E — tepada, faqat eng muhim yo'llar uchun: kirish, vazifa qo'shish, to'lov. Vizual va a11y testlar trofeyga alohida "bezak" sifatida qo'shiladi.
Nega frontendda aynan shunday? Integratsiya testi ishonch bilan tezlik orasidagi eng yaxshi muvozanat. U foydalanuvchi ko'radigan narsani tekshiradi, lekin brauzer ochmaydi.
Maslahat: Trofey — qonun emas, yo'l-yo'riq. Agar ilovangizda murakkab hisob-kitob ko'p bo'lsa (narx, soliq, jadval), unit testlar ham ko'p bo'ladi. Muhimi — har xatoni uni eng arzon ushlaydigan qavatda ushlash.
5. Xulqni test qiling, implementatsiyani emas
5.1 Qoida
Testing Library hujjatidagi asosiy tamoyil shunday: "Testlaringiz dasturdan foydalanilish usuliga qanchalik o'xshasa, shuncha ko'p ishonch beradi". Boshqacha aytganda: foydalanuvchi va kodning boshqa qismlari ko'radigan xulq (behavior) ni tekshiring. Kodning ichida qanday yozilgani — implementatsiya (implementation) ni emas.
O'xshatish: oshxonaga mehmon bo'lib keldingiz. Siz oshning ta'mini baholaysiz — qozonning rangini emas. Oshpaz ertaga boshqa qozonda pishirsa ham, osh mazali bo'lsa — hammasi joyida.
Buni tekshiradigan kichik misol tuzamiz. Natijani aniq ko'rish uchun o'zimizning ikki qatorli "test yurgizuvchisi" bilan ishlaymiz. U node:test kabi ishlaydi, faqat natijani bitta qatorda chiqaradi.
5.2 Ikki test — bitta savatcha
«Bahor» savatchasi: taom qo'shiladi, jami hisoblanadi. Ikkita test yozamiz. Birinchisi savatchaning ichki massiviga qaraydi, ikkinchisi — faqat jami narxga:
function check(name, fn) {
try {
fn();
console.log(`✓ ${name}`);
} catch (error) {
console.log(`× ${name} — ${error.message}`);
}
}
function equal(actual, expected) {
if (actual !== expected) {
throw new Error(`kutilgan ${expected}, chiqdi ${actual}`);
}
}
// 1-variant: savatcha ichida massiv
class Cart {
constructor() {
this.items = [];
}
add(name, price) {
this.items.push({ name, price });
}
total() {
return this.items.reduce((sum, item) => sum + item.price, 0);
}
}
check("implementatsiya: ichida 3 ta element", () => {
const cart = new Cart();
cart.add("Osh", 35000);
cart.add("Osh", 35000);
cart.add("Ko'k choy", 5000);
equal(cart.items.length, 3);
});
check("xulq: ikki osh va choy — 75 000", () => {
const cart = new Cart();
cart.add("Osh", 35000);
cart.add("Osh", 35000);
cart.add("Ko'k choy", 5000);
equal(cart.total(), 75000);
});Konsolda:
✓ implementatsiya: ichida 3 ta element
✓ xulq: ikki osh va choy — 75 000Ikkalasi ham yashil. Hozircha farq ko'rinmaydi.
5.3 Yolg'on qizil: kod yaxshilandi, test yiqildi
Sardor savatchani yaxshiladi: bir xil taom endi bitta qator bo'lib, soni bilan saqlanadi. Ekranda "Osh × 2" chiqishi uchun shunday qulay. Xulq o'zgarmadi — jami baribir 75 000. Testlarni yangi kod bilan ishga tushiramiz:
function check(name, fn) {
try {
fn();
console.log(`✓ ${name}`);
} catch (error) {
console.log(`× ${name} — ${error.message}`);
}
}
function equal(actual, expected) {
if (actual !== expected) {
throw new Error(`kutilgan ${expected}, chiqdi ${actual}`);
}
}
// 2-variant: nom → { price, qty }
class Cart {
constructor() {
this.lines = new Map();
}
add(name, price) {
const line = this.lines.get(name) ?? { price, qty: 0 };
line.qty += 1;
this.lines.set(name, line);
}
total() {
let sum = 0;
for (const line of this.lines.values()) {
sum += line.price * line.qty;
}
return sum;
}
}
check("implementatsiya: ichida 3 ta element", () => {
const cart = new Cart();
cart.add("Osh", 35000);
cart.add("Osh", 35000);
cart.add("Ko'k choy", 5000);
equal(cart.items.length, 3);
});
check("xulq: ikki osh va choy — 75 000", () => {
const cart = new Cart();
cart.add("Osh", 35000);
cart.add("Osh", 35000);
cart.add("Ko'k choy", 5000);
equal(cart.total(), 75000);
});Konsolda:
× implementatsiya: ichida 3 ta element — Cannot read properties of undefined (reading 'length')
✓ xulq: ikki osh va choy — 75 000Birinchi test yiqildi: cart.items endi yo'q — undefined, uning length ini o'qib bo'lmaydi. Lekin ilovada hech narsa buzilmagan! Bu — yolg'on qizil (false negative): test xato bor deydi, xato esa yo'q. Sardor endi testni "tuzatishi" kerak. Bunday testlar ko'paysa, dasturchilar refactoring qilishdan qo'rqa boshlaydi — testlar yordam o'rniga to'siq bo'ladi.
5.4 Yolg'on yashil: kod buzildi, test o'tdi
Endi teskarisi. Uchinchi variantda Sardor total() da qty ni unutdi — har taom faqat bir marta sanaladi. Implementatsiya testi ichki Map ning o'lchamiga qaraydi:
function check(name, fn) {
try {
fn();
console.log(`✓ ${name}`);
} catch (error) {
console.log(`× ${name} — ${error.message}`);
}
}
function equal(actual, expected) {
if (actual !== expected) {
throw new Error(`kutilgan ${expected}, chiqdi ${actual}`);
}
}
// 3-variant: xato — qty unutilgan
class Cart {
constructor() {
this.lines = new Map();
}
add(name, price) {
const line = this.lines.get(name) ?? { price, qty: 0 };
line.qty += 1;
this.lines.set(name, line);
}
total() {
let sum = 0;
for (const line of this.lines.values()) {
sum += line.price;
}
return sum;
}
}
check("implementatsiya: ikki xil taom — 2 qator", () => {
const cart = new Cart();
cart.add("Osh", 35000);
cart.add("Osh", 35000);
cart.add("Ko'k choy", 5000);
equal(cart.lines.size, 2);
});
check("xulq: ikki osh va choy — 75 000", () => {
const cart = new Cart();
cart.add("Osh", 35000);
cart.add("Osh", 35000);
cart.add("Ko'k choy", 5000);
equal(cart.total(), 75000);
});Konsolda:
✓ implementatsiya: ikki xil taom — 2 qator
× xulq: ikki osh va choy — 75 000 — kutilgan 75000, chiqdi 40000Implementatsiya testi yashil — Map da haqiqatan 2 qator bor. Mijoz esa 75 000 o'rniga 40 000 to'laydi. Bu — yolg'on yashil (false positive): xato bor, test jim. Bu holat yolg'on qizildan ham xavfli, chunki hech kim bilmay qoladi.
Xulq testi ikkala holatda ham to'g'ri gapirdi. Refactoring'da jim turdi, haqiqiy xatoda baqirdi. Yaxshi test shunday bo'lishi kerak.
5.5 Frontendda bu nimani anglatadi
Komponent testlarida xuddi shu qoida ishlaydi:
| Implementatsiya | Xulq |
|---|---|
useState qiymatini o'qish |
ekrandagi matnni o'qish |
.btn-primary sinfi bilan qidirish |
rol va nom bilan: «Saqlash» tugmasi |
| ichki funksiya chaqirilganini sanash | bosilgandan keyin ekranda nima o'zgargani |
komponent tuzilishi (nechta div) |
foydalanuvchi ko'radigan natija |
Sinf nomi dizayn bilan o'zgaradi. Tugmaning roli va nomi esa ekran o'quvchi foydalanuvchisi uchun ham bir xil. Shuning uchun Testing Library elementni avvalo rol va nom bilan qidiradi — Malikaning ekran o'quvchisi ham shunday "ko'radi". Buni React Testing Library I darsida batafsil o'rganamiz.
Tekshirib ko'ring: Qaysi test yaxshiroq: "
setFilterfunksiyasi"faol"bilan chaqirildi" yoki "«Faol» tugmasi bosilgach, ro'yxatda faqat bajarilmagan vazifalar qoldi"? Nega?
Javob
Ikkinchisi. Birinchisi implementatsiyaga bog'langan: setFilter nomini o'zgartirsangiz yoki holatni URL'ga ko'chirsangiz (vazifalar da filtr aynan URL'da), test yiqiladi — ilova esa to'g'ri ishlaydi. Ikkinchisi foydalanuvchi ko'radigan natijani tekshiradi va ichki o'zgarishlarga e'tibor bermaydi.
6. Nimani test qilish kerak
Hamma narsani test qilib bo'lmaydi, kerak ham emas. Uchta savol yordam beradi:
- Buzilsa, qanchalik qimmat? To'lov, kirish, ma'lumot yo'qolishi — albatta testlanadi. Footer'dagi matn — yo'q.
- Qanchalik tez-tez o'zgaradi? Ko'p o'zgaradigan va murakkab kod regressiyaga moyil.
- Qaysi qavat eng arzon ushlaydi? Tur xatosi — TypeScript. Hisob — unit. Tugma va ro'yxat — integratsiya. Sahifalararo oqim — e2e.
Yana bir foydali odat — har topilgan xatoga test. Avval xatoni ko'rsatadigan yiqiladigan test yoziladi, keyin kod tuzatiladi va test yashil bo'ladi. Bu node:test darsidagi "qizil → yashil" tartibi. Shunday test regressiya testi deyiladi.
Qancha kod testlar bilan qoplanganini coverage (qamrov) o'lchaydi. Lekin 100 % qamrov ham xatosizlik kafolati emas: yuqoridagi implementatsiya testi total() ning hamma qatorini ishga tushirishi mumkin edi, lekin natijani tekshirmasdi. Qamrovni Vitest II darsida o'lchaymiz.
7. Vazifalar qadami: testlar xaritasi (holat 01)
7.1 Vazifa
Testlar qo'shishdan oldin bor narsani ko'ramiz. Bu qadamda kod o'zgarmaydi — faqat bitta hujjat yoziladi: TESTLAR.md. U "qaysi qavatda nima bor, nima yo'q" savoliga javob beradi.
- Branch:
docs/testlar-xaritasi
git switch -c docs/testlar-xaritasi7.2 TESTLAR.md
Kanondan, asosiy jadval (ustunlar telefon uchun qisqartirilgan):
# Testlar xaritasi — vazifalar v11 (22/#01)
| Qavat | v11 da nima bor | Qancha |
|---|---|---|
| Statik | tsc -b, ESLint, Prettier, knip, commitlint | 5 vosita |
| Unit | node:test — *.test.js | 255 test, 36 fayl |
| Integratsiya | Vitest + RTL — *.test.tsx | 65 test, 13 fayl |
| E2E | Reposida YO'Q | 0 |
| Vizual | YO'Q | 0 |
| A11y | YO'Q (axe faqat kurs tekshiruvida) | 0 |
| Tarmoq | tekshiruv/api.tarmoq.js | 2 test |Raqamlarni grafikda ko'ring. Ustunlarning notekisligiga qarang:
- Unit (node:test)255 test
- Komponent (Vitest)65 test
- Tarmoq2 test
- E2E0 test
- Vizual0 test
- A11y0 test
Manba: O'lchandi: vazifalar kanoni holat 01, TESTLAR.md va natijalar/tekshiruv-00.txt, 2026-10-19
Bizning ilova hozir piramida shaklida: pastda ko'p unit, tepada hech narsa. Trofey uchun integratsiya qavati kengayishi va e2e paydo bo'lishi kerak.
7.3 Bo'shliqlar — qism rejasi
Hujjatning ikkinchi yarmi — nima yetishmasligi va qaysi darsda yopilishi:
| Bo'shliq | Nega muhim | Dars |
|---|---|---|
| Ikki test vositasi, ikki hisobot | bitta watch, bitta coverage yo'q |
Vitest I |
| Coverage o'lchanmaydi | qaysi kod hech ishlamaganini bilmaymiz | Vitest II |
fireEvent va textContent |
foydalanuvchiga yaqin emas | RTL I–II |
| Har test providerlarni qo'lda yig'adi | takror, o'zgartirish qimmat | RTL III |
fetch qo'lda soxtalanadi |
URL/metod xatosi ushlanmaydi | MSW |
jsdom'da dialog chala |
jsdom yolg'on "yashil" berishi mumkin | Browser Mode |
| E2E va CI yo'q | asosiy oqim buzilsa — faqat foydalanuvchi biladi | Playwright I–II |
| Vizual va a11y testlar yo'q | CSS va kontrast regressiyasi | Visual, A11y |
7.4 Topilma: hech kim ishga tushirmagan test
Xaritani tuzayotib, "Tarmoq" qatoridagi 2 ta testni ishga tushirdik. Ular haqiqiy mashq API'ga so'rov yuboradi (internet kerak), shuning uchun npm test ga kirmagan — faqat npm run test:tarmoq bilan. Natija: 2 tadan 1 tasi yiqildi.
Sabab — tekshiruv/api.tarmoq.js dagi bitta qator:
assert.equal(await api.ochir(3), null);Test ochir() dan null kutadi. Kod esa server 204 No Content javob berganda undefined qaytaradi — oddiy api.test.js ham aynan undefined ni kutadi. Kod qachondir o'zgargan, bu test esa eskirib qolgan. Hech kim uni yurgizmagani uchun hech kim bilmagan. Node 24 da xuddi shu tekshiruv shunday xabar beradi:
import assert from "node:assert/strict";
assert.equal(undefined, null);Konsolda:
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+ actual - expected
+ undefined
- nullTarjimasi: "Qiymatlar qat'iy teng bo'lishi kutilgan edi. + — haqiqiy qiymat (undefined), - — kutilgan (null)." Saboq: ishga tushirilmaydigan test — test emas. Qo'lda yurgiziladigan testlar albatta eskiradi. Bu testni Vitest I darsida tuzatamiz va boshqa testlar bilan bitta vositaga olamiz.
TESTLAR.md ning oxiriga shu topilma "Ma'lum muammolar" bo'limiga yoziladi.
7.5 Commit
git add TESTLAR.md
git commit -m "docs: TESTLAR.md — v11 testlar xaritasi (qavatlar, bo'shliqlar)"Kod o'zgarmagani uchun build, testlar va brauzer tekshiruvlari oldingi holat bilan bir xil.
8. Ko'p uchraydigan xatolar
| Xato | Nega yomon | To'g'risi |
|---|---|---|
| Ichki holat yoki sinf nomini tekshirish | refactoring'da yolg'on qizil, xatoda yolg'on yashil | foydalanuvchi ko'radigan natija |
| Hamma narsani e2e bilan tekshirish | sekin va beqaror, xato joyini topish qiyin | trofey: ko'pi integratsiya |
| Faqat unit testlar | bo'laklar ulanishini hech kim ko'rmaydi | komponent testlari qo'shing |
| TypeScript ushlaydigan narsaga test | ortiqcha kod | tur xatosini tsc'ga qoldiring |
| Testni qo'lda yurgizish | eskiradi (test:tarmoq misoli) |
npm test va CI'ga kiriting |
| "100 % coverage — xato yo'q" | qamrov natija tekshirilganini bildirmaydi | tekshiruvlar sifatiga qarang |
9. Mashqlar
Mashqlar kurs/mashqlar/22/01-test-turlari/ da.
1-mashq (oson): bo'sh joylarni to'ldiring
- Kodni ishga tushirmasdan xato qidirish — tekshiruv.
- Butun ilovani haqiqiy brauzerda bosib chiqadigan test — .
- Oldin ishlagan narsaning yangi o'zgarishdan keyin buzilishi — .
- Kent C. Dodds shaklida eng keng qavat — .
- Ba'zan o'tadigan, ba'zan yiqiladigan test — test.
Yechim
Statik tekshiruv — TypeScript va ESLint. E2E — boshidan oxirigacha. Regressiya — testlar aynan undan himoya qiladi. Trofeyda eng keng qism — integratsiya, chunki u ishonch va tezlik orasidagi eng yaxshi muvozanat. Flaky — beqaror test, Nozik xatolar darsidan.
2-mashq (o'rta): qaysi qavat?
«Bahor» ilovasida oltita xato topildi. Har biri uchun uni eng arzon ushlaydigan qavatni tanlang (statik, unit, integratsiya, e2e, vizual, a11y):
- Narx serverdan satr bo'lib keldi:
"35000" + 5000— natija"350005000". - 200 000 so'mlik buyurtmaga chegirma berilmaydi (
>va>=). - «Savatga qo'shish» tugmasi bosilsa, savatcha belgisidagi son o'zgarmaydi.
- Kirgandan keyin to'lov sahifasiga o'tib bo'lmaydi — production build'da router manzili noto'g'ri.
- Mobil ekranda «Buyurtma berish» tugmasi menyu ostida qolib, ko'rinmaydi.
- Ikonkali «×» tugmasining nomi yo'q — ekran o'quvchi faqat "tugma" deydi.
Yechim
- Statik —
price: numberdeb e'lon qilingan turga satr berilsa, TypeScript uni rad etadi (TS2322). Server javobini esa ishga tushganda tekshirish kerak (Zod bilan). - Unit — sof funksiya, chegara holati:
chegirma(200000)ni tekshiradigan bitta test. - Integratsiya — tugma, holat (Context yoki store) va belgi birga ishlashi kerak; komponent testi ularni birga chizadi.
- E2E — build, router va haqiqiy manzillar birga ishlaganda ko'rinadi; jsdom'dagi testda production build yo'q.
- Vizual — tugma DOM'da bor va
hiddenemas, faqat ustidan boshqa element yopgan. Buni faqat rasm ko'radi (xuddi «Qayta urinish» tugmasi kabi). - A11y — axe
button-nameqoidasi bilan ushlaydi.
3-mashq (qiyin): implementatsiya testini xulq testiga aylantiring
Quyidagi "buyurtmalar navbati" testi ichki massivga qaraydi. Uni shunday qayta yozingki, navbat ichida massiv o'rniga boshqa tuzilma (masalan Map yoki ikki massiv) ishlatilsa ham test yiqilmasin. Lekin next() noto'g'ri tartibda bersa — yiqilsin. Navbat qoidasi: avval kelgan buyurtma birinchi beriladi.
check("ichki massivda 2 ta buyurtma", () => {
const queue = new OrderQueue();
queue.push("Ali: osh");
queue.push("Vali: manti");
equal(queue.items.length, 2);
equal(queue.items[0], "Ali: osh");
});Ishora: tashqaridan faqat push(), next() va size ishlatiladi. next() buyurtmani qaytaradi va navbatdan olib tashlaydi; bo'sh navbatda undefined beradi. check va equal — «Xulqni test qiling» bo'limidagi yordamchilar.
Yechim
function check(name, fn) {
try {
fn();
console.log(`✓ ${name}`);
} catch (error) {
console.log(`× ${name} — ${error.message}`);
}
}
function equal(actual, expected) {
if (actual !== expected) {
throw new Error(`kutilgan ${expected}, chiqdi ${actual}`);
}
}
// Ichi boshqacha: massiv o'rniga indeksli Map
class OrderQueue {
#orders = new Map();
#head = 0;
#tail = 0;
push(order) {
this.#orders.set(this.#tail++, order);
}
next() {
if (this.#head === this.#tail) return undefined;
const order = this.#orders.get(this.#head);
this.#orders.delete(this.#head++);
return order;
}
get size() {
return this.#tail - this.#head;
}
}
check("avval kelgan — avval beriladi", () => {
const queue = new OrderQueue();
queue.push("Ali: osh");
queue.push("Vali: manti");
equal(queue.size, 2);
equal(queue.next(), "Ali: osh");
equal(queue.next(), "Vali: manti");
equal(queue.size, 0);
});
check("bo'sh navbat — undefined", () => {
equal(new OrderQueue().next(), undefined);
});Konsolda:
✓ avval kelgan — avval beriladi
✓ bo'sh navbat — undefinedTest endi faqat tashqi xulqqa qaraydi: kim birinchi kelgan bo'lsa, o'sha birinchi chiqadi. Ichki maydonlar # bilan yopiq (Class maydonlari) — test ularni ko'ra olmaydi ham. Agar next() oxirgisini bersa (stek kabi), birinchi test kutilgan Ali: osh, chiqdi Vali: manti bilan yiqiladi.
4-mashq: vazifalar qadami
docs/testlar-xaritasi branch'ida «Vazifalar qadami» ni bajaring: TESTLAR.md ni yozing (qavatlar jadvali, bo'shliqlar, ma'lum muammolar). Keyin:
npm testchiqishidan har qavatdagi testlar sonini o'zingiz sanang (ℹ tests …vaTests … passed).- Internet ulangan holda
npm run test:tarmoqni ishga tushiring. tekshiruv/papkasidan bitta komponent testini oching va unda implementatsiyaga qaraydigan joy bormi — toping.
Yechim
node:test:ℹ tests 255,ℹ pass 255. Vitest:Tests 65 passed (65),Test Files 13 passed (13).- 2 tadan 1 tasi yiqiladi:
ochir()undefinedqaytaradi, testnullkutadi — «Topilma» bo'limidagi xabar. Tuzatish keyingi darsda. - v11 testlarida
container.querySelector("label")?.textContentkabi joylar bor (17-qismdan) — ular DOM tuzilishiga tayanadi. React Testing Library I darsida rol bo'yicha so'rovlarni o'rganamiz — shundan keyin bu joylarni o'zingiz almashtirib ko'rasiz (o'sha darsdagi ixtiyoriy mashq).
10. Real ishda
- Pull request'da testlar avtomatik ishlaydi (CI). Yiqilgan test bilan kod
mainga kirmaydi. Workflow'ni Playwright II darsida yozamiz. - Kompaniyalarda odatda uchta-to'rtta vosita bor: Vitest yoki Jest (unit va komponent), Testing Library, Playwright yoki Cypress (e2e). Ba'zan Storybook va vizual xizmatlar ham.
- Intervyu savollari: "Test piramidasi va trofey farqi?", "Unit va integratsiya testi farqi?", "Nima uchun implementatsiyani test qilmaslik kerak?", "Flaky testni qanday tuzatasiz?", "Qaysi qavatda nimani testlaysiz?".
- Kod ko'rib chiqishda (code review) "bu o'zgarishga test qani?" — eng ko'p beriladigan savollardan biri.
Xulosa
- Test — dasturni tekshiradigan kod: refactoring'ga jasorat, regressiyadan himoya, tirik hujjat. Uning ham narxi bor.
- Qavatlar: statik (TS, ESLint) → unit → integratsiya (komponent) → e2e, yonida vizual va a11y. Har biri o'z xatosini ushlaydi.
- Test trofeyi frontend uchun: poydevor — statik, eng keng qism — integratsiya, tepada — oz e2e.
- Xulqni test qiling: implementatsiya testi refactoring'da yolg'on qizil, xatoda yolg'on yashil beradi.
- Ishga tushirilmaydigan test eskiradi —
vazifalardagitest:tarmoqbunga misol.
Keyingi dars: Vitest I: sozlash va birinchi testlar — vazifalar dagi hamma testlarni bitta vositaga olamiz, describe, test, expect va matcherlarni o'rganamiz. Birinchi testlarni natija oynasida jonli yurgizamiz.
Manbalar
- Kent C. Dodds: "The Testing Trophy and Testing Classifications", "Write tests. Not too many. Mostly integration." — kentcdodds.com/blog
- Martin Fowler: "TestPyramid" (2012) — martinfowler.com/bliki
- Mike Cohn: "Succeeding with Agile" (Addison-Wesley, 2009)
- Testing Library: "Guiding Principles" — testing-library.com/docs/guiding-principles
- Kanon:
vazifalarholat 01 (TESTLAR.md,tekshiruv/api.tarmoq.js),natijalar/02-vaqt.txt,08-brauzer.txt,09-e2e.txt(2026-10-19/20)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!