feat: add modular services and repositories for improved code organization
Introduce repository pattern across multiple services, including `favorites`, `tags`, `sessions`, `reports`, `auth`, and more. Decouple crypto functionalities into modular services like `HashingService`, `JwtService`, and `EncryptionService`. Improve testability and maintainability by simplifying dependencies and consolidating utility logic.
This commit is contained in:
@@ -1,54 +1,31 @@
|
||||
import { ConflictException, NotFoundException } from "@nestjs/common";
|
||||
import { Test, TestingModule } from "@nestjs/testing";
|
||||
import { DatabaseService } from "../database/database.service";
|
||||
import { FavoritesService } from "./favorites.service";
|
||||
import { FavoritesRepository } from "./repositories/favorites.repository";
|
||||
|
||||
describe("FavoritesService", () => {
|
||||
let service: FavoritesService;
|
||||
let repository: FavoritesRepository;
|
||||
|
||||
const mockDb = {
|
||||
select: jest.fn(),
|
||||
from: jest.fn(),
|
||||
where: jest.fn(),
|
||||
limit: jest.fn(),
|
||||
offset: jest.fn(),
|
||||
innerJoin: jest.fn(),
|
||||
insert: jest.fn(),
|
||||
values: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
returning: jest.fn(),
|
||||
const mockFavoritesRepository = {
|
||||
findContentById: jest.fn(),
|
||||
add: jest.fn(),
|
||||
remove: jest.fn(),
|
||||
findByUserId: jest.fn(),
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
const chain = {
|
||||
select: jest.fn().mockReturnThis(),
|
||||
from: jest.fn().mockReturnThis(),
|
||||
where: jest.fn().mockReturnThis(),
|
||||
limit: jest.fn().mockReturnThis(),
|
||||
offset: jest.fn().mockReturnThis(),
|
||||
innerJoin: jest.fn().mockReturnThis(),
|
||||
insert: jest.fn().mockReturnThis(),
|
||||
values: jest.fn().mockReturnThis(),
|
||||
delete: jest.fn().mockReturnThis(),
|
||||
returning: jest.fn().mockReturnThis(),
|
||||
};
|
||||
|
||||
const mockImplementation = () => Object.assign(Promise.resolve([]), chain);
|
||||
for (const mock of Object.values(chain)) {
|
||||
mock.mockImplementation(mockImplementation);
|
||||
}
|
||||
Object.assign(mockDb, chain);
|
||||
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
FavoritesService,
|
||||
{ provide: DatabaseService, useValue: { db: mockDb } },
|
||||
{ provide: FavoritesRepository, useValue: mockFavoritesRepository },
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<FavoritesService>(FavoritesService);
|
||||
repository = module.get<FavoritesRepository>(FavoritesRepository);
|
||||
});
|
||||
|
||||
it("should be defined", () => {
|
||||
@@ -57,26 +34,27 @@ describe("FavoritesService", () => {
|
||||
|
||||
describe("addFavorite", () => {
|
||||
it("should add a favorite", async () => {
|
||||
mockDb.limit.mockResolvedValue([{ id: "content1" }]);
|
||||
mockDb.returning.mockResolvedValue([
|
||||
mockFavoritesRepository.findContentById.mockResolvedValue({ id: "content1" });
|
||||
mockFavoritesRepository.add.mockResolvedValue([
|
||||
{ userId: "u1", contentId: "content1" },
|
||||
]);
|
||||
|
||||
const result = await service.addFavorite("u1", "content1");
|
||||
|
||||
expect(result).toEqual([{ userId: "u1", contentId: "content1" }]);
|
||||
expect(repository.add).toHaveBeenCalledWith("u1", "content1");
|
||||
});
|
||||
|
||||
it("should throw NotFoundException if content does not exist", async () => {
|
||||
mockDb.limit.mockResolvedValue([]);
|
||||
mockFavoritesRepository.findContentById.mockResolvedValue(null);
|
||||
await expect(service.addFavorite("u1", "invalid")).rejects.toThrow(
|
||||
NotFoundException,
|
||||
);
|
||||
});
|
||||
|
||||
it("should throw ConflictException on duplicate favorite", async () => {
|
||||
mockDb.limit.mockResolvedValue([{ id: "content1" }]);
|
||||
mockDb.returning.mockRejectedValue(new Error("Duplicate"));
|
||||
mockFavoritesRepository.findContentById.mockResolvedValue({ id: "content1" });
|
||||
mockFavoritesRepository.add.mockRejectedValue(new Error("Duplicate"));
|
||||
await expect(service.addFavorite("u1", "content1")).rejects.toThrow(
|
||||
ConflictException,
|
||||
);
|
||||
@@ -85,13 +63,14 @@ describe("FavoritesService", () => {
|
||||
|
||||
describe("removeFavorite", () => {
|
||||
it("should remove a favorite", async () => {
|
||||
mockDb.returning.mockResolvedValue([{ userId: "u1", contentId: "c1" }]);
|
||||
mockFavoritesRepository.remove.mockResolvedValue([{ userId: "u1", contentId: "c1" }]);
|
||||
const result = await service.removeFavorite("u1", "c1");
|
||||
expect(result).toEqual({ userId: "u1", contentId: "c1" });
|
||||
expect(repository.remove).toHaveBeenCalledWith("u1", "c1");
|
||||
});
|
||||
|
||||
it("should throw NotFoundException if favorite not found", async () => {
|
||||
mockDb.returning.mockResolvedValue([]);
|
||||
mockFavoritesRepository.remove.mockResolvedValue([]);
|
||||
await expect(service.removeFavorite("u1", "c1")).rejects.toThrow(
|
||||
NotFoundException,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user