Jest — o'rnatish, birinchi test, describe, it, expect

~20 daq · Express · Testing

Muammodan boshlaylik

Loyiha o'saydi. Yangi funksiya qo'shdingiz — eski narsa buzildi. Siz bilmaysiz. Foydalanuvchi topadi.

Yoki: tugmani bosib har safar qo'lda tekshirasiz — "ishladimi?". Bu samarasiz. Loyiha kattalashgani sari qo'lda tekshirish imkonsiz bo'ladi.

Test — bu: "men yozgan kod ishlaydi" ni tasdiqlash. Bir marta yoziladi, keyin har safar avtomatik ishlatiladi.


Test nima?

Test — funksiyangizga ma'lum kirish berilib, kutilgan chiqish tekshiriladigan kod.

sen yozgan funksiya:        test:
─────────────────────       ─────────────────────
qo'sh(2, 3)          →      natija 5 bo'lishi kerak
qo'sh(0, 0)          →      natija 0 bo'lishi kerak
qo'sh(-1, 1)         →      natija 0 bo'lishi kerak

Test o'tdi — funksiya to'g'ri ishlaydi. Test o'tmadi — qayerda buzilganini darhol bilasiz.


Hayotiy o'xshatma

Zavod konveyer. Har bir mahsulot chiqqanda — tekshiruv punkti. Nuqsonli bo'lsa — darhol to'xtatiladi, omborga bormaydi.

Testsiz dasturlash — tekshiruvsiz konveyer. Nuqsonli mahsulot foydalanuvchiga yetib boradi.


O'rnatish

npm install --save-dev jest

package.json:

{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch"
  }
}

ES module ishlatayotgan bo'lsangiz:

npm install --save-dev jest @babel/preset-env babel-jest

babel.config.json:

{
  "presets": [["@babel/preset-env", { "targets": { "node": "current" } }]]
}

Birinchi test

// utils/math.js
export const qo'sh = (a, b) => a + b;
export const ayir = (a, b) => a - b;
// utils/math.test.js
import { qo'sh, ayir } from './math.js';

test('2 + 3 = 5', () => {
  expect(qo'sh(2, 3)).toBe(5);
});

test('5 - 3 = 2', () => {
  expect(ayir(5, 3)).toBe(2);
});
npm test
✓ 2 + 3 = 5 (2ms)
✓ 5 - 3 = 2 (1ms)

Tests: 2 passed

describe — testlarni guruhlash

Bir funksiya uchun ko'p test bo'lsa — describe bilan guruhlang:

import { qo'sh } from './math.js';

describe('qo\'sh funksiyasi', () => {
  test('musbat sonlar', () => {
    expect(qo'sh(2, 3)).toBe(5);
  });

  test('manfiy sonlar', () => {
    expect(qo'sh(-2, -3)).toBe(-5);
  });

  test('nol bilan', () => {
    expect(qo'sh(5, 0)).toBe(5);
  });
});
qo'sh funksiyasi
  ✓ musbat sonlar
  ✓ manfiy sonlar
  ✓ nol bilan

💡 test o'rniga it ham ishlatiladi — ikkalasi bir xil. it('musbat sonlarni qo\'shadi', ...) — inglizcha o'qishda tabiiyroq.


expect — nimani tekshirish

// Teng
expect(natija).toBe(5);           // qat'iy tenglik (===)
expect(natija).toEqual({ a: 1 }); // obyekt/massiv tenglik

// To'g'ri/noto'g'ri
expect(natija).toBeTruthy();  // true bo'lsa
expect(natija).toBeFalsy();   // false bo'lsa
expect(natija).toBeNull();    // null bo'lsa

// Mavjudlik
expect(massiv).toContain(5);              // massivda bor
expect(matn).toMatch('salom');            // satrda bor
expect(funksiya).toThrow('xato xabari'); // xato tashlaydi

// Soni
expect(natija).toBeGreaterThan(3);      // > 3
expect(natija).toBeLessThanOrEqual(10); // <= 10

Async test

// utils/user.js
export const ismniOl = async (id) => {
  const user = await db.findById(id);
  return user.name;
};
// utils/user.test.js

// async/await bilan
test('foydalanuvchi ismini qaytaradi', async () => {
  const ism = await ismniOl(1);
  expect(ism).toBe('Ali');
});

Amaliy misol — parol tekshirish funksiyasi

// utils/validation.js
export const parolTekshir = (parol) => {
  if (parol.length < 8) return { togri: false, xabar: 'Kamida 8 belgi' };
  if (!/[A-Z]/.test(parol)) return { togri: false, xabar: 'Katta harf kerak' };
  if (!/[0-9]/.test(parol)) return { togri: false, xabar: 'Raqam kerak' };
  return { togri: true };
};
// utils/validation.test.js
import { parolTekshir } from './validation.js';

describe('parolTekshir', () => {
  test('qisqa parol', () => {
    const natija = parolTekshir('abc');
    expect(natija.togri).toBe(false);
    expect(natija.xabar).toBe('Kamida 8 belgi');
  });

  test('katta harf yo\'q', () => {
    const natija = parolTekshir('password1');
    expect(natija.togri).toBe(false);
    expect(natija.xabar).toBe('Katta harf kerak');
  });

  test('to\'g\'ri parol', () => {
    const natija = parolTekshir('Password1');
    expect(natija.togri).toBe(true);
  });
});

Test fayllarni qayerga qo'yish

Ikkita keng tarqalgan yondashuv:

// 1 — manba yonida
src/
├── utils/
│   ├── math.js
│   └── math.test.js   ← bir joyda

// 2 — alohida papka
src/
├── utils/
│   └── math.js
tests/
└── math.test.js

Ko'pchilik manba yonida usulni afzal ko'radi — faylni ko'rganingizda test ham ko'rinadi.


Tez-tez uchraydigan xatolar

1. toBe va toEqual aralashtirib yuborish

// ❌ — obyektda toBe ishlamaydi
expect({ a: 1 }).toBe({ a: 1 }); // false! Turli xotira manzili

// ✅
expect({ a: 1 }).toEqual({ a: 1 }); // ichini solishtiradi

2. Async testda await unutish

// ❌ — test har doim o'tadi (natijani kutmaydi)
test('test', () => {
  expect(asyncFn()).resolves.toBe('ok'); // await yo'q!
});

// ✅
test('test', async () => {
  await expect(asyncFn()).resolves.toBe('ok');
});

3. Test izolyatsiyasi

// ❌ — testlar bir-biriga bog'liq
let hisoblagich = 0;
test('birinchi', () => { hisoblagich++; });
test('ikkinchi', () => {
  expect(hisoblagich).toBe(1); // ← tartib o'zgansa — sinadi
});

// ✅ — har test o'z holatida
test('birinchi', () => {
  let h = 0; h++;
  expect(h).toBe(1);
});

Xulosa

  • Test — funksiyaga kirish berib, kutilgan chiqishni tekshirish
  • describe — guruh; test/it — bitta test; expect — tekshirish
  • toBe — qat'iy tenglik; toEqual — obyekt/massiv ichini solishtiradi
  • Async test — async/await bilan
  • Har test mustaqil bo'lsin — boshqa testga tayanmasin

Keyingi dars: 51-dars: Supertest — HTTP endpointlarni testlash