---
title: 'Görsel Gerileme Testi'
source: 'https://academia.sh/tr/kurslar/frontend-kalitesi/gorsel-gerileme-testi'
course: 'Frontend Kalitesi'
language: tr
updated: '2026-08-17T18:09:22+00:00'
license: 'CC BY-SA 4.0'
---

# Görsel Gerileme Testi

Referans görüntüyle aday görüntünün piksel düzeyinde karşılaştırılması, piksel toleransı ile oran eşiğinin ayrı işlevleri, maskeleme kararı ve karşılaştırmayı anlamlı kılan belirlenimcilik koşulları.

Akış testi ölçüm satırının göründüğünü doğrular; nasıl göründüğünü doğrulamaz. Bir biçem
kuralı yanlış kapsayıcıya uygulandığında, bir aralık değeri iki katına çıktığında ya da
kaydet düğmesi arka planla aynı renge geldiğinde önceki iki dersin testleri geçmeyi sürdürür.
Öge ağaçtadır, rolü yerindedir, tıklanabilir — ama ekranda yanlıştır.

Görsel gerileme testi bu boşluğu doldurur: bir ekran görüntüsünü kabul edilmiş bir referansla
karşılaştırır ve farkı sayar.

## Karşılaştırılan Şey

Üç görüntü vardır. **Referans görüntü**, daha önce incelenip onaylanmış hâldir ve depoda
saklanır. **Aday görüntü**, o anki koddan üretilen hâldir. **Fark görüntüsü** ise ikisinin
uyuşmadığı pikselleri işaretler.

Karşılaştırma üç ölçekte yapılabilir. Tam sayfa karşılaştırması en geniş kapsamı verir ama
en gürültülü olanıdır: sayfanın herhangi bir yerindeki değişiklik testi düşürür. Bileşen
karşılaştırması yalnız ilgili bileşenin çerçevesini alır ve kusuru daha dar bir alana
bağlar. Öge düzeyinde karşılaştırma en dar kapsamdır.

Buradan ayrı bir yöntem, **anlık görüntü testidir (snapshot test)**: çizilen ağacın metin
biçimine dökülüp kaydedilmesi. Yapıdaki değişikliği yakalar, görünüşteki değişikliği
yakalamaz — renk, aralık ve yazı tipi kararları ağaçta görünmez. İkisi farklı riskleri
kapsar.

## Fark Hesabı

Karşılaştırmanın çekirdeği kısa bir hesaptır: iki ızgaranın karşılıklı piksellerini gez,
farkı bir toleransla kıyasla, uyuşmayanları say.

```js
// gorsel-fark.mjs — iki gri tonlamali izgarayi karsilastirir
export function fark(referans, aday, { tolerans = 0, maske = [] } = {}) {
  if (referans.genislik !== aday.genislik || referans.yukseklik !== aday.yukseklik) {
    return { boyutFarki: true, farkliPiksel: NaN, oran: NaN };
  }
  const maskeli = (x, y) =>
    maske.some((m) => x >= m.x && x < m.x + m.en && y >= m.y && y < m.y + m.boy);
  let farkli = 0;
  let sayilan = 0;
  for (let y = 0; y < referans.yukseklik; y += 1) {
    for (let x = 0; x < referans.genislik; x += 1) {
      if (maskeli(x, y)) continue;
      sayilan += 1;
      const i = y * referans.genislik + x;
      if (Math.abs(referans.pikseller[i] - aday.pikseller[i]) > tolerans) farkli += 1;
    }
  }
  return { boyutFarki: false, farkliPiksel: farkli, oran: farkli / sayilan };
}

export function karar(sonuc, esik) {
  if (sonuc.boyutFarki) return 'kaldi (boyut degisti)';
  return sonuc.oran > esik ? 'kaldi' : 'gecti';
}
```

