Skip to content

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:

typescript
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

typescript
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.

typescript
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:

typescript
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:

typescript
adapter.callCount;      // number
adapter.firstCall;      // Request | undefined
adapter.lastCall;       // Request | undefined
adapter.wasCalled();    // boolean
adapter.wasNotCalled(); // boolean

Endpoint kapsamları, yollarına göre kapsanmış aynı assertion API'sini sunar:

typescript
const odemeKapsami = adapter.onEndpoint('/api/payments');
odemeKapsami.assertCalledTimes(1);
odemeKapsami.assertCalledWith({ body: { MERCHANT_ID: 'M001' } });
odemeKapsami.wasCalled(); // boolean

RequestMatcher — 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.

typescript
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:

typescript
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:

typescript
beforeEach(() => adapter.reset());

Tam Örnek

typescript
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);
  });
});

Released under the MIT License.