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:
@@ -4,33 +4,28 @@ jest.mock("uuid", () => ({
|
||||
|
||||
import { BadRequestException } from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { CACHE_MANAGER } from "@nestjs/cache-manager";
|
||||
import { Test, TestingModule } from "@nestjs/testing";
|
||||
import { DatabaseService } from "../database/database.service";
|
||||
import { MediaService } from "../media/media.service";
|
||||
import { S3Service } from "../s3/s3.service";
|
||||
import { ContentsService } from "./contents.service";
|
||||
import { ContentsRepository } from "./repositories/contents.repository";
|
||||
|
||||
describe("ContentsService", () => {
|
||||
let service: ContentsService;
|
||||
let s3Service: S3Service;
|
||||
let mediaService: MediaService;
|
||||
|
||||
const mockDb = {
|
||||
select: jest.fn().mockReturnThis(),
|
||||
from: jest.fn().mockReturnThis(),
|
||||
where: jest.fn().mockReturnThis(),
|
||||
limit: jest.fn().mockReturnThis(),
|
||||
offset: jest.fn().mockReturnThis(),
|
||||
orderBy: jest.fn().mockReturnThis(),
|
||||
innerJoin: jest.fn().mockReturnThis(),
|
||||
insert: jest.fn().mockReturnThis(),
|
||||
values: jest.fn().mockReturnThis(),
|
||||
update: jest.fn().mockReturnThis(),
|
||||
set: jest.fn().mockReturnThis(),
|
||||
returning: jest.fn().mockResolvedValue([]),
|
||||
onConflictDoNothing: jest.fn().mockReturnThis(),
|
||||
transaction: jest.fn().mockImplementation((cb) => cb(mockDb)),
|
||||
execute: jest.fn().mockResolvedValue([]),
|
||||
const mockContentsRepository = {
|
||||
findAll: jest.fn(),
|
||||
count: jest.fn(),
|
||||
create: jest.fn(),
|
||||
incrementViews: jest.fn(),
|
||||
incrementUsage: jest.fn(),
|
||||
softDelete: jest.fn(),
|
||||
findOne: jest.fn(),
|
||||
findBySlug: jest.fn(),
|
||||
};
|
||||
|
||||
const mockS3Service = {
|
||||
@@ -48,46 +43,24 @@ describe("ContentsService", () => {
|
||||
get: jest.fn(),
|
||||
};
|
||||
|
||||
const mockCacheManager = {
|
||||
store: {
|
||||
keys: jest.fn().mockResolvedValue([]),
|
||||
},
|
||||
del: jest.fn(),
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
const chain = {
|
||||
select: jest.fn().mockReturnThis(),
|
||||
from: jest.fn().mockReturnThis(),
|
||||
where: jest.fn().mockReturnThis(),
|
||||
orderBy: jest.fn().mockReturnThis(),
|
||||
limit: jest.fn().mockReturnThis(),
|
||||
offset: jest.fn().mockReturnThis(),
|
||||
innerJoin: jest.fn().mockReturnThis(),
|
||||
insert: jest.fn().mockReturnThis(),
|
||||
values: jest.fn().mockReturnThis(),
|
||||
update: jest.fn().mockReturnThis(),
|
||||
set: jest.fn().mockReturnThis(),
|
||||
returning: jest.fn().mockReturnThis(),
|
||||
onConflictDoNothing: jest.fn().mockReturnThis(),
|
||||
};
|
||||
|
||||
const mockImplementation = () => {
|
||||
return Object.assign(Promise.resolve([]), chain);
|
||||
};
|
||||
|
||||
for (const mock of Object.values(chain)) {
|
||||
|
||||
//TODO Fix : TS2774: This condition will always return true since this function is always defined. Did you mean to call it instead?
|
||||
if (mock.mockReturnValue) {
|
||||
mock.mockImplementation(mockImplementation);
|
||||
}
|
||||
}
|
||||
|
||||
Object.assign(mockDb, chain);
|
||||
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
ContentsService,
|
||||
{ provide: DatabaseService, useValue: { db: mockDb } },
|
||||
{ provide: ContentsRepository, useValue: mockContentsRepository },
|
||||
{ provide: S3Service, useValue: mockS3Service },
|
||||
{ provide: MediaService, useValue: mockMediaService },
|
||||
{ provide: ConfigService, useValue: mockConfigService },
|
||||
{ provide: CACHE_MANAGER, useValue: mockCacheManager },
|
||||
],
|
||||
}).compile();
|
||||
|
||||
@@ -127,7 +100,8 @@ describe("ContentsService", () => {
|
||||
mimeType: "image/webp",
|
||||
size: 500,
|
||||
});
|
||||
mockDb.returning.mockResolvedValue([{ id: "content-id" }]);
|
||||
mockContentsRepository.findBySlug.mockResolvedValue(null);
|
||||
mockContentsRepository.create.mockResolvedValue({ id: "content-id" });
|
||||
|
||||
const result = await service.uploadAndProcess("user1", file, {
|
||||
title: "Meme",
|
||||
@@ -155,8 +129,8 @@ describe("ContentsService", () => {
|
||||
|
||||
describe("findAll", () => {
|
||||
it("should return contents and total count", async () => {
|
||||
mockDb.where.mockResolvedValueOnce([{ count: 10 }]); // for count
|
||||
mockDb.offset.mockResolvedValueOnce([{ id: "1" }]); // for data
|
||||
mockContentsRepository.count.mockResolvedValue(10);
|
||||
mockContentsRepository.findAll.mockResolvedValue([{ id: "1" }]);
|
||||
|
||||
const result = await service.findAll({ limit: 10, offset: 0 });
|
||||
|
||||
@@ -167,9 +141,9 @@ describe("ContentsService", () => {
|
||||
|
||||
describe("incrementViews", () => {
|
||||
it("should increment views", async () => {
|
||||
mockDb.returning.mockResolvedValue([{ id: "1", views: 1 }]);
|
||||
mockContentsRepository.incrementViews.mockResolvedValue([{ id: "1", views: 1 }]);
|
||||
const result = await service.incrementViews("1");
|
||||
expect(mockDb.update).toHaveBeenCalled();
|
||||
expect(mockContentsRepository.incrementViews).toHaveBeenCalledWith("1");
|
||||
expect(result[0].views).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user