test(core): add nested transient isolation integration test

This commit is contained in:
mag123c
2025-10-22 09:34:24 +09:00
parent 4ffe045628
commit cde4fb8334
7 changed files with 162 additions and 0 deletions

View File

@@ -2,6 +2,7 @@ import { INestApplication, Injectable, Scope } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import { expect } from 'chai';
import * as request from 'supertest';
import { NestedTransientModule } from '../src/nested-transient/nested-transient.module';
import { Guard } from '../src/transient/guards/request-scoped.guard';
import { HelloController } from '../src/transient/hello.controller';
import { HelloModule } from '../src/transient/hello.module';
@@ -139,4 +140,53 @@ describe('Transient scope', () => {
await app.close();
});
});
describe('when nested transient providers are used in request scope', () => {
let server: any;
let app: INestApplication;
before(async () => {
const module = await Test.createTestingModule({
imports: [NestedTransientModule],
}).compile();
app = module.createNestApplication();
server = app.getHttpServer();
await app.init();
});
describe('when handling HTTP requests', () => {
let response: any;
before(async () => {
const performHttpCall = () =>
new Promise<any>((resolve, reject) => {
request(server)
.get('/nested-transient')
.end((err, res) => {
if (err) return reject(err);
resolve(res);
});
});
response = await performHttpCall();
});
it('should isolate nested transient instances for each parent service', () => {
expect(response.body.firstServiceContext).to.equal(
'NESTED-FirstService',
);
expect(response.body.secondServiceContext).to.equal(
'NESTED-SecondService',
);
expect(response.body.firstServiceNestedId).to.not.equal(
response.body.secondServiceNestedId,
);
});
});
after(async () => {
await app.close();
});
});
});

View File

@@ -0,0 +1,12 @@
import { Injectable, Scope } from '@nestjs/common';
import { TransientLoggerService } from './transient-logger.service';
@Injectable({ scope: Scope.REQUEST })
export class FirstRequestService {
static COUNTER = 0;
constructor(public readonly logger: TransientLoggerService) {
FirstRequestService.COUNTER++;
this.logger.setContext('FirstService');
}
}

View File

@@ -0,0 +1,25 @@
import { Controller, Get, Scope } from '@nestjs/common';
import { FirstRequestService } from './first-request.service';
import { SecondRequestService } from './second-request.service';
@Controller({ path: 'nested-transient', scope: Scope.REQUEST })
export class NestedTransientController {
static COUNTER = 0;
constructor(
private readonly firstService: FirstRequestService,
private readonly secondService: SecondRequestService,
) {
NestedTransientController.COUNTER++;
}
@Get()
getIsolationData() {
return {
firstServiceContext: this.firstService.logger.getNestedContext(),
firstServiceNestedId: this.firstService.logger.getNestedInstanceId(),
secondServiceContext: this.secondService.logger.getNestedContext(),
secondServiceNestedId: this.secondService.logger.getNestedInstanceId(),
};
}
}

View File

@@ -0,0 +1,17 @@
import { Module } from '@nestjs/common';
import { NestedTransientController } from './nested-transient.controller';
import { FirstRequestService } from './first-request.service';
import { SecondRequestService } from './second-request.service';
import { TransientLoggerService } from './transient-logger.service';
import { NestedTransientService } from './nested-transient.service';
@Module({
controllers: [NestedTransientController],
providers: [
FirstRequestService,
SecondRequestService,
TransientLoggerService,
NestedTransientService,
],
})
export class NestedTransientModule {}

View File

@@ -0,0 +1,21 @@
import { Injectable, Scope } from '@nestjs/common';
@Injectable({ scope: Scope.TRANSIENT })
export class NestedTransientService {
static COUNTER = 0;
public readonly instanceId: number;
private context?: string;
constructor() {
NestedTransientService.COUNTER++;
this.instanceId = NestedTransientService.COUNTER;
}
setContext(ctx: string) {
this.context = ctx;
}
getContext(): string | undefined {
return this.context;
}
}

View File

@@ -0,0 +1,12 @@
import { Injectable, Scope } from '@nestjs/common';
import { TransientLoggerService } from './transient-logger.service';
@Injectable({ scope: Scope.REQUEST })
export class SecondRequestService {
static COUNTER = 0;
constructor(public readonly logger: TransientLoggerService) {
SecondRequestService.COUNTER++;
this.logger.setContext('SecondService');
}
}

View File

@@ -0,0 +1,25 @@
import { Injectable, Scope } from '@nestjs/common';
import { NestedTransientService } from './nested-transient.service';
@Injectable({ scope: Scope.TRANSIENT })
export class TransientLoggerService {
static COUNTER = 0;
public readonly instanceId: number;
constructor(public readonly nested: NestedTransientService) {
TransientLoggerService.COUNTER++;
this.instanceId = TransientLoggerService.COUNTER;
}
setContext(ctx: string) {
this.nested.setContext(`NESTED-${ctx}`);
}
getNestedContext(): string | undefined {
return this.nested.getContext();
}
getNestedInstanceId(): number {
return this.nested.instanceId;
}
}