Mundarija (28)
- Bu darsda
- 1. Nega bu kerak?
- 2. Shart: listen() siz ilova
- 2.1 Kanondagi bo'linish
- 2.2 Bo'linmasa nima bo'ladi — sinadik
- 3. request(app): zanjir
- 3.1 O'rnatish va birinchi test
- 3.2 .expect() ning to'rt shakli va xato xabarlari
- 4. Sarlavhalar, avtorizatsiya va cookie
- 4.1 .set() bilan sarlavha
- 4.2 Cookie agent
- 5. Kanon: test/supertest.test.ts
- 6. Vitest'da backend testlari
- 7. API qadami: supertest (holat 51, 4-qism)
- 8. Ko'p uchraydigan xatolar
- 8.1 listen() ilova faylida
- 8.2 await siz zanjir
- 8.3 .expect(status, tana) bilan o'zgaruvchan maydon
- 8.4 .send("{...}") satr bilan
- 8.5 Testlar orasida bitta ilova va ombor
- 9. Mashqlar
- 1-mashq (oson): xabarni o'qing
- 2-mashq (o'rta): /teglar uchun testlar
- 3-mashq (qiyin): o'z mini-supertest'ingiz
- 4-mashq: API qadami
- 10. Real ishda
- Xulosa
- Manbalar
Supertest bilan HTTP integration test: Express ilovasini portsiz tekshirish
Qisqacha: Supertest — Express ilovasiga haqiqiy HTTP so'rov yuborib, javobni zanjir bilan tekshiradigan kutubxona:
await request(app).post("/v1/vazifalar").send({ matn: "Non" }).expect(201). Port ochish va yopish uning ishi —request(app)ilovani vaqtinchalik tasodifiy portda tinglatadi. Shart bitta: ilova faylidalisten()bo'lmasin. Bo'lsa — biz sinaganimizda test o'tdi, lekinnode --testtugamay osilib qoldi. Supertestfetchdan farqli ravishdaCache-Control: no-cacheqo'shmaydi, shuning uchun 304 ni to'g'ri tekshiradi.
Bu darsda
- Nega ilova va server alohida fayl bo'lishi kerakligini haqiqiy natija bilan ko'rsatasiz.
request(app)zanjiri bilan status, sarlavha va JSON tanani tekshirasiz.- Avtorizatsiya sarlavhasi va cookie agent bilan ishlaysiz.
- Supertest xato xabarlarini o'qiy olasiz.
- Vitest'da backend testlari uchun sozlamani bilasiz.
Oldin bilishingiz kerak: Backend test strategiyasi, node:test va node:assert, express.Router va qatlamli tuzilma, HTTP caching va shartli so'rovlar.
1. Nega bu kerak?
vazifalar-api ning integration testlari hozircha shunday yozilgan: before da server port 0 da ochiladi, testlar fetch yuboradi, after da server yopiladi. Bu ishlaydi — kanonda 33 ta test shunday. Lekin har faylda bir xil marosim: ochish, manzilni olish, yopish. Va fetch bilan bitta muammo bor — undan shartli so'rovlar darsida qoqilgansiz.
Supertest bu marosimni bitta chaqiruvga yig'adi. Hayotiy o'xshatish: avtomobil diagnostika stendi. Mashinani yo'lga olib chiqmasdan stendga qo'yasiz — g'ildiraklar aylanadi, dvigatel ishlaydi, asboblar hammasini o'lchaydi. Yo'l (haqiqiy port, haqiqiy mijoz) kerak emas, lekin mashinaning o'zi — haqiqiy.
2. Shart: listen() siz ilova
2.1 Kanondagi bo'linish
Qatlamli tuzilma darsida kanon ikki faylni ajratgan:
src/ilova.ts—ilovaYarat(bogliqliklar)Express ilovasini yasaydi va qaytaradi.listen()yo'q.src/server.ts— config o'qiydi, ilovani yasaydi,listen()qiladi, signallarni ushlaydi.
Test ilova.ts ni import qiladi va har safar yangi ilova yasaydi. Server fayli testlarga umuman kirmaydi.
2.2 Bo'linmasa nima bo'ladi — sinadik
Ko'p darsliklarda app.js ichida app.listen(3000) yoziladi va testlar shu faylni import qiladi. Shuni taqlid qildik: test fayli modul darajasida server ochadi, test esa unga so'rov yuboradi.
import { test } from "node:test";
import { createServer } from "node:http";
// app.js ichidagi listen() kabi
const server = createServer((q, s) => s.end("ok")).listen(0);
test("ishlaydi", async () => {
const { port } = server.address();
const r = await fetch(`http://127.0.0.1:${port}`);
if ((await r.text()) !== "ok") throw new Error();
});Biz ishga tushirdik (node --test, Node 24.21.0). Test bir zumda o'tdi (✔ ishlaydi (22.3467ms)), lekin node --test tugamadi. 8 soniyadan keyin jarayonni majburan to'xtatdik — shundagina hisobot chiqdi va fayl yiqilgan deb belgilandi:
✔ ishlaydi (22.3467ms)
✖ ochiq.test.mjs (7986.2424ms)
ℹ tests 2
ℹ pass 1
ℹ fail 1Sabab: ochiq server Node jarayonini tirik ushlab turadi (event loop darsi — faol handle bor ekan, jarayon chiqmaydi). --test-timeout=3000 ham yordam bermadi: u testni chegaralaydi, ochiq serverni emas. CI'da bu "testlar 6 soat osilib qoldi" degan xabar bilan tugaydi.
Port 3000 qat'iy bo'lsa, yana bir muammo: parallel ikki test fayli bir portni so'raydi — EADDRINUSE.
Tekshirib ko'ring:
ilova.tsdalisten()yo'q. Lekinilova.tsichidasetIntervalbilan har daqiqada eski idempotentlik kalitlarini tozalovchi taymer ishga tushirilsa-chi?
Javob
Xuddi shu muammo: faol taymer jarayonni tirik ushlaydi va test fayli tugamaydi. Yechimlar: taymerni server.ts da ishga tushirish; timer.unref() — taymer jarayonni ushlab turmasin; yoki to'xtatish funksiyasini qaytarib, testda after da chaqirish. Kanon idempotentlik omborida taymer ishlatmaydi — muddat ol() paytida tekshiriladi (o'tgan darsdagi TaymerOmbori kabi).
3. request(app): zanjir
3.1 O'rnatish va birinchi test
npm i -D --save-exact supertest@7.3.1 @types/supertest@7.2.1Kichik Express ilovasi bilan boshlaymiz (kanondan tashqari, faqat misol):
import express from "express";
import request from "supertest";
const app = express();
app.use(express.json());
const vazifalar = [];
app.post("/vazifalar", (req, res) => {
if (typeof req.body?.matn !== "string") {
return res.status(422).json({ xato: "matn kerak" });
}
const v = { id: vazifalar.length + 1, matn: req.body.matn };
vazifalar.push(v);
res.status(201).location(`/vazifalar/${v.id}`).json(v);
});
const r = await request(app)
.post("/vazifalar")
.send({ matn: "Non olish" })
.expect(201);
console.log(r.status, r.headers.location, r.body);Biz ishga tushirdik (express 5.3.0, supertest 7.3.1):
201 /vazifalar/1 { id: 1, matn: 'Non olish' }Zanjirni o'qiymiz:
| Qadam | Nima qiladi |
|---|---|
request(app) |
ilova tinglamayotgan bo'lsa — vaqtinchalik port 0 da ochadi |
.post(yo'l) |
metod va yo'l |
.send(obyekt) |
JSON tana, Content-Type: application/json o'zi qo'yiladi |
.set(nom, qiymat) |
sarlavha |
.expect(...) |
tekshiruv; mos kelmasa — xato |
await |
javob: status, headers, body (JSON parse qilingan), text |
r.body — tayyor obyekt; fetch dagi kabi await r.json() shart emas.
3.2 .expect() ning to'rt shakli va xato xabarlari
Ataylab noto'g'ri kutib ko'ramiz — xabarlar qanday ko'rinadi:
await request(app).post("/vazifalar").send({}).expect(201);
await request(app)
.post("/vazifalar")
.send({ matn: "a" })
.expect(201, { id: 9, matn: "a" });
await request(app)
.post("/vazifalar")
.send({ matn: "b" })
.expect("Content-Type", /xml/);Biz ishga tushirdik — har biri try/catch ichida, e.message:
expected 201 "Created", got 422 "Unprocessable Entity"
expected { id: 9, matn: 'a' } response body, got { id: 2, matn: 'a' }
expected "Content-Type" matching /xml/, got "application/json; charset=utf-8"Xabarlar aniq: nima kutildi, nima keldi. Shakllar:
.expect(201)— status..expect(201, tana)— status va tana (deepEqualkabi, to'liq moslik)..expect("Sarlavha", qiymat yoki /regex/)— sarlavha..expect((res) => { … })— o'z funksiyangiz; ichidaassertishlating.
.expect(201, { … }) to'liq tanani talab qiladi — yaratildi kabi o'zgaruvchan maydon bo'lsa yiqiladi. Kanon shuning uchun status va sarlavhalarni zanjirda, tanani esa alohida assert bilan tekshiradi.
4. Sarlavhalar, avtorizatsiya va cookie
4.1 .set() bilan sarlavha
Haqiqiy auth — 28-qismda. Hozir oddiy misol: /men faqat to'g'ri Authorization bilan javob beradi:
app.get("/men", (req, res) => {
if (req.get("authorization") !== "Bearer sinov-token") {
return res.sendStatus(401);
}
res.json({ ism: "Ali" });
});
await request(app).get("/men").expect(401);
const m = await request(app)
.get("/men")
.set("Authorization", "Bearer sinov-token")
.expect(200);
console.log(m.body);Biz ishga tushirdik:
{ ism: 'Ali' }Ikkala holat ham — tokensiz 401, token bilan 200 — testda bo'lishi shart. Faqat "token bilan ishlaydi" ni tekshirgan test, himoya umuman o'chiq bo'lganda ham o'tadi.
4.2 Cookie agent
request(app) har chaqiruvda yangi mijoz. Brauzer esa cookie'ni eslab qoladi. Buni request.agent(app) taqlid qiladi:
app.get("/sanoq", (req, res) => {
const eski = req.headers.cookie?.match(/n=(\d+)/)?.[1] ?? 0;
const n = Number(eski) + 1;
res.cookie("n", String(n)).json({ n });
});
const agent = request.agent(app);
const a1 = await agent.get("/sanoq");
const a2 = await agent.get("/sanoq");
console.log(a1.body, a2.body);
console.log((await request(app).get("/sanoq")).body,
(await request(app).get("/sanoq")).body);Biz ishga tushirdik:
{ n: 1 } { n: 2 }
{ n: 1 } { n: 1 }Agent ikkinchi so'rovda birinchi javobdagi Set-Cookie ni yubordi — sanoq oshdi. Oddiy request esa har safar "yangi brauzer". vazifalar-api da cookie yo'q (auth — 28-qism), lekin kanon agent testini qo'ygan: sessiya cookie'si qo'shilganda u tayyor turadi.
5. Kanon: test/supertest.test.ts
To'liq fayl (holat 51; uzun qatorlar telefon uchun bo'lindi, kod o'zgarmagan):
// supertest.test.ts — HTTP integration test PORTSIZ: request(app)
// ilovani o'zi vaqtinchalik tinglatadi va yopadi.
// listen() ilova.ts da yo'qligi (holat 13) shuning uchun —
// app'ni to'g'ridan import qilamiz
import { test } from "node:test";
import assert from "node:assert/strict";
import request from "supertest";
import { ilovaYarat } from "../src/ilova.ts";
import { XotiraOmbori } from "../src/vazifalar/xotira-ombor.ts";
const yangiIlova = () =>
ilovaYarat({
ombor: new XotiraOmbori(),
corsOriginlar: ["http://localhost:5173"],
});
test("supertest: yaratish → Location → o'qish", async () => {
const app = yangiIlova();
const yarat = await request(app)
.post("/v1/vazifalar")
.set("X-Request-Id", "supertest-0001")
// obyekt — supertest o'zi JSON va Content-Type qo'yadi
.send({ matn: "Non olish #uy" })
.expect(201)
.expect("Content-Type", /application\/json/)
.expect("X-Request-Id", "supertest-0001");
const joy = String(yarat.headers.location);
assert.equal(joy, "/v1/vazifalar/1");
const ol = await request(app)
.get(joy)
.expect(200)
.expect("ETag", '"1"');
const tana = ol.body as { teglar: string[] };
assert.deepEqual(tana.teglar, ["uy"]);
});
test("supertest: shartli so'rov — 304", async () => {
const app = yangiIlova();
await request(app)
.post("/v1/vazifalar")
.send({ matn: "a" })
.expect(201);
await request(app)
.get("/v1/vazifalar/1")
.set("If-None-Match", '"1"')
.expect(304);
});
test("supertest: Problem Details va CORS preflight", async () => {
const app = yangiIlova();
const r = await request(app)
.post("/v1/vazifalar")
.send({ matn: "" })
.expect(422)
.expect("Content-Type", /application\/problem\+json/);
assert.equal((r.body as { kod: string }).kod, "validatsiya");
await request(app)
.options("/v1/vazifalar/1")
.set("Origin", "http://localhost:5173")
.set("Access-Control-Request-Method", "PATCH")
.expect(204)
.expect("Access-Control-Allow-Origin", "http://localhost:5173");
});
test("supertest agent: ketma-ket so'rovlar", async () => {
const agent = request.agent(yangiIlova());
await agent.post("/v1/vazifalar")
.send({ matn: "bir" }).expect(201);
await agent.post("/v1/vazifalar")
.send({ matn: "ikki" }).expect(201);
const r = await agent.get("/v1/vazifalar?fields=matn").expect(200);
const tana = r.body as { vazifalar: { matn: string }[] };
assert.deepEqual(
tana.vazifalar.map((v) => v.matn),
["bir", "ikki"],
);
});Test nomlari kanondan qisqartirildi; kod qatorlarga bo'lindi va ikki joyda oraliq tana o'zgaruvchisi qo'shildi — ma'nosi aynan. yangiIlova() — har test o'z ilovasi va omborini oladi. before/after yo'q: ochish-yopishni supertest qiladi.
Ikkinchi test muhim: fetch bilan u 200 berardi — undici If-None-Match bor so'rovga o'zi Cache-Control: no-cache qo'shadi va Express yangi javob qaytaradi (kanon topilmasi, holat 13). Shuning uchun kanon shartli so'rovlarni fetch bilan emas, node:http (xomSorov) yoki supertest bilan tekshiradi.
Mavjud fetch testlari o'zgartirilmadi — ikkalasi ham haqiqiy HTTP. Kanon qarori: yangi testlar supertest bilan.
sequenceDiagram
participant T as test
participant S as supertest
participant A as ilova (Express)
T->>S: request(app).post(...).send(...)
S->>A: listen(0) — vaqtinchalik port
S->>A: haqiqiy HTTP so'rov
A-->>S: 201 + sarlavhalar + JSON
S->>S: .expect() tekshiruvlari
S->>A: server yopiladi
S-->>T: javob (status, headers, body)Diagrammaga qarang: so'rov haqiqiy HTTP orqali o'tadi — middleware, CORS, helmet, xato ishlovchi hammasi ishlaydi. Faqat port ochish va yopish yashirilgan.
Uchinchi testdagi POST /v1/vazifalar ({ "matn": "" }) ilova ichida qaysi yo'ldan o'tadi? src/ilova.ts dagi tartib bo'yicha:
| Qadam | Middleware | Natija |
|---|---|---|
| 1 | sorovId() |
X-Request-Id yo'q — yangi UUID |
| 2 | sorovLogi(log) |
so'rov logi va sorovId konteksti |
| 3 | helmet() |
xavfsizlik sarlavhalari javobga qo'yiladi |
| 4 | cors(...) |
Origin yo'q — CORS sarlavhasi qo'shilmaydi |
| 5 | express.static |
public/ da bunday fayl yo'q — keyingisiga |
| 6 | express.json() |
tana o'qiladi: { matn: "" } |
| 7 | idempotentlik(...) |
Idempotency-Key yo'q — o'tkazib yuboradi |
| 8 | marshrut: jsonKerak, tekshirib(...) |
Zod: matn bo'sh → ValidatsiyaXatosi |
| 9 | xatoIshlovchi(...) |
422, application/problem+json, kod: "validatsiya" |
Supertest testi faqat 9-qadam natijasini ko'radi. Lekin unga yetish uchun oldingi sakkiz qadam haqiqatan bajarildi — integration testning qiymati shunda.
6. Vitest'da backend testlari
vazifalar-api node:test da qoldi (o'lchov). Lekin monorepo'da frontend bilan bitta vosita xohlasangiz — Vitest backend uchun ham ishlaydi. Kanon tajribasidagi sozlama (t46-runner.mjs, Vitest 5.0.5):
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
include: ["vtest/**/*.test.ts"],
environment: "node", // jsdom emas
pool: "forks",
},
});environment: "node" — jsdom yuklanmaydi (backend'da window kerak emas). pool: "forks" — har fayl alohida jarayonda, node --test kabi (kanon o'lchovida threads biroz tezroq chiqdi: 3 044 va 3 265 ms). Supertest Vitest bilan o'zgarishsiz ishlaydi; node:assert ham. Faqat hook nomlari boshqa: before → beforeAll, after → afterAll.
7. API qadami: supertest (holat 51, 4-qism)
npm i -D --save-exact supertest@7.3.1 @types/supertest@7.2.1| Fayl | O'zgarish |
|---|---|
test/supertest.test.ts |
yangi, 4 test («Kanon» bo'limi) |
test/mock.test.ts |
idempotentlik spy testi — fetch o'rniga request(app) |
Hali commit qilmang — holat 51 commit'i Coverage darsida. Bu kesimni biz holat 44 nusxasida tekshirdik (ikki paket, supertest.test.ts, supertest'li idempotentlik testi): tip 0, lint 0, testlar 63/63 (58 + 4 + 1).
8. Ko'p uchraydigan xatolar
8.1 listen() ilova faylida
Testlar o'tadi, jarayon osilib qoladi («Bo'linmasa nima bo'ladi» bo'limi). ilova.ts — yasaydi, server.ts — tinglaydi.
8.2 await siz zanjir
request(app).get("/").expect(200) — await siz so'rov ketmaydi yoki test uni kutmaydi. Har doim await.
8.3 .expect(status, tana) bilan o'zgaruvchan maydon
yaratildi vaqti har safar boshqa — test tasodifan yiqiladi. Statusni zanjirda, tanani alohida assert bilan (kerakli maydonlar).
8.4 .send("{...}") satr bilan
Satr yuborsangiz, supertest Content-Type ni application/x-www-form-urlencoded qo'yadi. Biz kanonda sinadik: vazifalar-api 415 Unsupported Media Type qaytardi. Obyekt bering yoki .set("Content-Type", "application/json").
8.5 Testlar orasida bitta ilova va ombor
Bir test qo'shgan vazifa ikkinchisining natijasini buzadi. Har test — yangiIlova().
9. Mashqlar
1-mashq (oson): xabarni o'qing
Supertest test yiqildi: expected "Location" of "/v1/vazifalar/1", got "/v1/vazifalar/3". Bu nimani bildiradi va eng ehtimolli sabab nima?
Yechim
Sarlavha bor, lekin qiymati boshqa: vazifa id'si 3 bo'lib chiqdi. Demak bu test ishlaganda ombor bo'sh emas edi — oldingi testlar ham shu omborga 2 ta vazifa qo'shgan. Sabab — testlar orasida umumiy ilova yoki ombor («Testlar orasida bitta ilova va ombor» xatosi). Yechim: har test o'z yangiIlova() si bilan.
2-mashq (o'rta): /teglar uchun testlar
vazifalar-api ning GET /v1/teglar endpoint'i [{ teg, soni }] ni ko'pidan kamiga qaytaradi. Supertest bilan test yozing: uchta vazifa ("Non #uy", "Sut #uy #bozor", "Hisobot #ish") yarating, keyin /v1/teglar → 200 va tana tekshiring. Tenglikda teg nomi bo'yicha tartib (kanon ombor.ts izohi).
Yechim
test("teglar: ko'pidan kamiga, tenglikda alifbo", async () => {
const app = yangiIlova();
for (const matn of ["Non #uy", "Sut #uy #bozor", "Hisobot #ish"]) {
await request(app)
.post("/v1/vazifalar")
.send({ matn })
.expect(201);
}
const r = await request(app).get("/v1/teglar").expect(200);
assert.deepEqual(r.body, {
teglar: [
{ teg: "uy", soni: 2 },
{ teg: "bozor", soni: 1 },
{ teg: "ish", soni: 1 },
],
});
});Biz bu testni kanon holat 51 nusxasida yurgizdik — o'tdi, javob: {"teglar":[{"teg":"uy","soni":2},{"teg":"bozor","soni":1},{"teg":"ish","soni":1}]}. Tenglik qoidasi: bozor va ish ikkalasi 1 — alifbo bo'yicha bozor oldin. Tartibni tekshirish uchun aynan teng sonli teglar kerak — shuning uchun ikkitasi.
3-mashq (qiyin): o'z mini-supertest'ingiz
Supertest ichida nima bo'layotganini o'zingiz yozing: sora(ishlovchi, yol, init) — node:http server yaratadi, port 0 da tinglaydi, fetch yuboradi, har qanday holatda serverni yopadi va { status, tana } qaytaradi. Oddiy (req, res) ishlovchi bilan sinang (Express shart emas).
Yechim
import { createServer } from "node:http";
import { once } from "node:events";
// Mini-supertest: har so'rovga vaqtinchalik server (port 0)
async function sora(ishlovchi, yol, init) {
const server = createServer(ishlovchi).listen(0, "127.0.0.1");
await once(server, "listening");
try {
const { port } = server.address();
const r = await fetch(`http://127.0.0.1:${port}${yol}`, init);
return { status: r.status, tana: await r.text() };
} finally {
server.closeAllConnections();
server.close();
}
}
const app = (req, res) => {
res.setHeader("Content-Type", "application/json");
if (req.url === "/salomatlik") return res.end('{"holat":"ok"}');
res.statusCode = 404;
res.end('{"title":"Not Found"}');
};
console.log(await sora(app, "/salomatlik"));
console.log(await sora(app, "/yoq"));Konsolda:
{ status: 200, tana: '{"holat":"ok"}' }
{ status: 404, tana: '{"title":"Not Found"}' }finally — so'rov xato bilan tugasa ham server yopiladi. closeAllConnections() — fetch ochiq qoldirgan keep-alive ulanishlarini (keep-alive darsi) darhol uzadi. Biz uni olib tashlab ham sinadik: Node 24 da close() bo'sh turgan ulanishlarni o'zi yopdi va skript 0.7 s da tugadi. Lekin javob hali kelayotgan ulanish bo'lsa, close() uni kutadi — shuning uchun test yordamchisida closeAllConnections() ishonchliroq. Express ilovasi ham (req, res) funksiya — sora(expressApp, …) ham ishlaydi. Supertest bularning ustiga zanjir, .expect, agent va xato xabarlarini qo'shadi.
4-mashq: API qadami
supertest va @types/supertest ni o'rnating, test/supertest.test.ts ga «Kanon» bo'limidagi 4 testni yozing va test/mock.test.ts dagi idempotentlik testini request(app) ga o'tkazing. npm test — test soni oshganini tekshiring. Keyin bir testda ataylab .expect(200) ni .expect(201) ga o'zgartiring va xabarni o'qing. Commit qilmang.
Yechim
Kod — «Kanon» bo'limida va o'tgan darsdagi mock.test.ts parchasida. Ataylab buzilgan test xabari: expected 201 "Created", got 200 "OK". @types/supertest bo'lmasa, npm run tip TS7016: Could not find a declaration file for module 'supertest' beradi — shuning uchun ikkala paket birga.
10. Real ishda
- Express loyihalari: Supertest — de-fakto standart; Jest yoki Mocha bilan ham,
node:testva Vitest bilan ham bir xil. - NestJS (30-qism) e2e testlari ham
request(app.getHttpServer())— aynan Supertest. - Fastify o'z
app.inject()usuliga ega — u tarmoqsiz, soxta so'rov bilan ishlaydi; g'oya bir xil. - Intervyu savollari: "Express ilovasini qanday integration test qilasiz?", "Nega
app.listenalohida faylda?", "Supertest ichida nima bo'ladi?", "Cookie bilan testni qanday yozasiz?".
Xulosa
request(app)ilovani vaqtinchalik port 0 da ochadi, haqiqiy HTTP so'rov yuboradi va yopadi.- Shart: ilova faylida
listen()yo'q; bo'lsa — test o'tadi, lekinnode --testosilib qoladi (biz sinadik). - Zanjir:
.post().set().send().expect();.expect— status, sarlavha, tana yoki funksiya; xabarlar aniq. .set("Authorization", …)— ikkala holatni ham (bor va yo'q) tekshiring;request.agent(app)— cookie'ni eslaydi.- Supertest
no-cacheqo'shmaydi — 304 testlari uchunfetchdan to'g'ri. - Vitest'da:
environment: "node",pool: "forks"; supertest o'zgarishsiz ishlaydi.
Keyingi dars: Tashqi HTTP'ni mock qilish — vazifalar-api ga webhook qo'shamiz va uni to'rt usulda soxtalaymiz: fetchFn tikuvi, undici MockAgent, MSW va nock; testlar internetga chiqmasligini kafolatlash.
Manbalar
- Supertest: README (7.x; repo
ladjs/supertestdan ko'chgan, 2026-10-24 da ko'rildi). - Vitest: Test environment va Pools.
- Kanon:
vazifalar-apiholat 51 (test/supertest.test.ts,test/mock.test.ts,src/ilova.ts),natijalar/tajriba/t46-runner.txt,QADAMLAR.md(holat 13 — fetch va 304).
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!