diff --git a/packages/auth/src/di/container.test.ts b/packages/auth/src/di/container.test.ts new file mode 100644 index 0000000..73399e3 --- /dev/null +++ b/packages/auth/src/di/container.test.ts @@ -0,0 +1,51 @@ +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { authContainer } from "./container"; +import { AUTH_SYMBOLS } from "./symbols"; +import { AuthModule } from "./module"; +import { MockUsersRepository } from "@/infrastructure/repositories/mock-users.repository"; +import { MockAuthenticationService } from "@/infrastructure/services/mock-authentication.service"; +import type { IUsersRepository } from "@/application/repositories/users-repository.interface"; +import type { IAuthenticationService } from "@/application/services/authentication-service.interface"; + +describe("authContainer", () => { + beforeEach(() => { + authContainer.unbindAll(); + authContainer.load(AuthModule); + }); + + afterEach(() => { + authContainer.unbindAll(); + }); + + it("resolves IUsersRepository to MockUsersRepository by default", () => { + const repo = authContainer.get( + AUTH_SYMBOLS.IUsersRepository, + ); + expect(repo).toBeInstanceOf(MockUsersRepository); + }); + + it("resolves IAuthenticationService to MockAuthenticationService by default", () => { + const service = authContainer.get( + AUTH_SYMBOLS.IAuthenticationService, + ); + expect(service).toBeInstanceOf(MockAuthenticationService); + }); + + it("authentication service receives users repository via constructor injection", async () => { + const service = authContainer.get( + AUTH_SYMBOLS.IAuthenticationService, + ); + // The service should be able to validate against the seeded users + const { session, cookie } = await service.createSession({ + id: "1", + username: "alice", + passwordHash: "hashed_password_alice", + }); + expect(session.userId).toBe("1"); + expect(cookie.value).toBe(session.id); + + // After session creation, validateSession should resolve user via the repo + const validated = await service.validateSession(session.id); + expect(validated.user.username).toBe("alice"); + }); +}); diff --git a/packages/auth/src/di/container.ts b/packages/auth/src/di/container.ts new file mode 100644 index 0000000..209254b --- /dev/null +++ b/packages/auth/src/di/container.ts @@ -0,0 +1,6 @@ +import "reflect-metadata"; +import { Container } from "inversify"; +import { AuthModule } from "./module"; + +export const authContainer = new Container({ defaultScope: "Singleton" }); +authContainer.load(AuthModule); diff --git a/packages/auth/src/di/module.ts b/packages/auth/src/di/module.ts new file mode 100644 index 0000000..a6cbd2c --- /dev/null +++ b/packages/auth/src/di/module.ts @@ -0,0 +1,14 @@ +import { ContainerModule, type interfaces } from "inversify"; + +import type { IUsersRepository } from "../application/repositories/users-repository.interface"; +import type { IAuthenticationService } from "../application/services/authentication-service.interface"; +import { MockUsersRepository } from "../infrastructure/repositories/mock-users.repository"; +import { MockAuthenticationService } from "../infrastructure/services/mock-authentication.service"; +import { AUTH_SYMBOLS } from "./symbols"; + +export const AuthModule = new ContainerModule((bind: interfaces.Bind) => { + bind(AUTH_SYMBOLS.IUsersRepository).to(MockUsersRepository); + bind(AUTH_SYMBOLS.IAuthenticationService).to( + MockAuthenticationService, + ); +}); diff --git a/packages/auth/src/di/symbols.ts b/packages/auth/src/di/symbols.ts new file mode 100644 index 0000000..759f31d --- /dev/null +++ b/packages/auth/src/di/symbols.ts @@ -0,0 +1,4 @@ +export const AUTH_SYMBOLS = { + IUsersRepository: Symbol.for("auth:IUsersRepository"), + IAuthenticationService: Symbol.for("auth:IAuthenticationService"), +} as const;