# QA 25: Accessibility, Localization va Visual testing — WCAG 2.2, axe-core va o'zbek tili nozikliklari

> **Holat:** 2026-yil oktabr. Dars WCAG 2.2 (W3C Recommendation, 2023-yil 5-oktabr; joriy tahrir 2024-yil 12-dekabr), `@axe-core/playwright` 4.13.0 + Playwright 1.64 va Node.js 24 (ICU 78.2, CLDR 48) asosida yozilgan. Barcha axe, `Intl` va screenshot natijalari haqiqiy ishga tushirishdan olingan.

> **Bu darsdan keyin siz:** mahsulotni "hamma uchun, har tilda va har relizda bir xil ko'rinishda" ishlashini tekshira olasiz:

- WCAG 2.2 ning POUR printsiplari va AA darajasini amalda (klaviatura, kontrast, label, screen reader) tekshirasiz;
- axe-core'ni Playwright testlariga qo'shib, natijani o'qiysiz va avtomatlashtirish chegarasini bilasiz;
- o'zbek tili (lotin/kirill, `oʻ/gʻ`, apostroflar), rus plural shakllari, sana/son/valyuta formatlarini sinaysiz;
- `toHaveScreenshot` bilan visual regression testlar yozasiz;
- Nielsen evristikalari bilan tezkor usability tahlil qilasiz.

## Mundarija

