26 β Testlash va debugging¶
β¬ οΈ Oldingi: 25 β Autentifikatsiya Β· π Kitob boshi Β· Keyingi: 27 β Performance, New Architecture va deploy β‘οΈ
Bu bobda: Ilovangiz o'sgani sayin har bir ekranni qo'lda bosib tekshirish charchatadi va xatolarni o'tkazib yuboradi. Shu muammoni hal qiladigan avtomatik testlarni o'rganamiz: oddiy funksiya testidan tortib komponent, hodisa, async va custom hook testlarigacha.
jest-expova@testing-library/react-nativebilan ishlaymiz. Keyin esa xato topishning ikkinchi tomonini β debugging (xatoni qidirib tuzatish) asboblarini ko'rib chiqamiz: React Native DevTools,console.log, LogBox va element inspector.
Nega test yozamiz?¶
Tasavvur qiling, siz onlayn-do'kon ilovasini yozyapsiz. Bugun savatchaga mahsulot qo'shish ishlaydi. Ertaga siz narx hisoblash kodini o'zgartirasiz β va sezmagan holda savatcha jami summasi buzilib qoladi. Buni qachon bilib qolasiz? Foydalanuvchi shikoyat qilganda. Ya'ni juda kech.
Endi tasavvur qiling: har safar kod o'zgartirganingizda kompyuter o'zi savatchani sinab ko'radi, summani tekshiradi va "hammasi joyida" yoki "summa buzildi!" deb aytadi. Mana shu β avtomatik test.
Hayotiy o'xshatish. Test β bu zavoddagi sifat nazoratchisi kabi. Konveyerda har bir mahsulot chiqishidan oldin nazoratchi uni tekshiradi: o'lchami to'g'rimi, ishlayaptimi, sinmaganmi. Siz uxlab yotganingizda ham nazoratchi ishlaydi β har bir "mahsulot" (kod o'zgarishi) standartga mos kelishini kafolatlaydi. Qo'lda har birini tekshirsangiz, charchaysiz va o'tkazib yuborasiz; nazoratchi esa hech qachon zerikmaydi va e'tibordan chetda qoldirmaydi.
Test yozishning aniq foydalari:
- Ishonch. Kodni o'zgartirib, "buzmadimmi?" deb qo'rqmaysiz. Testlar yashil bo'lsa β ishlaydi.
- Regress himoyasi. "Regress" β ilgari ishlagan narsaning yangi o'zgarishdan keyin buzilishi. Test buni darhol ushlaydi. Bir marta tuzatilgan xato qaytib kelsa, test "qizil" bo'ladi.
- Hujjat. Yaxshi yozilgan test β kodning qanday ishlashi haqidagi tirik misol. Yangi dasturchi testni o'qib, funksiya nima qilishini tushunadi.
- Yaxshi dizayn. Testlash oson kod β odatda toza, ajratilgan kod. Test yozish qiyin bo'lsa, ko'pincha kod tuzilishida muammo bor.
Maslahat
Boshlovchilar ko'pincha "test keyin yozaman" deb qoldiradi. Lekin eng katta foyda β kichik, ko'p ishlatiladigan qismlarga (narx hisoblash, validatsiya, asosiy tugma) test yozishdan boshlanadi. 100% qamrov shart emas; muhim joylarni himoya qiling.
Test piramidasi: qaysi testdan qancha?¶
Hamma testlar bir xil emas. Ular tezligi, ishonchliligi va narxi bo'yicha farq qiladi. Buni odatda piramida ko'rinishida tasvirlashadi.
1. Unit (birlik) testlar β eng pastki, eng keng qatlam. Bitta funksiya yoki bitta hookni alohida, izolyatsiyada sinaydi. Masalan: "chegirma narxini hisoblovchi funksiya to'g'ri ishlaydimi?". Ular juda tez (millisekundlar) va juda ishonchli. Shuning uchun ulardan ko'p yozasiz.
2. Komponent (integratsiya) testlar β o'rta qatlam. Bir komponentni render qilib (chizib), u bilan foydalanuvchidek muloqot qiladi: tugma bosadi, matn kiritadi, natijani tekshiradi. React Native'da aynan shu qatlam eng foydali β chunki UI komponentlari ilovaning yuragi, va ularni tekshirish real foydalanuvchi tajribasiga eng yaqin.
3. E2E (end-to-end, "uchidan uchigacha") testlar β eng tepa, eng kam qatlam. Haqiqiy qurilma yoki emulyatorda ilovani to'liq ishga tushirib, butun oqimni sinaydi: "login qil β mahsulot qo'sh β buyurtma ber". Ular eng ishonchli (haqiqiy ilovani sinaydi), lekin eng sekin va eng nozik (tarmoq, animatsiya tufayli ba'zan sababsiz yiqiladi). Shuning uchun ulardan ozgina, faqat eng muhim oqimlar uchun yoziladi.
Eslatma
E2E uchun React Native dunyosida ikkita asosiy vosita bor: Maestro (sodda, YAML-ga asoslangan, boshlovchiga qulay) va Detox (kuchli, kod bilan yoziladi). Bu bobda biz piramidaning pastki va o'rta qatlamlariga (unit + komponent) e'tibor qaratamiz β chunki ular tezroq qaytim beradi va kundalik ishda eng ko'p qo'l keladi.
Sozlash: jest-expo va Testing Library¶
Test yozish uchun bizga ikkita asosiy vosita kerak:
- Jest β Facebook (Meta) yaratgan test "yuguruvchisi" (test runner). U testlarni topadi, ishga tushiradi va natijani ko'rsatadi.
jest-expoesa β Jest'ni Expo/React Native muhitiga moslab sozlangan preset (tayyor sozlama to'plami). @testing-library/react-native(qisqacha RNTL) β komponentlarni render qilib, ular bilan foydalanuvchidek muloqot qilish uchun. Uning falsafasi: "foydalanuvchi ko'rgan narsani sinang, ichki kod tafsilotini emas".
O'rnatish:
Keyin package.json ga Jest preset'ini qo'shamiz:
Endi terminalda testlarni shunday ishga tushirasiz:
npm test # bir marta hamma testni yuguritadi
npm test -- --watch # fayl o'zgarganda avtomatik qayta yuguritadi
Jest fayl nomi .test.ts / .test.tsx bilan tugaydigan yoki __tests__/ papkasidagi fayllarni avtomatik topadi.
Ehtiyot bo'ling β versiya muhim!
Bu bob jonli loyihada jest-expo 56 va @testing-library/react-native 14 bilan tekshirilgan. RNTL 14 β katta yangilanish: undagi render, fireEvent, renderHook funksiyalari endi asinxron (Promise qaytaradi) va ularni await qilish SHART. Bu eski kodlardan (v12 va undan oldin) jiddiy farq. Quyida buni har joyda ko'rasiz β agar testingiz "render function has not been called" desa, demak await qo'yishni unutgansiz.
Birinchi test: oddiy funksiya¶
Eng oddiy testdan boshlaymiz β hech qanday UI yo'q, faqat sof funksiya. Bu unit testning klassik namunasi.
Aytaylik, narxdan chegirma hisoblaydigan kichik funksiyamiz bor:
// narx.ts
export function chegirmaNarxi(narx: number, foiz: number): number {
if (foiz < 0 || foiz > 100) {
throw new Error('Foiz 0 va 100 oralig\'ida bo\'lishi kerak');
}
return Math.round(narx - (narx * foiz) / 100);
}
Endi shu funksiya yonida narx.test.ts faylini yaratamiz:
// narx.test.ts
import { chegirmaNarxi } from './narx';
describe('chegirmaNarxi', () => {
it('20% chegirmani to\'g\'ri hisoblaydi', () => {
expect(chegirmaNarxi(1000, 20)).toBe(800);
});
it('0% chegirmada narx o\'zgarmaydi', () => {
expect(chegirmaNarxi(1000, 0)).toBe(1000);
});
it('noto\'g\'ri foizda xato beradi', () => {
expect(() => chegirmaNarxi(1000, 150)).toThrow();
});
});
Bu yerda uchta yangi atama bor β ularni eslab qoling, ular butun test dunyosining alifbosi:
describe('nom', () => {...})β bir-biriga bog'liq testlarni guruhlaydi (xuddi kitobdagi bo'lim sarlavhasi kabi).it('tavsif', () => {...})β bitta aniq testni e'lon qiladi. Tavsif odatdagi gap kabi o'qilishi kerak: "it kiritilgan 20% chegirmani to'g'ri hisoblaydi". (test(...)ham xuddi shu, ikkalasi bir xil.)expect(qiymat).matcher(...)β kutilgan natijani tekshiradi.expectβ "men kutaman",.toBe(800)β "bu aynan 800 bo'lishini" degani.
Eng ko'p ishlatiladigan matcherlar (tekshiruvchilar):
| Matcher | Ma'nosi |
|---|---|
.toBe(x) |
aynan teng (sonlar, satrlar uchun) |
.toEqual(obj) |
obyekt/massivlar ichki teng |
.toBeNull() / .toBeTruthy() |
null / "rost" qiymat |
.toThrow() |
funksiya xato tashlaydimi |
.toContain(x) |
massiv/satr ichida bormi |
.toHaveBeenCalledWith(x) |
mock shu argument bilan chaqirilganmi |
Misol
Yuqoridagi narx.test.ts jonli Expo loyihasida ishga tushirilib, uchta test ham xatosiz o'tdi. npm test natijasi: β 20% chegirmani to'g'ri hisoblaydi, β 0% chegirmada narx o'zgarmaydi, β noto'g'ri foizda xato beradi.
Komponent test: render va so'rovlar¶
Endi qiziqroq qismga o'tamiz β komponentni sinash. Bu uchun Testing Library'ning to'rtta asosiy quroli bor:
render(<Komponent />)β komponentni xotirada chizadi (haqiqiy ekran kerak emas). RNTL 14'da bu asinxron βawait render(...).screenβ eng oxirgi render qilingan natijaga ulanish. Undan elementlarni qidirasiz.fireEventβ foydalanuvchi harakatini taqlid qiladi (bosish, matn kiritish).
screen orqali elementlarni topishning bir nechta usuli bor. Eng ko'p ishlatiladiganlari:
screen.getByText('Salom') // matn bo'yicha topadi
screen.getByPlaceholderText('Ism') // input placeholder bo'yicha
screen.getByTestId('natija') // testID prop bo'yicha
screen.queryByText('Yo\'q') // topilmasa null qaytaradi (xato tashlamaydi)
screen.findByText('Yuklandi') // KUTADI β async (Promise qaytaradi)
Uch xil prefiksning farqini yodda tuting β bu eng ko'p adashtiradigan joy:
getBy...β element bo'lishi shart. Topilmasa, darhol xato beradi (test yiqiladi).queryBy...β element bo'lmasligini tekshirish uchun. Topilmasanullqaytaradi, xato bermaydi. ("Bu matn ekranda yo'qligini isbotlamoqchiman" βqueryByishlating.)findBy...β element keyinroq paydo bo'ladi (masalan API javobidan keyin). U biroz kutadi va Promise qaytaradi, shuning uchunawaitbilan.
testID β testning 'tutqichi'
Ko'pincha matn bo'yicha topish noaniq bo'ladi (bir xil matn ikki joyda). Shunda komponentga testID="natija" propini qo'shing va getByTestId('natija') bilan aniq topib oling. testID β faqat test uchun, foydalanuvchiga ko'rinmaydi. Lekin uni me'yorida ishlating: imkon bo'lsa, foydalanuvchi ko'radigan narsa (matn, rol) bo'yicha qidirish afzal.
Hodisa va holat testi: counter¶
Endi haqiqiy o'zaro ta'sirni sinaymiz. Mana oddiy "hisoblagich" (counter) komponenti β tugma bosilganda son oshadi:
// Hisoblagich.tsx
import { View, Text, Pressable, StyleSheet } from 'react-native';
import { useState } from 'react';
export default function Hisoblagich() {
const [soni, setSoni] = useState(0);
return (
<View style={styles.box}>
<Text testID="natija">Hisob: {soni}</Text>
<Pressable onPress={() => setSoni(soni + 1)}>
<Text>Oshirish</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
box: { alignItems: 'center', gap: 8 },
});
Test esa foydalanuvchini taqlid qiladi: tugmani ikki marta bosadi va sonni tekshiradi.
// Hisoblagich.test.tsx
import { render, screen, fireEvent } from '@testing-library/react-native';
import Hisoblagich from './Hisoblagich';
describe('<Hisoblagich />', () => {
it('boshida 0 ni ko\'rsatadi', async () => {
await render(<Hisoblagich />);
expect(screen.getByText('Hisob: 0')).toBeOnTheScreen();
});
it('tugma bosilganda son oshadi', async () => {
await render(<Hisoblagich />);
await fireEvent.press(screen.getByText('Oshirish'));
await fireEvent.press(screen.getByText('Oshirish'));
expect(screen.getByTestId('natija')).toHaveTextContent('Hisob: 2');
});
});
Bu yerda nima bo'lyapti, qadam-baqadam:
await render(<Hisoblagich />)β komponentni xotirada chizdik.await fireEvent.press(...)β "Oshirish" matnli elementni bosdik (ikki marta).fireEvent.pressham async βawaitqilamiz.expect(screen.getByTestId('natija')).toHaveTextContent('Hisob: 2')βtestID="natija"bo'lgan elementning ichidaHisob: 2borligini tekshirdik.
fireEventning eng ko'p ishlatiladigan turlari:
fireEvent.press(element)β bosish (onPress).fireEvent.changeText(input, 'matn')β inputga matn yozish (onChangeText).fireEvent(element, 'scroll', {...})β boshqa istalgan hodisa.
Misol
Bu test jonli loyihada ishlatildi va o'tdi: β boshida 0 ni ko'rsatadi, β tugma bosilganda son oshadi. Ikkita press dan keyin holat haqiqatan 2 ga yetdi.
Eslatma β RNTL'ning oltin qoidasi.
toBeOnTheScreen(),toHaveTextContent()kabi maxsus matcherlar (matchers)@testing-library/react-nativeo'rnatilganda avtomatik qo'shiladi. Ular faqat React Native elementlarida ishlaydi. Eski kodlarda@testing-library/jest-nativealohida o'rnatilardi β endi kerak emas, hammasi RNTL ichida.
Input testi: matn kiritish¶
Inputni sinash β formali ilovalarda eng ko'p uchraydigan vazifa. Mana foydalanuvchi ism kiritganda salomlashadigan komponent:
// Salomlash.tsx
import { View, Text, TextInput } from 'react-native';
import { useState } from 'react';
export default function Salomlash() {
const [ism, setIsm] = useState('');
return (
<View>
<TextInput placeholder="Ismingiz" value={ism} onChangeText={setIsm} />
{ism.length > 0 && <Text>Salom, {ism}!</Text>}
</View>
);
}
Diqqat: salom matni faqat ism kiritilgandagina ko'rinadi. Buni tekshiramiz:
// Salomlash.test.tsx
import { render, screen, fireEvent } from '@testing-library/react-native';
import Salomlash from './Salomlash';
describe('<Salomlash />', () => {
it('boshida salom matni yo\'q', async () => {
await render(<Salomlash />);
expect(screen.queryByText(/Salom/)).toBeNull(); // queryBy β yo'qligini tekshiramiz
});
it('matn kiritilganda salomlashadi', async () => {
await render(<Salomlash />);
await fireEvent.changeText(screen.getByPlaceholderText('Ismingiz'), 'Olim');
expect(screen.getByText('Salom, Olim!')).toBeOnTheScreen();
});
});
E'tibor bering: boshida salom matni yo'qligini tekshirish uchun queryByText ishlatdik (getByText bo'lsa, topa olmay xato berardi). Bu β "yo'qlikni isbotlash" uslubining klassik namunasi. /Salom/ β regulyar ifoda; "Salom" so'zi qaysidir matn ichida bormi degani.
Async test: API mock qilish¶
Haqiqiy ilovalar serverdan ma'lumot oladi. Lekin testda haqiqiy serverga chiqib bo'lmaydi β sekin, ishonchsiz, internet kerak. Yechim: mock (soxta versiya). Biz fetchni o'z nazoratimizdagi soxta funksiya bilan almashtiramiz, va u istalgan ma'lumotni darhol qaytaradi.
Hayotiy o'xshatish. Mock β kino suratga olishdagi kaskadyor-dublyor kabi. Asl aktyorni xavfli sahnada ishlatmaysiz β uni juda o'xshash dublyor bilan almashtirasiz. Test ham haqiqiy serverga "tegmaydi": u o'rniga oldindan tayyorlangan javob beradigan dublyor
fetchni qo'yadi. Shunda test tez, barqaror va internetga bog'liq emas.
Avval API'dan foydalanuvchini yuklaydigan komponent:
// Profil.tsx
import { View, Text, ActivityIndicator } from 'react-native';
import { useFoydalanuvchi } from './useFoydalanuvchi';
export default function Profil({ id }: { id: number }) {
const { data, yuklanmoqda } = useFoydalanuvchi(id);
if (yuklanmoqda) {
return <ActivityIndicator testID="spinner" />;
}
return (
<View>
<Text>Ism: {data?.ism}</Text>
</View>
);
}
Endi test β fetchni mock qilamiz:
// Profil.test.tsx
import { render, screen } from '@testing-library/react-native';
import Profil from './Profil';
beforeEach(() => {
// global fetch ni soxta funksiya bilan almashtiramiz
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve({ id: 1, ism: 'Olim' }),
})
) as jest.Mock;
});
afterEach(() => jest.restoreAllMocks()); // har testdan keyin asl holatga qaytaramiz
describe('<Profil />', () => {
it('yuklangach foydalanuvchi ismini ko\'rsatadi', async () => {
await render(<Profil id={1} />);
// findByText yuklanishni KUTADI (Promise qaytaradi)
expect(await screen.findByText('Ism: Olim')).toBeOnTheScreen();
});
});
Bu yerda yangi tushunchalar:
jest.fn(() => ...)β soxta funksiya yaratadi. U haqiqiyfetcho'rniga turadi va biz aytgan qiymatni qaytaradi.beforeEach/afterEachβ har testdan oldin va keyin ishlaydigan tayyorgarlik/tozalash kodi.beforeEachda mockni o'rnatamiz,afterEachdajest.restoreAllMocks()bilan tozalaymiz (aks holda mock keyingi testlarga ham ta'sir qiladi).findByTextβgetByTextdan farqli, u ma'lumot kelishini kutadi. API javobi (mock bo'lsa ham) keyingi "tik"da keladi, shuning uchunawaitshart.
Ehtiyot bo'ling: yuklanish holati tezda o'tib ketadi
RNTL 14'da await render(...) o'zining ichida act() ni chaqiradi β ya'ni effektlar (useEffect) darhol ishlab ulguradi. Shuning uchun mock fetch zudlik bilan javob bersa, await render qaytganida <ActivityIndicator> (yuklanish spinneri) allaqachon yo'qolgan bo'ladi. Demak "avval spinner, keyin matn" degan testlar mock bilan ishonchsiz. To'g'ri yondashuv: yakuniy natijani findByText bilan tekshiring (yuqoridagidek). Bu nuanceni biz jonli loyihada o'z ko'zimiz bilan ko'rdik β getByTestId('spinner') mock tezda javob bergani uchun topa olmadi.
Custom hook testi: renderHook va waitFor¶
13-bobda custom hook (useXxx) yozishni o'rgangandik. Hookni alohida sinash uchun maxsus vosita bor β renderHook. U hookni soxta komponent ichida ishga tushiradi va natijasini beradi.
Avval yuqorida <Profil> ishlatgan hookning o'zi:
// useFoydalanuvchi.ts
import { useState, useEffect } from 'react';
type Foydalanuvchi = { id: number; ism: string };
export function useFoydalanuvchi(id: number) {
const [data, setData] = useState<Foydalanuvchi | null>(null);
const [yuklanmoqda, setYuklanmoqda] = useState(true);
useEffect(() => {
let bekorQilindi = false;
fetch(`https://api.example.com/users/${id}`)
.then((r) => r.json())
.then((j: Foydalanuvchi) => {
if (!bekorQilindi) {
setData(j);
setYuklanmoqda(false);
}
});
return () => {
bekorQilindi = true; // tozalash: komponent o'chsa, holatni o'zgartirmaymiz
};
}, [id]);
return { data, yuklanmoqda };
}
Test:
// useFoydalanuvchi.test.ts
import { renderHook, waitFor } from '@testing-library/react-native';
import { useFoydalanuvchi } from './useFoydalanuvchi';
beforeEach(() => {
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve({ id: 1, ism: 'Olim' }),
})
) as jest.Mock;
});
afterEach(() => jest.restoreAllMocks());
describe('useFoydalanuvchi', () => {
it('yuklangach data ni qaytaradi', async () => {
const { result } = await renderHook(() => useFoydalanuvchi(1));
// yuklanish tugashini kutamiz
await waitFor(() => {
expect(result.current.yuklanmoqda).toBe(false);
});
expect(result.current.data).toEqual({ id: 1, ism: 'Olim' });
});
it('to\'g\'ri manzilga so\'rov yuboradi', async () => {
await renderHook(() => useFoydalanuvchi(7));
expect(global.fetch).toHaveBeenCalledWith('https://api.example.com/users/7');
});
});
Muhim tushunchalar:
renderHook(() => useXxx(...))β hookni ishga tushiradi. RNTL 14'da bu ham async βawaitqiling.result.currentβ hookning eng oxirgi qaytargan qiymati. Holat o'zgargach,result.currentyangilanadi.waitFor(() => {...})β ichidagiexpecto'tguncha qayta-qayta tekshirib kutadi. Async holat o'zgarishini kutish uchun ishlatiladi. Vaqt tugasa (default ~1 soniya) test yiqiladi.toHaveBeenCalledWith(...)β mock funksiya aynan shu argument bilan chaqirilganmi. Ikkinchi testid=7uchun manzil to'g'ri qurilganini tekshiradi.
Misol
Bu hook testi jonli loyihada jest-expo bilan ishga tushirilib o'tdi: β yuklangach data ni qaytaradi, β to'g'ri manzilga so'rov yuboradi. waitFor yuklanish tugashini kutdi va result.current.data to'g'ri obyektni qaytardi.
Snapshot testi (qisqacha)¶
Snapshot ("oniy surat") testi β komponentning chiqishini matn ko'rinishida suratga olib, faylga saqlaydi. Keyingi safar test komponentni qayta chizib, eski surat bilan solishtiradi. Agar farq bo'lsa β test ogohlantiradi.
// Snapshot.test.tsx
import { render, screen } from '@testing-library/react-native';
import Hisoblagich from './Hisoblagich';
it('chiqishi o\'zgarmaganini tekshiradi', async () => {
await render(<Hisoblagich />);
expect(screen.toJSON()).toMatchSnapshot();
});
Birinchi yuguritishda Jest __snapshots__/ papkasida .snap faylini yaratadi. Keyingisida β solishtiradi. UI'ni ataylab o'zgartirsangiz, npm test -- -u bilan snapshotni yangilaysiz.
Snapshot β ehtiyotkorlik bilan
Snapshot oson, lekin haddan ko'p ishlatmang. Katta komponentning butun strukturasini "muzlatib" qo'ysangiz, har kichik o'zgarishda test "qizil" bo'ladi va odamlar -u bilan ko'r-ko'rona yangilashga o'rganadi β bu testning ma'nosini yo'qotadi. Maslahat: snapshotni kichik, barqaror komponentlarga ishlating; mantiqni esa yuqoridagi aniq expect'lar bilan sinang. (Biz snapshotni <Hisoblagich>ning boshlang'ich holatida β sinxron, barqaror β ishlatdik, async <Profil>da emas.)
Debugging: xatoni qidirib tuzatish¶
Test β xatoning oldini olish. Debugging esa β paydo bo'lib qolgan xatoni topib tuzatish. React Native'da buning uchun bir nechta kuchli asbob bor.
1. React Native DevTools β zamonaviy asosiy vosita¶
Dev serverda (npx expo start) terminalda j tugmasini bossangiz, React Native DevTools ochiladi. Bu Chrome DevTools'ga asoslangan zamonaviy debugger (Hermes dvigeli uchun). Imkoniyatlari:
- Console β
console.logchiqishlari, xatolar. - Sources β kodga breakpoint (to'xtash nuqtasi) qo'yib, qator-qator yurish, o'zgaruvchilarni ko'rish.
- Components (React DevTools) β komponentlar daraxti, har birining props/state qiymati.
- Network β yuborilgan tarmoq so'rovlari va javoblari.
Eski debugger endi tarixda
Ilgari "Remote JS Debugging" (d β Debug) ishlatilardi β u endi eskirgan. Hozir React Native DevTools (j) rasmiy va tavsiya etilgan yo'l. New Architecture + Hermes bilan u to'liq ishlaydi.
2. console.log β eng sodda, eng tez¶
Eng oddiy, lekin baribir foydali usul β kerakli joyga console.log qo'yib, qiymatni terminalda yoki DevTools console'da ko'rish:
function hisobla(narx: number, foiz: number) {
console.log('hisobla chaqirildi:', { narx, foiz }); // qiymatlarni ko'ramiz
const natija = narx - (narx * foiz) / 100;
console.log('natija:', natija);
return natija;
}
Obyektlar uchun console.log('teg:', obyekt) ko'rinishida teg qo'shsangiz, qaysi log ekanini osongina topasiz. Faqat productionga (do'konga) chiqarishdan oldin loglarni tozalashni unutmang.
3. LogBox β ekrandagi sariq va qizil ogohlantirishlar¶
Development rejimida ilova ichida xatolar avtomatik ko'rsatiladi:
- Sariq quti (warning) β jiddiy emas, lekin e'tibor bering (masalan "har element uchun noyob
keyyo'q"). - Qizil ekran (error) β jiddiy xato, ilova ishlamayapti. To'liq xabar va stack trace (xato qaysi qatordan kelganini ko'rsatuvchi zanjir) chiqadi.
Qizil ekranni diqqat bilan o'qing β pastdagi stack ko'pincha aynan sizning faylingiz va qatoringizni ko'rsatadi.
4. Element inspector¶
Terminalda m (yoki qurilmada chayqatish β "Toggle Element Inspector") bilan inspektorni yoqasiz. Keyin ekrandagi istalgan elementga bossangiz β uning o'lchami, paddingi, stillari ko'rinadi. Layout muammosini ("nega bu quti shu yerda?") topishda ajoyib yordam beradi.
Keng tarqalgan xatolar va ularning sababi¶
React Native'da boshlovchilar deyarli har doim shu uchta xatoga duch keladi:
1. Text strings must be rendered within a <Text> component
Eng mashhur xato. Matnni <View> ichiga to'g'ridan-to'g'ri qo'yib bo'lmaydi β u albatta <Text> ichida bo'lishi kerak.
Ko'pincha bu shartli renderda yashirinadi: {soni && <Komponent />} β agar soni 0 bo'lsa, RN ekranga 0 matnini chizmoqchi bo'ladi va xato beradi! Yechim: {soni > 0 && <Komponent />} yoki {!!soni && ...}.
2. undefined is not an object (evaluating 'x.y')
x qiymati undefined ekanida uning ichidagi yga murojaat qildingiz. Odatda API javobi hali kelmaganda yuz beradi: data.ism β lekin data hali null. Yechim: ixtiyoriy zanjir (optional chaining) β data?.ism, yoki yuklanish holatini tekshirish (if (yuklanmoqda) return ...).
3. Native/ko'prik xatolari
"Native module cannot be null" yoki shunga o'xshash xabar β odatda yangi native paket o'rnatib, ilovani qayta build qilmaganingizda chiqadi. Yechim: dev serverni to'xtatib, npx expo start -c (kesh tozalash) bilan qayta ishga tushiring; kerak bo'lsa dev build'ni qayta yarating. Bu xatolar JS xatosi emas β kodni emas, build/o'rnatishni tekshiring.
Eslatma. Debugging β sehr emas, tartibli izlash. Avval xato xabarini to'liq o'qing. Keyin "qaysi o'zgartirishdan keyin buzildi?" deb so'rang. Kerakli joyga
console.logqo'ying yoki breakpoint bilan to'xtab, qiymatlarni ko'ring. Muammoni bo'lib-bo'lib torayting β bu eng kuchli ko'nikma.
Test ishlash oqimi: yashildan qizilgacha¶
Quyidagi diagrammada bitta komponent testining to'liq yo'li tasvirlangan β renderdan tortib natijagacha.
To'liq oqim shunday: render (komponentni chizish) β so'rov (getByText/getByTestId bilan element topish) β harakat (fireEvent.press/changeText) β tekshiruv (expect(...).matcher(...)). Agar tekshiruv mos kelsa β yashil (test o'tdi); mos kelmasa β qizil (yiqildi, va Jest farqni ko'rsatadi).
Hammasi birga: jonli verifikatsiya
Ushbu bobning barcha kod misollari β util test, counter, input, async mock, custom hook, snapshot β haqiqiy Expo loyihasida jest-expo + @testing-library/react-native 14 bilan o'rnatilib ishlatildi. Yakuniy natija: 6 ta test fayli, 11 ta test β hammasi o'tdi (Tests: 11 passed), snapshot esa ikkinchi yuguritishda eskisiga mos keldi. Demak misollardagi async/await namunalari aynan ishlaydigan kod.
Xulosa¶
- Test = avtomatik sifat nazoratchisi. U regressni (ilgari ishlagan narsaning buzilishini) darhol ushlaydi, kodni o'zgartirishga ishonch beradi va tirik hujjat bo'lib xizmat qiladi.
- Test piramidasi: pastda ko'p unit (funksiya/hook, tez), o'rtada komponent testlar (React Native'da eng foydali qatlam), tepada kam E2E (Maestro/Detox, sekin lekin ishonchli).
- Sozlash:
jest-expopreset (package.jsonβ"preset": "jest-expo") +@testing-library/react-native.npm testbilan yuguritasiz; maxsus matcherlar RNTL bilan avtomatik keladi. - Asoslar:
describe/it/expect+ matcherlar (toBe,toEqual,toThrow). Komponent uchunrenderβscreenso'rovlari (getBy/queryBy/findBy) βfireEvent(press/changeText) βexpect. getByvsqueryByvsfindBy:getByβ bo'lishi shart;queryByβ yo'qligini tekshirish (null);findByβ keyin paydo bo'ladigan element (async,await).- RNTL 14 β async!
render,fireEvent,renderHookendi Promise qaytaradi vaawaitqilinadi. Mockfetchtezda javob bergani uchun boshlang'ich yuklanish holatiawait renderdan keyin ko'rinmasligi mumkin β yakuniy natijanifindBy/waitForbilan tekshiring. - Async va hook: API'ni
jest.fn()bilan mock qiling (beforeEach/afterEachbilan tozalang);findByTextvawaitFornatijani kutadi;renderHook+result.currentbilan custom hook sinaladi. - Debugging: zamonaviy React Native DevTools (terminalda
jβ console, breakpoint, Components, Network), tezkorconsole.log, ekrandagi LogBox (sariq warning / qizil error),mbilan element inspector. Eng ko'p uchraydigan xatolar: "Text must be in<Text>", "undefined is not an object" (?.bilan yeching), native/build xatolari (expo start -c).
Amaliy mashqlar¶
-
Counter testi (oson). Yangi
Hisoblagichkomponentiga "Kamaytirish" tugmasini qo'shing. Test yozing: ikki marta oshirib, bir marta kamaytirgachHisob: 1chiqishini tekshiring. Yo'naltirish:await fireEvent.press(...)ni uch marta chaqiring, har bir tugmani matni bo'yicha toping,getByTestId('natija')nitoHaveTextContentbilan tekshiring. -
Input testi (oson). Parol kiritish komponentini yozing: parol 6 belgidan qisqa bo'lsa "Juda qisqa" matnini ko'rsatsin. Test yozing: boshida xato matni yo'qligini (
queryByText), "abc" kiritilganda paydo bo'lishini (getByText) tekshiring. Yo'naltirish:fireEvent.changeText(getByPlaceholderText('Parol'), 'abc'). -
Async mock (o'rta). Berilgan shahar uchun ob-havoni yuklaydigan komponent yozing. Testda
global.fetchnijest.fnbilan mock qiling va{ harorat: 25 }qaytarsin.findByText('25Β°')bilan natijani tekshiring. Yo'naltirish:beforeEachda mockni o'rnating,afterEachdajest.restoreAllMocks();await renderdan keyinfindByTextishlating. -
Hook testi (o'rta).
useHisoblagich(boshlangich)custom hookini yozing βsoni,oshir,kamaytirqaytarsin.renderHook+actbilan test yozing:oshirchaqirilgachsoniortishini tekshiring. Yo'naltirish: holatni o'zgartiruvchi chaqiruvniawait act(async () => { result.current.oshir(); })ichiga oling, keyinresult.current.sonini tekshiring (actni@testing-library/react-nativedan import qiling). -
Debugging mashqi (qiyin). Ataylab xato kod yozing:
<View>{soni}</View>(matn<Text>siz) yokidata.ism(datanull bo'lganda). Ilovani ishga tushirib, LogBox/qizil ekran nima deyishini o'qing, React Native DevTools (j) ni oching vaconsole.logbilan muammoni topib tuzating. Yo'naltirish: har xato uchun "qanday xabar chiqdi, qaysi qatorni ko'rsatdi, qanday tuzatdim" deb yozib boring β bu debugging ko'nikmasini mustahkamlaydi.
β¬ οΈ Oldingi: 25 β Autentifikatsiya Β· π Kitob boshi Β· Keyingi: 27 β Performance, New Architecture va deploy β‘οΈ