ViraStack
  • Akademi
  • Hakkında
  • Destek
Genel BakışKaynaklarKatkı
ViraStack

Frontend geliştiricileri için DX odaklı araç seti: starter’lar, ajan kuralları, form hook’ları ve rehber.

Ürünler

  • ViraStack Start
  • ViraStack AI
  • ViraStack Mask
  • ViraStack Password
  • ViraStack Guide

Keşfet

  • Akademi
  • Hakkında
  • Marka
  • Destek

© 2026 ViraStack.

Açık kaynak · MIT

Vitest

09 / 12

Mock

vi.fn, vi.mock ve MSW ile API mock'u.

Mock nedir?

Mock, gerçek bir bağımlılığın yerine geçen test kopyasıdır. Testin kontrolünü elinize verir. Gerçek bir ağ isteği, gerçek bir analitik servisi veya gerçek bir zamanlayıcı kullanmazsınız.

Neyi mock'lamalı?

Yap

  • Ağ istekleri (API çağrıları).

  • Analitik ve loglama servisleri.

  • Tarayıcıda olmayan veya yan etkisi olan API'ler (window.open, navigator.sendBeacon).

  • Zaman (setTimeout, Date).

Yapma

  • Kendi alt component'lerinizi. Kullanıcı bunları ekranda gerçek halleriyle görür.

  • Test ettiğiniz component'in kendisini.

  • React veya Testing Library fonksiyonlarını.

vi.fn: sahte fonksiyon

vi.fn() çağrıları kaydeden bir fonksiyon üretir. Callback prop'larını test etmek için kullanılır. Önceki adımlarda onAddToCart ve onApply için kullandınız.

KodAnlamı
vi.fn()Boş sahte fonksiyon. undefined döner.
vi.fn().mockReturnValue(5)Her çağrıda 5 döner.
vi.fn().mockResolvedValue(data)Promise.resolve(data) döner. Async fonksiyonlar için.
vi.fn().mockRejectedValue(new Error("hata"))Reddedilen Promise döner.

Bu tablodaki dönüş değerleri için bkz. 1

const loadProducts = vi.fn().mockResolvedValue(products);

render(<ProductList loadProducts={loadProducts} onAddToCart={vi.fn()} />);
await screen.findAllByRole("article");

expect(loadProducts).toHaveBeenCalledTimes(1);
KontrolAnlamı
toHaveBeenCalled()En az bir kez çağrıldı.
toHaveBeenCalledTimes(n)Tam n kez çağrıldı.
toHaveBeenCalledWith(...)Bu argümanlarla en az bir kez çağrıldı.
not.toHaveBeenCalled()Hiç çağrılmadı.

vi.mock: modülü mock'lama

Ürün butonu, her tıklamada analitik olayı gönderir:

import { trackEvent } from "./analytics";
import type { Product } from "./types";

type AddToCartButtonProps = {
  product: Product;
  onAdd: (product: Product) => void;
};

export function AddToCartButton({ product, onAdd }: AddToCartButtonProps) {
  function handleClick() {
    onAdd(product);
    trackEvent("add_to_cart", { productId: product.id });
  }

  return (
    <button type="button" onClick={handleClick}>
      Sepete ekle
    </button>
  );
}

trackEvent fonksiyonu navigator.sendBeacon çağırır. jsdom bu API'yi sunmaz. Mock olmadan test hata verir. Modülü mock'layın:

import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { AddToCartButton } from "./AddToCartButton";
import { trackEvent } from "./analytics";
import type { Product } from "./types";

vi.mock(import("./analytics"));

const keyboard: Product = {
  id: 2,
  name: "Mekanik Klavye",
  price: 2199,
  inStock: true,
};

test("ürünü ekler ve analitik olayı gönderir", async () => {
  const user = userEvent.setup();
  const onAdd = vi.fn();
  render(<AddToCartButton product={keyboard} onAdd={onAdd} />);

  await user.click(screen.getByRole("button", { name: "Sepete ekle" }));

  expect(onAdd).toHaveBeenCalledWith(keyboard);
  expect(trackEvent).toHaveBeenCalledWith("add_to_cart", { productId: 2 });
});