Denemek için gerçek bir ekran görüntüsü gerekmez; ölçüm tablosu ekranını belirlenimci olarak
çizen kırk sütunluk bir ızgara yeter. Aşağıdaki modül başlık şeridini, saat alanını, dört
ölçüm satırını ve kaydet düğmesini gri tonlarla yerleştirir.

```js
// goruntu.mjs — olcum tablosu ekraninin belirlenimci gri tonlamali cizimi
const GENISLIK = 40;
const YUKSEKLIK = 20;

function bos() {
  return { genislik: GENISLIK, yukseklik: YUKSEKLIK, pikseller: new Uint8Array(GENISLIK * YUKSEKLIK).fill(255) };
}

function kutu(g, x, y, en, boy, ton) {
  for (let sy = y; sy < y + boy; sy += 1) {
    for (let sx = x; sx < x + en; sx += 1) {
      if (sx >= 0 && sx < g.genislik && sy >= 0 && sy < g.yukseklik) g.pikseller[sy * g.genislik + sx] = ton;
    }
  }
}

export function ekran({ dugmeTonu = 60, saatDeseni = 0, kaydir = 0 } = {}) {
  const g = bos();
  kutu(g, 0, 0 + kaydir, 40, 2, 200);              // baslik seridi
  kutu(g, 30, 0 + kaydir, 8, 1, 120 + saatDeseni); // saat alani
  for (let s = 0; s < 4; s += 1) {                 // olcum satirlari
    kutu(g, 2, 4 + s * 3 + kaydir, 34, 2, 230);
    kutu(g, 3, 5 + s * 3 + kaydir, 10, 1, 90);
  }
  kutu(g, 26, 17 + kaydir, 12, 2, dugmeTonu);      // kaydet dugmesi
  return g;
}

// cizim motorunun kenar yumusatma benzeri kucuk sapmasi
export function gurultuEkle(g, tohum = 12345, genlik = 3) {
  const kopya = { ...g, pikseller: Uint8Array.from(g.pikseller) };
  let s = tohum;
  for (let i = 0; i < kopya.pikseller.length; i += 1) {
    s = (s * 1103515245 + 12345) % 2147483648;
    const sapma = (s % (2 * genlik + 1)) - genlik;
    kopya.pikseller[i] = Math.min(255, Math.max(0, kopya.pikseller[i] + sapma));
  }
  return kopya;
}
```

```js
// rapor.mjs — adaylarin referansla karsilastirilmasi
import { fark, karar } from './gorsel-fark.mjs';
import { ekran, gurultuEkle } from './goruntu.mjs';

const referans = ekran();
const ESIK = 0.005;
const SAAT_MASKESI = [{ x: 30, y: 0, en: 8, boy: 1 }];

const adaylar = [
  ['ayni cizim', ekran(), {}],
  ['kenar yumusatma sapmasi', gurultuEkle(ekran()), {}],
  ['ayni sapma, tolerans 5', gurultuEkle(ekran()), { tolerans: 5 }],
  ['saat alani degisti', ekran({ saatDeseni: 40 }), {}],
  ['saat alani maskeli', ekran({ saatDeseni: 40 }), { maske: SAAT_MASKESI }],
  ['dugme rengi degisti', ekran({ dugmeTonu: 30 }), {}],
  ['icerik 1 piksel kaydi', ekran({ kaydir: 1 }), {}],
];

console.log('durum                     farkli   oran    karar');
for (const [ad, aday, secenek] of adaylar) {
  const s = fark(referans, aday, secenek);
  const oran = (s.oran * 100).toFixed(2).padStart(6);
  console.log(`${ad.padEnd(25)} ${String(s.farkliPiksel).padStart(6)} ${oran}%  ${karar(s, ESIK)}`);
}
```

```sh
node rapor.mjs
```

