UNPKG

@kitstack/nest-powertools

Version:

A comprehensive collection of NestJS powertools, decorators, and utilities to supercharge your backend development

80 lines 3.67 kB
"use strict"; 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