Fabrika fonksiyonu vermezseniz Vitest özgün modülü yükler ve dışa aktardığı her şeyi otomatik olarak mock'lar. Metotlar undefined döner.2 import("./analytics") biçimi yolun yazım hatasını TypeScript'e doğrulatır. Dosya taşınırsa yol ile tipler birlikte güncellenir.2

Uyarı

Vitest vi.mock çağrısını dosyanın başına taşır (hoisting). Çağrıyı nereye yazarsanız yazın, import'lardan önce çalışır. Bu yüzden çağrıyı dosyanın en üst seviyesine yazın. Mock'un fabrika fonksiyonunda dosyadaki diğer değişkenleri kullanamazsınız.2

İpucu

Vitest varsayılan olarak her testten önce mock çağrı geçmişini temizler (clearMocks). Bu yüzden bir testteki çağrı sayısı diğer testi etkilemez.3

  • vi.spyOn(nesne, "metot") mevcut bir metodu izler. Örnek: vi.spyOn(window, "open").mockImplementation(() => null). Böylece "Paylaş" butonunun yeni pencere açtığını test edersiniz.

  • vi.restoreAllMocks() yalnızca vi.spyOn ile oluşturulan spy'ları orijinal haline döndürür. Otomatik mock'lanan modülleri etkilemez.4

  • Spy'ı her testten sonra geri almak için afterEach(() => vi.restoreAllMocks()) yazın.

MSW: ağ isteğini mock'lama

Ürünler API'den gelir. fetch fonksiyonunu elle mock'lamak yerine MSW (Mock Service Worker) kullanın.5 MSW ağ isteğini yakalar ve sahte yanıt döner.67 Uygulama kodunuz gerçek fetch kullanmaya devam eder.

Önce API çağrısını yazın:

import type { Product } from "./types";

export async function fetchProducts(): Promise<Product[]> {
  const response = await fetch("https://api.magaza.test/products");

  if (!response.ok) {
    throw new Error("Ürünler yüklenemedi.");
  }

  return response.json();
}

Uyarı

Testte fetch("/products") gibi göreli URL kullanmayın. Node ortamında göreli URL çözümlenemez ve istek başarısız olur. Tam URL kullanın.

Paketi kurun:8

$ pnpm add -D msw

Varsayılan yanıtları src/mocks/handlers.ts dosyasında tanımlayın. http ve HttpResponse MSW 3'te msw/http yolundan gelir:9

import { http, HttpResponse } from "msw/http";
import type { Product } from "../types";

export const products: Product[] = [
  { id: 1, name: "Kablosuz Kulaklık", price: 1299, oldPrice: 1499, inStock: true },
  { id: 2, name: "Mekanik Klavye", price: 2199, inStock: true },
  { id: 3, name: "Oyuncu Faresi", price: 899, inStock: false },
];

export const handlers = [
  http.get("https://api.magaza.test/products", () =>
    HttpResponse.json(products),
  ),
];

Sunucuyu src/mocks/server.ts dosyasında oluşturun:

import { setupServer } from "msw/node";
import { handlers } from "./handlers";

export const server = setupServer(...handlers);

Sunucuyu src/vitest.setup.ts dosyasında başlatın:

import "@testing-library/jest-dom/vitest";
import { server } from "./mocks/server";