```
durum                     farkli   oran    karar
ayni cizim                     0   0.00%  gecti
kenar yumusatma sapmasi      502  62.75%  kaldi
ayni sapma, tolerans 5         0   0.00%  gecti
saat alani degisti             8   1.00%  kaldi
saat alani maskeli             0   0.00%  gecti
dugme rengi degisti           24   3.00%  kaldi
icerik 1 piksel kaydi        424  53.00%  kaldi
```

Yedi satır, yöntemin bütün karar noktalarını içeriyor.

## Tolerans, Eşik ve Maske

İkinci satır, sıfır toleransın neden kullanılamadığını gösteriyor. Her piksele en çok üç
birimlik bir sapma eklendiğinde sekiz yüz pikselin beş yüz ikisi "farklı" sayıldı: yüzde
62,75. Gözle görülmeyen bir sapma, karşılaştırmanın tamamını anlamsız kıldı. Üçüncü satırda
aynı görüntü beş birimlik toleransla karşılaştırıldı ve fark sıfıra indi.

Buradan iki ayrı kelepçe çıkar ve ikisi karıştırılmamalıdır. **Piksel toleransı** tek bir
pikselin ne kadar sapabileceğini söyler; çizim motorunun kenar yumuşatma gürültüsünü
soğurur. **Oran eşiği** kaç pikselin sapabileceğini söyler; kabul edilen toplam değişim
miktarıdır. Tolerans gürültüye, eşik küçük ve önemsiz kaymalara karşıdır.

Dördüncü ve beşinci satırlar dinamik içeriği gösteriyor. Başlıktaki saat alanı her koşumda
farklı bir değer taşır ve sekiz pikseli değiştirir: yüzde bir. Bu, kodla ilgisi olmayan bir
farktır ve maskeyle karşılaştırma dışında bırakılır. Maske dikdörtgeni sayımdan tümüyle
düşer; oran, kalan piksellere göre hesaplanır.

Altıncı satır gerçek bir gerilemedir: kaydet düğmesinin tonu değişti, yirmi dört piksel
farklı, yüzde üç. Eşiğin üstünde olduğu için test kaldı.

Yedinci satır yöntemin en önemli sınırını gösteriyor. İçerik bir piksel aşağı kaydığında
dört yüz yirmi dört piksel değişti — yüzde elli üç. Görsel karşılaştırma **yerel değildir**:
bir kapsayıcının dış boşluğundaki tek birimlik değişiklik, altındaki her şeyi kaydırır ve
farkı sayfanın tamamına yayar. Bu yüzden fark oranı kusurun büyüklüğünü ölçmez; yalnız
"bir şey değişti" der. Kusurun yerini bulmak fark görüntüsüne bakmayı gerektirir.

Sonuncu ayrıntı boyut denetimidir. Görüntülerin ölçüleri farklıysa piksel karşılaştırması
tanımsızdır; karşılaştırma başlamadan geçersiz sayılır.

## Testin İçine Koymak

Karar ölçütü belirlendiğinde bu bir teste dönüşür.

```js
// gorsel.test.mjs
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { fark, karar } from './gorsel-fark.mjs';
import { ekran, gurultuEkle } from './goruntu.mjs';

const ESIK = 0.005;
const OLCUT = { tolerans: 5, maske: [{ x: 30, y: 0, en: 8, boy: 1 }] };

test('cizim sapmasi ve saat alani gerileme sayilmaz', () => {
  const aday = gurultuEkle(ekran({ saatDeseni: 40 }));
  assert.equal(karar(fark(ekran(), aday, OLCUT), ESIK), 'gecti');
});

test('dugme tonundaki degisiklik gerileme olarak bildirilir', () => {
  const sonuc = fark(ekran(), ekran({ dugmeTonu: 30 }), OLCUT);
  assert.equal(karar(sonuc, ESIK), 'kaldi');
  assert.equal(sonuc.farkliPiksel, 24);
});

test('boyut degisikligi karsilastirmayi gecersiz kilar', () => {
  const dar = { genislik: 39, yukseklik: 20, pikseller: new Uint8Array(39 * 20) };
  assert.equal(karar(fark(ekran(), dar, OLCUT), ESIK), 'kaldi (boyut degisti)');
});
```

