İçeriğe geç

Bileşen Testi — Sınıf Adı Değişti, Test Neden Kırıldı?

Orta 8 dk Sık karşılaşılır

Önce şunu oku: Erişilebilirlik Temelleri — Gözü Kapalı Para Gönderebilir misin?

30 saniyede özet

Bileşenin içine bakan testler, davranış aynıyken kırılır ve gerçek hatayı kaçırır. Testing Library ile öğeleri rol ve etiketle bulup kullanıcı gibi yazan, tıklayan testler düzenlemede yeşil, hatada kırmızı kalır.

Bir araç muayenesinde iki muayeneci var. Biri boyanın rengine ve cıvataların markasına bakıyor; öbürü arabayı sürüp fren yapıyor. Yeniden boyanan araba ilkinden kalıyor, freni tutmayan araba ondan geçiyor.

  1. Bayt: Havale formunda düğmenin CSS sınıfını yeniden adlandırdım. Kırk test kırmızı!

  2. Sen: Hepsini düzelttim. Bir hafta sonra tutar boşken Gönder çalışmaya başladı.

  3. Bayt: Ve hiçbir test kırılmadı. Testler düğmenin sınıfına bakıyormuş, ne yaptığına değil.

  4. Bayt: Arabanın rengine değil, sürüşüne bakmamız gerekiyor.

Test neye bakıyor?

Bir test bileşenin iç ayrıntısına bakabilir: hangi CSS sınıfı var, hangi state değişkeni değişti. Bu testler, davranış aynıyken kod yeniden düzenlenince kırılır.

Daha kötüsü, gerçek bir hatayı kaçırabilir. Tutar boşken Gönder çalışsa bile “setAmount çağrıldı” testi yeşil kalır; çünkü davranışa hiç bakmamıştır.

Kafam karıştı, daha basit anlat

İçe bakan test, düzenlemede kırılır, hatada yeşil kalır.

Hızlı kontrolBaşlangıç

İyi bir bileşen testi neyi kontrol etmeli?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Bir düğmenin CSS sınıfı yeniden adlandırıldı, davranışı aynı. İyi bir test ne yapmalı?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Kullanıcı gibi test et

Test, düğmeyi rolü ve üstündeki yazıyla buluyor: Gönder. Biri düğmenin CSS sınıfını yeniden adlandırdı, davranış aynı. Test ne der? Cevabı göster

Yeşil kalır. Rol de yazı da değişmedi. Test, kullanıcının gördüğüne bakıyor; kullanıcı için hiçbir şey değişmedi.

Rengine değil, sürüşüne bak.
Adım adım oku
  1. Araba yeniden boyandı: muayeneden kaldı.
  2. Fren tutmuyor: boya aynı, geçti.
  3. Öbür muayeneci arabayı sürüyor.
  4. Rengine değil, sürüşüne bak.

Testing LibraryBileşeni kullanıcı gibi test etmeye yarayan kütüphane: öğeleri rol, etiket ve metinle bulur, yazar, tıklar ve ekranda ne olduğuna bakar.Sözlükte gör → öğeleri kullanıcının bulduğu gibi bulur: rolü, etiketi, metni. Sonra kullanıcı gibi yazar, tıklar ve ekranda ne olduğuna bakar.

Bu yüzden bir düğmeyi getByRole('button', { name: 'Gönder' }) ile bulmak, onun accessible nameBir kontrolün ekran okuyucuda okunan adı. label for, düğmenin yazısı, aria-label ya da aria-labelledby'dan gelir.Sözlükte gör → da sınar. Test bir alanı bulamıyorsa, ekran okuyucu da çoğu zaman bulamaz.

Kafam karıştı, daha basit anlat

Öğeyi rolü ve yazısıyla bul, kullanıcı gibi yaz ve tıkla, ekranda ne olduğuna bak.

Hızlı kontrolOrta

Testing Library'de bir düğmeyi bulmanın önerilen yolu hangisi?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Tıklanan bir div, gerçek bir button'a çevrildi. getByRole kullanan test ne olur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Kendin gör

Havale formu üç kez değişiyor

Tohum 26051
  1. 1. CSS sınıfı .btn-send, .send-button oldu · davranış aynı
  2. 2. Tıklanan div, gerçek bir <button> oldu · davranış aynı
  3. 3. Hata: tutar boşken Gönder çalışıyor · gerçek hata

⚠ boşuna kırmızı: 0 · ✕ kaçan hata: 0

Hız
Adım 0

Şu an ne oldu?

İç ayrıntı: sınıf adı, setAmount çağrıldı mı

Form değişiyor; testler her değişiklikten sonra çalışıyor.

Görevler0/3

  • Gerçek hata yeşil geçsinaçık

    İpucu

    İç ayrıntıya bak.

  • Her değişiklikte kırmızı yansınaçık

    İpucu

    Bütün HTML.

  • Düzenlemede yeşil, hatada kırmızıaçık

    İpucu

    Kullanıcı gibi.

Olay günlüğü (0)

Henüz olay yok. Oynat veya adımla.

  1. Varsayılanla oynat. İç ayrıntıya bakan testler iki düzenlemede boşuna kırıldı, gerçek hatada yeşil kaldı.
  2. “Snapshot” seç. Her değişiklikte kırmızı: hata da yakalandı, ama iki boşuna alarmın arasında kayboldu.
  3. “Kullanıcı gibi” seç. İki düzenlemede yeşil, gerçek hatada kırmızı.
Hızlı kontrolOrta

Snapshot testinin en büyük sorunu nedir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Test 'setAmount çağrıldı mı' diye bakıyor. Tutar boşken Gönder çalışıyor. Test ne der?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Tuzaklar

