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