1. [Nega accessibility muhim](#nega-a11y)
2. [WCAG 2.2: POUR, darajalar va yangi mezonlar](#wcag)
3. [Qo'lda a11y tekshiruvi: klaviatura, kontrast, screen reader](#manual-a11y)
4. [Avtomatik a11y: axe-core + Playwright](#axe)
5. [Mobil accessibility](#mobil-a11y)
6. [i18n va l10n: asosiy tushunchalar](#i18n)
7. [O'zbek tili nozikliklari: oʻ/gʻ, lotin/kirill, alifbo islohoti](#ozbek-tili)
8. [Sana, son, valyuta va plural: Intl bilan tekshirish](#intl)
9. [Visual testing: toHaveScreenshot va vositalar](#visual)
10. [Usability asoslari: Nielsen'ning 10 evristikasi](#usability)
11. [Amaliy mashqlar](#mashqlar)
12. [O'zingizni tekshiring](#checklist)
13. [Xulosa](#xulosa)
14. [Manbalar](#manbalar)

---

## 1. Nega accessibility muhim {#nega-a11y}

**Accessibility (a11y)** — mahsulotdan imkoniyati cheklangan odamlar ham to'liq foydalana olishi: ko'zi ojiz yoki zaif ko'radiganlar (screen reader, kattalashtirish), rang ajratishda qiynaladiganlar, qo'l harakati cheklanganlar (faqat klaviatura yoki switch qurilma), eshitishi zaiflar (subtitr), kognitiv qiyinchiligi borlar.

Bundan tashqari **vaziyatli** cheklovlar ham bor: quyosh ostida ekran yomon ko'rinadi, bir qo'lda bola ko'tarib telefon ishlatiladi, shovqinli metroda video ovozsiz ko'riladi. A11y uchun qilingan har bir yaxshilanish hammaga foyda beradi.

**Qonuniy kontekst.** Yevropa Ittifoqining **European Accessibility Act** (Direktiva 2019/882) 2025-yil 28-iyundan keyin bozorga chiqarilgan mahsulotlar va iste'molchilarga ko'rsatiladigan xizmatlarga qo'llanadi — ro'yxatda e-commerce, bank xizmatlari, elektron kitoblar, smartfon va kompyuterlar bor. DemoBozor Yevropa mijozlariga sotsa yoki ilova xalqaro bozorga chiqsa, bu to'g'ridan-to'g'ri talabga aylanadi.

**QA'ning roli** — a11y'ni reliz oxirida "bir marta audit" qilish emas, har feature'ning Definition of Done'iga qo'shish: klaviatura bilan o'tib chiqish, avtomatik skaner, kerak bo'lsa screen reader bilan tekshiruv.

> **🎯 Intervyuda:** Accessibility testlashni qanday tashkil qilasiz? — Uch qatlam: (1) har PR'da avtomatik skaner (axe) — tez topiladigan xatolar uchun; (2) har feature'da qo'lda tekshiruv — klaviatura, fokus, kontrast, label'lar, 200% zoom; (3) muhim ssenariylarni screen reader (VoiceOver, NVDA, TalkBack) bilan tekshirish. Mezon — WCAG 2.2 AA.

---

## 2. WCAG 2.2: POUR, darajalar va yangi mezonlar {#wcag}

**WCAG** (Web Content Accessibility Guidelines) — W3C'ning WAI guruhi chiqargan xalqaro standart. **WCAG 2.2** 2023-yil 5-oktabrda W3C Recommendation bo'ldi (joriy tahrir — 2024-yil 12-dekabr). Muhim jihati: WCAG 2.2 ga mos kontent WCAG 2.1 va 2.0 ga ham mos keladi.

![WCAG 2.2 ning to'rt printsipi: Perceivable, Operable, Understandable, Robust va muvofiqlik darajalari](/lessons/images/qa/qa_25_pour.svg)

### Tuzilma: printsip → guideline → success criterion

- **4 printsip (POUR):** Perceivable, Operable, Understandable, Robust.
- Har printsip ostida **guideline**'lar, ular ostida tekshiriladigan **success criterion** (SC)'lar bor — masalan, `1.4.3 Contrast (Minimum)`.
- Har SC'ning darajasi: **A**, **AA** yoki **AAA**. Amalda maqsad odatda **AA** (A + AA mezonlari). W3C'ning o'zi butun sayt uchun AAA'ni umumiy talab qilib qo'yishni tavsiya etmaydi — ba'zi kontent uchun barcha AAA mezonlarini bajarib bo'lmaydi.

### QA eng ko'p tekshiradigan mezonlar

| SC     | Nomi                   | Daraja | Qisqacha                                                        |
| ------ | ---------------------- | ------ | --------------------------------------------------------------- |
| 1.1.1  | Non-text Content       | A      | Rasm/ikonkada mazmunli muqobil matn                             |
| 1.3.1  | Info and Relationships | A      | Sarlavhalar, ro'yxatlar, jadvallar, label'lar kodda ham to'g'ri |
| 1.4.3  | Contrast (Minimum)     | AA     | Matn ≥ 4.5:1; katta matn (≥ 18pt yoki ≥ 14pt bold) ≥ 3:1        |
| 1.4.10 | Reflow                 | AA     | 320 CSS px kenglikda ikki yo'nalishli scroll'siz ishlaydi       |
| 1.4.11 | Non-text Contrast      | AA     | UI komponentlar va muhim grafika ≥ 3:1                          |
| 2.1.1  | Keyboard               | A      | Hamma funksiya klaviaturadan                                    |
| 2.1.2  | No Keyboard Trap       | A      | Fokus biror joyda "qamalib" qolmaydi                            |
| 2.4.3  | Focus Order            | A      | Fokus tartibi mantiqiy                                          |
| 2.4.7  | Focus Visible          | AA     | Fokus ko'rinib turadi                                           |
| 3.1.1  | Language of Page       | A      | `<html lang="uz">`                                              |
| 3.3.1  | Error Identification   | A      | Xato aniqlanib, matn bilan tushuntiriladi                       |
| 3.3.2  | Labels or Instructions | A      | Maydonlarda label yoki ko'rsatma                                |
| 4.1.2  | Name, Role, Value      | A      | Har boshqaruv elementining nomi, roli, holati bor               |

### WCAG 2.2 da qo'shilgan 9 ta mezon

| SC     | Nomi                                 | Daraja | QA nimani tekshiradi                                                                                      |
| ------ | ------------------------------------ | ------ | --------------------------------------------------------------------------------------------------------- |
| 2.4.11 | Focus Not Obscured (Minimum)         | AA     | Fokusdagi element sticky header/banner ostida to'liq yashirinib qolmaydi                                  |
| 2.4.12 | Focus Not Obscured (Enhanced)        | AAA    | Fokusdagi element umuman yopilmaydi                                                                       |
| 2.4.13 | Focus Appearance                     | AAA    | Fokus indikatori yetarlicha katta va kontrastli                                                           |
| 2.5.7  | Dragging Movements                   | AA     | Sudrash (drag) bilan qilinadigan amalning bir bosishli muqobili bor                                       |
| 2.5.8  | Target Size (Minimum)                | AA     | Bosiladigan nishon kamida 24×24 CSS px (istisnolar bor)                                                   |
| 3.2.6  | Consistent Help                      | A      | Yordam havolasi har sahifada bir xil joyda                                                                |
| 3.3.7  | Redundant Entry                      | A      | Bir jarayonda kiritilgan ma'lumot qayta so'ralmaydi                                                       |
| 3.3.8  | Accessible Authentication (Minimum)  | AA     | Login uchun "eslab qolish yoki hisoblash" testi majburiy emas (parol menejeri, nusxa ko'chirish ishlaydi) |
| 3.3.9  | Accessible Authentication (Enhanced) | AAA    | Yuqoridagining qat'iyroq varianti                                                                         |

**4.1.1 Parsing** esa eskirgan deb WCAG 2.2 dan olib tashlangan.

> **🇺🇿 Mahalliy kontekst:** DemoBozor'da SMS kod maydoni: 3.3.8 nuqtai nazaridan foydalanuvchi kodni **nusxalab qo'ya olishi** va telefon SMS kodini avtomatik taklif qilishi (autofill) ishlashi kerak. 6 ta alohida katakchali OTP maydonlari ko'pincha aynan shu joyda buziladi.

### WCAG 3.0 haqida

WCAG 3.0 hozircha **Working Draft** (oxirgi qoralama — 2026-yil 10-sentabr). Hujjatning o'zida u WCAG 2 ni almashtirmasligi va ishlar hali bir necha yil davom etishi aytilgan. Amaliy testlash uchun mezon — **WCAG 2.2 AA**.

### ARIA'ning birinchi qoidasi

W3C'ning "Using ARIA" hujjati: kerakli semantika va xatti-harakat allaqachon mavjud bo'lgan native HTML element yoki atribut bo'lsa — **ARIA qo'shish o'rniga o'sha native elementni ishlating**. Ya'ni `<div role="button" tabindex="0">` emas, `<button>`. QA uchun signal: kodda `role="button"` ko'p bo'lsa, klaviatura (Enter/Space), fokus va screen reader'ni ayniqsa sinchiklab tekshiring.

---

## 3. Qo'lda a11y tekshiruvi: klaviatura, kontrast, screen reader {#manual-a11y}

### 5 daqiqalik klaviatura testi

Sichqonchani chetga qo'ying va DemoBozor checkout sahifasini faqat klaviatura bilan bajaring:

| Qadam                       | Tekshiruv                                                               | Kutilgan natija                          |
| --------------------------- | ----------------------------------------------------------------------- | ---------------------------------------- |
| `Tab` / `Shift+Tab`         | Hamma interaktiv elementga yetib borasizmi?                             | Ha, mantiqiy tartibda (2.4.3)            |
| Fokus                       | Hozir qayerda turganingiz ko'rinadimi?                                  | Aniq ko'rinadigan fokus halqasi (2.4.7)  |
| Sticky header               | Fokusdagi element header ostida qolib ketmaydimi?                       | Ko'rinadi (2.4.11)                       |
| `Enter` / `Space`           | Tugma va havolalar ishlaydimi?                                          | Ha                                       |
| Modal oyna                  | Fokus modal ichida qoladimi, `Esc` yopadimi, yopilgach fokus qaytadimi? | Ha                                       |
| Chiqish                     | Biror joyda fokus "qamalib" qolmaydimi?                                 | Yo'q (2.1.2)                             |
| "Kontentga o'tish" havolasi | Sahifa boshida bormi?                                                   | Uzun menyuli sahifalarda tavsiya etiladi |

### Kontrast

- Normal matn: kamida **4.5:1**; katta matn (≥ 18pt yoki ≥ 14pt bold): **3:1**; UI komponent chegaralari va ikonkalar: **3:1**.
- Tekshirish: WebAIM Contrast Checker yoki Chrome DevTools'dagi rang tanlagich (u kontrast nisbatini ko'rsatadi).
- Faqat rang bilan ma'no berilmasin (1.4.1): "Qizil maydonlar — xato" emas, xato matni ham bo'lsin.

### Zoom va reflow

- Brauzerni **200%** ga kattalashtiring: matn kesilmaydi, tugmalar ustma-ust tushmaydi.
- Oynani **320 CSS px** kenglikka toraytiring (taxminan 400% zoom): faqat vertikal scroll bo'lishi kerak (1.4.10).

### Formalar

- Har maydonning **ko'rinadigan label**'i bor. W3C WAI forms qo'llanmasi: placeholder — foydali ko'rsatma, lekin **label o'rnini bosmaydi**; yozishni boshlaganingizda u yo'qoladi.
- Xato maydon bilan bog'langan va matnli: "Telefon raqam +998 dan keyin 9 ta raqamdan iborat bo'lishi kerak".
- Majburiy maydonlar faqat rang yoki `*` bilan emas, matn yoki atribut bilan ham belgilangan.

### Screen reader bilan tekshiruv

| Platforma    | Screen reader | Yoqish                               |
| ------------ | ------------- | ------------------------------------ |
| macOS        | VoiceOver     | `Cmd + F5`                           |
| iOS / iPadOS | VoiceOver     | Settings → Accessibility → VoiceOver |
| Windows      | NVDA (bepul)  | O'rnatib, ishga tushirish            |
| Android      | TalkBack      | Settings → Accessibility → TalkBack  |

Nimalarni eshitishingiz kerak: sahifa sarlavhasi; sarlavhalar bo'yicha navigatsiya; har maydonning nomi ("Telefon raqam, matn maydoni"); tugma nomlari ("Savatchaga qo'shish, tugma" — "tugma, tugma" emas); rasmlarning mazmuni; xato va "Savatchaga qo'shildi" kabi status xabarlari (4.1.3).

---

## 4. Avtomatik a11y: axe-core + Playwright {#axe}

**axe-core** (Deque) — ochiq kodli a11y qoidalar dvigateli. Chrome Lighthouse'ning accessibility bahosi ham axe'ning foydalanuvchiga ta'sir baholariga asoslangan og'irliklardan foydalanadi. Playwright bilan integratsiya — `@axe-core/playwright`.

```bash
npm i -D @playwright/test @axe-core/playwright
npx playwright install chromium
```

```typescript
// playwright.config.ts
import { defineConfig, devices } from "@playwright/test";

export default defineConfig({
  testDir: "./tests",
  reporter: "list",
  use: {
    baseURL: "https://www.saucedemo.com",
    testIdAttribute: "data-test",
  },
  projects: [{ name: "chromium", use: { ...devices["Desktop Chrome"] } }],
});
```

```typescript
// tests/a11y.spec.ts
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";

const WCAG_TAGS = ["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22aa"];

test("login sahifasida WCAG A/AA buzilishlari yo'q", async ({
  page,
}, testInfo) => {
  await page.goto("/");

  const results = await new AxeBuilder({ page }).withTags(WCAG_TAGS).analyze();

  // to'liq natija HTML hisobotga ilova bo'ladi
  await testInfo.attach("axe-violations", {
    body: JSON.stringify(results.violations, null, 2),
    contentType: "application/json",
  });
  expect(results.violations).toEqual([]);
});

test("DemoBozor mini sahifa: axe xatolarni topadi", async ({ page }) => {
  await page.setContent(`
    <html lang="uz"><body>
      <h1>DemoBozor</h1>
      <img src="choynak.png">
      <span>Telefon raqam</span> <input type="tel" id="phone">
      <input type="text" placeholder="Promo-kod">
      <button><svg width="16" height="16"></svg></button>
      <p style="color:#aaaaaa;background:#ffffff">Yetkazib berish bepul</p>
    </body></html>`);

  const results = await new AxeBuilder({ page }).withTags(WCAG_TAGS).analyze();
  const ids = results.violations.map((v) => v.id).sort();

  expect(ids).toEqual([
    "button-name",
    "color-contrast",
    "document-title",
    "image-alt",
    "label",
  ]);
});

test("faqat login formasi, bitta qoida o'chirilgan holda", async ({ page }) => {
  await page.goto("/");
  const results = await new AxeBuilder({ page })
    .include("#login_button_container")
    .disableRules(["color-contrast"])
    .analyze();

  expect(results.violations).toEqual([]);
});
```

Uchala test ham o'tadi (2026-yil oktabr). Ikkinchi testdan muhim saboqlar:

| Element                                      | axe qoidasi      | Muammo                                           |
| -------------------------------------------- | ---------------- | ------------------------------------------------ |
| `<img src="choynak.png">`                    | `image-alt`      | `alt` yo'q                                       |
| `<input type="tel">` (yonida oddiy `<span>`) | `label`          | Matn ko'rinadi, lekin maydonga **bog'lanmagan**  |
| `<button><svg></button>`                     | `button-name`    | Tugma nomsiz — screen reader faqat "tugma" deydi |
| `#aaaaaa` matn oq fonda                      | `color-contrast` | 2.32:1 < 4.5:1                                   |
| `<title>` yo'q                               | `document-title` | Sahifa sarlavhasi yo'q                           |

> **⚠️ Diqqat:** Faqat placeholder'i bor "Promo-kod" maydoni uchun axe xato **bermadi**: placeholder accessible name hisoblashda zaxira manba bo'lishi mumkin. Saucedemo login'i ham axe'dan 0 xato bilan o'tadi — uning maydonlarida `aria-label` va placeholder bor, lekin **ko'rinadigan label yo'q**. Avtomatik skaner "o'tdi" degani — hali "foydalanuvchi uchun qulay" degani emas; buni qo'lda tekshirish (3-bo'lim) topadi.

### Haqiqiy topilmalar: TodoMVC

```typescript
test("TodoMVC: jiddiy buzilishlar", async ({ page }) => {
  await page.goto("https://demo.playwright.dev/todomvc/");
  await page
    .getByPlaceholder("What needs to be done?")
    .fill("Choynak sotib olish");
  await page.getByPlaceholder("What needs to be done?").press("Enter");

  const { violations } = await new AxeBuilder({ page })
    .withTags(WCAG_TAGS)
    .analyze();
  const serious = violations.filter(
    (v) => v.impact === "serious" || v.impact === "critical",
  );

  for (const v of serious) {
    for (const node of v.nodes) {
      console.log(
        `${v.impact} | ${v.id} | ${node.target.join(" ")} | ${node.any[0]?.message}`,
      );
    }
  }
  expect(serious, "jiddiy a11y buzilishlari bo'lmasligi kerak").toEqual([]);
});
```

2026-yil oktabrdagi ishga tushirishda bu test **yiqildi** va konsolga quyidagilar chiqdi (qisqartirilgan; sayt o'zgarsa, natija ham o'zgaradi):

```text
serious | color-contrast | h1 | ... contrast of 1.26 (foreground color: #ebd7d7, background color: #f5f5f5, font size: 75.0pt (100px) ...). Expected contrast ratio of 3:1
serious | color-contrast | .selected | ... contrast of 4.47 (foreground color: #777777, background color: #ffffff, font size: 10.5pt (14px) ...). Expected contrast ratio of 4.5:1
serious | color-contrast | p:nth-child(1) | ... contrast of 1.68 (foreground color: #bfbfbf, background color: #f5f5f5, font size: 7.5pt (10px) ...). Expected contrast ratio of 4.5:1
```

E'tibor bering: `.selected` filtrining kontrasti **4.47** — chegaraga juda yaqin, lekin baribir **fail**. Katta (100px) sarlavha uchun talab 3:1, kichik matn uchun 4.5:1 — axe shriftga qarab to'g'ri chegarani o'zi tanlaydi.

### axe natijasini o'qish

- `violations` — buzilishlar: `id` (qoida), `impact` (`minor` / `moderate` / `serious` / `critical`), `help`, `helpUrl`, `nodes` (har biri `target` selector va `failureSummary` bilan).
- `passes` — o'tgan tekshiruvlar; `incomplete` — axe aniq hal qila olmagan, **qo'lda ko'rish kerak** bo'lganlar; `inapplicable` — sahifaga taalluqli bo'lmagan qoidalar.

### Avtomatlashtirish chegarasi

Ko'p mezonlar inson baholashini talab qiladi: `alt` matni **mazmunli**mi, fokus tartibi **mantiqiy**mi, xato xabari **tushunarli**mi. Deque'ning 2021-yildagi tadqiqoti (vendor tadqiqoti, mustaqil emas) avtomatik testlar topilgan muammolar **hajmining** taxminan 57% ini aniqlaganini ko'rsatgan — qolgan qismi baribir qo'lda topiladi. Lighthouse'da 100 ball ham "to'liq accessible" degani emas.

> **💡 Maslahat:** CI'da axe'ni muhim sahifalarda ishlating va `serious`/`critical` buzilishlarda pipeline'ni yiqiting. Eski (ma'lum) muammolar ko'p bo'lsa — ularni alohida ticket'larga ajratib, yangi buzilish qo'shilishiga yo'l qo'ymaslik siyosatini qo'llang.

---

## 5. Mobil accessibility {#mobil-a11y}

| Tekshiruv        | iOS                                                                        | Android                                      |
| ---------------- | -------------------------------------------------------------------------- | -------------------------------------------- |
| Screen reader    | VoiceOver: har element nomi, roli, holati o'qiladimi                       | TalkBack: xuddi shunday                      |
| Shrift kattaligi | Dynamic Type'ning eng katta (accessibility) o'lchamlari                    | Font size / Display size maksimal            |
| Bosish nishoni   | Apple HIG: tugma bosish maydoni kamida **44×44 pt** (visionOS'da 60×60 pt) | Google: kamida **48×48 dp**, oralig'i ≥ 8 dp |
| Harakat          | Reduce Motion yoqilganda animatsiyalar kamayadi                            | Animatsiya sozlamalari                       |
| Kontrast         | Increase Contrast, Bold Text                                               | High contrast text                           |
| Avtomatik audit  | Xcode **Accessibility Inspector**                                          | **Accessibility Scanner** ilovasi            |

DemoBozor uchun tipik mobil a11y bug'lari:

- savatcha ikonkasidagi badge VoiceOver'da "3" deb o'qiladi — "Savatcha, 3 ta mahsulot" bo'lishi kerak;
- Dynamic Type maksimal o'lchamda "Buyurtma berish" tugmasi ekrandan chiqib ketadi;
- mahsulot rasmi karuseli faqat swipe bilan ishlaydi — VoiceOver foydalanuvchisi uchun muqobil yo'q;
- OTP katakchalari har biri alohida o'qiladi va SMS kod autofill ishlamaydi.

> **🧠 Esda tuting:** `accessibilityIdentifier` (iOS) / `testTag` (Compose) — **avtomatik testlar** uchun, foydalanuvchiga o'qilmaydi. VoiceOver o'qiydigan matn — `accessibilityLabel` / `contentDescription`. Ikkalasi ham kerak, lekin vazifasi har xil ([QA 22](/ios-lessons/qa-mobile-automation)). Mobil testlash checklisti: [QA 14](/ios-lessons/qa-mobile-testing).

---

## 6. i18n va l10n: asosiy tushunchalar {#i18n}

- **Internationalization (i18n)** — mahsulotni **turli tillarga moslashtirish mumkin** qilib qurish: matnlar koddan tashqarida (resurs fayllar), Unicode, locale'ga qarab formatlash, egiluvchan layout.
- **Localization (l10n)** — aniq bir locale uchun moslashtirish: tarjima, sana/son/valyuta formatlari, madaniy jihatlar, huquqiy matnlar.

DemoBozor 4 locale bilan ishlaydi: `uz-Latn`, `uz-Cyrl`, `ru`, `en`.

### Tipik l10n bug'lari

| Bug                        | Misol                                        | Sabab                                            |
| -------------------------- | -------------------------------------------- | ------------------------------------------------ |
| Tarjima qilinmagan matn    | Rus tilida "Out of stock"                    | Hardcoded string yoki backend xatosi             |
| Gap bo'laklardan yig'ilgan | `"Savatchada " + n + " ta mahsulot"`         | Tillarda so'z tartibi va qo'shimchalar boshqacha |
| Noto'g'ri plural           | "5 товара" (to'g'risi "5 товаров")           | Plural qoidalari hisobga olinmagan               |
| Kesilgan matn              | "Buyurtma be..."                             | Tarjima uzunroq, tugma kengligi qat'iy           |
| Rasm ichidagi matn         | Banner faqat o'zbekcha                       | Matn rasmga "yopishtirilgan"                     |
| Noaniq sana                | `09/10/2026` — 9-oktabrmi yoki 10-sentabrmi? | Format talabda belgilanmagan                     |
| Shriftda belgi yo'q        | `ʻ` o'rnida bo'sh kvadrat                    | Shriftda U+02BB glif yo'q                        |
| Backend xabari tarjimasiz  | API inglizcha xato qaytaradi                 | Xato kodlari o'rniga matn                        |

### Matn kengayishi

W3C'ning "Text size in translation" maqolasida keltirilgan IBM yo'riqnomasiga ko'ra, ingliz tilidan Yevropa tillariga tarjimada **qisqa matnlar eng ko'p uzayadi**: 10 belgigacha bo'lgan matnlar 200–300% gacha, 70 belgidan uzunlari esa taxminan 130% gacha. Tugma, tab va menyu nomlari — eng xavfli joylar.

### Pseudo-localization

Haqiqiy tarjimani kutmasdan, matnlarni sun'iy ravishda "chet tilga o'xshatish" usuli: harflarni diakritikali variantlarga almashtirish va uzaytirish, masalan `Savatcha` → `[Šàvàtçhà ~~~~]`. Natijada hardcoded matnlar (o'zgarmay qolganlari) va kesilish joylari darhol ko'rinadi.

### RTL tillar

Arab yoki fors tilini qo'shish rejasi bo'lsa: `dir="rtl"`, layout ko'zgu kabi aylanadi, CSS'da `margin-left` o'rniga mantiqiy `margin-inline-start`. Node 24'da tekshirish: `new Intl.Locale('ar').getTextInfo()` → `{ direction: 'rtl' }`.

---

## 7. O'zbek tili nozikliklari: oʻ/gʻ, lotin/kirill, alifbo islohoti {#ozbek-tili}

### Apostroflarning besh xil ko'rinishi

O'zbek lotin alifbosidagi `Oʻ` va `Gʻ` harflari uchun to'g'ri belgi — **`ʻ` (U+02BB, MODIFIER LETTER TURNED COMMA)**; tutuq belgisi uchun — `ʼ` (U+02BC). Amalda esa klaviaturada qulay bo'lgani uchun boshqa belgilar ishlatiladi:

| Yozilishi  | Belgi                        | Unicode |
| ---------- | ---------------------------- | ------- |
| `o'zbek`   | ASCII apostrof               | U+0027  |
| `oʻzbek`   | Modifier letter turned comma | U+02BB  |
| `o‘zbek`   | Left single quotation mark   | U+2018  |
| `o’zbek`   | Right single quotation mark  | U+2019  |
| ``o`zbek`` | Backtick                     | U+0060  |

Inson uchun beshalasi "bir xil so'z", kompyuter uchun esa — **besh xil satr**. Natijada qidiruv, takrorlarni topish, saralash va login (masalan, foydalanuvchi nomi) buziladi.

### Qidiruvni tekshirish va tuzatish

```javascript
// Qidiruv kaliti: barcha apostrof variantlarini bitta belgiga (U+02BB) keltiramiz
const APOSTROPHES = /['`‘’ʼ]/g;

export function searchKey(text) {
  return text
    .normalize("NFC")
    .replace(APOSTROPHES, "ʻ")
    .toLocaleLowerCase("uz");
}

const products = [
  "Oʻzbek atlasi",
  "O'zbek do'ppisi",
  "O‘zbekcha choynak",
  "Gʻijduvon kosasi",
];
const query = "o'zbek";

const naive = products.filter((p) => p.toLowerCase().includes(query));
const smart = products.filter((p) => searchKey(p).includes(searchKey(query)));

console.log("oddiy qidiruv:", naive);
console.log("normallashtirilgan:", smart);
```

Node 24 natijasi:

```text
oddiy qidiruv: [ "O'zbek do'ppisi" ]
normallashtirilgan: [ 'Oʻzbek atlasi', "O'zbek do'ppisi", 'O‘zbekcha choynak' ]
```

Oddiy qidiruv 3 ta mos mahsulotdan faqat bittasini topdi. `searchKey` — **faqat qidiruv indeksi uchun** kalit: ekranda matn foydalanuvchi yozgandek qoladi.

**QA test g'oyalari:** har bir apostrof varianti bilan qidirish; nomida `ʻ` bo'lgan mahsulotni `'` bilan qidirish va aksincha; ro'yxatdan o'tishda bir xil ism turli apostrof bilan "boshqa odam" bo'lib qolmaydimi; shriftlarda `ʻ` glifi bormi.

### Saralash (collation)

O'zbek alifbosida `Oʻ`, `Gʻ`, `Sh`, `Ch` harflari `Z` dan keyin keladi. Oddiy `sort()` esa kod nuqtalari bo'yicha saralaydi:

```javascript
const words = [
  "shakar",
  "sabzi",
  "olma",
  "oʻrik",
  "gʻisht",
  "gilos",
  "chinni",
  "tuz",
];
console.log("sort():          ", [...words].sort().join(", "));
console.log(
  "Collator('uz'):  ",
  [...words].sort(new Intl.Collator("uz").compare).join(", "),
);
```

```text
sort():           chinni, gilos, gʻisht, olma, oʻrik, sabzi, shakar, tuz
Collator('uz'):   gilos, olma, sabzi, tuz, oʻrik, gʻisht, shakar, chinni
```

Shahar, toifa yoki brend ro'yxatlari alifbo tartibida chiqsa — locale'ga mos saralash talabda belgilanganmi, tekshiring.

### Lotin va kirill

Ikkala yozuv ham faol ishlatiladi. Tekshiruvlar: ilova tanlangan yozuvda **izchil** ko'rsatiladimi (bir ekranda aralash emas); foydalanuvchi ism yoki manzilni kirillda kiritsa, saqlanadi va to'g'ri ko'rinadimi; qidiruv qaysi yozuvlarda ishlashi talabda yozilganmi.

> **🇺🇿 Mahalliy kontekst:** **Alifbo islohoti.** O'zbek lotin alifbosini takomillashtirish haqidagi qonun loyihasini Senat 2026-yil 10-sentabrda ma'qulladi va Prezidentga yubordi. Xabarlarga ko'ra yangi alifboda 28 harf va bitta apostrof bo'ladi: `Oʻ → Ö`, `Gʻ → Ğ`, `Sh → Ş`, `Ch → Ç`. Rasmiy xabarda raqamli texnologiyalar bo'yicha yagona texnik standart ishlab chiqilayotgani va qidiruv mexanizmlari yangi harflarga moslashtirilayotgani aytilgan. Qonun kuchga kirsa, o'tish davrida ilovalar **ikkala imloni** ham to'g'ri qidirishi va saqlashi kerak bo'ladi (`oʻrik` va `örik`). Holatni rasmiy manbalardan kuzatib boring.

---

## 8. Sana, son, valyuta va plural: Intl bilan tekshirish {#intl}

JavaScript'ning `Intl` API'si CLDR ma'lumotlari asosida formatlaydi. Quyidagi natijalar Node.js 24 (ICU 78.2, CLDR 48) da olingan; brauzer va OS versiyasiga qarab biroz farq qilishi mumkin.

| Kod                                                               | Natija                       |
| ----------------------------------------------------------------- | ---------------------------- |
| `new Intl.NumberFormat('uz-UZ').format(1250000)`                  | `1 250 000`                  |
| `... ('uz-UZ', { style: 'currency', currency: 'UZS' })`           | `1 250 000,00 soʻm`          |
| `... + maximumFractionDigits: 0`                                  | `1 250 000 soʻm`             |
| `... ('uz-Cyrl-UZ', ...)`                                         | `1 250 000 сўм`              |
| `... ('ru-RU', ...)`                                              | `1 250 000 UZS`              |
| `... ('en-US', ...)`                                              | `UZS 1,250,000`              |
| `new Intl.DateTimeFormat('uz-UZ', { timeZone: 'Asia/Tashkent' })` | `09/10/2026`                 |
| `... ('uz-UZ', { dateStyle: 'long', timeStyle: 'short', ... })`   | `9-oktabr, 2026, 14:30`      |
| `... ('ru-RU', ...)`                                              | `9 октября 2026 г. в 14:30`  |
| `... ('en-US', ...)`                                              | `October 9, 2026 at 2:30 PM` |

(Sana: `2026-10-09T09:30:00Z` — Toshkentda 14:30.)

Bu jadvaldan uchta muhim QA xulosasi:

1. **Format — mahsulot qarori.** `uz-UZ` ning standart qisqa formati `09/10/2026`, O'zbekistonda esa hujjatlarda ko'pincha `09.10.2026` yoziladi. Talabda qaysi format ekanini aniq yozdiring va hamma ekranda izchilligini tekshiring.
2. **CLDR `soʻm` da U+02BB ishlatadi**, ko'p dizayn maketlarida esa `so'm` (U+0027) yozilgan. Matnni aynan taqqoslaydigan testlar shu yerda yiqiladi.
3. **Bo'shliqlar oddiy probel emas.** Raqam guruhlari va valyuta oldidagi bo'shliq — **NBSP (U+00A0)**:

```javascript
const price = new Intl.NumberFormat("uz-UZ", {
  style: "currency",
  currency: "UZS",
  maximumFractionDigits: 0,
}).format(1250000);

console.log(price); // 1 250 000 soʻm
console.log(price === "1 250 000 soʻm"); // false — bo'shliqlar NBSP (U+00A0)
console.log(price.replace(/[  ]/g, " ") === "1 250 000 soʻm"); // true
```

Playwright'ning web-first assertion'i `toHaveText` satr bilan solishtirganda bo'shliqlarni normallashtiradi, shuning uchun `await expect(locator).toHaveText('1 250 000 soʻm')` o'tadi; lekin `textContent()` ni `toBe` bilan solishtirsangiz — yiqiladi. Bu "flaky emas, lekin tushunarsiz" testlarning klassik sababi.

### Plural qoidalari

CLDR bo'yicha o'zbek tilida plural kategoriyalari ikkita: `one`, `other`. Rus tilida to'rtta: `one`, `few`, `many`, `other`.

```javascript
const messages = {
  uz: { one: "{n} ta mahsulot", other: "{n} ta mahsulot" },
  ru: {
    one: "{n} товар",
    few: "{n} товара",
    many: "{n} товаров",
    other: "{n} товара",
  },
};

function cartLabel(locale, n) {
  const category = new Intl.PluralRules(locale).select(n); // 'one' | 'few' | 'many' | 'other'
  return messages[locale][category].replace("{n}", String(n));
}

for (const n of [1, 2, 5, 11, 21, 22, 25]) {
  console.log(`${n}: ${cartLabel("ru", n)} | ${cartLabel("uz", n)}`);
}
```

```text
1: 1 товар | 1 ta mahsulot
2: 2 товара | 2 ta mahsulot
5: 5 товаров | 5 ta mahsulot
11: 11 товаров | 11 ta mahsulot
21: 21 товар | 21 ta mahsulot
22: 22 товара | 22 ta mahsulot
25: 25 товаров | 25 ta mahsulot
```

**Rus tili uchun test qiymatlari:** 0, 1, 2, 5, 11, 12, 21, 22, 25, 101, 111 — ayniqsa `11–14` (har doim `many`) va `21`, `22` (yana `one`, `few`) chegaralari. Bu — [QA 5](/ios-lessons/qa-test-design-1) dagi equivalence partitioning'ning tilga xos qo'llanilishi.

### Vaqt zonasi

`Asia/Tashkent` — UTC+5, yozgi vaqtga o'tish yo'q: Node 24'da yanvar va iyul uchun ham `GMT+5` chiqadi. Tekshiruvlar: server UTC'da saqlab, ekranda Toshkent vaqtida ko'rsatadimi; promo-kod "bugun 23:59 gacha" Toshkent vaqti bo'yicha tugaydimi; chet eldagi foydalanuvchi uchun buyurtma vaqti qanday ko'rinadi.

---

## 9. Visual testing: toHaveScreenshot va vositalar {#visual}

**Visual regression testing** — sahifa yoki komponentning skrinshotini oldindan tasdiqlangan **baseline** bilan solishtirish. Funksional assertion'lar "tugma bor va bosiladi" deydi, visual test esa "tugma o'z joyida, to'g'ri rangda, matn kesilmagan" ekanini ushlaydi.

| Yondashuv                | Qanday ishlaydi                                           | Misollar                                                        |
| ------------------------ | --------------------------------------------------------- | --------------------------------------------------------------- |
| Pixel diff               | Piksellarni solishtiradi                                  | Playwright `toHaveScreenshot`                                   |
| Bulutli vizual xizmatlar | Baseline'larni saqlaydi, review UI beradi                 | Percy (BrowserStack), Chromatic (Storybook komponentlari uchun) |
| AI asosidagi taqqoslash  | Inson ko'ziga sezilmaydigan farqlarni filtrlashga urinadi | Applitools Eyes                                                 |

### Playwright bilan

```typescript
// tests/visual.spec.ts
import { test, expect } from "@playwright/test";

const PRICE_COLOR = process.env.PRICE_COLOR ?? "#0F766E";

const productCard = (updatedAt: string) => `
  <html lang="uz"><head><title>DemoBozor</title><style>
    body { font-family: Arial, sans-serif; margin: 24px; }
    .card { width: 280px; padding: 16px; border: 1px solid #ddd; border-radius: 12px; }
    .price { color: ${PRICE_COLOR}; font-size: 22px; font-weight: bold; }
    .spinner { width: 16px; height: 16px; border: 3px solid #ccc; border-top-color: #333;
               border-radius: 50%; animation: spin 1s linear infinite; }
    @keyframes spin { to { transform: rotate(360deg); } }
  </style></head><body>
    <div class="card" data-test="product-card">
      <h2>Elektr choynak</h2>
      <p class="price">349 000 so'm</p>
      <p data-test="updated-at">Yangilandi: ${updatedAt}</p>
      <div class="spinner"></div>
      <button>Savatchaga qo'shish</button>
    </div>
  </body></html>`;

test("mahsulot kartasi vizual ko'rinishi", async ({ page }) => {
  await page.setViewportSize({ width: 400, height: 360 });
  await page.setContent(productCard(new Date().toISOString()));

  await expect(page.getByTestId("product-card")).toHaveScreenshot(
    "product-card.png",
    {
      mask: [page.getByTestId("updated-at")], // har safar o'zgaradigan vaqt
      animations: "disabled", // spinner to'xtatiladi
      maxDiffPixels: 50, // kichik farqlarga ruxsat
    },
  );
});
```

Haqiqiy ish oqimi (Playwright 1.64, macOS):

```bash
# 1) Birinchi ishga tushirish — baseline yo'q, test yiqiladi:
npx playwright test tests/visual.spec.ts
#    Error: A snapshot doesn't exist at .../visual.spec.ts-snapshots/product-card-chromium-darwin.png, writing actual.

# 2) Baseline yaratish (natijani ko'z bilan tekshirib, commit qiling):
npx playwright test tests/visual.spec.ts --update-snapshots

# 3) Keyingi ishga tushirishlar baseline bilan solishtiradi — o'tadi.

# 4) Narx rangi o'zgarsa (PRICE_COLOR='#DC2626'):
#    Error: expect(locator).toHaveScreenshot(expected) failed
#      669 pixels (ratio 0.01 of all image pixels) are different.
#    test-results/ papkasida: product-card-expected.png, -actual.png, -diff.png
```

Muhim jihatlar:

- **Baseline nomida brauzer va platforma bor** (`-chromium-darwin.png`). Playwright hujjati: render OS, versiya, sozlamalar, apparat va headless rejimga qarab farq qiladi — baseline'lar qayerda yaratilgan bo'lsa, testlar ham **o'sha muhitda** ishlashi kerak. Amalda baseline'larni CI bilan bir xil muhitda (masalan, Linux konteynerida) yarating ([QA 21](/ios-lessons/qa-ci-cd)).
- `mask` — vaqt, tasodifiy reklama, avatar kabi o'zgaruvchan joylarni yopadi; `animations: 'disabled'` — CSS animatsiyalarini to'xtatadi; `maxDiffPixels` / `threshold` — sezgirlik; `stylePath` — skrinshot paytida maxsus CSS (masalan, iframe'larni yashirish).
- **Komponent darajasidagi kichik skrinshotlar** butun sahifadan barqarorroq.
- Responsive tekshiruv: bir xil test 375 / 768 / 1280 px kengliklarda.
- Diff'ni **PR'da ko'rib tasdiqlash** jarayoni bo'lsin: `--update-snapshots` ni o'ylamasdan ishga tushirish — bug'ni baseline'ga "muhrlab qo'yish" demakdir.

Batafsil Playwright amaliyoti: [QA 19](/ios-lessons/qa-playwright-advanced).

---

## 10. Usability asoslari: Nielsen'ning 10 evristikasi {#usability}

Jakob Nielsen'ning 10 ta usability evristikasi (1994) — interfeysni tez baholash uchun tekshiruv ro'yxati:

| #   | Evristika                                               | DemoBozor'dagi buzilish misoli                                           |
| --- | ------------------------------------------------------- | ------------------------------------------------------------------------ |
| 1   | Visibility of System Status                             | "To'lash" bosilgach hech narsa o'zgarmaydi — yuklanish ko'rsatkichi yo'q |
| 2   | Match Between the System and the Real World             | "SKU qoldig'i: 0" — xaridor uchun "Sotuvda yo'q" bo'lishi kerak          |
| 3   | User Control and Freedom                                | Savatchadan o'chirilgan mahsulotni qaytarib bo'lmaydi                    |
| 4   | Consistency and Standards                               | Bir ekranda "Savatcha", boshqasida "Korzina"                             |
| 5   | Error Prevention                                        | Muddatli to'lov formasida yosh chegarasi oldindan ko'rsatilmaydi         |
| 6   | Recognition Rather than Recall                          | Checkout'da avvalgi manzillar taklif qilinmaydi                          |
| 7   | Flexibility and Efficiency of Use                       | Doimiy mijoz uchun "qayta buyurtma" tugmasi yo'q                         |
| 8   | Aesthetic and Minimalist Design                         | Mahsulot sahifasida 5 ta bir-biriga o'xshash banner                      |
| 9   | Help Users Recognize, Diagnose, and Recover from Errors | "Xato 4012" — nima qilish kerakligi yozilmagan                           |
| 10  | Help and Documentation                                  | Qaytarish qoidalari faqat ofertaning 20-sahifasida                       |

### "5 ta foydalanuvchi" qoidasi

Nielsen'ning 2000-yildagi maqolasiga ko'ra, bir xil turdagi 5 ta foydalanuvchi bilan test taxminan **85%** usability muammolarini topadi (bitta foydalanuvchi o'rtacha ~31% ni topadi degan modelga asoslangan). Muallifning o'zi qo'shgan shartlar: bitta katta test o'rniga **bir nechta kichik testlar** (har redizayndan keyin), foydalanuvchilar guruhlari juda farq qilsa — har guruhdan alohida, miqdoriy (metrikali) tadqiqotlar uchun esa ko'proq ishtirokchi kerak. Bu — qat'iy qonun emas, amaliy "rule of thumb".

---

## 11. Amaliy mashqlar {#mashqlar}

### Mashq 1: Kontrastni tuzating

axe TodoMVC'da `.selected` filtri uchun quyidagini chiqardi: `contrast of 4.47 (foreground color: #777777, background color: #ffffff, font size: 10.5pt (14px)...). Expected contrast ratio of 4.5:1`. (a) Bu qaysi SC? (b) Nega 4.47 yetmaydi? (c) Eng kam o'zgarish bilan qaysi rangni taklif qilasiz?

<details>
<summary>💡 Javobni ko'rish</summary>

- (a) **1.4.3 Contrast (Minimum)**, AA.
- (b) 14px oddiy matn "katta matn" emas (≥ 18pt yoki ≥ 14pt bold emas), shuning uchun talab **4.5:1**. 4.47 < 4.5 — chegaraga yaqin bo'lsa ham **fail**.
- (c) Bir pog'ona to'qroq kulrang: `#767676` oq fonda **≈ 4.54:1** — talabdan o'tadi (hisob WCAG formulasi bo'yicha). Kattaroq zaxira kerak bo'lsa `#6B6B6B` (≈ 5.33:1). Dizayner bilan kelishib, design token'ni o'zgartirish kerak — bitta ekranni emas.

</details>

### Mashq 2: Modal oyna klaviatura testi

DemoBozor'da "Manzil qo'shish" modal oynasi bor (maydonlar: shahar, ko'cha, uy, izoh; tugmalar: "Saqlash", "Bekor qilish", yopish ✕). Klaviatura bo'yicha test case'larni yozing.

<details>
<summary>💡 Javobni ko'rish</summary>

| #   | Qadam                                     | Kutilgan natija                                                  |
| --- | ----------------------------------------- | ---------------------------------------------------------------- |
| 1   | Modalni klaviatura bilan ochish (`Enter`) | Modal ochiladi, fokus birinchi maydonga (yoki sarlavhaga) o'tadi |
| 2   | `Tab` bilan aylanish                      | Fokus faqat modal ichida aylanadi, orqadagi sahifaga chiqmaydi   |
| 3   | Har elementda                             | Fokus aniq ko'rinadi (2.4.7)                                     |
| 4   | Yopish ✕ tugmasi                          | Screen reader uni "Yopish, tugma" deb o'qiydi (nomli)            |
| 5   | `Esc`                                     | Modal yopiladi                                                   |
| 6   | Yopilgandan keyin                         | Fokus modalni ochgan tugmaga qaytadi                             |
| 7   | Bo'sh maydon bilan "Saqlash"              | Xato matni maydon yonida, screen reader o'qiydi                  |
| 8   | 200% zoom                                 | Modal kontenti kesilmaydi, scroll qilinadi                       |

</details>

### Mashq 3: Rus plural test qiymatlari

Savatcha sarlavhasi: "В корзине N товар/товара/товаров". Equivalence partitioning bilan minimal, lekin to'liq qamrovli test qiymatlarini tanlang va kutilgan shaklni yozing.

<details>
<summary>💡 Javobni ko'rish</summary>

| N   | Kategoriya (`Intl.PluralRules('ru')`) | Kutilgan                      |
| --- | ------------------------------------- | ----------------------------- |
| 1   | one                                   | 1 товар                       |
| 2   | few                                   | 2 товара                      |
| 5   | many                                  | 5 товаров                     |
| 11  | many                                  | 11 товаров (11–14 — istisno!) |
| 12  | many                                  | 12 товаров                    |
| 21  | one                                   | 21 товар                      |
| 22  | few                                   | 22 товара                     |
| 25  | many                                  | 25 товаров                    |
| 101 | one                                   | 101 товар                     |
| 111 | many                                  | 111 товаров                   |

0 qiymati uchun alohida xabar ("Корзина пуста") talabda bormi — tekshiring. Kodda shakllarni qo'lda `if` bilan emas, `Intl.PluralRules` (yoki i18n kutubxonasi) bilan tanlash kerak.

</details>

### Mashq 4: Qidiruv uchun test to'plami

DemoBozor katalogida "Gʻijduvon kosasi" (U+02BB bilan) bor. Apostrof muammosini ushlaydigan qidiruv test'larini yozing va `searchKey` funksiyasi bilan kutilgan natijani ayting.

<details>
<summary>💡 Javobni ko'rish</summary>

| Qidiruv so'rovi | Ishlatilgan belgi | Kutilgan                                   |
| --------------- | ----------------- | ------------------------------------------ |
| `gʻijduvon`     | U+02BB            | Topiladi                                   |
| `g'ijduvon`     | U+0027            | Topiladi                                   |
| `g‘ijduvon`     | U+2018            | Topiladi                                   |
| `g’ijduvon`     | U+2019            | Topiladi                                   |
| ``g`ijduvon``   | U+0060            | Topiladi                                   |
| `GʻIJDUVON`     | Katta harflar     | Topiladi                                   |
| `гиждувон`      | Kirill            | Talabga qarab (yozuvlararo qidiruv bormi?) |

`searchKey` barcha apostrof variantlarini U+02BB ga keltirib, kichik harfga o'tkazgani uchun dastlabki 6 holatda ham kalitlar teng bo'ladi. Kirill → lotin moslashtirish alohida talab va alohida algoritm (transliteratsiya) talab qiladi.

</details>

### Mashq 5: L10n bug'larini toping

Rus tilidagi buyurtma ekrani tavsifi: sarlavha "Ваш заказ", tugma "Buyurtma berish", matn "В корзине 5 товара", narx "1250000 so'm", sana "10/09/2026", yetkazib berish izohi kesilgan: "Бесплатная доставка от 300 000 сў...", xato xabari "Promo code expired". Bug'larni sanang.

<details>
<summary>💡 Javobni ko'rish</summary>

1. "Buyurtma berish" — tugma tarjima qilinmagan (hardcoded yoki kalit yo'q).
2. "5 товара" — noto'g'ri plural, to'g'risi "5 товаров".
3. "1250000 so'm" — guruhlash yo'q va valyuta locale'ga mos emas (rus interfeysida `Intl` `UZS` beradi yoki mahsulot talabidagi rus yozuvi kerak).
4. "10/09/2026" — noaniq format; rus locale'da odatda `10.09.2026`, umuman olganda talab bo'yicha bitta izchil format.
5. "сў..." — rus matni ichida o'zbek kirill valyuta nomi va matn kesilgan (kenglik/uzunlik muammosi).
6. "Promo code expired" — backend xabari tarjima qilinmagan; API xato **kodini** qaytarishi, matnni esa mijoz locale bo'yicha ko'rsatishi kerak.

</details>

### Mashq 6: Beqaror visual test

`toHaveScreenshot` testi lokal kompyuterda o'tadi, CI'da esa doim yiqiladi; ba'zan lokalda ham har 5 ishga tushirishda bir marta yiqiladi. Kamida 4 ta ehtimoliy sababni va yechimini yozing.

<details>
<summary>💡 Javobni ko'rish</summary>

| Sabab                                                            | Yechim                                                                            |
| ---------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| Baseline macOS'da yaratilgan, CI — Linux (`-darwin` vs `-linux`) | Baseline'larni CI bilan bir xil muhitda (konteynerda) yaratish                    |
| Sahifada vaqt, tasodifiy banner, avatar                          | `mask` yoki test data'ni qotirish                                                 |
| Animatsiya/karusel                                               | `animations: 'disabled'`, karuselni to'xtatish                                    |
| Shrift kech yuklanadi                                            | Shriftlarni lokal ulash, yuklanishini kutish                                      |
| Ma'lumot o'zgaradi (narx, reyting)                               | Mock/route bilan barqaror ma'lumot ([QA 19](/ios-lessons/qa-playwright-advanced)) |
| Juda katta (butun sahifa) skrinshot                              | Komponent darajasidagi kichik skrinshotlar                                        |

</details>

### Mashq 7: Evristik tahlil

Quyidagi DemoBozor kuzatuvlarini Nielsen evristikalariga bog'lang: (a) to'lov 8 soniya davom etadi, ekran o'zgarmaydi; (b) xato: "ERR_PAYMENT_DECLINED_51"; (c) savatchadan mahsulot tasdiqsiz va qaytarib bo'lmaydigan tarzda o'chadi; (d) iOS'da "Orqaga" yuqori chapda, Android versiyasida esa pastki o'ngda.

<details>
<summary>💡 Javobni ko'rish</summary>

- (a) **#1 Visibility of System Status** — yuklanish holati ko'rsatilishi kerak.
- (b) **#9 Help Users Recognize, Diagnose, and Recover from Errors** (va #2) — oddiy tilda: "Karta to'lovni rad etdi. Boshqa karta bilan urinib ko'ring yoki bank bilan bog'laning."
- (c) **#3 User Control and Freedom** (va #5 Error Prevention) — "Bekor qilish" imkoniyati yoki tasdiq.
- (d) **#4 Consistency and Standards** — lekin ehtiyot bo'ling: har platformaning o'z standarti bor; platforma konventsiyasiga mos kelishi muhimroq.

</details>

---

## 12. O'zingizni tekshiring {#checklist}

- [ ] POUR printsiplarini va AA darajasini misollar bilan tushuntira olaman
- [ ] WCAG 2.2 da qo'shilgan mezonlardan kamida 5 tasini aytib bera olaman
- [ ] Sahifani faqat klaviatura bilan tekshirib, fokus muammolarini topa olaman
- [ ] `@axe-core/playwright` testini yozib, `violations` ni o'qiy olaman
- [ ] Avtomatik a11y skanerining chegarasini tushuntira olaman
- [ ] O'zbek apostroflari, saralash va plural bo'yicha test g'oyalarini bera olaman
- [ ] `Intl` natijasidagi NBSP muammosini bilaman
- [ ] `toHaveScreenshot` bilan baseline yaratib, diff'ni tahlil qila olaman

---

## Xulosa {#xulosa}

- Accessibility — WCAG 2.2 AA: POUR printsiplari; QA har feature'da klaviatura, fokus, kontrast, label va screen reader'ni tekshiradi.
- WCAG 2.2 9 ta yangi mezon qo'shdi (fokus yashirinmasligi, 24×24 px nishon, sudrash muqobili, accessible authentication va boshqalar) va 4.1.1 Parsing'ni olib tashladi.
- axe-core tez topiladigan xatolarni ushlaydi, lekin "0 violations" — "accessible" degani emas: placeholder-label, mazmunsiz `alt` kabi muammolarni inson topadi.
- L10n bug'larining ko'pi oldindan bashorat qilinadi: hardcoded matn, plural, kesilish, sana/valyuta formati, backend xabarlari.
- O'zbek tilida: apostrofning 5 xil ko'rinishi qidiruvni buzadi, `Oʻ/Gʻ` alifboda `Z` dan keyin keladi, lotin va kirill parallel; alifbo islohoti holatini kuzatib boring.
- `Intl` natijasida NBSP va U+02BB bor — testlarda buni hisobga oling.
- Visual testlar: barqaror ma'lumot, `mask`, `animations: 'disabled'`, CI bilan bir xil muhitdagi baseline va PR'da diff review.
- **Keyingi dars:** [QA 26: AI va QA (2026) — LLM bilan test dizayn, Playwright Agents, MCP va AI tizimlarini testlash](/ios-lessons/qa-ai-testing)

## Manbalar {#manbalar}

1. [W3C — WCAG 2.2](https://www.w3.org/TR/WCAG22/)
2. [W3C WAI — What's New in WCAG 2.2](https://www.w3.org/WAI/standards-guidelines/wcag/new-in-22/)
3. [W3C WAI — Understanding SC 2.5.8 Target Size (Minimum)](https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html)
4. [W3C WAI — WCAG 2.2 Quick Reference](https://www.w3.org/WAI/WCAG22/quickref/)
5. [W3C WAI — Accessibility Principles](https://www.w3.org/WAI/fundamentals/accessibility-principles/)
6. [W3C — WCAG 3.0 Working Draft](https://www.w3.org/TR/wcag-3.0/)
7. [W3C — Using ARIA](https://www.w3.org/TR/using-aria/)
8. [W3C WAI — ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/)
9. [W3C WAI — Forms tutorial: Instructions (placeholder)](https://www.w3.org/WAI/tutorials/forms/instructions/)
10. [European Commission — European Accessibility Act](https://commission.europa.eu/strategy-and-policy/policies/justice-and-fundamental-rights/disability/union-equality-strategy-rights-persons-disabilities-2021-2030/european-accessibility-act_en)
11. [EUR-Lex — Directive (EU) 2019/882](https://eur-lex.europa.eu/eli/dir/2019/882/oj/eng)
12. [Playwright — Accessibility testing](https://playwright.dev/docs/accessibility-testing)
13. [Playwright — Visual comparisons](https://playwright.dev/docs/test-snapshots)
14. [dequelabs/axe-core — GitHub](https://github.com/dequelabs/axe-core)
15. [Deque — Automated testing study (57%)](https://www.deque.com/blog/automated-testing-study-identifies-57-percent-of-digital-accessibility-issues/)
16. [Chrome — Lighthouse accessibility scoring](https://developer.chrome.com/docs/lighthouse/accessibility/scoring)
17. [WebAIM — Contrast Checker](https://webaim.org/resources/contrastchecker/)
18. [WAVE — WebAIM](https://wave.webaim.org/)
19. [NV Access — NVDA](https://www.nvaccess.org/)
20. [Apple HIG — Buttons](https://developer.apple.com/design/human-interface-guidelines/buttons)
21. [Apple HIG — Accessibility](https://developer.apple.com/design/human-interface-guidelines/accessibility)
22. [Apple — Accessibility Inspector](https://developer.apple.com/documentation/accessibility/accessibility-inspector)
23. [Google — Accessibility Scanner va touch target tavsiyasi](https://support.google.com/accessibility/android/answer/7101858)
24. [W3C Internationalization — Text size in translation](https://www.w3.org/International/articles/article-text-size)
25. [Unicode CLDR — Language Plural Rules](https://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html)
26. [Wikipedia — Uzbek alphabet](https://en.wikipedia.org/wiki/Uzbek_alphabet)
27. [UzA — Senate approves changes to Uzbek alphabet (2026-09-10)](https://www.uza.uz/en/posts/senate-approves-changes-to-uzbek-alphabet_907067)
28. [The Times of Central Asia — Uzbekistan Latin alphabet changes](https://timesca.com/uzbekistan-latin-alphabet-changes-senate/)
29. [Kun.uz — Lower house passes bill to revise Uzbek alphabet (2026-07-07)](https://kun.uz/en/news/2026/07/07/parliaments-lower-house-passes-bill-to-revise-uzbek-alphabet-848eb2)
30. [Percy — BrowserStack](https://www.browserstack.com/percy)
31. [Applitools](https://applitools.com/)
32. [Chromatic](https://www.chromatic.com/)
33. [NN/g — 10 Usability Heuristics](https://www.nngroup.com/articles/ten-usability-heuristics/)
34. [NN/g — Why You Only Need to Test with 5 Users](https://www.nngroup.com/articles/why-you-only-need-to-test-with-5-users/)
