refactor: format with biome
This commit is contained in:
@@ -1,73 +1,73 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
import { describe, expect, test } from "bun:test";
|
||||||
import "reflect-metadata";
|
import "reflect-metadata";
|
||||||
import {
|
import {
|
||||||
AlveoFactory,
|
AlveoFactory,
|
||||||
CircularDependencyError,
|
CircularDependencyError,
|
||||||
forwardRef,
|
forwardRef,
|
||||||
Inject,
|
Inject,
|
||||||
Injectable,
|
Injectable,
|
||||||
Module,
|
Module,
|
||||||
} from "../index";
|
} from "../index";
|
||||||
|
|
||||||
describe("Alveo Circular Dependencies", () => {
|
describe("Alveo Circular Dependencies", () => {
|
||||||
test("should detect circular dependencies without forwardRef", async () => {
|
test("should detect circular dependencies without forwardRef", async () => {
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class A {
|
class A {
|
||||||
constructor(_b: unknown) {}
|
constructor(_b: unknown) {}
|
||||||
}
|
}
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class B {
|
class B {
|
||||||
constructor(_a: A) {}
|
constructor(_a: A) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manually define metadata to simulate circular dep without forwardRef
|
// Manually define metadata to simulate circular dep without forwardRef
|
||||||
Reflect.defineMetadata("design:paramtypes", [Object], A);
|
Reflect.defineMetadata("design:paramtypes", [Object], A);
|
||||||
Reflect.defineMetadata("design:paramtypes", [A], B);
|
Reflect.defineMetadata("design:paramtypes", [A], B);
|
||||||
Reflect.defineMetadata("alveo:inject", [B], A);
|
Reflect.defineMetadata("alveo:inject", [B], A);
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [A, B],
|
providers: [A, B],
|
||||||
})
|
})
|
||||||
class RootModule {}
|
class RootModule {}
|
||||||
|
|
||||||
expect(AlveoFactory.create(RootModule)).rejects.toThrow(
|
expect(AlveoFactory.create(RootModule)).rejects.toThrow(
|
||||||
CircularDependencyError,
|
CircularDependencyError,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should resolve circular dependencies with forwardRef", async () => {
|
test("should resolve circular dependencies with forwardRef", async () => {
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class ServiceA {
|
class ServiceA {
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(forwardRef(() => ServiceB))
|
@Inject(forwardRef(() => ServiceB))
|
||||||
public readonly serviceB: { name: () => string },
|
public readonly serviceB: { name: () => string },
|
||||||
) {}
|
) {}
|
||||||
name() {
|
name() {
|
||||||
return "A";
|
return "A";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class ServiceB {
|
class ServiceB {
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(forwardRef(() => ServiceA))
|
@Inject(forwardRef(() => ServiceA))
|
||||||
public readonly serviceA: { name: () => string },
|
public readonly serviceA: { name: () => string },
|
||||||
) {}
|
) {}
|
||||||
name() {
|
name() {
|
||||||
return "B";
|
return "B";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [ServiceA, ServiceB],
|
providers: [ServiceA, ServiceB],
|
||||||
})
|
})
|
||||||
class RootModule {}
|
class RootModule {}
|
||||||
|
|
||||||
const app = await AlveoFactory.create(RootModule);
|
const app = await AlveoFactory.create(RootModule);
|
||||||
const a = await app.get(ServiceA);
|
const a = await app.get(ServiceA);
|
||||||
const b = await app.get(ServiceB);
|
const b = await app.get(ServiceB);
|
||||||
|
|
||||||
expect(a.serviceB.name()).toBe("B");
|
expect(a.serviceB.name()).toBe("B");
|
||||||
expect(b.serviceA.name()).toBe("A");
|
expect(b.serviceA.name()).toBe("A");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,123 +1,123 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
import { describe, expect, test } from "bun:test";
|
||||||
import "reflect-metadata";
|
import "reflect-metadata";
|
||||||
import {
|
import {
|
||||||
AlveoFactory,
|
AlveoFactory,
|
||||||
Inject,
|
Inject,
|
||||||
Injectable,
|
Injectable,
|
||||||
Module,
|
Module,
|
||||||
ProviderNotFoundError,
|
ProviderNotFoundError,
|
||||||
} from "../index";
|
} from "../index";
|
||||||
|
|
||||||
describe("Alveo Injection", () => {
|
describe("Alveo Injection", () => {
|
||||||
test("should resolve a simple singleton service", async () => {
|
test("should resolve a simple singleton service", async () => {
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class SimpleService {
|
class SimpleService {
|
||||||
getValue() {
|
getValue() {
|
||||||
return "hello";
|
return "hello";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [SimpleService],
|
providers: [SimpleService],
|
||||||
})
|
})
|
||||||
class RootModule {}
|
class RootModule {}
|
||||||
|
|
||||||
const app = await AlveoFactory.create(RootModule);
|
const app = await AlveoFactory.create(RootModule);
|
||||||
const service = await app.get(SimpleService);
|
const service = await app.get(SimpleService);
|
||||||
|
|
||||||
expect(service).toBeInstanceOf(SimpleService);
|
expect(service).toBeInstanceOf(SimpleService);
|
||||||
expect(service.getValue()).toBe("hello");
|
expect(service.getValue()).toBe("hello");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should inject dependencies via constructor", async () => {
|
test("should inject dependencies via constructor", async () => {
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class Dependency {
|
class Dependency {
|
||||||
name = "dep";
|
name = "dep";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class MainService {
|
class MainService {
|
||||||
constructor(public readonly dep: Dependency) {}
|
constructor(public readonly dep: Dependency) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [Dependency, MainService],
|
providers: [Dependency, MainService],
|
||||||
})
|
})
|
||||||
class RootModule {}
|
class RootModule {}
|
||||||
|
|
||||||
const app = await AlveoFactory.create(RootModule);
|
const app = await AlveoFactory.create(RootModule);
|
||||||
const main = await app.get(MainService);
|
const main = await app.get(MainService);
|
||||||
|
|
||||||
expect(main.dep).toBeInstanceOf(Dependency);
|
expect(main.dep).toBeInstanceOf(Dependency);
|
||||||
expect(main.dep.name).toBe("dep");
|
expect(main.dep.name).toBe("dep");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should support Value Providers", async () => {
|
test("should support Value Providers", async () => {
|
||||||
const TOKEN = Symbol("CONFIG");
|
const TOKEN = Symbol("CONFIG");
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class Service {
|
class Service {
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(TOKEN) public readonly config: { apiKey: string },
|
@Inject(TOKEN) public readonly config: { apiKey: string },
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [
|
providers: [
|
||||||
Service,
|
Service,
|
||||||
{ provide: TOKEN, useValue: { apiKey: "123" } },
|
{ provide: TOKEN, useValue: { apiKey: "123" } },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
class RootModule {}
|
class RootModule {}
|
||||||
|
|
||||||
const app = await AlveoFactory.create(RootModule);
|
const app = await AlveoFactory.create(RootModule);
|
||||||
const service = await app.get(Service);
|
const service = await app.get(Service);
|
||||||
|
|
||||||
expect(service.config.apiKey).toBe("123");
|
expect(service.config.apiKey).toBe("123");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should support existing providers (aliases)", async () => {
|
test("should support existing providers (aliases)", async () => {
|
||||||
const ALIAS = "ALIAS_TOKEN";
|
const ALIAS = "ALIAS_TOKEN";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class RealService {
|
class RealService {
|
||||||
ok() {
|
ok() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [
|
providers: [
|
||||||
RealService,
|
RealService,
|
||||||
{ provide: ALIAS, useExisting: RealService },
|
{ provide: ALIAS, useExisting: RealService },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
class RootModule {}
|
class RootModule {}
|
||||||
|
|
||||||
const app = await AlveoFactory.create(RootModule);
|
const app = await AlveoFactory.create(RootModule);
|
||||||
const real = await app.get(RealService);
|
const real = await app.get(RealService);
|
||||||
const aliased = await app.get(ALIAS);
|
const aliased = await app.get(ALIAS);
|
||||||
|
|
||||||
expect(aliased).toBe(real);
|
expect(aliased).toBe(real);
|
||||||
expect((aliased as RealService).ok()).toBe(true);
|
expect((aliased as RealService).ok()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should throw ProviderNotFoundError when dependency is missing", async () => {
|
test("should throw ProviderNotFoundError when dependency is missing", async () => {
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class MissingDep {}
|
class MissingDep {}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class Target {
|
class Target {
|
||||||
constructor(_dep: MissingDep) {}
|
constructor(_dep: MissingDep) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [Target],
|
providers: [Target],
|
||||||
})
|
})
|
||||||
class RootModule {}
|
class RootModule {}
|
||||||
|
|
||||||
expect(AlveoFactory.create(RootModule)).rejects.toThrow(
|
expect(AlveoFactory.create(RootModule)).rejects.toThrow(
|
||||||
ProviderNotFoundError,
|
ProviderNotFoundError,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,71 +1,71 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
import { describe, expect, test } from "bun:test";
|
||||||
import "reflect-metadata";
|
import "reflect-metadata";
|
||||||
import { AlveoFactory, Injectable, Module } from "../index";
|
import { AlveoFactory, Injectable, Module } from "../index";
|
||||||
|
|
||||||
describe("Alveo Lifecycles", () => {
|
describe("Alveo Lifecycles", () => {
|
||||||
test("should call lifecycle hooks", async () => {
|
test("should call lifecycle hooks", async () => {
|
||||||
let initCalled = false;
|
let initCalled = false;
|
||||||
let destroyCalled = false;
|
let destroyCalled = false;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class LifecycleService {
|
class LifecycleService {
|
||||||
async onModuleInit() {
|
async onModuleInit() {
|
||||||
initCalled = true;
|
initCalled = true;
|
||||||
}
|
}
|
||||||
async onModuleDestroy() {
|
async onModuleDestroy() {
|
||||||
destroyCalled = true;
|
destroyCalled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [LifecycleService],
|
providers: [LifecycleService],
|
||||||
})
|
})
|
||||||
class RootModule {}
|
class RootModule {}
|
||||||
|
|
||||||
const app = await AlveoFactory.create(RootModule);
|
const app = await AlveoFactory.create(RootModule);
|
||||||
expect(initCalled).toBe(true);
|
expect(initCalled).toBe(true);
|
||||||
|
|
||||||
await app.close();
|
await app.close();
|
||||||
expect(destroyCalled).toBe(true);
|
expect(destroyCalled).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should call all lifecycle hooks in the correct order", async () => {
|
test("should call all lifecycle hooks in the correct order", async () => {
|
||||||
const callOrder: string[] = [];
|
const callOrder: string[] = [];
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class FullLifecycleService {
|
class FullLifecycleService {
|
||||||
async onModuleInit() {
|
async onModuleInit() {
|
||||||
callOrder.push("onModuleInit");
|
callOrder.push("onModuleInit");
|
||||||
}
|
}
|
||||||
async onApplicationBootstrap() {
|
async onApplicationBootstrap() {
|
||||||
callOrder.push("onApplicationBootstrap");
|
callOrder.push("onApplicationBootstrap");
|
||||||
}
|
}
|
||||||
async onModuleDestroy() {
|
async onModuleDestroy() {
|
||||||
callOrder.push("onModuleDestroy");
|
callOrder.push("onModuleDestroy");
|
||||||
}
|
}
|
||||||
async beforeApplicationShutdown(signal?: string) {
|
async beforeApplicationShutdown(signal?: string) {
|
||||||
callOrder.push(`beforeApplicationShutdown:${signal}`);
|
callOrder.push(`beforeApplicationShutdown:${signal}`);
|
||||||
}
|
}
|
||||||
async onApplicationShutdown(signal?: string) {
|
async onApplicationShutdown(signal?: string) {
|
||||||
callOrder.push(`onApplicationShutdown:${signal}`);
|
callOrder.push(`onApplicationShutdown:${signal}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [FullLifecycleService],
|
providers: [FullLifecycleService],
|
||||||
})
|
})
|
||||||
class RootModule {}
|
class RootModule {}
|
||||||
|
|
||||||
const app = await AlveoFactory.create(RootModule);
|
const app = await AlveoFactory.create(RootModule);
|
||||||
expect(callOrder).toEqual(["onModuleInit", "onApplicationBootstrap"]);
|
expect(callOrder).toEqual(["onModuleInit", "onApplicationBootstrap"]);
|
||||||
|
|
||||||
await app.close("SIGTERM");
|
await app.close("SIGTERM");
|
||||||
expect(callOrder).toEqual([
|
expect(callOrder).toEqual([
|
||||||
"onModuleInit",
|
"onModuleInit",
|
||||||
"onApplicationBootstrap",
|
"onApplicationBootstrap",
|
||||||
"onModuleDestroy",
|
"onModuleDestroy",
|
||||||
"beforeApplicationShutdown:SIGTERM",
|
"beforeApplicationShutdown:SIGTERM",
|
||||||
"onApplicationShutdown:SIGTERM",
|
"onApplicationShutdown:SIGTERM",
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,95 +1,95 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
import { describe, expect, test } from "bun:test";
|
||||||
import "reflect-metadata";
|
import "reflect-metadata";
|
||||||
import { AlveoFactory, Inject, Injectable, Module } from "../index";
|
import { AlveoFactory, Inject, Injectable, Module } from "../index";
|
||||||
|
|
||||||
describe("Alveo Modules", () => {
|
describe("Alveo Modules", () => {
|
||||||
test("should handle Module imports and exports", async () => {
|
test("should handle Module imports and exports", async () => {
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class SharedService {
|
class SharedService {
|
||||||
identify() {
|
identify() {
|
||||||
return "shared";
|
return "shared";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [SharedService],
|
providers: [SharedService],
|
||||||
exports: [SharedService],
|
exports: [SharedService],
|
||||||
})
|
})
|
||||||
class LibModule {}
|
class LibModule {}
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [LibModule],
|
imports: [LibModule],
|
||||||
})
|
})
|
||||||
class AppModule {}
|
class AppModule {}
|
||||||
|
|
||||||
const app = await AlveoFactory.create(AppModule);
|
const app = await AlveoFactory.create(AppModule);
|
||||||
const service = await app.get(SharedService);
|
const service = await app.get(SharedService);
|
||||||
|
|
||||||
expect(service.identify()).toBe("shared");
|
expect(service.identify()).toBe("shared");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should support Synchronous Dynamic Modules", async () => {
|
test("should support Synchronous Dynamic Modules", async () => {
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class DynamicService {
|
class DynamicService {
|
||||||
constructor(@Inject("CONFIG") public readonly config: string) {}
|
constructor(@Inject("CONFIG") public readonly config: string) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Module({})
|
@Module({})
|
||||||
class DynamicModule {
|
class DynamicModule {
|
||||||
static forRoot(config: string) {
|
static forRoot(config: string) {
|
||||||
return {
|
return {
|
||||||
module: DynamicModule,
|
module: DynamicModule,
|
||||||
providers: [
|
providers: [
|
||||||
DynamicService,
|
DynamicService,
|
||||||
{ provide: "CONFIG", useValue: config },
|
{ provide: "CONFIG", useValue: config },
|
||||||
],
|
],
|
||||||
exports: [DynamicService],
|
exports: [DynamicService],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [DynamicModule.forRoot("dynamic_config")],
|
imports: [DynamicModule.forRoot("dynamic_config")],
|
||||||
})
|
})
|
||||||
class AppModule {}
|
class AppModule {}
|
||||||
|
|
||||||
const app = await AlveoFactory.create(AppModule);
|
const app = await AlveoFactory.create(AppModule);
|
||||||
const service = await app.get(DynamicService);
|
const service = await app.get(DynamicService);
|
||||||
|
|
||||||
expect(service.config).toBe("dynamic_config");
|
expect(service.config).toBe("dynamic_config");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should support Asynchronous Dynamic Modules", async () => {
|
test("should support Asynchronous Dynamic Modules", async () => {
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class AsyncDynamicService {
|
class AsyncDynamicService {
|
||||||
constructor(
|
constructor(
|
||||||
@Inject("ASYNC_CONFIG") public readonly config: string,
|
@Inject("ASYNC_CONFIG") public readonly config: string,
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Module({})
|
@Module({})
|
||||||
class AsyncDynamicModule {
|
class AsyncDynamicModule {
|
||||||
static async forRoot(config: string) {
|
static async forRoot(config: string) {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||||
return {
|
return {
|
||||||
module: AsyncDynamicModule,
|
module: AsyncDynamicModule,
|
||||||
providers: [
|
providers: [
|
||||||
AsyncDynamicService,
|
AsyncDynamicService,
|
||||||
{ provide: "ASYNC_CONFIG", useValue: config },
|
{ provide: "ASYNC_CONFIG", useValue: config },
|
||||||
],
|
],
|
||||||
exports: [AsyncDynamicService],
|
exports: [AsyncDynamicService],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [AsyncDynamicModule.forRoot("async_dynamic_config")],
|
imports: [AsyncDynamicModule.forRoot("async_dynamic_config")],
|
||||||
})
|
})
|
||||||
class AppModule {}
|
class AppModule {}
|
||||||
|
|
||||||
const app = await AlveoFactory.create(AppModule);
|
const app = await AlveoFactory.create(AppModule);
|
||||||
const service = await app.get(AsyncDynamicService);
|
const service = await app.get(AsyncDynamicService);
|
||||||
|
|
||||||
expect(service.config).toBe("async_dynamic_config");
|
expect(service.config).toBe("async_dynamic_config");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,78 +1,78 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
import { describe, expect, test } from "bun:test";
|
||||||
import "reflect-metadata";
|
import "reflect-metadata";
|
||||||
import { AlveoFactory, Container, Module } from "../index";
|
import { AlveoFactory, Container, Module } from "../index";
|
||||||
|
|
||||||
describe("Alveo Providers", () => {
|
describe("Alveo Providers", () => {
|
||||||
test("should support Factory Providers", async () => {
|
test("should support Factory Providers", async () => {
|
||||||
const TOKEN = "FACTORY";
|
const TOKEN = "FACTORY";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: TOKEN,
|
provide: TOKEN,
|
||||||
useFactory: () => "dynamic_value",
|
useFactory: () => "dynamic_value",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
class RootModule {}
|
class RootModule {}
|
||||||
|
|
||||||
const app = await AlveoFactory.create(RootModule);
|
const app = await AlveoFactory.create(RootModule);
|
||||||
const value = await app.get(TOKEN);
|
const value = await app.get(TOKEN);
|
||||||
|
|
||||||
expect(value).toBe("dynamic_value");
|
expect(value).toBe("dynamic_value");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should support Asynchronous Factory Providers", async () => {
|
test("should support Asynchronous Factory Providers", async () => {
|
||||||
const TOKEN = "ASYNC_FACTORY";
|
const TOKEN = "ASYNC_FACTORY";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: TOKEN,
|
provide: TOKEN,
|
||||||
useFactory: async () => {
|
useFactory: async () => {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||||
return "async_value";
|
return "async_value";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
class RootModule {}
|
class RootModule {}
|
||||||
|
|
||||||
const app = await AlveoFactory.create(RootModule);
|
const app = await AlveoFactory.create(RootModule);
|
||||||
const value = await app.get(TOKEN);
|
const value = await app.get(TOKEN);
|
||||||
|
|
||||||
expect(value).toBe("async_value");
|
expect(value).toBe("async_value");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should handle concurrent resolution of the same async provider", async () => {
|
test("should handle concurrent resolution of the same async provider", async () => {
|
||||||
const TOKEN = "CONCURRENT_ASYNC";
|
const TOKEN = "CONCURRENT_ASYNC";
|
||||||
let callCount = 0;
|
let callCount = 0;
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: TOKEN,
|
provide: TOKEN,
|
||||||
useFactory: async () => {
|
useFactory: async () => {
|
||||||
callCount++;
|
callCount++;
|
||||||
await new Promise((resolve) => setTimeout(resolve, 20));
|
await new Promise((resolve) => setTimeout(resolve, 20));
|
||||||
return { id: Math.random() };
|
return { id: Math.random() };
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
class RootModule {}
|
class RootModule {}
|
||||||
|
|
||||||
// We use a fresh container to test concurrent resolution
|
// We use a fresh container to test concurrent resolution
|
||||||
// bypassing the sequential resolveAll() of AlveoFactory.create()
|
// bypassing the sequential resolveAll() of AlveoFactory.create()
|
||||||
const container = new Container();
|
const container = new Container();
|
||||||
await container.registerRootModule(RootModule);
|
await container.registerRootModule(RootModule);
|
||||||
|
|
||||||
const [val1, val2] = await Promise.all([
|
const [val1, val2] = await Promise.all([
|
||||||
container.get(TOKEN),
|
container.get(TOKEN),
|
||||||
container.get(TOKEN),
|
container.get(TOKEN),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(val1).toBe(val2);
|
expect(val1).toBe(val2);
|
||||||
expect(callCount).toBe(1);
|
expect(callCount).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user