```sh
node --test gorsel.test.mjs
```

```
✔ cizim sapmasi ve saat alani gerileme sayilmaz (0.923334ms)
✔ dugme tonundaki degisiklik gerileme olarak bildirilir (0.115667ms)
✔ boyut degisikligi karsilastirmayi gecersiz kilar (0.053917ms)
ℹ tests 3
ℹ suites 0
ℹ pass 3
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 32.929375
```

## Belirlenimcilik Koşulları

Görsel karşılaştırma ancak aday görüntü belirlenimci üretildiğinde işe yarar. Beş koşul
sağlanmalıdır.

Görüntü alanı ve piksel oranı sabitlenir; farklı genişlik farklı bir düzen üretir. Animasyon
ve geçiş durdurulur, yoksa görüntü hangi karede alındığına bağlı olur — Düzen Sistemleri
kursundaki hareket azaltma tercihi bu iş için de kullanılabilir. Yazı tipi yüklenene kadar
beklenir; yedek yazı tipiyle çizilmiş bir kare her satırın genişliğini değiştirir. Saat,
rastgele kimlik ve canlı veri sabitlenir ya da maskelenir. Kaydırma konumu sıfırlanır.

Bir koşul daha vardır ve dışarıdan gelir: çizim motoru ile işletim sistemi. Aynı kod, farklı
bir ortamda kenar yumuşatmayı farklı yapar. Bu yüzden referans görüntüler üretildikleri
ortama bağlıdır ve tek bir ortamda üretilip orada karşılaştırılır.

Referansların kendisi de yönetilmesi gereken bir varlıktır. Depoda ikili dosya olarak
dururlar ve Sürüm Kontrolüne Giriş kursunda anlatıldığı gibi ikili dosyaların farkı
okunamaz. Her kabul edilen değişiklik depoyu büyütür. Bu yüzden referans güncellemesi
kendiliğinden yapılmaz: değişikliği bir kişi görür, onaylar ve yeni referans o onayla
kaydedilir. Onaysız güncelleme, gerileme testini kendi kendini haklı çıkaran bir düzeneğe
çevirir.

## Özet

- Görsel gerileme testi referans ve aday görüntüyü piksel düzeyinde karşılaştırır; anlık
  görüntü testi ise yapıyı yakalar, görünüşü yakalamaz.
- Piksel toleransı tek pikselin sapmasını, oran eşiği toplam değişim miktarını sınırlar;
  ikisi farklı sorunlara karşıdır ve karıştırılmamalıdır.
- Dinamik alanlar maskelenir; maskelenen bölge sayımın tamamen dışında kalır.
- Fark oranı yerel değildir: bir piksellik kayma sayfanın yarısını farklı gösterdi, bu yüzden
  oran kusurun büyüklüğünü ölçmez.
- Karşılaştırma ancak görüntü alanı, animasyon, yazı tipi, saat ve kaydırma sabitlendiğinde
  anlamlıdır; referanslar üretildikleri ortama bağlıdır ve güncellemeleri onaya bağlanır.

## Sonraki Adım

Dört ders boyunca kurulan testlerin hepsi bir varsayıma dayanıyordu: aynı kod aynı sonucu
verir. Uygulamada bu varsayım sık sık bozulur. Bir test yirmi koşumun on dokuzunda geçer,
birinde düşer; kimse bir şey değiştirmemiştir. Ekip önce yeniden çalıştırmayı dener, sonra
o testi görmezden gelmeye başlar ve paketin verdiği işaret değersizleşir. Sonraki ders bu
davranışın nedenlerini — zamanlama, sıraya bağımlılık ve paylaşılan durum — sayılabilir hâle
getirir ve her birinin çözümünü gösterir.
