Skip to content

Commit

Permalink
Fix: refactored tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Villarley committed Dec 22, 2024
1 parent 23e83a8 commit bbd937e
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 122 deletions.
108 changes: 50 additions & 58 deletions src/services/User.service.ts
Original file line number Diff line number Diff line change
@@ -1,66 +1,58 @@
import { QueryFailedError, Repository } from "typeorm";
import { Repository } from "typeorm";
import { User } from "../entities/User";
import { DataSource } from "typeorm";

import AppDataSource from "../config/ormconfig";

export class UserService {
private userRepository: Repository<User>;

constructor(dataSource: DataSource) {
this.userRepository = dataSource.getRepository(User);
}

async createUser(data: Partial<User>): Promise<User> {

try {
const user = this.userRepository.create(data);
return await this.userRepository.save(user);
} catch (error) {
if (error instanceof QueryFailedError && error.message.includes("UNIQUE constraint failed")) {
throw new Error("The wallet address is already in use. Please use a unique wallet address.");
}
if (error.code === '23505' || error.code === 'SQLITE_CONSTRAINT') { // Handle unique constraint errors
if (error.message.includes('UQ_fc71cd6fb73f95244b23e2ef113')) {
throw new Error('The wallet address is already in use. Please use a unique wallet address.');
}
}
throw error;
private userRepository: Repository<User>;

constructor() {
this.userRepository = AppDataSource.getRepository(User);
}

async createUser(data: Partial<User>): Promise<User> {
try {
const user = this.userRepository.create(data);
return await this.userRepository.save(user);
} catch (error: any) {
if (error.code === "23505" || error.code === "SQLITE_CONSTRAINT") {
if (error.message.includes("UQ_fc71cd6fb73f95244b23e2ef113")) {
throw new Error("The wallet address is already in use. Please use a unique wallet address.");
}

}

async getUserById(id: number): Promise<User | null> {
return await this.userRepository.findOneBy({ id });
}
throw error;
}

async updateUser(id: number, data: Partial<User>): Promise<User | null> {
try {
await this.userRepository.update(id, data);
return await this.getUserById(id);
} catch (error) {
if (error.code === '23505' || error.code === 'SQLITE_CONSTRAINT') { // Handle unique constraint errors
if (error.message.includes('UQ_fc71cd6fb73f95244b23e2ef113')) {
throw new Error('The wallet address is already in use. Please use a unique wallet address.');
}
}

if (error.code === '23505' || error.code === 'SQLITE_CONSTRAINT') { // Handle unique constraint errors
if (error.message.includes('UQ_fc71cd6fb73f95244b23e2ef113')) {
throw new Error('The wallet address is already in use. Please use a unique wallet address.');
}
}
throw error;
}

async getUserById(id: number): Promise<User | null> {
return await this.userRepository.findOneBy({ id });
}

async updateUser(id: number, data: Partial<User>): Promise<User | null> {
try {
const user = await this.userRepository.findOneBy({ id });
if (!user) {
return null;
}

Object.assign(user, data);

return await this.userRepository.save(user);
} catch (error: any) {
if (error.code === "23505" || error.code === "SQLITE_CONSTRAINT") {
if (error.message.includes("UQ_fc71cd6fb73f95244b23e2ef113")) {
throw new Error("The wallet address is already in use. Please use a unique wallet address.");
}
}
throw error;
}

async deleteUser(id: number): Promise<boolean> {
const result = await this.userRepository.delete(id);
return result.affected === 1;
}

async getAllUsers(): Promise<User[]> {
return await this.userRepository.find();
}
}

async deleteUser(id: number): Promise<boolean> {
const result = await this.userRepository.delete(id);
return result.affected === 1;
}

async getAllUsers(): Promise<User[]> {
return await this.userRepository.find();
}
}

export default UserService;
6 changes: 3 additions & 3 deletions src/services/test.service.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Repository } from "typeorm";
import { TestEntity } from "../entities/testEntity";
import { DataSource } from "typeorm";
import AppDataSource from "../config/ormconfig";

export class TestService {
private repo: Repository<TestEntity>;

constructor(dataSource: DataSource) {
this.repo = dataSource.getRepository(TestEntity);
constructor() {
this.repo = AppDataSource.getRepository(TestEntity);
}

async getEntityByName(name: string): Promise<TestEntity | null> {
Expand Down
42 changes: 30 additions & 12 deletions src/tests/services/testService.spec.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,54 @@
import { setupTestDB, teardownTestDB } from "../../utils/test-utils";
import { Repository } from "typeorm";
import AppDataSource from "../../config/ormconfig";
import { TestService } from "../../services/test.service";
import { TestEntity } from "../../entities/testEntity";

jest.mock("../../config/ormconfig", () => ({
getRepository: jest.fn(),
}));

describe("TestService", () => {
let service: TestService;
let mockRepo: jest.Mocked<Repository<TestEntity>>;

beforeAll(async () => {
await setupTestDB();
service = new TestService(AppDataSource);
beforeEach(() => {
jest.clearAllMocks();

const repo = AppDataSource.getRepository(TestEntity);
await repo.save({ name: "Existing Entity" });
});
mockRepo = {
find: jest.fn(),
findOneBy: jest.fn(),
save: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
} as unknown as jest.Mocked<Repository<TestEntity>>;

(AppDataSource.getRepository as jest.Mock).mockReturnValue(mockRepo);

afterAll(async () => {
await teardownTestDB();
service = new TestService();
});

it("should return true if the entity exists", async () => {
mockRepo.findOneBy.mockResolvedValue({ id: 1, name: "Existing Entity" } as TestEntity);

const result = await service.validateEntityExists("Existing Entity");
expect(result).toBe(true);
expect(mockRepo.findOneBy).toHaveBeenCalledWith({ name: "Existing Entity" });
});

it("should return false if the entity does not exist", async () => {
mockRepo.findOneBy.mockResolvedValue(null);

const result = await service.validateEntityExists("Nonexistent Entity");
expect(result).toBe(false);
expect(mockRepo.findOneBy).toHaveBeenCalledWith({ name: "Nonexistent Entity" });
});

it("should retrieve an entity by name", async () => {
const entity = await service.getEntityByName("Existing Entity");
expect(entity).toBeDefined();
expect(entity?.name).toBe("Existing Entity");
const entity = { id: 1, name: "Existing Entity" } as TestEntity;
mockRepo.findOneBy.mockResolvedValue(entity);

const result = await service.getEntityByName("Existing Entity");
expect(result).toEqual(entity);
expect(mockRepo.findOneBy).toHaveBeenCalledWith({ name: "Existing Entity" });
});
});
107 changes: 68 additions & 39 deletions src/tests/services/userService.spec.ts
Original file line number Diff line number Diff line change
@@ -1,87 +1,116 @@
import { setupTestDB, teardownTestDB } from "../../utils/test-utils";
import { Repository } from "typeorm";
import AppDataSource from "../../config/ormconfig";
import { UserService } from "../../services/User.service";
import { User } from "../../entities/User";

jest.mock("../../config/ormconfig", () => ({
getRepository: jest.fn(),
}));

describe("UserService", () => {
let service: UserService;
let mockRepo: jest.Mocked<Repository<User>>;

beforeAll(async () => {
await setupTestDB();
service = new UserService(AppDataSource);
beforeEach(() => {
jest.clearAllMocks();

const userRepo = AppDataSource.getRepository(User);
await userRepo.save({
name: "Existing User",
email: "[email protected]",
walletAddress: "0x06D97198756295A96C2158a23963306f507b2f69",
role: "buyer" as "buyer", // Explicit type cast
});
});
mockRepo = {
find: jest.fn(),
findOneBy: jest.fn(),
save: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
update: jest.fn(),
} as unknown as jest.Mocked<Repository<User>>;

(AppDataSource.getRepository as jest.Mock).mockReturnValue(mockRepo);

afterAll(async () => {
await teardownTestDB();
service = new UserService();
});

it("should create a new user", async () => {
const newUser: Partial<User> = {
name: "New User",
email: "[email protected]",
walletAddress: "0x07D97198756295A96C2158a23963306f507b2f70",
role: "buyer", // Ensure it's a valid value
role: "buyer",
};

const createdUser = await service.createUser(newUser);
expect(createdUser).toBeDefined();
expect(createdUser.name).toBe("New User");
expect(createdUser.email).toBe("[email protected]");
const createdUser = { id: 1, ...newUser } as User;
mockRepo.create.mockReturnValue(createdUser);
mockRepo.save.mockResolvedValue(createdUser);

const result = await service.createUser(newUser);
expect(result).toEqual(createdUser);
expect(mockRepo.create).toHaveBeenCalledWith(newUser);
expect(mockRepo.save).toHaveBeenCalledWith(createdUser);
});

it("should not create a user with a duplicate wallet address", async () => {
const duplicateUser: Partial<User> = {
name: "Duplicate User",
email: "[email protected]",
walletAddress: "0x06D97198756295A96C2158a23963306f507b2f69", // Same as pre-populated wallet address
role: "buyer", // Ensure it's a valid value
walletAddress: "0x06D97198756295A96C2158a23963306f507b2f69",
role: "buyer",
};

const error = new Error("The wallet address is already in use. Please use a unique wallet address.") as any;
error.code = "SQLITE_CONSTRAINT";
mockRepo.save.mockRejectedValue(error);

await expect(service.createUser(duplicateUser)).rejects.toThrowError(
"The wallet address is already in use. Please use a unique wallet address."
);
});

it("should retrieve an existing user by ID", async () => {
const userRepo = AppDataSource.getRepository(User);
const user = await userRepo.findOne({ where: { email: "[email protected]" } });
const user = { id: 1, name: "Existing User", email: "[email protected]" } as User;
mockRepo.findOneBy.mockResolvedValue(user);

const fetchedUser = await service.getUserById(user?.id || 0);
expect(fetchedUser).toBeDefined();
expect(fetchedUser?.email).toBe("[email protected]");
const result = await service.getUserById(1);
expect(result).toEqual(user);
expect(mockRepo.findOneBy).toHaveBeenCalledWith({ id: 1 });
});

it("should return null if the user does not exist", async () => {
const nonExistentUser = await service.getUserById(9999);
expect(nonExistentUser).toBeNull();
mockRepo.findOneBy.mockResolvedValue(null);

const result = await service.getUserById(9999);
expect(result).toBeNull();
expect(mockRepo.findOneBy).toHaveBeenCalledWith({ id: 9999 });
});

it("should update a user's information", async () => {
const userRepo = AppDataSource.getRepository(User);
const user = await userRepo.findOne({ where: { email: "[email protected]" } });
const user = { id: 1, name: "Existing User", email: "[email protected]" } as User;
const updatedData = { name: "Updated User" };
const updatedUser = { ...user, ...updatedData } as User;

mockRepo.findOneBy.mockResolvedValue(user);
mockRepo.save.mockResolvedValue(updatedUser);

const updatedUser = await service.updateUser(user?.id || 0, { name: "Updated User" });
expect(updatedUser).toBeDefined();
expect(updatedUser?.name).toBe("Updated User");
const result = await service.updateUser(1, updatedData);
expect(result).toEqual(updatedUser);
expect(mockRepo.save).toHaveBeenCalledWith({ ...user, ...updatedData });
});

it("should delete a user", async () => {
const userRepo = AppDataSource.getRepository(User);
const user = await userRepo.findOne({ where: { email: "[email protected]" } });
mockRepo.delete.mockResolvedValue({ affected: 1 } as any);

const result = await service.deleteUser(1);
expect(result).toBe(true);
expect(mockRepo.delete).toHaveBeenCalledWith(1);
});

it("should retrieve all users", async () => {
const users = [
{ id: 1, name: "User 1", email: "[email protected]" },
{ id: 2, name: "User 2", email: "[email protected]" },
] as User[];

const success = await service.deleteUser(user?.id || 0);
expect(success).toBe(true);
mockRepo.find.mockResolvedValue(users);

const deletedUser = await userRepo.findOne({ where: { email: "[email protected]" } });
expect(deletedUser).toBeNull();
const result = await service.getAllUsers();
expect(result).toEqual(users);
expect(mockRepo.find).toHaveBeenCalled();
});
});
28 changes: 18 additions & 10 deletions src/utils/test-utils.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import testDataSource from "../config/ormconfig.test";
import AppDataSource from "../config/ormconfig";

export const setupTestDB = async () => {
if (!testDataSource.isInitialized) {
await testDataSource.initialize();
export async function setupTestDB() {
console.log("Initializing database...");
if (!AppDataSource.isInitialized) {
await AppDataSource.initialize();
console.log("Database initialized.");
}
await testDataSource.synchronize(true); // Sync
};
export const teardownTestDB = async () => {
if (testDataSource.isInitialized) {
await testDataSource.destroy();

console.log("Synchronizing database...");
await AppDataSource.synchronize(true); // Forzar sincronización
console.log("Database synchronized.");
}

export async function teardownTestDB() {
console.log("Destroying database...");
if (AppDataSource.isInitialized) {
await AppDataSource.destroy();
console.log("Database destroyed.");
}
};
}

0 comments on commit bbd937e

Please sign in to comment.