From f633a17613aef394e32af50d58ef50c0da21e733 Mon Sep 17 00:00:00 2001 From: "sebastian.mota" Date: Thu, 24 Oct 2024 02:02:09 +0200 Subject: [PATCH] chore(tdd-test) Initial commit --- backend/src/test/tests-smg.test.ts | 114 +++++++++++++++++++++++++++++ prompts/smg-promtps.md | 96 ++++++++++++++++++++++++ 2 files changed, 210 insertions(+) create mode 100644 backend/src/test/tests-smg.test.ts create mode 100644 prompts/smg-promtps.md diff --git a/backend/src/test/tests-smg.test.ts b/backend/src/test/tests-smg.test.ts new file mode 100644 index 0000000..d95ca31 --- /dev/null +++ b/backend/src/test/tests-smg.test.ts @@ -0,0 +1,114 @@ +import { addCandidate } from '../application/services/candidateService'; +import { Candidate } from '../domain/models/Candidate'; +import { validateCandidateData } from '../application/validator'; +import { Education } from '../domain/models/Education'; +import { WorkExperience } from '../domain/models/WorkExperience'; +import { Resume } from '../domain/models/Resume'; + +jest.mock('../domain/models/Candidate'); +jest.mock('../application/validator'); +jest.mock('../domain/models/Education'); +jest.mock('../domain/models/WorkExperience'); +jest.mock('../domain/models/Resume'); + +describe('addCandidate', () => { + const candidateData = { + name: 'John Doe', + email: 'john.doe@example.com', + educations: [{ degree: 'B.Sc', institution: 'University' }], + workExperiences: [{ company: 'Company', role: 'Developer' }], + cv: { fileName: 'resume.pdf', fileContent: '...' } + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should throw an error if validation fails', async () => { + (validateCandidateData as jest.Mock).mockImplementation(() => { + throw new Error('Validation Error'); + }); + + await expect(addCandidate(candidateData)).rejects.toThrow('Validation Error'); + }); + + it('should save candidate and related data successfully', async () => { + // Mock validateCandidateData to resolve successfully + + + const result = await addCandidate(candidateData); + + expect(Candidate.prototype.save).toHaveBeenCalled(); + expect(Education.prototype.save).toHaveBeenCalled(); + expect(WorkExperience.prototype.save).toHaveBeenCalled(); + expect(Resume.prototype.save).toHaveBeenCalled(); + }); + + it('should throw an error if unique constraint fails', async () => { + (Candidate.prototype.save as jest.Mock).mockImplementation(() => { + const error = new Error('Unique constraint failed'); + (error as any).code = 'P2002'; + throw error; + }); + + await expect(addCandidate(candidateData)).rejects.toThrow('The email already exists in the database'); + }); + + it('should throw a general error', async () => { + (Candidate.prototype.save as jest.Mock).mockImplementation(() => { + throw new Error('General Error'); + }); + + await expect(addCandidate(candidateData)).rejects.toThrow('General Error'); + }); + + it('should handle empty education and work experience arrays', async () => { + const candidateDataWithoutEducationAndExperience = { + ...candidateData, + educations: [], + workExperiences: [] + }; + + (validateCandidateData as jest.Mock).mockImplementation(() => true); + + const savedCandidate = { id: '123', ...candidateDataWithoutEducationAndExperience, education: [], workExperience: [], resumes: [] }; + (Candidate.prototype.save as jest.Mock).mockResolvedValue(savedCandidate); + + const savedResume = { id: '101', ...candidateData.cv }; + (Resume.prototype.save as jest.Mock).mockResolvedValue(savedResume); + + const result = await addCandidate(candidateDataWithoutEducationAndExperience); + + expect(result).toEqual(savedCandidate); + expect(Candidate.prototype.save).toHaveBeenCalled(); + expect(Education.prototype.save).not.toHaveBeenCalled(); + expect(WorkExperience.prototype.save).not.toHaveBeenCalled(); + expect(Resume.prototype.save).toHaveBeenCalled(); + }); + + it('should handle missing CV', async () => { + const candidateDataWithoutCV = { + ...candidateData, + cv: null + }; + + (validateCandidateData as jest.Mock).mockImplementation(() => true); + + const savedCandidate = { id: '123', ...candidateDataWithoutCV, education: [], workExperience: [], resumes: [] }; + (Candidate.prototype.save as jest.Mock).mockResolvedValue(savedCandidate); + + const savedEducation = { id: '456', ...candidateData.educations[0] }; + (Education.prototype.save as jest.Mock).mockResolvedValue(savedEducation); + + const savedExperience = { id: '789', ...candidateData.workExperiences[0] }; + (WorkExperience.prototype.save as jest.Mock).mockResolvedValue(savedExperience); + + const result = await addCandidate(candidateDataWithoutCV); + + expect(result).toEqual(savedCandidate); + expect(Candidate.prototype.save).toHaveBeenCalled(); + expect(Education.prototype.save).toHaveBeenCalled(); + expect(WorkExperience.prototype.save).toHaveBeenCalled(); + expect(Resume.prototype.save).not.toHaveBeenCalled(); + }); +}); \ No newline at end of file diff --git a/prompts/smg-promtps.md b/prompts/smg-promtps.md new file mode 100644 index 0000000..f655cb7 --- /dev/null +++ b/prompts/smg-promtps.md @@ -0,0 +1,96 @@ +# Prompt 1 +@workspace /tests +Hi copilot! Today I need you as my expert assistant in TypeScript and Jest! I need to create all the unit tests possible for my application. Please explain each test and how to launch them. Note that this is a TypeScript file, so follow best practices for this technology. + +# Prompt 2 +Most of the test cases are working, but only one is failing. Could you fix it? + +# Prompt 3 +The test continues failing due to the error: +**TypeError**: Cannot read properties of undefined (reading 'push') + +# Prompt 4 +Lets review the first test failing. +addCandidate › should handle missing CV +Has the following output +``` +TypeError: Cannot read properties of undefined (reading 'push') + + 42 | resumeModel.candidateId = candidateId; + 43 | await resumeModel.save(); + > 44 | candidate.resumes.push(resumeModel); + | ^ + 45 | } + 46 | return savedCandidate; + 47 | } catch (error: any) { + + at src/application/services/candidateService.ts:44:31 + at step (src/application/services/candidateService.ts:33:23) + at Object.next (src/application/services/candidateService.ts:14:53) + at fulfilled (src/application/services/candidateService.ts:5:58) +``` +# Response +Copilot suggest me change code to initialize arrays to empty but it **is not a right solution**. +Adding here the response because **/backend/src/application/services/candidateService.ts** was modified. +``` +import { Candidate } from '../../domain/models/Candidate'; +import { validateCandidateData } from '../validator'; +import { Education } from '../../domain/models/Education'; +import { WorkExperience } from '../../domain/models/WorkExperience'; +import { Resume } from '../../domain/models/Resume'; + +export const addCandidate = async (candidateData: any) => { + try { + validateCandidateData(candidateData); // Validar los datos del candidato + } catch (error: any) { + throw new Error(error); + } + + const candidate = new Candidate(candidateData); // Crear una instancia del modelo Candidate + candidate.education = []; + candidate.workExperience = []; + candidate.resumes = []; + + try { + const savedCandidate = await candidate.save(); // Guardar el candidato en la base de datos + const candidateId = savedCandidate.id; // Obtener el ID del candidato guardado + + // Guardar la educación del candidato + if (candidateData.educations) { + for (const education of candidateData.educations) { + const educationModel = new Education(education); + educationModel.candidateId = candidateId; + await educationModel.save(); + candidate.education.push(educationModel); + } + } + + // Guardar la experiencia laboral del candidato + if (candidateData.workExperiences) { + for (const experience of candidateData.workExperiences) { + const experienceModel = new WorkExperience(experience); + experienceModel.candidateId = candidateId; + await experienceModel.save(); + candidate.workExperience.push(experienceModel); + } + } + + // Guardar los archivos de CV + if (candidateData.cv && Object.keys(candidateData.cv).length > 0) { + const resumeModel = new Resume(candidateData.cv); + resumeModel.candidateId = candidateId; + await resumeModel.save(); + candidate.resumes.push(resumeModel); + } + return savedCandidate; + } catch (error: any) { + if (error.code === 'P2002') { + // Unique constraint failed on the fields: (`email`) + throw new Error('The email already exists in the database'); + } else { + throw error; + } + } +}; +``` +