From 821b080963719dee7f52d3f41cb6c83eff0429a1 Mon Sep 17 00:00:00 2001 From: sheepster1 Date: Sat, 6 Jul 2024 18:27:56 +0300 Subject: [PATCH] fix(core): unhandled promise rejection in interceptors consumer --- .../interceptors/interceptors-consumer.ts | 3 +- .../interceptors-consumer.spec.ts | 47 ++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/packages/core/interceptors/interceptors-consumer.ts b/packages/core/interceptors/interceptors-consumer.ts index 6853e1b1a92..a2b690a721e 100644 --- a/packages/core/interceptors/interceptors-consumer.ts +++ b/packages/core/interceptors/interceptors-consumer.ts @@ -30,7 +30,8 @@ export class InterceptorsConsumer { return defer(AsyncResource.bind(() => this.transformDeferred(next))); } const handler: CallHandler = { - handle: () => fromPromise(nextFn(i + 1)).pipe(mergeAll()), + handle: () => + defer(AsyncResource.bind(() => nextFn(i + 1))).pipe(mergeAll()), }; return interceptors[i].intercept(context, handler); }; diff --git a/packages/core/test/interceptors/interceptors-consumer.spec.ts b/packages/core/test/interceptors/interceptors-consumer.spec.ts index 306d3f33b15..8ac10f8d3a1 100644 --- a/packages/core/test/interceptors/interceptors-consumer.spec.ts +++ b/packages/core/test/interceptors/interceptors-consumer.spec.ts @@ -1,7 +1,7 @@ import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common'; import { AsyncLocalStorage } from 'async_hooks'; import { expect } from 'chai'; -import { Observable, lastValueFrom, of, retry } from 'rxjs'; +import { Observable, defer, lastValueFrom, merge, of, retry } from 'rxjs'; import * as sinon from 'sinon'; import { InterceptorsConsumer } from '../../interceptors/interceptors-consumer'; @@ -179,6 +179,51 @@ describe('InterceptorsConsumer', () => { }); }); }); + describe('deferred promise conversion', () => { + it('should convert promise to observable deferred', async () => { + class TestError extends Error {} + const testInterceptors = [ + { + intercept: sinon.stub().callsFake(async (ctx, handler) => { + return merge( + handler.handle(), + defer(() => { + throw new TestError(); + }), + ); + }), + }, + { + intercept: sinon + .stub() + .callsFake(async (ctx, handler) => handler.handle()), + }, + { + intercept: sinon + .stub() + .callsFake(async (ctx, handler) => handler.handle()), + }, + , + ]; + + const observable = await consumer.intercept( + testInterceptors, + null, + { constructor: null }, + null, + async () => 1, + ); + + try { + await transformToResult(observable); + } catch (error) { + if (!(error instanceof TestError)) { + throw error; + } + } + expect(testInterceptors[2].intercept.called).to.be.false; + }); + }); }); async function transformToResult(resultOrDeferred: any) {