Testing Overview & MockHttpAdapter
@yildizpay/http-adapter ships a dedicated testing sub-path with purpose-built test doubles, spies, and no-op helpers. Import them without polluting your production bundle:
import {
MockHttpAdapter,
MockHttpClient,
NoopInterceptor,
SpyInterceptor,
SpyObserver,
} from '@yildizpay/http-adapter/testing';MockHttpAdapter
A full in-memory test double for HttpAdapter that implements HttpAdapterContract. Use it in unit tests to control exactly what adapter.send() returns — without making real HTTP calls.
Setting Up Responses
const adapter = new MockHttpAdapter();
// Always return this response
adapter.mockResolvedValue({ STATUS: 'SUCCESS', ORDER_ID: '123' });
// Always throw this error
adapter.mockRejectedValue(new ServiceUnavailableException(/* ... */));
// One-time responses consumed in FIFO order, with a fallback default
adapter
.mockResolvedOnce({ STATUS: 'PENDING' })
.mockResolvedOnce({ STATUS: 'SUCCESS' })
.mockResolvedValue({ STATUS: 'UNKNOWN' }); // fallback after queue is exhausted
// Custom factory — receives the full Request object
adapter.mockImplementation((request) => ({
STATUS: request.body?.type === 'REFUND' ? 'REFUNDED' : 'SUCCESS',
}));Endpoint-Specific Mocking
Use onEndpoint() to scope responses and assertions to a single path. Endpoint-scoped responses take priority over global ones.
adapter.onEndpoint('/api/payments').mockResolvedValue({ STATUS: 'SUCCESS' });
adapter.onEndpoint('/api/refunds').mockRejectedValue(new NotFoundException(/* ... */));
// One-time queue per endpoint
adapter.onEndpoint('/api/payments')
.mockResolvedOnce({ STATUS: 'PENDING' })
.mockResolvedValue({ STATUS: 'SUCCESS' }); // fallbackAssertions
After running the code under test:
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();Convenience getters:
adapter.callCount; // number
adapter.firstCall; // Request | undefined
adapter.lastCall; // Request | undefined
adapter.wasCalled(); // boolean
adapter.wasNotCalled(); // booleanEndpoint scopes expose the same assertion API, scoped to their path:
const paymentsScope = adapter.onEndpoint('/api/payments');
paymentsScope.assertCalledTimes(1);
paymentsScope.assertCalledWith({ body: { MERCHANT_ID: 'M001' } });
paymentsScope.wasCalled(); // booleanRequestMatcher — Partial Request Matching
All assertCalledWith variants accept an optional RequestMatcher for deep partial matching on method, body, headers, and queryParams. Only the fields you specify are checked; extra fields in the actual request are ignored.
adapter.assertCalledWith('/api/payments', {
method: HttpMethod.POST,
body: { AMOUNT: '100' }, // extra keys in actual body are ignored
headers: { 'x-merchant-id': 'M001' },
});Body matching uses deep partial equality: nested objects are matched partially, NaN is handled correctly via Object.is, Date instances are compared by value, and arrays are never confused with plain objects.
Strict Mode
Enable strict mode to fail fast whenever a call is made to an unregistered endpoint — even when a global default is configured. Useful for catching unexpected HTTP calls:
const adapter = new MockHttpAdapter({ strict: true });
adapter.onEndpoint('/api/payments').mockResolvedValue({ STATUS: 'SUCCESS' });
// This throws immediately — '/api/users' is not registered
await adapter.send(unregisteredRequest);Reset
reset() clears all calls, queues, and default behaviours without invalidating existing onEndpoint() references:
beforeEach(() => adapter.reset());Full Example
import { MockHttpAdapter } from '@yildizpay/http-adapter/testing';
import { HttpMethod, NotFoundException } from '@yildizpay/http-adapter';
import { PaymentService } from './payment.service';
describe('PaymentService', () => {
let adapter: MockHttpAdapter;
let service: PaymentService;
beforeEach(() => {
adapter = new MockHttpAdapter();
service = new PaymentService(adapter);
});
afterEach(() => adapter.reset());
it('creates a charge and returns the charge ID', async () => {
adapter.onEndpoint('/v1/charges').mockResolvedValue({ id: 'ch_123', status: 'succeeded' });
const result = await service.charge({ amount: 1000, currency: 'USD' });
expect(result.chargeId).toBe('ch_123');
adapter.assertCalledWith('/v1/charges', {
method: HttpMethod.POST,
body: { amount: 1000, currency: 'USD' },
});
});
it('throws when the charge endpoint returns 404', async () => {
adapter.onEndpoint('/v1/charges').mockRejectedValue(
new NotFoundException('Charge not found', /* response */ null),
);
await expect(service.charge({ amount: 1000, currency: 'USD' }))
.rejects.toThrow(NotFoundException);
});
});