07 / 12
Asenkron Testler
findBy, waitFor ve fake timers.
Asenkron arayüz nedir?
Bazı değişiklikler hemen olmaz. Örnekler:
API yanıtı gelince ürün listesi görünür.
Ürün sepete eklenince bildirim çıkar ve 3 saniye sonra kapanır.
Testiniz bu değişikliği beklemelidir. Beklemezseniz test, arayüz güncellenmeden kontrol yapar ve başarısız olur.1
Hangi aracı kullanmalıyım?
findBy: sonradan görünecek eleman
findBy* elemanı bulana kadar bekler. Süre dolarsa hata fırlatır. Varsayılan süre 1000 ms.3
test("yüklenirken bilgi mesajı, sonra ürünleri gösterir", async () => {
render(
<ProductList
loadProducts={() => Promise.resolve(products)}
onAddToCart={vi.fn()}
/>,
);
expect(screen.getByText("Ürünler yükleniyor...")).toBeInTheDocument();
expect(await screen.findAllByRole("article")).toHaveLength(3);
});İlk satırda getBy* kullanıldı. Yükleme mesajı ilk render'da zaten ekrandadır. Bekleme gerekmez.3
waitFor: koşulun doğru olmasını bekleme
waitFor, verdiğiniz fonksiyon hata fırlatmayı bırakana kadar onu tekrar tekrar çalıştırır. Varsayılan süre 1000 ms.1
Bir elemanın kaybolmasını beklerken queryBy* kullanın:3
await waitFor(() =>
expect(screen.queryByText("Ürünler yükleniyor...")).not.toBeInTheDocument(),
);Fake timers: zamanı kontrol etme
Ürün sepete eklenince bir bildirim görünür. Bildirim 3 saniye sonra kapanır. 3 saniye bekleyen bir test yavaştır. Zamanı kendiniz ilerletin.2
import { useEffect, useState } from "react";
export function AddedToast({ productName }: { productName: string }) {
const [visible, setVisible] = useState(true);
useEffect(() => {
const id = setTimeout(() => setVisible(false), 3000);
return () => clearTimeout(id);
}, []);
return visible ? <div role="status">{productName} sepete eklendi.</div> : null;
}import { act, render, screen } from "@testing-library/react";
import { AddedToast } from "./AddedToast";
beforeEach(() => {
vi.useFakeTimers({ shouldAdvanceTime: true });
});
afterEach(() => {
vi.useRealTimers();
});
test("3 saniye sonra bildirim kaybolur", async () => {
render(<AddedToast productName="Kablosuz Kulaklık" />);
expect(await screen.findByRole("status")).toHaveTextContent(
"Kablosuz Kulaklık sepete eklendi.",
);
act(() => {
vi.advanceTimersByTime(3000);
});
expect(screen.queryByRole("status")).not.toBeInTheDocument();
});Üç kurala dikkat edin:
vi.useFakeTimersçağrısınırenderöncesinde yapın. Component'insetTimeoutçağrısı fake olmalıdır.6vi.advanceTimersByTimeçağrısınıactiçine alın. Zamanlayıcı bir React state'ini günceller.7vi.useRealTimersçağrısınıafterEachiçinde yapın.8 Test hata verse bileafterEachçalışır.
vi.advanceTimersByTime(ms): zamanımskadar ilerletir.vi.advanceTimersByTimeAsync(ms): aynısını yapar, asenkron kurulan zamanlayıcıları da çalıştırır.6vi.runOnlyPendingTimers(): bekleyen zamanlayıcıları hemen çalıştırır.vi.setSystemTime(date):Date.now()venew Date()değerini ayarlar.6Bekleme süresi kısaysa (300 ms gibi) fake timers kullanmayın.
findByile bekleyin.
Kendin dene
API çağrısı başarısız olunca ne görünür? Bunu test edin:
loadProductsfonksiyonuPromise.reject(new Error("ağ hatası"))döndürür.findByRole("alert")ile Ürünler yüklenemedi. mesajını bulun.queryBy* ile Ürünler yükleniyor... mesajının kaybolduğunu doğrulayın.
Kaynaklar
`findBy`, `waitFor` ve `waitForElementToBeRemoved`.
Fake timers rehberi.
`getBy`, `queryBy` ve `findBy` farkı.
`waitFor` içinde yan etki ve `find*` yerine `waitFor` hataları.
Verilen değerin HTMLElement olup olmadığı kontrol edilir.
Fake timers komutları.
Güncellemeleri assertion'dan önce uygulama.
Fake timers kurulumu ve temizliği.
Vitest'te `findBy` timeout'a düşer.
`shouldAdvanceTime` seçeneği.
`advanceTimers` seçeneği.
Son güncelleme tarihi: 14 Ekim 2026
