React Testing Guide

React testing guide for beginners and advanced developers


React Testing Guide

Test yozish — kod sifati va barqarorligini ta’minlash uchun eng muhim bosqich. Bu maqolada sizga unit, integration va end-to-end testlarni qanday tashkil qilish, qaysi vositalardan foydalanish, testlar strukturasini professional darajada yaratish va ularni CI/CD ga integratsiya qilish bo‘yicha to‘liq qadam-boqadam ko‘rsatmalar beramiz.


1. Test Piramidasi va Strategiya

graph LR
  A[End-to-End Tests] --> B[Integration Tests]
  B --> C[Unit Tests]
  • Unit Tests (70-80%): individual funktsiyalar & komponentlar
  • Integration Tests (15-20%): komponentlar va servislar o‘zaro aloqasi
  • End-to-End Tests (5-10%): foydalanuvchi yo‘li (UI → API → DB)

Nima uchun?

  • 🔍 Unit tests tez va izolyatsiya qilingan
  • 🔗 Integration tests modulár ishini ta’minlaydi
  • 🌐 E2E tests haqiqiy foydalanuvchi jarayonini tekshiradi

2. Muhitni Sozlash

2.1. Jest bilan (Create-React-App yoki Next.js)

npm install --save-dev jest @testing-library/react @testing-library/jest-dom babel-jest

jest.config.js:

module.exports = {
	testEnvironment: 'jsdom',
	transform: {
		'^.+\\.(js|jsx|ts|tsx)$': 'babel-jest',
	},
	moduleNameMapper: {
		'\\.(css|less|scss)$': 'identity-obj-proxy',
	},
	setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
}

jest.setup.js:

import '@testing-library/jest-dom'

2.2. Vitest bilan (Vite)

npm install --save-dev vitest @testing-library/react @testing-library/jest-dom jsdom

vite.config.ts:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
 
export default defineConfig({
	plugins: [react()],
	test: {
		environment: 'jsdom',
		globals: true,
		setupFiles: './vitest.setup.ts',
	},
})

vitest.setup.ts:

import '@testing-library/jest-dom'

3. Unit Testlar

3.1. AAA Pattern (Arrange-Act-Assert)

  1. Arrange: test uchun zarur holatni yaratish
  2. Act: funksiya yoki komponentni chaqirish
  3. Assert: kutgan natijani tekshirish
// Counter.tsx
import { useState } from 'react'
 
export function Counter() {
	const [count, setCount] = useState(0)
	return (
		<div>
			<button onClick={() => setCount(c => c + 1)}>+</button>
			<span data-testid='value'>{count}</span>
		</div>
	)
}
 
// Counter.test.tsx
import { render, screen, fireEvent } from '@testing-library/react'
import { Counter } from './Counter'
 
test('Counter + tugmasi bosilganda bittaga oshadi', () => {
	// Arrange
	render(<Counter />)
	const btn = screen.getByText('+')
	const value = screen.getByTestId('value')
 
	// Act
	fireEvent.click(btn)
 
	// Assert
	expect(value).toHaveTextContent('1')
})

3.2. Mocking & Spy

  • jest.mock() API chaqiruvlarini soxtalashtirish
  • jest.fn() callback funktsiyalarni kuzatish
// api.ts
export async function fetchUser(id: string) {
	const res = await fetch(`/api/users/${id}`)
	return res.json()
}
 
// api.test.ts
import { fetchUser } from './api'
global.fetch = jest.fn(() =>
	Promise.resolve({ json: () => Promise.resolve({ id: '1', name: 'Ali' }) })
)
 
test('fetchUser foydalanuvchi maʼlumotini qaytaradi', async () => {
	const user = await fetchUser('1')
	expect(fetch).toHaveBeenCalledWith('/api/users/1')
	expect(user.name).toBe('Ali')
})

4. Integration Testlar

Integration testlar bir nechta komponent yoki modulni birga sinovdan o‘tkazadi.

// LoginForm.tsx
import { useState } from 'react'
import { login } from './services/auth.service'
 
export function LoginForm() {
	const [email, setEmail] = useState('')
	const [msg, setMsg] = useState('')
	const handleSubmit = async e => {
		e.preventDefault()
		const res = await login(email)
		setMsg(res.success ? 'Xush kelibsiz!' : 'Xato')
	}
	return (
		<form onSubmit={handleSubmit}>
			<input
				placeholder='Email'
				value={email}
				onChange={e => setEmail(e.target.value)}
			/>
			<button type='submit'>Kirish</button>
			{msg && <p>{msg}</p>}
		</form>
	)
}
 
// LoginForm.test.tsx
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import { LoginForm } from './LoginForm'
import * as auth from './services/auth.service'
 
jest.spyOn(auth, 'login').mockResolvedValue({ success: true })
 
test('muvaffaqiyatli login xabarini ko‘rsatadi', async () => {
	render(<LoginForm />)
	fireEvent.change(screen.getByPlaceholderText('Email'), {
		target: { value: 'a@example.com' },
	})
	fireEvent.click(screen.getByText('Kirish'))
 
	await waitFor(() =>
		expect(screen.getByText('Xush kelibsiz!')).toBeInTheDocument()
	)
})

5. End-to-End (E2E) Testlar

5.1. Cypress

npm install --save-dev cypress

cypress/integration/login.spec.js:

describe('Login Flow', () => {
	it('foydalanuvchi muvaffaqiyatli kirishi', () => {
		cy.visit('/login')
		cy.get('input[placeholder="Email"]').type('a@example.com')
		cy.get('button').contains('Kirish').click()
		cy.contains('Dashboard').should('be.visible')
	})
})

5.2. Playwright

npm install --save-dev playwright @playwright/test

tests/login.spec.ts:

import { test, expect } from '@playwright/test'
 
test('foydalanuvchi login bo‘lishi', async ({ page }) => {
	await page.goto('http://localhost:3000/login')
	await page.fill('input[placeholder="Email"]', 'a@example.com')
	await page.click('text=Kirish')
	await expect(page.locator('text=Dashboard')).toBeVisible()
})

6. CI/CD ga Integratsiya

GitHub Actions misoli

.github/workflows/test.yml:

name: Test
 
on: [push, pull_request]
 
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
      - run: npm ci
      - run: npm run test -- --coverage
      - name: Upload coverage report
        uses: actions/upload-artifact@v3
        with:
          name: coverage-report
          path: coverage

7. Eng Yaxshi Amaliyotlar

  • 🛡️ Test isolation: har bir test o‘z holatida bo‘lsin
  • 📑 Fast coverage check: < 80% ni pasaytirmang
  • 🏷️ Clear test names: should, renders, calls kabi
  • ⚖️ Avoid flaky tests: waitFor o‘rniga findBy…
  • 🧹 Fast cleanup (Teardown): DOM va mocks’larni qayta tiklash

8. Xulosa

  • Unit tests - kod logikasini tekshiradi
  • Integration tests - modulár o‘zaro aloqasini sinaydi
  • E2E tests - foydalanuvchi tajribasini sinaydi
  • CI/CD - har push va PR’da avtomatik test

Test yozish — bu kodga sarmoya. Ustuvorlik berilsin, muntazam qayta ko‘rib chiqilsin va jamoaviy madaniyatga aylanadi.