feat(auth): add signUpUseCase (test red until DI lands)
This commit is contained in:
@@ -0,0 +1,47 @@
|
|||||||
|
import { beforeEach, describe, expect, it } from "vitest";
|
||||||
|
import { authContainer } from "@/di/container";
|
||||||
|
import { AUTH_SYMBOLS } from "@/di/symbols";
|
||||||
|
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";
|
||||||
|
import { AuthenticationError } from "@/entities/errors";
|
||||||
|
import { signUpUseCase } from "./sign-up.use-case";
|
||||||
|
|
||||||
|
describe("signUpUseCase", () => {
|
||||||
|
let usersRepo: MockUsersRepository;
|
||||||
|
let authService: MockAuthenticationService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
if (authContainer.isBound(AUTH_SYMBOLS.IUsersRepository)) {
|
||||||
|
authContainer.unbind(AUTH_SYMBOLS.IUsersRepository);
|
||||||
|
}
|
||||||
|
if (authContainer.isBound(AUTH_SYMBOLS.IAuthenticationService)) {
|
||||||
|
authContainer.unbind(AUTH_SYMBOLS.IAuthenticationService);
|
||||||
|
}
|
||||||
|
usersRepo = new MockUsersRepository();
|
||||||
|
authService = new MockAuthenticationService(usersRepo);
|
||||||
|
authContainer
|
||||||
|
.bind<IUsersRepository>(AUTH_SYMBOLS.IUsersRepository)
|
||||||
|
.toConstantValue(usersRepo);
|
||||||
|
authContainer
|
||||||
|
.bind<IAuthenticationService>(AUTH_SYMBOLS.IAuthenticationService)
|
||||||
|
.toConstantValue(authService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("creates a new user and returns session + cookie + user", async () => {
|
||||||
|
const result = await signUpUseCase({
|
||||||
|
username: "carol",
|
||||||
|
password: "secret_password",
|
||||||
|
});
|
||||||
|
expect(result.user.username).toBe("carol");
|
||||||
|
expect(result.session.userId).toBe(result.user.id);
|
||||||
|
expect(result.cookie.name).toBe("session");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throws AuthenticationError when username taken", async () => {
|
||||||
|
await expect(
|
||||||
|
signUpUseCase({ username: "alice", password: "secret_password" }),
|
||||||
|
).rejects.toBeInstanceOf(AuthenticationError);
|
||||||
|
});
|
||||||
|
});
|
||||||
46
packages/auth/src/application/use-cases/sign-up.use-case.ts
Normal file
46
packages/auth/src/application/use-cases/sign-up.use-case.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { AuthenticationError } from "../../entities/errors";
|
||||||
|
import type { Cookie } from "../../entities/cookie";
|
||||||
|
import type { Session } from "../../entities/session";
|
||||||
|
import type { User } from "../../entities/user";
|
||||||
|
import { authContainer } from "../../di/container";
|
||||||
|
import { AUTH_SYMBOLS } from "../../di/symbols";
|
||||||
|
import type { IUsersRepository } from "../repositories/users-repository.interface";
|
||||||
|
import type { IAuthenticationService } from "../services/authentication-service.interface";
|
||||||
|
|
||||||
|
export async function signUpUseCase(input: {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
}): Promise<{
|
||||||
|
session: Session;
|
||||||
|
cookie: Cookie;
|
||||||
|
user: Pick<User, "id" | "username">;
|
||||||
|
}> {
|
||||||
|
const usersRepository = authContainer.get<IUsersRepository>(
|
||||||
|
AUTH_SYMBOLS.IUsersRepository,
|
||||||
|
);
|
||||||
|
const authService = authContainer.get<IAuthenticationService>(
|
||||||
|
AUTH_SYMBOLS.IAuthenticationService,
|
||||||
|
);
|
||||||
|
|
||||||
|
const existingUser = await usersRepository.getUserByUsername(input.username);
|
||||||
|
if (existingUser) {
|
||||||
|
throw new AuthenticationError("Username taken");
|
||||||
|
}
|
||||||
|
|
||||||
|
const passwordHash = await authService.hashPassword(input.password);
|
||||||
|
const userId = authService.generateUserId();
|
||||||
|
|
||||||
|
const newUser = await usersRepository.createUser({
|
||||||
|
id: userId,
|
||||||
|
username: input.username,
|
||||||
|
passwordHash,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { cookie, session } = await authService.createSession(newUser);
|
||||||
|
|
||||||
|
return {
|
||||||
|
cookie,
|
||||||
|
session,
|
||||||
|
user: { id: newUser.id, username: newUser.username },
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user