beforeAll(() => server.listen({ onUnhandledFrame: "error" }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
SatırGörevi
onUnhandledFrame: "error"Handler'ı olmayan istek hata verir. Gerçek API'ye yanlışlıkla istek atmazsınız.10
resetHandlers()Bir testte eklenen geçici handler'ları siler. Testler birbirini etkilemez.

İpucu

MSW 2.x kullanıyorsanız seçeneğin adı onUnhandledRequest ve http ile HttpResponse doğrudan msw paketinden import edilir.9

Artık fetchProducts fonksiyonunu doğrudan kullanın:

import { render, screen } from "@testing-library/react";
import { http, HttpResponse } from "msw/http";
import { fetchProducts } from "./fetch-products";
import { server } from "./mocks/server";
import { ProductList } from "./ProductList";

test("API'den gelen ürünleri gösterir", async () => {
  render(<ProductList loadProducts={fetchProducts} onAddToCart={vi.fn()} />);

  expect(await screen.findAllByRole("article")).toHaveLength(3);
});

test("API boş liste dönerse boş durum gösterir", async () => {
  server.use(
    http.get("https://api.magaza.test/products", () => HttpResponse.json([])),
  );

  render(<ProductList loadProducts={fetchProducts} onAddToCart={vi.fn()} />);

  expect(await screen.findByText("Ürün bulunamadı.")).toBeInTheDocument();
});

server.use yeni handler'ı mevcut handler'ların önüne ekler. Bu handler resetHandlers çağrılana kadar kalır.11 afterEach içindeki resetHandlers çağrısı bu yüzden gereklidir.

İpucu

Aynı handler'ları tarayıcıda geliştirme ortamı için de kullanabilirsiniz. Bu konu bu rehberin kapsamı dışındadır.

Hangisini kullanmalıyım?

DurumAraç
Callback prop'uvi.fn()
Analitik, logger, tarayıcı API'sivi.mock veya vi.spyOn
API çağrısıMSW
setTimeout, DateFake timers.12

Kendin dene

API 500 hatası döndürdüğünde ne olur? Bunu test edin:

  • server.use ile https://api.magaza.test/products adresine new HttpResponse(null, { status: 500 }) döndüren bir handler ekleyin.

  • ProductList bileşenini fetchProducts ile render edin.

  • findByRole("alert") ile Ürünler yüklenemedi. mesajını doğrulayın.

Kaynaklar

  • 1DokümanVitest: Mock Functions

    `mockReturnValue`, `mockResolvedValue` ve `mockRejectedValue` davranışı.

  • 2DokümanVitest: Mocking Modules

    `vi.mock` hoisting'i, otomatik mock kuralları ve `import()` biçimi.

  • 3DokümanVitest: clearMocks

    Her testten önce `vi.clearAllMocks()` çağrısı ve varsayılan değer.

  • 4DokümanVitest: vi

    `vi.spyOn`, `vi.restoreAllMocks` ve `mockImplementation` davranışı.

  • 5MakaleKent C. Dodds: Stop mocking fetch

    Kod örnekleri MSW v1 ve Jest kullanır. Ağ sınırını mock'lama fikri bu dersle aynıdır.

  • 6DokümanVitest: Mocking Requests

    MSW kurulumu, `onUnhandledRequest` ve sunucu yaşam döngüsü.

  • 7VideoArtem Zakharchenko: Mock Service Worker 2.0

    MSW'nin isteği yakalayıp sahte yanıt dönme mantığı. Konuşma 2.0 sürümünü anlatır.

  • 8DokümanMSW: Quick start

    Kurulum, handler tanımı, `setupServer` ve Vitest setup dosyası.

  • 9DokümanMSW: Migrating from 2.x to 3.x

    `msw/http` import yolu, `onUnhandledFrame` adı ve Node 22 gereksinimi.

  • 10DokümanMSW: server.listen()

    `onUnhandledFrame` seçeneği ve `"error"` stratejisi.

  • 11DokümanMSW: server.use()

    Çalışma anında handler ekleme ve kalıcılığı.

  • 12DokümanVitest: Mocking

    Zaman mock'lama ve `vi.useFakeTimers` ile `Date`'in değişmesi.

Bu sayfayı düzenle

Son güncelleme tarihi: 14 Ekim 2026

Önceki adım08. Ürün ListesiProjeSonraki adım10. Provider ve Hook