Mundarija (31)
- Bu darsda
- 1. Nega bu kerak?
- 2. Jest API: siz allaqachon bilasiz
- 2.1 Bir xil narsa, boshqa nom
- 2.2 Jest terminali
- 3. jest.config.js va kod o'giruvchilar
- 3.1 Asosiy maydonlar
- 3.2 Kim o'giradi: babel-jest, ts-jest, @swc/jest
- 4. ES modullar: Jest'ning eng og'riqli joyi
- 5. CRA testlari va Enzyme
- 5.1 Create React App
- 5.2 Enzyme — tanib oling, yozmang
- 6. Ko'chirishning jim tuzoqlari
- 6.1 done callback
- 6.2 mockReset
- 6.3 Soxta modul fabrikasi va requireActual
- 7. Kanon tajribasi: vazifalar Jest'da (holatsiz)
- 7.1 O'rnatish va konfiguratsiya
- 7.2 Uch tuzatish
- 7.3 Natija: 283/329
- 7.4 Nega kanonga kirmadi
- 8. Ko'chirish tartibi
- 9. Ko'p uchraydigan xatolar
- 10. Mashqlar
- 1-mashq (oson): bo'sh joylarni to'ldiring
- 2-mashq (o'rta): Jest testini Vitest'ga ko'chiring
- 3-mashq (qiyin): Enzyme testini RTL'ga qayta yozing
- 4-mashq: kanon tajribasini takrorlang (ixtiyoriy)
- 11. Real ishda
- Xulosa
- Manbalar
Jest va eski test muhitlari: Jest'li loyihani o'qish va Vitest'ga ko'chirish
Qisqacha: Jest — Vitest'dan oldingi eng mashhur JavaScript test vositasi; ko'p mavjud loyihalar hali unda. API deyarli bir xil:
describe,test,expect,jest.fn↔vi.fn. Farq — muhitda: Jest kodni o'zi o'giradi (babel-jest,ts-jest,@swc/jest), sukut bo'yicha CommonJS'da ishlaydi va ES modullar uchun hali--experimental-vm-modulesbayrog'ini so'raydi. CRA loyihalari Jest + jsdom bilan keladi, Enzyme esa eskirgan. Ko'chirishda kod deyarli o'zgarmaydi, lekin tuzoqlar bor:donecallback,mockReset,jest.requireActual.
Bu darsda
- Jest'li loyihaning
jest.config.jsva test fayllarini o'qiysiz. babel-jest,ts-jestva@swc/jestfarqini, ESM muammosini tushuntirasiz.- CRA testlari va Enzyme kodini tanib, Enzyme testini RTL'ga qayta yozasiz.
- Jest'dan Vitest'ga ko'chirish bosqichlari va jim tuzoqlarini bilasiz.
vazifalardagi Jest tajribasidan (283/329) narxni raqamlar bilan baholaysiz.
Oldin bilishingiz kerak: Vitest I, Vitest II, RTL I, CommonJS va ESM.
1. Nega bu kerak?
Vitest I darsida va'da qilgan edik: "Jest — eng mashhur eski test vositasi, uni alohida ko'ramiz". Sizning birinchi ishingiz deyarli albatta yangi loyiha bo'lmaydi. Jasur aka «Bahor» uchun 2021 yilda yozilgan buyurtma panelini beradi: package.json da "test": "react-scripts test", papkada App.test.js, setupTests.js, ba'zi testlarda shallow(...). Bularni o'qiy olmasangiz — ishga kirisha olmaysiz.
Jest 2014 yilda Facebook'da yaratilgan, 2022 yildan OpenJS Foundation loyihasi. Vitest 2021 yilda paydo bo'ldi va API'ni ataylab Jest'ga o'xshatdi. Shuning uchun Jest testini o'qish — siz bilgan narsaning 90 %i. Qolgan 10 % — muhit: kod qanday o'giriladi, modullar qanday yuklanadi, eski kutubxonalar.
Bu darsda vazifalar o'zgarmaydi. Uning o'rniga kanon tajribasi: holat 15 ning nusxasi Jest 30 da ishga tushirildi. Natija — ko'chirish narxining aniq raqamlari.
2. Jest API: siz allaqachon bilasiz
2.1 Bir xil narsa, boshqa nom
| Jest | Vitest |
|---|---|
global describe, test, expect |
import { … } from "vitest" (yoki globals: true) |
jest.fn(), jest.spyOn() |
vi.fn(), vi.spyOn() |
jest.mock("./sms") |
vi.mock("./sms") |
jest.requireActual("./sms") |
await vi.importActual("./sms") |
jest.useFakeTimers(), jest.advanceTimersByTime() |
vi.useFakeTimers(), vi.advanceTimersByTime() |
jest.setTimeout(10000) |
vi.setConfig({ testTimeout: 10000 }) |
jest.config.js |
vitest.config.ts (yoki vite.config.ts dagi test) |
Jest'da describe va expect import qilinmaydi — ular global. Shuning uchun eski test faylining boshida import yo'q bo'lsa, hayron bo'lmang.
Farqning kichikligini o'zingiz ko'ring. Pastdagi test Jest uslubida yozilgan — faqat jest nomini Vitest'ning vi siga ulaymiz:
import { describe, expect, test, vi as jest } from "vitest";
function createReminder(send) {
return (order) =>
setTimeout(() => send(order.phone, "Buyurtmangiz tayyor"), 15000);
}
describe("eslatma (Jest uslubida)", () => {
test("15 soniyadan keyin bitta SMS", () => {
jest.useFakeTimers();
const send = jest.fn();
createReminder(send)({ phone: "+998 90 000 00 12" });
jest.advanceTimersByTime(14999);
expect(send).not.toHaveBeenCalled();
jest.advanceTimersByTime(1);
expect(send).toHaveBeenCalledWith(
"+998 90 000 00 12",
"Buyurtmangiz tayyor",
);
jest.useRealTimers();
});
});Konsolda:
✓ eslatma (Jest uslubida) > 15 soniyadan keyin bitta SMS
Testlar: 1 o'tdi (jami 1)Tana — o'zgarmagan Jest kodi. Kanon tajribasida ham aynan shu fokus ishlatildi, faqat teskari yo'nalishda: Vitest testlarini Jest'da ishga tushirish uchun vitest importini Jest'ga ulaydigan kichik shim (o'rinbosar modul) yozildi (izoh qatori telefon uchun bo'lingan):
// Tajriba (22/#16): testlar "vitest" dan import qiladi —
// Jest'da o'sha nomlar
import { jest, describe, test, it, expect, beforeEach, afterEach, beforeAll, afterAll } from "@jest/globals";
export { describe, test, it, expect, beforeEach, afterEach, beforeAll, afterAll };
export const vi = jest;2.2 Jest terminali
Jest chiqishi biroz boshqacha. Biz Jest 30.5.2 ni alohida papkada ishga tushirdik (kanon emas): order.js buyurtmani tasdiqlaydi va sms.send ni chaqiradi, test SMS modulini jest.mock bilan soxtalaydi.
const { confirmOrder } = require("./order");
const sms = require("./sms");
jest.mock("./sms");
describe("confirmOrder", () => {
test("SMS yuboriladi, holat — qabul", () => {
const phone = "+998 90 000 00 12";
const order = confirmOrder({ id: 12, phone });
expect(order.status).toBe("qabul");
expect(sms.send).toHaveBeenCalledWith(
phone,
"Buyurtma #12 qabul qilindi",
);
});
});PASS src/order.test.js
confirmOrder
√ SMS yuboriladi, holat — qabul (3 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.319 s, estimated 1 s
Ran all test suites.Uch narsaga qarang:
require— CommonJS (CommonJS va ESM dagi eski tizim). Jest sukut bo'yicha shunda ishlaydi.jest.mockimportlardan keyin yozilgan, lekin ishladi.babel-jestningbabel-plugin-jest-hoistplagini uni fayl boshiga ko'taradi — Vitest'dagivi.mockhoisting'ining asli (Vitest II).Test Suites— Jest'da test fayli "suite" deb ataladi; Vitest'daTest Files. Windows terminalida✓o'rniga√chiqadi.
Yiqilgan testda Jest Expected: 3 / Received: 2 deb yozadi (Vitest — - Expected / + Received). Ma'nosi bir xil.
3. jest.config.js va kod o'giruvchilar
3.1 Asosiy maydonlar
Jest Vite'ni bilmaydi. Ikki vositada test fayli qanday yo'l bosib o'tishini solishtiring:
flowchart LR
subgraph J["Jest"]
J1["test.tsx"] --> J2["transformer<br/>babel-jest / ts-jest"]
J2 --> J3["CommonJS<br/>(ESM — bayroq bilan)"]
J3 --> J4["vm konteksti<br/>+ jsdom"]
end
subgraph V["Vitest"]
V1["test.tsx"] --> V2["Vite<br/>plaginlar, alias"]
V2 --> V3["ESM"]
V3 --> V4["worker<br/>+ jsdom"]
endRasmda: Vitest ilovani quradigan o'sha Vite'dan foydalanadi — plaginlar, taxalluslar, import.meta.env testda ham bor. Jest'da esa har biri uchun alohida sozlama kerak:
// jest.config.js — oddiy React loyihasi (CommonJS)
module.exports = {
testEnvironment: "jsdom", // jest-environment-jsdom paketi alohida
setupFilesAfterEnv: ["<rootDir>/src/setupTests.js"],
testMatch: ["<rootDir>/src/**/*.test.{js,jsx}"],
moduleNameMapper: {
"\\.(css|less)$": "identity-obj-proxy", // CSS importlari
"^@/(.*)$": "<rootDir>/src/$1", // taxallus
},
transform: { "^.+\\.[jt]sx?$": "babel-jest" },
collectCoverageFrom: ["src/**/*.{js,jsx}"],
coverageThreshold: { global: { lines: 60 } },
};| Maydon | Vitest'dagi o'xshashi |
|---|---|
testEnvironment |
environment |
setupFilesAfterEnv |
setupFiles |
testMatch |
include |
moduleNameMapper |
resolve.alias (Vite'dan) |
transform |
kerak emas — Vite o'giradi |
coverageThreshold |
coverage.thresholds |
Nomga e'tibor bering: setupFilesAfterEnv ("muhit tayyor bo'lgach"). Eski loyihalarda xato yozilgan setupFilesAfterEach ham uchraydi. Biz sinadik — Jest testlarni baribir ishga tushiradi, faqat ogohlantiradi: Unknown option "setupFilesAfterEach" with value ["./x.js"] was found. This is probably a typing mistake. ("noma'lum sozlama, ehtimol yozishda xato"). Sozlash fayli esa ulanmaydi va jest-dom matcherlari yo'q bo'lib qoladi.
moduleNameMapper dagi CSS qatori ham muhim. Komponent import "./card.css" qiladi. Jest uchun bu JavaScript fayl — u CSS'ni JS sifatida o'qib, sintaksis xatosi beradi. identity-obj-proxy yoki bo'sh modul — o'rinbosar.
3.2 Kim o'giradi: babel-jest, ts-jest, @swc/jest
Jest faqat JavaScript'ni tushunadi. JSX va TypeScript'ni transformer o'giradi:
| Transformer | Qanday | Narxi |
|---|---|---|
babel-jest |
sukut; Babel konfiguratsiyasi bo'yicha | turlarni tekshirmaydi |
ts-jest |
TypeScript kompilyatori bilan | sekinroq, lekin tur xatosi testni yiqitadi |
@swc/jest |
Rust'da yozilgan SWC | eng tez; turlarni tekshirmaydi |
ts-jest ning "turlarni ham tekshiradi" degan afzalligi Vite loyihasida kamroq kerak: turlarni baribir tsc alohida tekshiradi (Vitest I). Kanon tajribasida ts-jest 29.4.14 olindi: Jest 30 bilan ishlaydigan ESM preset'i bor. Narxi ko'rindi — komponent testlarining birinchi (sovuq) ishga tushirilishi 28.1 s.
4. ES modullar: Jest'ning eng og'riqli joyi
Zamonaviy loyihada "type": "module" va import. Jest esa ichida CommonJS'da ishlaydi. Biz sinab ko'rdik — transformersiz, sozlamasiz ESM test:
FAIL esm/price.test.js
● Test suite failed to run
Must use import to load ES Module: C:\…\esm\price.test.js
The file contains ESM syntax (import/export) that could not be executed as CommonJS. Either:
- Configure a transform (e.g. babel-jest) that compiles this file to CommonJS (see https://jestjs.io/docs/code-transformation)Tarjima: "ES modulni yuklash uchun import kerak. Faylda CommonJS sifatida bajarib bo'lmaydigan ESM sintaksisi bor". Ikki yo'l: kodni CommonJS'ga o'girish (Babel) yoki Node'ning eksperimental VM modullarini yoqish:
node --experimental-vm-modules node_modules/jest/bin/jest.jsShu bayroq bilan o'sha test o'tdi, lekin har ishga tushirishda ExperimentalWarning: VM Modules is an experimental feature. Ikkinchi muammo — soxta modul. ESM'da import ni ko'tarib bo'lmaydi, shuning uchun jest.mock ishlamaydi:
FAIL esm/order.test.js
● Test suite failed to run
ReferenceError: require is not definedESM'dagi yo'l — jest.unstable_mockModule va dinamik import():
import { jest } from "@jest/globals";
jest.unstable_mockModule("./sms.js", () => ({ send: jest.fn() }));
const { send } = await import("./sms.js");
const { confirmOrder } = await import("./order.js");Bu ishladi (PASS). Lekin nomidagi unstable — "beqaror API". Jest 30.5 hujjati ham (2026-10 holatiga) ESM qo'llovini "eksperimental" deydi: jest.mock faqat CommonJS fayllarga ta'sir qiladi, ESM uchun — jest.unstable_mockModule. Yangilik: Node 24.9+ da avtomatik mock va __mocks__ papkasidagi qo'lda yozilgan soxtalar ESM'ga ham qo'llanadi (top-level await li modullardan tashqari). Vitest'da esa vi.mock ESM'da odatdagidek ishlaydi: Vite importlarni o'zi boshqaradi.
Tekshirib ko'ring: Jest'li loyihada
"type": "module"qo'shdingiz va hamma testlar yiqildi. Nima bo'ldi?
Javob
.js fayllar endi ES modul. Jest ularni CommonJS sifatida yuklashga urinadi va Must use import to load ES Module beradi. Yo "type": "module" ni qaytaring (Babel o'girishi bilan qoling), yo --experimental-vm-modules va jest.mock → jest.unstable_mockModule ga o'ting. Vite loyihasida bu — Vitest'ga o'tish uchun kuchli sabab.
5. CRA testlari va Enzyme
5.1 Create React App
Create React App (CRA, react-scripts) 2016–2025 yillarda React loyihasini boshlashning rasmiy yo'li edi. React jamoasi uni 2025-02-14 da rasman to'xtatdi ("Sunsetting Create React App", react.dev blogi). Oxirgi react-scripts — 5.0.1 (2022-04), ichida Jest 27. Lekin bunday loyihalar minglab. CRA'da test shunday ko'rinadi:
// src/setupTests.js — CRA har testdan oldin o'zi ulaydi
import "@testing-library/jest-dom";// src/App.test.js — CRA shablonidagi birinchi test
import { render, screen } from "@testing-library/react";
import App from "./App";
test("renders learn react link", () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});npm test → react-scripts test → Jest watch rejimida. jest.config.js yo'q: sozlama react-scripts ichida yashiringan, o'zgartirish uchun package.json dagi "jest" kaliti (cheklangan) yoki npm run eject (qaytarib bo'lmaydi — hamma konfiguratsiya loyihaga to'kiladi). Bunday loyihani yangilashning odatiy yo'li — Vite + Vitest'ga ko'chish; testlarning o'zi (RTL bilan yozilgan bo'lsa) deyarli o'zgarmaydi.
5.2 Enzyme — tanib oling, yozmang
Enzyme — Airbnb'ning React test kutubxonasi, 2016–2019 yillarda eng mashhuri. Uni tanish kerak, chunki eski kodda uchraydi:
import { shallow } from "enzyme";
import Counter from "./Counter";
test("bosilsa son oshadi", () => {
const wrapper = shallow(<Counter />);
wrapper.find("button.plus").simulate("click");
expect(wrapper.state("count")).toBe(1);
expect(wrapper.find(".count").text()).toBe("1");
});Nega test yozamiz darsidagi "implementatsiyani test qilmang" qoidasining deyarli hamma buzilishi shu yerda:
shallow— bolalar komponentlarini chizmaydi: komponent yolg'iz, integratsiya sinalmaydi.find("button.plus"),find(".count")— CSS sinflari bo'yicha qidirish; sinf nomi o'zgarsa test yiqiladi.wrapper.state("count")— komponentning ichki holati. Hook'li funksiya komponentida bunday narsa umuman yo'q.simulate("click")— haqiqiy hodisa emas, React handler'ini to'g'ridan chaqirish.
Enzyme'ning oxirgi versiyasi 3.11.0 — 2019-12-20. Rasmiy adapter faqat React 16 gacha (enzyme-adapter-react-16). React 17–19 uchun faqat norasmiy adapterlar bor — React 19 adapterining npm'dagi tavsifida o'zi "probably shouldn't use" ("ehtimol ishlatmasligingiz kerak") deb yozilgan. Ya'ni Enzyme'li loyihani React 18/19 ga ko'tarish — testlarni RTL'ga qayta yozish demak. Mashqda buni qilasiz.
| Enzyme | RTL |
|---|---|
shallow(<X />), mount(<X />) |
render(<X />) (doim to'liq) |
wrapper.find(".count") |
screen.getByRole(…), getByText(…) |
.simulate("click") |
await user.click(…) |
wrapper.state("count") |
ekrandagi natija: toHaveTextContent("1") |
wrapper.setProps({...}) |
rerender(<X … />) |
6. Ko'chirishning jim tuzoqlari
Jest → Vitest ko'chirishda ko'p narsa "o'zi ishlaydi". Xavflisi — jim farqlar: test yiqilmaydi, lekin boshqa narsani tekshiradi.
6.1 done callback
Eski Jest testlarida async kod done bilan kutiladi. Biz bir xil faylni ikkala vositada ishga tushirdik — tekshiruv ataylab xato (1 + 1 ni 3 deb kutadi):
test("done bilan (Jest uslubi)", (done) => {
setTimeout(() => {
expect(1 + 1).toBe(3);
done();
}, 10);
});Jest 30 — to'g'ri yiqildi:
FAIL src/done.test.js (6.322 s)
× done bilan (Jest uslubi) (5019 ms)
● done bilan (Jest uslubi)
expect(received).toBe(expected) // Object.is equality
Expected: 3
Received: 2Vitest 5.0.4 — o'tdi:
✓ t/done.test.js (1 test) 4ms
Test Files 1 passed (1)
Tests 1 passed (1)Vitest done callback'ni qo'llamaydi: birinchi argument — test konteksti obyekti, done emas. Funksiya darhol tugadi, setTimeout ichidagi tekshiruv test tugagandan keyin ishladi va hech kim uni eshitmadi. Yolg'on yashil. Ko'chirishda done li har testni Promise'ga aylantiring:
test("Promise bilan", async () => {
await new Promise((resolve) => setTimeout(resolve, 10));
expect(1 + 1).toBe(2);
});Qidirish uchun: grep -rn "(done)" src/.
6.2 mockReset
Bir xil nom, boshqa xulq:
const price = jest.fn(() => 35000); // Vitest'da: vi.fn(() => 35000)
price.mockReset();
console.log("natija:", price());Biz sinadik: Jest 30 — natija: undefined (implementatsiya o'chadi), Vitest 5 — natija: 35000 (boshlang'ich implementatsiyaga qaytadi; Vitest II da ko'rgan edik). afterEach da mockReset chaqiradigan eski testlar Vitest'da boshqacha holatdan boshlanadi.
6.3 Soxta modul fabrikasi va requireActual
// Jest (CommonJS): module.exports = fetchMenu — fabrika
// funksiyaning o'zini qaytaradi; asl modul — sinxron
jest.mock("./api", () => jest.fn());
const asl = jest.requireActual("./format");
// Vitest (ESM): default eksport — `default` kaliti bilan;
// asl modul — Promise
vi.mock("./api", () => ({ default: vi.fn() }));
const asl = await vi.importActual("./format");Vitest hujjatining ko'chirish bo'limi yana bir nechta farqni sanaydi: snapshot faylining sarlavhasi (// Jest Snapshot v1 → // Vitest Snapshot v1), globals sukut bo'yicha o'chiq. Ko'chirishdan oldin o'sha ro'yxatni o'qing.
7. Kanon tajribasi: vazifalar Jest'da (holatsiz)
Bu darsda vazifalar ga qadam yo'q — kanon v12 = holat 15. Uning o'rniga savolga javob: "vazifalar ni Jest'da ishlatsak nima bo'ladi?". Holat 15 nusxasi alohida papkada Jest 30.5.2, ts-jest 29.4.14 (ESM preset) va jest-environment-jsdom 30.5.2 bilan ishga tushirildi.
7.1 O'rnatish va konfiguratsiya
O'rnatish — 26 s, node_modules 436 → 480 MB (+44 MB), lock faylga +304 yozuv. jest-environment-jsdom o'zi bilan jsdom 26.1.0 ni olib keldi — loyihada Vitest uchun jsdom 30.1.2 allaqachon bor: ikki nusxa. Konfiguratsiya — 4 fayl, 60 qator: jest.config.js, vitest shim'i, CSS o'rinbosari va tsconfig.jest.json. jest.config.js dan bir bo'lak:
const umumiy = {
...ts,
extensionsToTreatAsEsm: [".ts", ".tsx"],
moduleNameMapper: {
"^vitest$": "<rootDir>/jest-vitest-shim.js",
"^@/(.*)$": "<rootDir>/src/$1",
},
globals: { __RELIZ__: "test" },
};^@/(.*)$ — Vite'dagi @/ taxallusi qayta yozildi; __RELIZ__ — Vite'ning define i. Vitest bularni vite.config.ts dan o'zi oladi.
7.2 Uch tuzatish
Birinchi ishga tushirishlar ketma-ket uch xato berdi:
'./vazifa.js'topilmadi. tsconfig'dagirewriteRelativeImportExtensions—.tsimportlarni.jsga aylantiradi, Jest esa.jsfaylni qidiradi. Sozlama Jest uchun olib tashlandi.ReferenceError: Request is not defined— 18 ta komponent faylining hammasida. MSW Node'ningfetch/Requestiga tayanadi,jest-environment-jsdomesa Node globallarini bermaydi. Yechim — qo'shimcha paketjest-fixed-jsdom0.0.11.Cannot read properties of undefined (reading 'BASE_URL')—import.meta.envVite'niki, Jest'da yo'q. Yechim — yana bir paketts-jest-mock-import-meta1.3.2 (qiymatlar konfiguratsiyada qo'lda yozildi).
7.3 Natija: 283/329
Test Suites: 22 failed, 33 passed, 55 total
Tests: 46 failed, 283 passed, 329 totalVitest'da o'sha holat — 349/349. Jest 329 testni yig'di (20 tasi umuman yig'ilmadi), 46 tasi yiqildi; 55 fayldan 22 tasi qizil. Vaqt: Jest 33.6 / 39.8 s, Vitest o'sha mashinada 19.6 s (issiq).
Yiqilish sabablari (log'dagi xabarlar soni; performance.measure log'da ikki shaklda yozilgan — bu yerda bir marta):
| Sabab | Xabar | Soni |
|---|---|---|
| jsdom 26 | FormData(form, submitter) |
20 |
| jsdom 26 | performance.measure |
10 |
| Jest'ning vm konteksti | assert.deepStrictEqual |
16 |
| Jest'da yo'q API | vi.stubGlobal, unstubAllGlobals, vi.waitFor |
26 |
| Jest qoidasi | async describe taqiqlangan |
4 |
| Vite sintaksisi | ?worker&url import |
2 |
Eng qiziqi — deepStrictEqual. Xabarda "Expected" va "Received" bir xil ko'rinadi, lekin test yiqiladi. Sabab: Jest har test faylini alohida vm kontekstida ishlatadi. U yerda yaratilgan massiv boshqa "dunyo"ning (realm) Array idan. node:assert ning qat'iy tengligi prototipni ham solishtiradi. Buni Node'ning o'zida takrorlash mumkin:
import assert from "node:assert";
import vm from "node:vm";
const dishes = vm.runInNewContext('["Osh", "Manti"]');
console.log(Array.isArray(dishes), dishes instanceof Array);
assert.deepEqual(dishes, ["Osh", "Manti"]);
console.log("deepEqual: o'tdi");
assert.deepStrictEqual(dishes, ["Osh", "Manti"]);Konsolda:
true false
deepEqual: o'tdi
AssertionError [ERR_ASSERTION]: Values have same structure but are not reference-equal:Array.isArray — true, instanceof Array — false: massiv, lekin boshqa Array dan. Tarjima: "qiymatlar tuzilishi bir xil, lekin havolasi teng emas". vazifalar dagi 255 ta node:test testi (node:test dan beri) aynan node:assert bilan yozilgan — Vitest ularni bitta realm'da ishlatadi, Jest — yo'q.
7.4 Nega kanonga kirmadi
- Narx: +44 MB, 2 qo'shimcha paket, 60 qator konfiguratsiya, jsdom ikki nusxa.
- Eksperimental bayroq:
--experimental-vm-modules— ESM Jest'da hali barqaror emas. - Ikki marta sozlash: taxallus,
define,import.meta.env— Vite'da bor narsa Jest'ga qayta yozildi. - 46 test — ko'chirish uchun qo'shimcha ish, foydasi yo'q.
Xulosa: eski loyihada Jest uchraydi — uni o'qing va hurmat qiling; yangi Vite loyihasida — Vitest. Jest'li loyihani ko'chirish odatda bitta yo'nalishda: Jest → Vitest.
8. Ko'chirish tartibi
- Hozirgi holatni o'lchang:
npx jest— nechta test, nechta yiqiladi, vaqt. Ko'chirishdan keyin shu raqam bilan solishtirasiz. - O'rnating:
vitest, kerak bo'lsajsdom;vitest.config.tsdaenvironment,setupFiles,include. Ko'p faylli loyihada vaqtinchaglobals: true— har faylga import yozmaslik uchun. - Nomlarni almashtiring:
jest.→vi.,jest.requireActual→await vi.importActual. - Jim tuzoqlarni qidiring:
(done),mockReset,vi.mockfabrikasidagi default eksport,jest.setTimeout. - Snapshot'larni qayta yozing:
npx vitest run -u— va farqni ko'zdan kechiring. - Ikkalasini parallel ishlating — raqamlar mos kelguncha. Keyin Jest paketlari va
jest.config.jsni o'chiring.
9. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
Must use import to load ES Module |
Jest CommonJS'da | Babel o'girishi yoki --experimental-vm-modules |
ReferenceError: require is not defined |
ESM'da jest.mock |
jest.unstable_mockModule + import() |
CSS importida SyntaxError |
Jest CSS'ni JS deb o'qiydi | moduleNameMapper → o'rinbosar |
Request is not defined |
jsdom muhitida Node globallari yo'q | jest-fixed-jsdom |
Vitest'da done li test doim yashil |
done qo'llanmaydi |
async / Promise |
mockReset dan keyin boshqa qiymat |
Jest — undefined, Vitest — asl |
testni aniq yozing |
wrapper.state is not a function |
hook'li komponent | RTL: ekrandagi natija |
| sozlash fayli ishlamaydi | setupFilesAfterEach (xato nom) |
setupFilesAfterEnv |
10. Mashqlar
Mashqlar kurs/mashqlar/22/16-jest-vitest/ da. Jonli yechimlarni «Ishga tushir» bilan sinang.
1-mashq (oson): bo'sh joylarni to'ldiring
jest.fn()ning Vitest'dagisi:.fn()jest.requireActual("./x")ning Vitest'dagisi:await vi.("./x")- Jest'ning sozlash fayli maydoni:
setupFilesAfter - Jest'da ESM uchun Node bayrog'i:
--experimental--modules - CRA'da test buyrug'i:
react-scripts
Yechim
- vi — Vitest'ning
jestobyektiga o'xshashi; import qilinadi. - importActual — Promise qaytaradi,
awaitbilan. - Env — "muhit tayyor bo'lgach" (jsdom o'rnatilgach) ishlaydi.
- vm — Node'ning VM modullari; hali eksperimental.
- test — Jest'ni watch rejimida ishga tushiradi.
2-mashq (o'rta): Jest testini Vitest'ga ko'chiring
Eski test (Jest, done bilan):
const { loadMenu } = require("./menu");
test("menyu yuklanadi", (done) => {
const fetchMenu = jest.fn().mockResolvedValue(["Osh", "Manti"]);
loadMenu(fetchMenu).then((dishes) => {
expect(dishes).toEqual(["Osh", "Manti"]);
expect(fetchMenu).toHaveBeenCalledTimes(1);
done();
});
});
test("server xatosi — bo'sh menyu", (done) => {
const fetchMenu = jest.fn().mockRejectedValue(new Error("500"));
loadMenu(fetchMenu).then((dishes) => {
expect(dishes).toEqual([]);
done();
});
});loadMenu(fetchMenu) — fetchMenu() natijasini qaytaradi, xato bo'lsa bo'sh massiv. Vitest'ga ko'chiring: import, vi.fn, done o'rniga async/await. loadMenu ni o'zingiz yozing. Keyin expect ni ataylab buzib, test yiqilishini tekshiring.
Yechim
import { expect, test, vi } from "vitest";
async function loadMenu(fetchMenu) {
try {
return await fetchMenu();
} catch {
return [];
}
}
test("menyu yuklanadi", async () => {
const fetchMenu = vi.fn().mockResolvedValue(["Osh", "Manti"]);
const dishes = await loadMenu(fetchMenu);
expect(dishes).toEqual(["Osh", "Manti"]);
expect(fetchMenu).toHaveBeenCalledTimes(1);
});
test("server xatosi — bo'sh menyu", async () => {
const fetchMenu = vi.fn().mockRejectedValue(new Error("500"));
await expect(loadMenu(fetchMenu)).resolves.toEqual([]);
});
test("buzilgan tekshiruv yiqiladi", async () => {
const fetchMenu = vi.fn().mockResolvedValue(["Osh"]);
expect(await loadMenu(fetchMenu)).toEqual(["Manti"]);
});Konsolda:
✓ menyu yuklanadi
✓ server xatosi — bo'sh menyu
× buzilgan tekshiruv yiqiladi
→ expected [ 'Osh' ] to deeply equal [ 'Manti' ]
Testlar: 1 yiqildi, 2 o'tdi (jami 3)Uchinchi test — ko'chirishning tekshiruvi: await bilan yozilgan test buzilganda yiqiladi. done li asl testni Vitest'ga import bilan ko'chirganingizda u yashil qolardi va hech narsani tekshirmasdi. Uchinchi testni o'chiring — u faqat isbot uchun.
3-mashq (qiyin): Enzyme testini RTL'ga qayta yozing
Eski Enzyme testi «Bahor» savatchasining son tugmalari uchun:
const wrapper = mount(<QtyPicker max={3} />);
wrapper.find(".plus").simulate("click");
wrapper.find(".plus").simulate("click");
expect(wrapper.find(".qty").text()).toBe("2");
wrapper.find(".plus").simulate("click");
wrapper.find(".plus").simulate("click");
expect(wrapper.find(".qty").text()).toBe("3");
expect(wrapper.find(".plus").prop("disabled")).toBe(true);
expect(wrapper.find(".minus").prop("disabled")).toBe(false);QtyPicker ni hook'li funksiya komponent sifatida yozing (tugmalar faqat −/+ belgili — nom bering!) va testni RTL + user-event bilan qayta yozing: rol va nom bo'yicha qidirish, son ekrandagi matndan, toBeDisabled. Son o'zgarganda ekran o'quvchi eshitsin (aria-live).
Ishora: <button aria-label="Ko'paytirish">+</button>; son — <output aria-live="polite">, uning roli status.
Yechim
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { useState } from "react";
import { expect, test } from "vitest";
function QtyPicker({ max }) {
const [qty, setQty] = useState(1);
return (
<div role="group" aria-label="Soni">
<button
aria-label="Kamaytirish"
disabled={qty === 1}
onClick={() => setQty(qty - 1)}
>
−
</button>
<output aria-live="polite">{qty}</output>
<button
aria-label="Ko'paytirish"
disabled={qty === max}
onClick={() => setQty(qty + 1)}
>
+
</button>
</div>
);
}
test("son max gacha oshadi, keyin tugma o'chadi", async () => {
const user = userEvent.setup();
render(<QtyPicker max={3} />);
const plus = screen.getByRole("button", { name: "Ko'paytirish" });
const minus = screen.getByRole("button", { name: "Kamaytirish" });
const qty = screen.getByRole("status");
expect(minus).toBeDisabled();
await user.click(plus);
expect(qty).toHaveTextContent("2");
await user.click(plus);
console.log(qty.textContent);
expect(plus).toBeDisabled();
expect(minus).toBeEnabled();
await user.click(plus);
expect(qty).toHaveTextContent("3");
});Konsolda:
3
✓ son max gacha oshadi, keyin tugma o'chadi
Testlar: 1 o'tdi (jami 1)Farqlar: Enzyme testi .plus sinfiga bog'langan edi va tugmaning nomsizligini sezmasdi. RTL testi nomsiz tugmani topa olmaydi — shuning uchun komponentga aria-label qo'shildi, Malika uchun ham. Oxirgi qadam yangi tekshiruv: o'chirilgan tugmani bosish sonni o'zgartirmaydi (user.click haqiqiy foydalanuvchidek — disabled tugmada click bo'lmaydi). Enzyme'ning simulate i esa handler'ni to'g'ridan chaqirardi.
4-mashq: kanon tajribasini takrorlang (ixtiyoriy)
vazifalar nusxasini alohida papkaga oling (asosiy repo emas!) va Jest'da ishga tushirib ko'ring: jest@30.5.2, ts-jest, jest-environment-jsdom, vitest shim'i, node --experimental-vm-modules.
Yechim
Tekshiruv ro'yxati:
- Birinchi ishga tushirishdagi xatolarni tartib bilan yozing: kengaytma,
Request is not defined,import.meta.env— har biri uchun sabab va yechim. - Uchala tuzatishdan keyin natijani kanon bilan solishtiring (283/329). Farq bo'lsa — versiyalarni tekshiring.
node_moduleshajmini oldin va keyin o'lchang (kanonda +44 MB).- Bitta
deepStrictEqualyiqilishini toping va «Natija: 283/329» bo'limidagi vm sababini o'z faylingizda tushuntiring. - Papkani o'chiring; asosiy repo o'zgarmadi (
git statustoza).
11. Real ishda
- Ish joyida Jest'li loyihalar hali ko'p: React Native (Jest — sukut vosita), eski CRA va Next.js loyihalari, Node backend'lar. Jest 30 faol rivojlanmoqda (30.5.2 — 2026-09).
- Ko'chirish qarori — jamoa ishi: tezlik va ESM foydasi ko'chirish narxidan katta bo'lsa. Kichik loyihada bir kun, katta monorepo'da — haftalar; ikkala vosita bir muddat parallel ishlaydi.
- Kod ko'rib chiqishda:
done,shallow,wrapper.state,container.querySelector— eski uslub belgilari. - Intervyu savollari: "Jest va Vitest farqi?", "
jest.mocknega fayl boshiga ko'tariladi?", "Enzyme'dan RTL'ga nega o'tishdi?", "Jest'da ESM bilan qanday muammo bor?".
Xulosa
- Jest API'si Vitest'niki bilan deyarli bir xil:
jest.fn↔vi.fn,jest.mock↔vi.mock; Jest'dadescribe/expectglobal. - Jest Vite'ni bilmaydi: transformer (
babel-jest,ts-jest,@swc/jest),moduleNameMapper, CSS o'rinbosari — qo'lda. - ESM — Jest'ning og'riqli joyi:
--experimental-vm-modules,jest.unstable_mockModule. - CRA (2025 da to'xtatilgan) — Jest 27 + RTL; Enzyme (2019 dan yangilanmagan) — implementatsiya testi, RTL'ga qayta yoziladi.
- Ko'chirishdagi jim tuzoqlar:
done(Vitest'da yolg'on yashil),mockReset, default eksportli soxta modul. - Kanon tajribasi:
vazifalarJest'da — +44 MB, 60 qator, 283/329; Vitest'da 349/349.
Keyingi dars: Next.js nima va qachon kerak — 23-qism boshlanadi: React ustidagi framework, server render va fayl asosidagi marshrutlar.
Manbalar
- Jest: Configuration (jestjs.io/docs/configuration), ECMAScript Modules (jestjs.io/docs/ecmascript-modules),
jest.unstable_mockModule - Vitest: Migrating from Jest (vitest.dev/guide/migration),
vi.importActual,globals - React blog: "Sunsetting Create React App" (react.dev/blog, 2025-02-14)
- Enzyme (github.com/enzymejs/enzyme); npm: enzyme 3.11.0 (2019-12-20), enzyme-adapter-react-16 1.15.8
- Testing Library: "Migrate from Enzyme" (testing-library.com/docs/react-testing-library/migrate-from-enzyme)
- Haqiqiy chiqishlar: Jest 30.5.2, jest-environment-jsdom 30.5.2 (jsdom 26.1.0), Vitest 5.0.4, Node 24.21.0, Windows 11 (2026-10-20)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!