Genel Bakış & MockHttpAdapter
@yildizpay/http-adapter, özel test double'ları, spy'lar ve noop yardımcıları içeren özel bir testing alt yolu sunar. Üretim bundle'ınızı kirletmeden içe aktarın:
import {
MockHttpAdapter,
MockHttpClient,
NoopInterceptor,
SpyInterceptor,
SpyObserver,
} from '@yildizpay/http-adapter/testing';MockHttpAdapter
HttpAdapterContract'ı uygulayan HttpAdapter için tam bellek içi test double'ı. Gerçek HTTP çağrısı yapmadan adapter.send()'in tam olarak ne döndüreceğini kontrol etmek için birim testlerinde kullanın.
Yanıtları Ayarlama
const adapter = new MockHttpAdapter();
// Her zaman bu yanıtı döndür
adapter.mockResolvedValue({ STATUS: 'SUCCESS', ORDER_ID: '123' });
// Her zaman bu hatayı fırlat
adapter.mockRejectedValue(new ServiceUnavailableException(/* ... */));
// FIFO sırasıyla tüketilen tek seferlik yanıtlar, varsayılan geri dönüşle
adapter
.mockResolvedOnce({ STATUS: 'PENDING' })
.mockResolvedOnce({ STATUS: 'SUCCESS' })
.mockResolvedValue({ STATUS: 'UNKNOWN' }); // kuyruk bittikten sonra geri dönüş
// Özel factory — tam Request nesnesini alır
adapter.mockImplementation((request) => ({
STATUS: request.body?.type === 'REFUND' ? 'REFUNDED' : 'SUCCESS',
}));Endpoint Bazlı Mock'lama
Yanıtları ve assertion'ları tek bir yola kapsamak için onEndpoint() kullanın. Endpoint bazlı yanıtlar global olanların önüne geçer.
adapter.onEndpoint('/api/payments').mockResolvedValue({ STATUS: 'SUCCESS' });
adapter.onEndpoint('/api/refunds').mockRejectedValue(new NotFoundException(/* ... */));
// Endpoint başına tek seferlik kuyruk
adapter.onEndpoint('/api/payments')
.mockResolvedOnce({ STATUS: 'PENDING' })
.mockResolvedValue({ STATUS: 'SUCCESS' }); // geri dönüşAssertion'lar
Test edilen kodu çalıştırdıktan sonra:
adapter.assertCalledTimes(2);
adapter.assertCalledWith('/api/payments', { method: HttpMethod.POST });
adapter.assertCalledWithBody(0, { AMOUNT: '100', CURRENCY: 'TRY' });
adapter.assertNthCalledWith(1, '/api/payments');
adapter.assertLastCalledWith('/api/refunds');
adapter.assertCallOrder('/api/payments', '/api/refunds');
adapter.assertNotCalled();Kullanım kolaylığı için getter'lar:
adapter.callCount; // number
adapter.firstCall; // Request | undefined
adapter.lastCall; // Request | undefined
adapter.wasCalled(); // boolean
adapter.wasNotCalled(); // booleanEndpoint kapsamları, yollarına göre kapsanmış aynı assertion API'sini sunar:
const odemeKapsami = adapter.onEndpoint('/api/payments');
odemeKapsami.assertCalledTimes(1);
odemeKapsami.assertCalledWith({ body: { MERCHANT_ID: 'M001' } });
odemeKapsami.wasCalled(); // booleanRequestMatcher — Kısmi İstek Eşleştirme
Tüm assertCalledWith varyantları, method, body, headers ve queryParams üzerinde derin kısmi eşleştirme için isteğe bağlı bir RequestMatcher kabul eder. Yalnızca belirttiğiniz alanlar kontrol edilir; gerçek istekteki ekstra alanlar görmezden gelinir.
adapter.assertCalledWith('/api/payments', {
method: HttpMethod.POST,
body: { AMOUNT: '100' }, // gerçek gövdedeki ekstra anahtarlar görmezden gelinir
headers: { 'x-merchant-id': 'M001' },
});Gövde eşleştirmesi derin kısmi eşitlik kullanır: iç içe nesneler kısmen eşleştirilir, NaN Object.is ile doğru şekilde işlenir, Date instance'ları değere göre karşılaştırılır ve diziler düz nesnelerle karıştırılmaz.
Strict Mode
Kayıtlı olmayan bir endpoint'e çağrı yapıldığında — global bir varsayılan yapılandırılmış olsa bile — anında başarısız olmak için strict mode'u etkinleştirin. Testlerde beklenmedik HTTP çağrılarını yakalamak için kullanışlıdır:
const adapter = new MockHttpAdapter({ strict: true });
adapter.onEndpoint('/api/payments').mockResolvedValue({ STATUS: 'SUCCESS' });
// Bu anında hata fırlatır — '/api/users' kayıtlı değil
await adapter.send(kayitsizIstek);Sıfırlama
reset(), mevcut onEndpoint() referanslarını geçersiz kılmadan tüm çağrıları, kuyrukları ve varsayılan davranışları temizler:
beforeEach(() => adapter.reset());Tam Örnek
import { MockHttpAdapter } from '@yildizpay/http-adapter/testing';
import { HttpMethod, NotFoundException } from '@yildizpay/http-adapter';
import { OdemeServisi } from './odeme.service';
describe('OdemeServisi', () => {
let adapter: MockHttpAdapter;
let servis: OdemeServisi;
beforeEach(() => {
adapter = new MockHttpAdapter();
servis = new OdemeServisi(adapter);
});
afterEach(() => adapter.reset());
it('ödeme oluşturur ve ödeme ID döndürür', async () => {
adapter
.onEndpoint('/v1/charges')
.mockResolvedValue({ id: 'ch_123', status: 'succeeded' });
const sonuc = await servis.odemeYap({ tutar: 1000, para_birimi: 'TRY' });
expect(sonuc.odemeId).toBe('ch_123');
adapter.assertCalledWith('/v1/charges', {
method: HttpMethod.POST,
body: { tutar: 1000, para_birimi: 'TRY' },
});
});
it('endpoint 404 döndürdüğünde hata fırlatır', async () => {
adapter
.onEndpoint('/v1/charges')
.mockRejectedValue(new NotFoundException('Ödeme bulunamadı', null));
await expect(servis.odemeYap({ tutar: 1000, para_birimi: 'TRY' }))
.rejects.toThrow(NotFoundException);
});
});