Merge pull request #16005 from malkovitc/fix/resolve-each-multiple-providers

fix(core): resolve all providers when using resolve() with each option
This commit is contained in:
Kamil Mysliwiec
2025-12-15 10:11:24 +01:00
committed by GitHub
3 changed files with 82 additions and 2 deletions

View File

@@ -24,7 +24,7 @@ describe('Multiple providers under the same token ("each" feature)', () => {
});
});
describe('resolve()', () => {
it('should return an array of providers', async () => {
it('should return an array of request-scoped providers', async () => {
const builder = Test.createTestingModule({
imports: [MultipleProvidersModule],
});
@@ -43,5 +43,25 @@ describe('Multiple providers under the same token ("each" feature)', () => {
expect(multiProviderInstances).to.be.eql(['A', 'B', 'C']);
});
it('should return an array of default-scoped providers', async () => {
const builder = Test.createTestingModule({
imports: [MultipleProvidersModule],
});
const testingModule = await builder.compile();
const multiProviderInstances = await testingModule.resolve<string>(
'MULTI_PROVIDER',
undefined,
{
each: true,
},
);
// @ts-expect-error: make sure "multiProviderInstances" is string[] not string
multiProviderInstances.charAt;
expect(multiProviderInstances).to.be.eql(['A', 'B', 'C']);
});
});
});

View File

@@ -60,7 +60,7 @@ export abstract class AbstractInstanceResolver {
const pluckInstance = async (instanceLink: InstanceLink) => {
const { wrapperRef, collection } = instanceLink;
if (wrapperRef.isDependencyTreeStatic() && !wrapperRef.isTransient) {
return this.get(typeOrToken, { strict: options?.strict });
return wrapperRef.instance;
}
const ctorHost = wrapperRef.instance || { constructor: typeOrToken };

View File

@@ -485,4 +485,64 @@ describe('NestApplicationContext', () => {
expect(instance).instanceOf(Host);
});
});
describe('resolve with each: true', () => {
it('should resolve all default-scoped providers registered under the same token', async () => {
class Service1 {}
class Service2 {}
class Service3 {}
const TOKEN = 'MULTI_TOKEN';
const nestContainer = new NestContainer();
const injector = new Injector();
const instanceLoader = new InstanceLoader(
nestContainer,
injector,
new GraphInspector(nestContainer),
);
// Create three modules, each with a provider under the same token
const { moduleRef: module1 } = (await nestContainer.addModule(
class Module1 {},
[],
))!;
const { moduleRef: module2 } = (await nestContainer.addModule(
class Module2 {},
[],
))!;
const { moduleRef: module3 } = (await nestContainer.addModule(
class Module3 {},
[],
))!;
nestContainer.addProvider(
{ provide: TOKEN, useClass: Service1 },
module1.token,
);
nestContainer.addProvider(
{ provide: TOKEN, useClass: Service2 },
module2.token,
);
nestContainer.addProvider(
{ provide: TOKEN, useClass: Service3 },
module3.token,
);
const modules = nestContainer.getModules();
await instanceLoader.createInstancesOfDependencies(modules);
const appCtx = new NestApplicationContext(nestContainer);
const instances = await appCtx.resolve(TOKEN, undefined, {
strict: false,
each: true,
});
expect(instances).to.be.an('array');
expect(instances).to.have.length(3);
expect(instances[0]).to.be.instanceOf(Service1);
expect(instances[1]).to.be.instanceOf(Service2);
expect(instances[2]).to.be.instanceOf(Service3);
});
});
});