Her şeyi snapshot’a bağlamak. Bir snapshot testiBileşenin bütün çıktısını kayıtlı bir kopyayla karşılaştıran test. Her farkta kırmızı yanar; neyin önemli olduğunu söylemez.Sözlükte gör → her farkta kırmızı yanar ve hangisinin önemli olduğunu söylemez. Ekip bir süre sonra onu körü körüne günceller; bir gün gerçek hatayla birlikte.

Bekleyen yazıyı hemen aramak. “Havale gönderildi” bir saniye sonra geliyorsa, getByText onu bulamaz. await findByText(...) yazı görünene kadar bekler; sabit bir süre beklemek ise testi yavaş ve kararsız yapar.

Bulunamayan alanı test kimliğiyle geçiştirmek. Önce alana gerçek bir etiket ekle. Test kimliği son çaredir.

Kafam karıştı, daha basit anlat

Snapshot’ı az kullan, yazıyı findBy ile bekle, eksik etiketi test kimliğiyle örtme.

Hızlı kontrolOrta

Kaydet'e basınca bir saniye sonra "Havale gönderildi" yazıyor. Testte bu nasıl beklenir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.
Derinleş · Mobil bankacılık: havale formunu kullanıcı gibi test etmek 3 dosya · ~73 satır · ilk okumada atlayabilirsin
Proje dosyaları

web/src/transfer/ TransferForm.tsx Form: her alanın gerçek bir etiketi var, düğme gerçek bir button; tutar boşsa gönderilmiyor.

web/src/transfer/TransferForm.tsx
import { useState } from 'react';
interface Props {
onSend: (iban: string, amount: number) => Promise<void>;
}
export function TransferForm({ onSend }: Props) {
const [iban, setIban] = useState('');
const [amount, setAmount] = useState('');
const [message, setMessage] = useState('');
async function submit(event: React.FormEvent) {
event.preventDefault();
const value = Number(amount);
if (!amount || value <= 0) {
setMessage('Tutar girin.');
return;
}
await onSend(iban, value);
setMessage('Havale gönderildi.');
}
return (
<form onSubmit={submit}>
<label htmlFor="iban">Alıcı IBAN</label>
<input id="iban" value={iban} onChange={(e) => setIban(e.target.value)} />
<label htmlFor="amount">Tutar (TL)</label>
<input id="amount" inputMode="decimal" value={amount} onChange={(e) => setAmount(e.target.value)} />
<button type="submit" className="send-button">Gönder</button>
<p role="status">{message}</p>
</form>
);
}

web/src/transfer/ TransferForm.test.tsx Test: öğeler rol ve etiketle bulunuyor, userEvent ile yazılıyor ve tıklanıyor, sonuç ekranda okunuyor.

web/src/transfer/TransferForm.test.tsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { expect, it, vi } from 'vitest';
import { TransferForm } from './TransferForm';
it('sends the transfer and says so', async () => {
const user = userEvent.setup();
const onSend = vi.fn().mockResolvedValue(undefined);
render(<TransferForm onSend={onSend} />);
await user.type(screen.getByLabelText('Alıcı IBAN'), 'TR330006100519786457841326');
await user.type(screen.getByLabelText('Tutar (TL)'), '500');
await user.click(screen.getByRole('button', { name: 'Gönder' }));
expect(await screen.findByText('Havale gönderildi.')).toBeVisible();
expect(onSend).toHaveBeenCalledWith('TR330006100519786457841326', 500);
});
it('does not send without an amount', async () => {
const user = userEvent.setup();
const onSend = vi.fn();
render(<TransferForm onSend={onSend} />);
await user.click(screen.getByRole('button', { name: 'Gönder' }));
expect(screen.getByRole('status')).toHaveTextContent('Tutar girin.');
expect(onSend).not.toHaveBeenCalled();
});

web/src/transfer/ TransferForm.brittle.test.tsx Şöyle de yazılabilirdi, ama bak ne oluyor: sınıf adına ve iç çağrıya bakan test.

web/src/transfer/TransferForm.brittle.test.tsx
// Tempting, but look what happens: the test knows class names, not behaviour.
it('sends when the button is clicked', () => {
const onSend = vi.fn();
const { container } = render(<TransferForm onSend={onSend} />);
fireEvent.change(container.querySelector('#amount')!, { target: { value: '500' } });
fireEvent.click(container.querySelector('.btn-send')!); // breaks when the class is renamed
expect(onSend).toHaveBeenCalled(); // never tries an empty amount, so that bug stays green
});

Kendini sına

Şimşek turu1/4

Bir CSS sınıfının adını değiştirmek iyi bir testi kırmalıdır.

Soru 1/3İleri

getByRole bir alanı bulamıyor; alanın görünür bir etiketi yok. En doğru çözüm hangisi?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Aklında kalacak üç şey

  1. 1 İç ayrıntıya bakan test, davranış aynıyken kırılır ve gerçek hatayı kaçırabilir. Bir süre sonra kimse kırmızıya inanmaz.
  2. 2 Testing Library ile öğeler rol, etiket ve metinle bulunur; test kullanıcı gibi yazar, tıklar ve ekranda ne olduğuna bakar.
  3. 3 getByRole bir alanı bulamıyorsa, ekran okuyucu da çoğu zaman bulamaz. Test burada bir erişilebilirlik eksiğini haber verir.
Sonraki kapı Müşteri arama kutusuna "kira" yazdı. Ekranda market alışverişleri çıktı. Arama doğru çalışıyordu; peki ne oldu? Anında Arama — Müşteri "kira" Yazdı, Ekranda Neden "k" Sonuçları Var? · 8 dk

4 kart sonraki derste seni bekliyor

0/4 kart bu dersten toplandı