Jest vs. Alternatifler: Güvenli Kod İçin Nihai Rehber [2026]
Yazar: Burak Balkı | Kategori: Security | Okuma Süresi: 64 dk
Bu kapsamlı 2026 rehberi, Jest'in JavaScript uygulamalarında güvenlik testleri için nasıl kullanılacağını, başlıca alternatifleriyle karşılaştırmasını ve pra...
### Giriş: Yazılım Güvenliğinde Testlerin Kritik Rolü
Günümüzün hızla değişen dijital dünyasında, yazılım güvenliği artık bir lüks değil, bir zorunluluktur. Her yıl milyarlarca dolarlık zarara yol açan siber saldırılar ve veri ihlalleri, geliştiricilerin kodlarını baştan sona güvenlik odaklı tasarlamasını ve test etmesini kaçınılmaz kılmaktadır. Peki, JavaScript ekosisteminde bu kritik görevi üstlenmek için hangi test çatısını seçmelisiniz? Bu kapsamlı 2026 rehberinde, modern JavaScript uygulamalarınızın güvenliğini sağlamak amacıyla önde gelen test çerçevelerinden **Jest**'i ve başlıca alternatiflerini derinlemesine inceleyeceğiz. Bu makaleyi okuyarak, projeniz için en uygun test çözümünü seçecek, güvenlik odaklı test stratejileri geliştirecek ve kodunuzu olası tehditlere karşı daha dirençli hale getireceksiniz. Güvenli bir geleceğe adım atmak için okumaya devam edin.
## Jest Nedir?
Jest, Facebook tarafından geliştirilen ve JavaScript kodlarının test edilmesini kolaylaştıran, zengin özelliklere sahip bir test çerçevesidir. Özellikle React uygulamalarıyla popülerleşse de, 2026 itibarıyla Node.js, Vue, Angular ve diğer JavaScript tabanlı projelerde de yaygın olarak kullanılmaktadır. Jest, hızlı performans, anlık geri bildirim sağlayan interaktif izleme modu, güçlü mocking yetenekleri ve sıfır yapılandırma gerektiren (zero-config) yaklaşımıyla geliştiricilerin test yazma süreçlerini basitleştirir. Temel amacı, geliştiricilerin güvenilir ve bakımı kolay testler yazmasını sağlayarak yazılım kalitesini ve dolayısıyla güvenliğini artırmaktır.
Jest'in güçlü yönleri, onu modern JavaScript geliştirme süreçlerinin vazgeçilmez bir parçası haline getirmiştir. Entegre bir test koşucusu, assertion kütüphanesi ve mocking sistemi sunarak, geliştiricilerin ek araçlar kurma ihtiyacını ortadan kaldırır. Bu bütünleşik yapı, özellikle güvenlik testleri gibi hassas alanlarda tutarlılık ve güvenilirlik sağlar. Snapshot testleri, UI bileşenlerinin beklenmedik değişikliklerini tespit ederek, potansiyel güvenlik açıklarının veya yanlış görselleştirmelerin önüne geçebilir. Ayrıca, kod kapsamı raporlama (code coverage) özelliği sayesinde, test edilmemiş alanları belirleyerek güvenlik testlerinin eksiksizliğini garanti altına almaya yardımcı olur.
## Neden Jest Kullanmalısınız? Güvenlik Perspektifinden Değer Önerisi
Jest'i tercih etmek, sadece kod kalitesini artırmakla kalmaz, aynı zamanda yazılım güvenliğini de önemli ölçüde pekiştirir. İşte 2026 yılında Jest kullanmanız için güvenlik odaklı başlıca nedenler:
* **Hızlı ve Güvenilir Geri Bildirim Döngüsü:** Jest'in anlık izleme modu (watch mode), kodunuzda yaptığınız değişikliklerin güvenlik testlerini anında çalıştırmasını sağlar. Bu, özellikle bir güvenlik açığını düzeltirken veya yeni bir güvenlik özelliği eklerken, değişikliklerin beklendiği gibi çalıştığını ve yeni sorunlar yaratmadığını hızlıca doğrulamanıza olanak tanır. Production ortamında, bu hız, kritik güvenlik yamalarının daha hızlı devreye alınmasına yardımcı olur.
* **Güçlü Mocking Yetenekleri:** Jest, harici bağımlılıkları (API çağrıları, veritabanı işlemleri, üçüncü taraf kütüphaneleri) izole etme ve sahte (mock) nesnelerle değiştirme konusunda üstün yeteneklere sahiptir. Bu, güvenlik testleri yazarken kritik öneme sahiptir. Örneğin, bir kullanıcının yetkilendirme kontrolünü test ederken, gerçek bir kimlik doğrulama servisine bağlanmak yerine, sahte bir servis kullanarak farklı yetki seviyelerini (admin, user, guest) simüle edebilir ve yetki kaçırma (privilege escalation) gibi güvenlik açıklarını tespit edebilirsiniz. Ekibimizde, bu özellik sayesinde karmaşık yetkilendirme akışlarını detaylıca test etme imkanı bulduk.
* **Snapshot Testleri ile Regresyon Güvenliği:** Jest'in snapshot testleri, UI bileşenlerinin veya veri yapılarının belirli bir anlık görüntüsünü alır ve gelecekteki testlerde bu görüntünün değişip değişmediğini kontrol eder. Görsel regresyonların ötesinde, bu özellik, bir veri yapısının veya API yanıtının beklenmedik şekilde değişmesini tespit ederek potansiyel veri manipülasyonu veya bilgi sızıntısı risklerini işaret edebilir. Son projemizde, kritik API yanıtlarının yapısını snapshot testleri ile koruyarak, beklenmedik veri formatı değişikliklerinden kaynaklanabilecek güvenlik zafiyetlerini önledik.
* **Kapsamlı Kod Kapsamı Raporlama:** Jest, varsayılan olarak kod kapsamı (code coverage) raporları üretir. Bu raporlar, kodunuzun hangi kısımlarının test edildiğini ve hangi kısımlarının test edilmediğini gösterir. Güvenlik testleri açısından bu paha biçilmez bir özelliktir; test edilmemiş kritik güvenlik kontrolleri veya hassas veri işleme mantığı alanlarını belirleyerek, buralara özel testler yazılmasını teşvik eder. Bu sayede, güvenlik açıklarının gözden kaçma olasılığı azalır.
* **Aktif Topluluk ve Zengin Ekosistem:** 2026 itibarıyla Jest, geniş ve aktif bir geliştirici topluluğuna sahiptir. Bu, güvenlik odaklı test stratejileri geliştirirken karşılaşılan sorunlara hızlı çözümler bulunabileceği, zengin eklentiler ve entegrasyonlar olduğu anlamına gelir. Özellikle güvenlik alanında, topluluk tarafından geliştirilen araçlar ve best practice'ler, test süreçlerinizi daha da güçlendirebilir.
* **Kolay Öğrenme Eğrisi ve Entegrasyon:** Jest'in basit ve sezgisel API'si, yeni başlayanlar için bile kolayca öğrenilebilir olmasını sağlar. Mevcut projelere entegrasyonu da oldukça basittir, bu da güvenlik testlerinin mevcut geliştirme akışına sorunsuz bir şekilde dahil edilmesini kolaylaştırır.
Jest, özellikle modern JavaScript ve TypeScript projelerinde, güvenlik odaklı test stratejilerini uygulamak isteyen geliştiriciler ve ekipler için güçlü ve güvenilir bir seçenektir. Kapsamlı özellikleri ve aktif topluluk desteğiyle, 2026'nın zorlu güvenlik gereksinimlerini karşılamada önemli bir rol oynar.
## Jest vs. Alternatifler: Güvenli Kod İçin Karşılaştırma [2026]
JavaScript test ekosistemi oldukça zengindir ve Jest'in yanı sıra Vitest, Mocha ve Chai gibi güçlü alternatifler de bulunmaktadır. Güvenlik testleri perspektifinden, bu çerçevelerin karşılaştırması projeniz için doğru seçimi yapmanıza yardımcı olacaktır. İşte 2026 itibarıyla güncel bir karşılaştırma tablosu:
| Özellik | Jest | Vitest | Mocha & Chai (Birlikte) |
| :-------------------------- | :---------------------------------------------------------------- | :---------------------------------------------------------------- | :------------------------------------------------------------ |
| **Performans** | Orta-Yüksek. Büyük projelerde cacheleme ve paralel çalıştırma ile hızlı. | Çok Yüksek. Vite üzerine inşa edildiği için oldukça hızlı ve hafif. | Orta. Test koşucusu ve assertion kütüphanesi ayrı olduğu için yapılandırma ve hız optimizasyonu gerektirebilir. |
| **Öğrenme Eğrisi** | Düşük-Orta. Kapsamlı dokümantasyon, hepsi bir arada çözüm. | Düşük. Vite kullanıcıları için tanıdık, Jest benzeri API. | Orta-Yüksek. Mocha test koşucusu, Chai assertion ve diğer araçların entegrasyonu zaman alabilir. |
| **Ekosistem** | Çok Geniş. React, Vue, Angular gibi tüm büyük kütüphanelerle uyumlu. | Gelişmekte Olan. Vite projeleri için ideal, hızla büyüyor. | Geniş. Uzun süredir piyasada, birçok eklenti ve raporlama aracı. |
| **Topluluk** | Çok Aktif ve Büyük. Bol kaynak, hızlı destek. | Hızla Büyüyen ve Aktif. Özellikle Vite kullanıcıları arasında popüler. | Aktif ve Köklü. Uzun geçmişi sayesinde geniş bilgi tabanı. |
| **Kurumsal Destek** | Facebook tarafından destekleniyor, kurumsal projelerde yaygın. | Vue ekibi tarafından destekleniyor, Vite ekosisteminde güçlü. | Bağımsız, ancak birçok büyük şirket tarafından kullanılıyor. |
| **Güvenlik Odaklı Özellikler**| Güçlü mocking, snapshot testleri, kapsam raporlama. | Jest benzeri mocking, Jest uyumlu API, hızlı geri bildirim. | Esnek mocking (sinon.js ile), geniş eklenti desteği, özel güvenlik testleri için yüksek özelleştirme. |
| **Kullanım Alanı** | Her türlü JavaScript/TypeScript projesi, özellikle büyük ölçekli uygulamalar ve React. | Vite tabanlı projeler, modern frontend uygulamaları. | Her türlü JavaScript/TypeScript projesi, özellikle esneklik ve özelleştirme isteyenler. |
Bu karşılaştırmayı değerlendirirken, projenizin büyüklüğü, kullandığı teknoloji yığını (örneğin Vite kullanıyorsanız Vitest daha entegre olabilir) ve ekibinizin mevcut deneyimi önemli faktörlerdir. Jest, güvenlik testleri için gereken güçlü mocking ve snapshot özelliklerini “kutudan çıktığı gibi” sunarken, Vitest modern ve hızlı bir alternatif olarak öne çıkıyor. Mocha ve Chai ise daha modüler bir yaklaşım sunarak, güvenlik testleri için özel araçları entegre etme esnekliği sağlar.
## Kurulum ve İlk Adımlar: Jest ile Güvenlik Testlerine Başlangıç [2026]
Jest'i projenize entegre etmek ve güvenlik testleri yazmaya başlamak oldukça basittir. İşte adım adım kurulum ve ilk test örneği:
**Ön Gereksinimler:**
* Node.js (LTS sürümü, 2026 itibarıyla genellikle Node.js 20.x veya 22.x önerilir)
* npm veya Yarn
1. **Jest'i Yükleyin:**
Projenizin ana dizininde aşağıdaki komutu çalıştırarak Jest'i `devDependencies` olarak yükleyin:
```bash
npm install --save-dev jest
# veya
yarn add --dev jest
```
2. **`package.json` Dosyasını Yapılandırın:**
`package.json` dosyanıza bir test betiği ekleyin. Bu, testleri çalıştırmanızı kolaylaştırır.
```json
{
"name": "jest-security-app",
"version": "1.0.0",
"description": "Jest ile güvenlik testleri örneği 2026",
"main": "index.js",
"scripts": {
"test": "jest"
},
"keywords": [],
"author": "Burak Balkı",
"license": "ISC",
"devDependencies": {
"jest": "^29.7.0"
}
}
```
> **Pro Tip:** 2026 itibarıyla Jest'in kararlı sürümü genellikle 29.x veya 30.x serilerindedir. En güncel sürüm için resmi Jest dökümantasyonunu kontrol ediniz.
3. **Basit Bir Fonksiyon Oluşturun (Hassas Veri Kontrolü):**
`src/utils.js` adında bir dosya oluşturalım. Bu fonksiyon, bir kullanıcının hassas verilere erişim yetkisini kontrol etsin.
```javascript
// src/utils.js
export function hasAdminAccess(userRoles) {
if (!Array.isArray(userRoles)) {
throw new Error('User roles must be an array.');
}
return userRoles.includes('admin');
}
export function sanitizeInput(input) {
if (typeof input !== 'string') {
return '';
}
// Basit bir sanitizasyon örneği: XSS saldırılarını engellemek için World";
const sanitizedOutput = "Hello World"; // script etiketi kaldırılmış
expect(sanitizeInput(maliciousInput)).toBe(sanitizedOutput);
});
test('Normal girişler etkilenmemeli', () => {
const normalInput = "Hello World";
expect(sanitizeInput(normalInput)).toBe(normalInput);
});
});
```
5. **Testleri Çalıştırın:**
Terminalinizde aşağıdaki komutu çalıştırın:
```bash
npm test
# veya
yarn test
```
Jest testleri çalıştıracak ve sonuçları gösterecektir. Bu basit adımlarla, Jest'i projenize entegre ettiniz ve temel güvenlik kontrolleri için testler yazmaya başladınız. Ekibimizde, bu tür temel kontroller, daha karmaşık güvenlik testlerinin temelini oluşturur.
## Temel Kullanım ve Örnekler: Güvenlik Testleri İçin Jest
Jest, güvenlik açıklarını tespit etmek ve önlemek için kullanılabilecek çeşitli test senaryoları sunar. İşte 2026 standartlarında, gerçek dünya senaryolarına odaklanan bazı pratik örnekler:
### Örnek 1: Yetkilendirme Kontrollerini Mocking ile Test Etme
**Problem:** Bir API endpoint'inin yalnızca belirli yetkilere sahip kullanıcılar tarafından erişilebilir olduğundan emin olmak istiyoruz. Gerçek bir kimlik doğrulama servisiyle entegrasyon olmadan bu testi nasıl yaparız?
**Çözüm:** Jest'in mocking yeteneklerini kullanarak kimlik doğrulama modülünü taklit edebilir ve farklı kullanıcı rolleri için erişim senaryolarını test edebiliriz.
```javascript
// src/authService.js
// Bu, gerçek kimlik doğrulama servisiniz olsun
export const authService = {
checkPermission: (user, requiredPermission) => {
// Gerçek bir veritabanı veya JWT kontrolü yapar
return user && user.permissions.includes(requiredPermission);
}
};
// src/apiHandler.js
import { authService } from './authService';
export function getSensitiveData(user) {
if (!authService.checkPermission(user, 'read:sensitive')) {
throw new Error('Yetkisiz Erişim: Hassas verilere erişim izniniz yok.');
}
return { data: 'Çok gizli bilgiler!' };
}
```
```javascript
// __tests__/apiHandler.test.js
import { getSensitiveData } from '../src/apiHandler';
import { authService } from '../src/authService';
// authService modülünü mock'la
jest.mock('../src/authService', () => ({
authService: {
checkPermission: jest.fn(), // checkPermission metodunu mock'la
},
}));
describe('API Handler Güvenlik Testleri', () => {
beforeEach(() => {
// Her testten önce mock'ları temizle
authService.checkPermission.mockClear();
});
test('Yeterli yetkiye sahip kullanıcı hassas verilere erişebilmeli', () => {
authService.checkPermission.mockReturnValue(true);
const adminUser = { id: 1, permissions: ['read:sensitive'] };
expect(getSensitiveData(adminUser)).toEqual({ data: 'Çok gizli bilgiler!' });
expect(authService.checkPermission).toHaveBeenCalledWith(adminUser, 'read:sensitive');
});
test('Yetersiz yetkiye sahip kullanıcı hassas verilere erişememeli', () => {
authService.checkPermission.mockReturnValue(false);
const regularUser = { id: 2, permissions: ['read:public'] };
expect(() => getSensitiveData(regularUser)).toThrow('Yetkisiz Erişim: Hassas verilere erişim izniniz yok.');
expect(authService.checkPermission).toHaveBeenCalledWith(regularUser, 'read:sensitive');
});
test('Kullanıcı nesnesi yoksa hata fırlatılmalı', () => {
authService.checkPermission.mockReturnValue(false); // Bu çağrılmasa da güvenlik için mock'luyoruz
expect(() => getSensitiveData(null)).toThrow('Yetkisiz Erişim: Hassas verilere erişim izniniz yok.');
});
});
```
### Örnek 2: XSS (Cross-Site Scripting) Korumasını Test Etme
**Problem:** Kullanıcı tarafından sağlanan içeriğin bir web sayfasında güvenli bir şekilde görüntülendiğinden ve XSS saldırılarına karşı korunduğundan emin olmak.
**Çözüm:** Giriş temizleme (sanitization) fonksiyonunu test ederek, zararlı betiklerin kaldırıldığını doğrularız.
```javascript
// src/sanitizer.js
import DOMPurify from 'dompurify'; // 2026'da yaygın ve güvenilir bir kütüphane
export function sanitizeHTML(html) {
return DOMPurify.sanitize(html, { USE_PROFILES: { html: true } });
}
// src/commentService.js
import { sanitizeHTML } from './sanitizer';
export function addComment(rawComment) {
const sanitizedComment = sanitizeHTML(rawComment);
// Yorumu veritabanına kaydetme veya UI'da gösterme mantığı burada olur
return { success: true, comment: sanitizedComment };
}
```
```javascript
// __tests__/sanitizer.test.js
import { sanitizeHTML } from '../src/sanitizer';
describe('HTML Sanitizasyon Güvenlik Testleri', () => {
test('XSS payload içeren HTML düzgünce sanitize edilmeli', () => {
const maliciousHtml = '
';
const expectedSanitizedHtml = '
'; // DOMPurify varsayılan olarak onerror'ı kaldırır
expect(sanitizeHTML(maliciousHtml)).toBe(expectedSanitizedHtml);
});
test('script etiketleri tamamen kaldırılmalı', () => {
const scriptHtml = 'Hello World';
const expectedSanitizedHtml = 'Hello World';
expect(sanitizeHTML(scriptHtml)).toBe(expectedSanitizedHtml);
});
test('Normal HTML içeriği etkilenmemeli', () => {
const safeHtml = '';
expect(sanitizeHTML(safeHtml)).toBe(safeHtml);
});
test('SVG XSS payloadları sanitize edilmeli', () => {
const svgMalicious = '';
const expectedSanitized = '';
expect(sanitizeHTML(svgMalicious)).toBe(expectedSanitized);
});
});
```
### Örnek 3: Hassas Veri İşleme ve Kayıt Güvenliği
**Problem:** Uygulamanın hassas kullanıcı verilerini (örn. şifreler) loglamadığından veya açık metin olarak depolamadığından emin olmak.
**Çözüm:** Hassas veri işleme fonksiyonlarını test ederek, bu verilerin düzgün bir şekilde maskelendiğini veya hash'lendiğini doğrularız.
```javascript
// src/userService.js
import bcrypt from 'bcryptjs'; // 2026'da hala güçlü bir hashleme kütüphanesi
const SALT_ROUNDS = 10;
export async function hashPassword(password) {
if (!password) {
throw new Error('Şifre boş olamaz.');
}
return await bcrypt.hash(password, SALT_ROUNDS);
}
export function createUser(username, password) {
// Bu fonksiyon gerçekte hashPassword'u çağırır ve loglamaz
// Örnek için burada basitçe gösteriyoruz.
const user = {
username,
// password: password, // Asla açık metin şifreyi depolama veya loglama!
// passwordHash: await hashPassword(password) // Gerçek uygulamada böyle olur
};
console.log('Kullanıcı oluşturuldu:', user.username); // Sadece kullanıcı adını logla
// Veritabanına kaydetme vb.
return user;
}
export function logSensitiveOperation(operationDetails, sensitiveData) {
// Bu fonksiyon hassas verileri loglamamalı
const maskedData = sensitiveData ? '***MASKED***' : 'N/A';
console.log(`İşlem: ${operationDetails}, Veri: ${maskedData}`);
}
```
```javascript
// __tests__/userService.test.js
import { hashPassword, createUser, logSensitiveOperation } from '../src/userService';
import bcrypt from 'bcryptjs';
// bcrypt'i mock'luyoruz ki testler hızlı ve deterministik olsun
jest.mock('bcryptjs', () => ({
hash: jest.fn((password, salt) => Promise.resolve(`hashed_${password}_${salt}`)),
compare: jest.fn((password, hash) => Promise.resolve(hash === `hashed_${password}_10`)),
}));
describe('Kullanıcı Servisi Güvenlik Testleri', () => {
const consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {}); // console.log'u yakala
afterEach(() => {
consoleSpy.mockClear();
});
afterAll(() => {
consoleSpy.mockRestore(); // Testler bittikten sonra orijinal console.log'u geri yükle
});
test('Şifreler hashlenerek saklanmalı', async () => {
const password = 'mySecurePassword123!';
const hashedPassword = await hashPassword(password);
expect(hashedPassword).toBe('hashed_mySecurePassword123!_10');
expect(bcrypt.hash).toHaveBeenCalledWith(password, 10);
});
test('createUser fonksiyonu açık metin şifreyi loglamamalı', () => {
createUser('testuser', 'testpassword');
expect(consoleSpy).toHaveBeenCalledWith('Kullanıcı oluşturuldu:', 'testuser');
expect(consoleSpy).not.toHaveBeenCalledWith(expect.stringContaining('testpassword'));
});
test('logSensitiveOperation hassas verileri maskelemeli', () => {
logSensitiveOperation('Kredi Kartı İşlemi', '1234-5678-9012-3456');
expect(consoleSpy).toHaveBeenCalledWith('İşlem: Kredi Kartı İşlemi, Veri: ***MASKED***');
expect(consoleSpy).not.toHaveBeenCalledWith(expect.stringContaining('1234-5678-9012-3456'));
});
test('Boş şifre hashlenirken hata fırlatmalı', async () => {
await expect(hashPassword('')).rejects.toThrow('Şifre boş olamaz.');
});
});
```
### Örnek 4: Rate Limiting (Oran Sınırlama) Kontrolü
**Problem:** Bir API endpoint'inin DoS (Denial of Service) saldırılarına karşı korunması için oran sınırlaması uygulandığından emin olmak.
**Çözüm:** Oran sınırlama mantığını test ederek, belirli bir zaman diliminde yapılan istek sayısının aşıldığında uygun bir şekilde reddedildiğini doğrularız.
```javascript
// src/rateLimiter.js
const requestCounts = new Map();
const WINDOW_MS = 60 * 1000; // 1 dakika
const MAX_REQUESTS = 5; // Dakikada 5 istek
export function checkRateLimit(ipAddress) {
const now = Date.now();
const requests = requestCounts.get(ipAddress) || [];
// Eski istekleri temizle
const freshRequests = requests.filter(timestamp => timestamp > now - WINDOW_MS);
requestCounts.set(ipAddress, freshRequests);
if (freshRequests.length >= MAX_REQUESTS) {
return false; // Oran sınırı aşıldı
}
freshRequests.push(now);
return true; // İstek kabul edildi
}
// src/apiRoutes.js
import { checkRateLimit } from './rateLimiter';
export function handleLoginRequest(req, res) {
const ip = req.ip || '127.0.0.1'; // Gerçek bir uygulamada req.ip kullanılır
if (!checkRateLimit(ip)) {
res.status(429).send('Çok fazla istek! Lütfen daha sonra tekrar deneyin.');
return;
}
// Login mantığı burada devam eder
res.status(200).send('Giriş başarılı.');
}
```
```javascript
// __tests__/rateLimiter.test.js
import { checkRateLimit } from '../src/rateLimiter';
import { handleLoginRequest } from '../src/apiRoutes';
describe('Rate Limiting Güvenlik Testleri', () => {
let mockReq, mockRes;
const testIp = '192.168.1.1';
beforeEach(() => {
// Her testten önce Map'i temizle
// Jest'in modül izolasyonu sayesinde her testte yeni bir Map'e sahip oluruz
// ancak yine de manuel temizlik iyi bir pratik olabilir.
// Gerçekte, checkRateLimit içindeki requestCounts'u dışarıya sızdırmamak daha iyidir.
// Bu örnekte, modül scope'unda olduğu için Jest'in resetModules ile çalışır.
jest.resetModules(); // Her test için modülü yeniden yükle
const { checkRateLimit: newCheckRateLimit } = require('../src/rateLimiter');
mockReq = { ip: testIp };
mockRes = {
status: jest.fn().mockReturnThis(),
send: jest.fn(),
};
});
test('Belirlenen limit içinde istekler kabul edilmeli', () => {
for (let i = 0; i < 5; i++) {
expect(checkRateLimit(testIp)).toBe(true);
}
expect(checkRateLimit(testIp)).toBe(false); // 6. istek reddedilmeli
});
test('Limit aşıldığında handleLoginRequest 429 status döndürmeli', () => {
for (let i = 0; i < 5; i++) {
checkRateLimit(testIp); // Limit'i doldur
}
handleLoginRequest(mockReq, mockRes);
expect(mockRes.status).toHaveBeenCalledWith(429);
expect(mockRes.send).toHaveBeenCalledWith('Çok fazla istek! Lütfen daha sonra tekrar deneyin.');
});
test('Limit sıfırlandıktan sonra istekler tekrar kabul edilmeli', () => {
// Limit'i doldur
for (let i = 0; i < 5; i++) {
checkRateLimit(testIp);
}
expect(checkRateLimit(testIp)).toBe(false);
// Zamanı ileri sar (örneğin 1 dakika + 1ms)
jest.advanceTimersByTime(60 * 1000 + 1);
// Şimdi istekler tekrar kabul edilmeli
expect(checkRateLimit(testIp)).toBe(true);
});
});
```
> **Not:** `jest.advanceTimersByTime` kullanabilmek için test dosyanızın başında `jest.useFakeTimers();` eklemeniz ve `jest.runOnlyPendingTimers();` veya `jest.runAllTimers();` ile zamanlayıcıları çalıştırmanız gerekebilir. Bu örnekte `advanceTimersByTime` kullandık.
## İleri Seviye Teknikler: Jest ile Derinlemesine Güvenlik Testleri [2026]
Jest'in temel yeteneklerinin ötesine geçerek, daha karmaşık güvenlik senaryolarını test etmek için ileri seviye teknikler kullanabiliriz. Bu bölümde, production ortamında karşılaştığımız zorlu güvenlik testlerini kolaylaştıran yaklaşımları ele alacağız.
### 1. Entegrasyon Testleri ile Uçtan Uca Güvenlik Akışlarını Doğrulama
Birim testleri (unit tests) tek tek bileşenlerin güvenliğini sağlarken, entegrasyon testleri farklı modüllerin veya servislerin bir araya geldiğinde güvenlik akışlarının doğru çalıştığını doğrular. Örneğin, bir kullanıcının kayıt, giriş, şifre sıfırlama ve yetkilendirme süreçlerinin uçtan uca güvenli olduğunu test etmek.
```javascript
// src/app.js (Express uygulaması örneği)
import express from 'express';
import bodyParser from 'body-parser';
import { hashPassword } from './userService';
import jwt from 'jsonwebtoken'; // JWT kullanımı
const app = express();
app.use(bodyParser.json());
const USERS = {}; // Basit bir kullanıcı depolama
const JWT_SECRET = 'SUPER_SECRET_KEY_2026'; // Production'da çevresel değişken olmalı!
app.post('/register', async (req, res) => {
const { username, password } = req.body;
if (USERS[username]) {
return res.status(409).send('Kullanıcı adı zaten mevcut.');
}
try {
const hashedPassword = await hashPassword(password);
USERS[username] = { password: hashedPassword, roles: ['user'] };
res.status(201).send('Kayıt başarılı.');
} catch (error) {
res.status(400).send(error.message);
}
});
app.post('/login', async (req, res) => {
const { username, password } = req.body;
const user = USERS[username];
if (!user || !(await bcrypt.compare(password, user.password))) {
return res.status(401).send('Geçersiz kimlik bilgileri.');
}
const token = jwt.sign({ username, roles: user.roles }, JWT_SECRET, { expiresIn: '1h' });
res.status(200).json({ token });
});
app.get('/admin/data', (req, res) => {
const authHeader = req.headers['authorization'];
if (!authHeader) return res.status(401).send('Kimlik doğrulaması gerekli.');
const token = authHeader.split(' ')[1];
if (!token) return res.status(401).send('Token bulunamadı.');
try {
const decoded = jwt.verify(token, JWT_SECRET);
if (!decoded.roles.includes('admin')) {
return res.status(403).send('Yetkisiz erişim.');
}
res.status(200).send('Yönetici verileri.');
} catch (error) {
res.status(403).send('Geçersiz token.');
}
});
export default app; // Testler için dışa aktar
```
```javascript
// __tests__/e2e.security.test.js
import request from 'supertest'; // API testleri için popüler bir kütüphane
import app from '../src/app';
import bcrypt from 'bcryptjs'; // Gerçek bcrypt'i kullan
// bcrypt'i mock'lamıyoruz çünkü bu bir entegrasyon testi
// Ancak hızlı testler için yine de mock'lamak tercih edilebilir.
// Bu örnekte gerçek bcrypt'i kullanıyoruz.
describe('Uçtan Uca Güvenlik Akışları Testleri', () => {
beforeAll(() => {
// Uygulama başlatılmadan önce gerekli kurulumlar
});
afterAll(() => {
// Testler bittikten sonra temizlik
});
test('Kullanıcı kayıt ve giriş yapıp yetkili kaynağa erişememeli', async () => {
const username = 'testuser_e2e';
const password = 'Password123!';
// 1. Kayıt
await request(app)
.post('/register')
.send({ username, password })
.expect(201);
// 2. Giriş
const loginRes = await request(app)
.post('/login')
.send({ username, password })
.expect(200);
const { token } = loginRes.body;
expect(token).toBeDefined();
// 3. Yönetici kaynağına erişim denemesi (yetkisiz olmalı)
await request(app)
.get('/admin/data')
.set('Authorization', `Bearer ${token}`)
.expect(403) // Yetkisiz erişim bekleniyor
.expect('Yetkisiz erişim.');
});
test('Admin rolü olan kullanıcı yönetici kaynağına erişebilmeli', async () => {
const username = 'admin_e2e';
const password = 'AdminPassword123!';
// Geçici olarak admin rolü ekleyelim (gerçekte admin paneli veya CLI ile yapılır)
// Bu bir entegrasyon testi olduğu için, uygulama içindeki global USERS objesini manipüle edebiliriz.
// Production ortamında bu tür bir manuel manipülasyondan kaçınılır.
const hashedPassword = await bcrypt.hash(password, 10); // bcrypt.hash'in mock olmadığını varsayıyoruz
app.USERS = { ...app.USERS, [username]: { password: hashedPassword, roles: ['user', 'admin'] } };
// 1. Giriş
const loginRes = await request(app)
.post('/login')
.send({ username, password })
.expect(200);
const { token } = loginRes.body;
expect(token).toBeDefined();
// 2. Yönetici kaynağına erişim denemesi (yetkili olmalı)
await request(app)
.get('/admin/data')
.set('Authorization', `Bearer ${token}`)
.expect(200)
.expect('Yönetici verileri.');
});
});
```
### 2. Güvenlik Politikalarını Snapshot Testleri ile İzleme
**Problem:** Güvenlik başlıkları (Content-Security-Policy, X-Frame-Options vb.) gibi kritik HTTP yanıt başlıklarının beklenmedik şekilde değişmediğinden emin olmak.
**Çözüm:** Bir HTTP isteği yaparak yanıt başlıklarının bir snapshot'ını alabilir ve gelecekteki değişiklikleri otomatik olarak tespit edebiliriz.
```javascript
// src/server.js (Basit bir Express sunucusu)
import express from 'express';
const app = express();
app.use((req, res, next) => {
// Güvenlik başlıkları
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('Content-Security-P
Hello World