@kitstack/nest-powertools
Version:
A comprehensive collection of NestJS powertools, decorators, and utilities to supercharge your backend development
80 lines • 3.67 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const resilient_http_hook_1 = require("../resilient-http.hook");
const hooks_1 = require("../../types/hooks");
const rxjs_1 = require("rxjs");
describe('CircuitBreaker', () => {
const config = { failureThreshold: 2, resetTimeout: 100 };
let breaker;
beforeEach(() => {
breaker = new resilient_http_hook_1.CircuitBreaker(config);
});
it('should start in CLOSED state', () => {
expect(breaker.getStats().state).toBe(hooks_1.CircuitBreakerState.CLOSED);
});
it('should open after failures', async () => {
const failingOp = () => (0, rxjs_1.throwError)(() => new Error('fail'));
await (0, rxjs_1.lastValueFrom)(await breaker.execute(failingOp).catch(() => (0, rxjs_1.of)(undefined)));
await (0, rxjs_1.lastValueFrom)(await breaker.execute(failingOp).catch(() => (0, rxjs_1.of)(undefined)));
expect(breaker.getStats().state).toBe(hooks_1.CircuitBreakerState.OPEN);
});
it('should reset to CLOSED after success in HALF_OPEN', async () => {
const failingOp = () => (0, rxjs_1.throwError)(() => new Error('fail'));
await (0, rxjs_1.lastValueFrom)(await breaker.execute(failingOp).catch(() => (0, rxjs_1.of)(undefined)));
await (0, rxjs_1.lastValueFrom)(await breaker.execute(failingOp).catch(() => (0, rxjs_1.of)(undefined)));
breaker.nextAttemptTime = new Date(Date.now() - 1);
const successOp = () => (0, rxjs_1.of)('ok');
await (0, rxjs_1.lastValueFrom)(await breaker.execute(successOp));
expect(breaker.getStats().state).toBe(hooks_1.CircuitBreakerState.CLOSED);
});
it('should use fallback handler if provided', async () => {
const fallbackBreaker = new resilient_http_hook_1.CircuitBreaker({
...config,
fallbackHandler: () => 'fallback',
});
fallbackBreaker.state = hooks_1.CircuitBreakerState.OPEN;
fallbackBreaker.nextAttemptTime = new Date(Date.now() + 1000);
const result = await (0, rxjs_1.lastValueFrom)(await fallbackBreaker.execute(() => (0, rxjs_1.throwError)(() => new Error('fail'))));
expect(result).toBe('fallback');
});
});
describe('ResilientHttpService', () => {
let service;
let httpService;
beforeEach(() => {
httpService = {
get: jest.fn(() => (0, rxjs_1.of)({ data: 'ok' })),
post: jest.fn(() => (0, rxjs_1.of)({ data: 'ok' })),
put: jest.fn(() => (0, rxjs_1.of)({ data: 'ok' })),
delete: jest.fn(() => (0, rxjs_1.of)({ data: 'ok' })),
patch: jest.fn(() => (0, rxjs_1.of)({ data: 'ok' })),
};
service = new resilient_http_hook_1.ResilientHttpService(httpService);
});
it('should make GET request', (done) => {
service.get('url').subscribe((res) => {
expect(res.data).toBe('ok');
done();
});
});
it('should make POST request', (done) => {
service.post('url', { foo: 'bar' }).subscribe((res) => {
expect(res.data).toBe('ok');
done();
});
});
it('should record metrics', () => {
service.get('url').subscribe();
expect(service.getMetrics().length).toBeGreaterThan(0);
});
it('should reset circuit breaker', () => {
service.get('url').subscribe();
service.resetCircuitBreaker('url');
});
it('should clear metrics', () => {
service.get('url').subscribe();
service.clearMetrics();
expect(service.getMetrics().length).toBe(0);
});
});
//# sourceMappingURL=resilient-http.hook.spec.js.map