because I got bored of customising my CV for every job

fix(server): remove any types and tighten typings in services/tests

+100 -214
+12 -7
apps/server/src/modules/organization/organization-role.service.ts
··· 1 1 import { Injectable, Logger, NotFoundException } from "@nestjs/common"; 2 2 import { PrismaService } from "../database/prisma.service"; 3 3 import { OrganizationRole } from "./organization-role.entity"; 4 + import { OrganizationRoleMapper } from "./organization-role.mapper"; 4 5 5 6 @Injectable() 6 7 export class OrganizationRoleService { 7 8 private readonly logger = new Logger(OrganizationRoleService.name); 8 9 9 - constructor(private readonly prisma: PrismaService) {} 10 + constructor( 11 + private readonly prisma: PrismaService, 12 + private readonly organizationRoleMapper: OrganizationRoleMapper, 13 + ) {} 10 14 11 15 async findById(id: string): Promise<OrganizationRole | null> { 12 16 this.logger.log(`Finding organization role by id: ${id}`); ··· 15 19 where: { id }, 16 20 }); 17 21 18 - return role ? OrganizationRole.fromDomain(role) : null; 22 + return this.organizationRoleMapper.toDomain(role); 19 23 } 20 24 21 25 async findByIdOrFail(id: string): Promise<OrganizationRole> { ··· 34 38 const roles = await this.prisma["organizationRole"].findMany({ 35 39 orderBy: { name: "asc" }, 36 40 }); 37 - 38 - return roles.map((role: any) => OrganizationRole.fromDomain(role)); 41 + return this.organizationRoleMapper.mapToDomain(roles); 39 42 } 40 43 41 44 async create(data: { ··· 53 56 }, 54 57 }); 55 58 56 - return OrganizationRole.fromDomain(role); 59 + return this.organizationRoleMapper.toDomain(role); 57 60 } 58 61 59 62 async update( ··· 70 73 where: { id }, 71 74 data: { 72 75 ...(data.name !== undefined && { name: data.name }), 73 - ...(data.description !== undefined && { description: data.description }), 76 + ...(data.description !== undefined && { 77 + description: data.description, 78 + }), 74 79 ...(data.color !== undefined && { color: data.color }), 75 80 }, 76 81 }); 77 82 78 - return OrganizationRole.fromDomain(role); 83 + return this.organizationRoleMapper.toDomain(role); 79 84 } 80 85 81 86 async delete(id: string): Promise<boolean> {
+88 -207
apps/server/test/job-experience-integration.e2e-spec.ts
··· 1 1 import type { INestApplication } from "@nestjs/common"; 2 - import { createTestReferenceData, createTestUser, makeAuthenticatedRequest, makeUnauthenticatedRequest, setupTestApp, type TestUser } from "./test-utils"; 3 - import { 4 - CREATE_JOB_EXPERIENCE_MUTATION, 5 - UPDATE_JOB_EXPERIENCE_MUTATION, 6 - DELETE_JOB_EXPERIENCE_MUTATION, 7 - MY_EMPLOYMENT_HISTORY_QUERY, 8 - MY_EMPLOYMENT_HISTORY_SIMPLE_QUERY, 2 + import { 9 3 ALL_COMPANIES_QUERY, 10 - ALL_SKILLS_QUERY, 4 + ALL_LEVELS_QUERY, 11 5 ALL_ROLES_QUERY, 12 - ALL_LEVELS_QUERY 6 + ALL_SKILLS_QUERY, 7 + CREATE_COMPANY_MUTATION, 8 + CREATE_JOB_EXPERIENCE_MUTATION, 9 + DELETE_JOB_EXPERIENCE_MUTATION, 10 + MY_EMPLOYMENT_HISTORY_MINIMAL, 11 + MY_EMPLOYMENT_HISTORY_QUERY, 12 + UPDATE_JOB_EXPERIENCE_DETAILED_MUTATION, 13 13 } from "./queries/load-queries"; 14 + import { 15 + createTestReferenceData, 16 + createTestUser, 17 + makeAuthenticatedRequest, 18 + makeUnauthenticatedRequest, 19 + setupTestApp, 20 + type TestUser, 21 + } from "./test-utils"; 14 22 15 23 describe("Job Experience Integration Tests (e2e)", () => { 16 24 let app: INestApplication; ··· 34 42 35 43 describe("Job Experience Management", () => { 36 44 it("should create a job experience", async () => { 37 - 38 - const response = await makeAuthenticatedRequest(app, testUser.accessToken) 39 - .send({ 40 - query: CREATE_JOB_EXPERIENCE_MUTATION, 41 - variables: { 42 - companyId: referenceData.companyId, 43 - roleId: referenceData.roleId, 44 - levelId: referenceData.levelId, 45 - startDate: "2023-01-01T00:00:00.000Z", 46 - endDate: "2023-12-31T23:59:59.999Z", 47 - description: "Worked on various projects", 48 - skillIds: [referenceData.skillId], 49 - }, 50 - }); 45 + const response = await makeAuthenticatedRequest( 46 + app, 47 + testUser.accessToken, 48 + ).send({ 49 + query: CREATE_JOB_EXPERIENCE_MUTATION, 50 + variables: { 51 + companyId: referenceData.companyId, 52 + roleId: referenceData.roleId, 53 + levelId: referenceData.levelId, 54 + startDate: "2023-01-01T00:00:00.000Z", 55 + endDate: "2023-12-31T23:59:59.999Z", 56 + description: "Worked on various projects", 57 + skillIds: [referenceData.skillId], 58 + }, 59 + }); 51 60 52 61 if (response.status !== 200) { 53 - console.log('Error response:', JSON.stringify(response.body, null, 2)); 54 - console.log('Query:', CREATE_JOB_EXPERIENCE_MUTATION); 55 62 } 56 - 63 + 57 64 expect(response.status).toBe(200); 58 65 59 66 expect(response.body.data.createJobExperience).toBeDefined(); 60 67 expect(response.body.data.createJobExperience.id).toBeDefined(); 61 - expect(response.body.data.createJobExperience.company.id).toBe(referenceData.companyId); 62 - expect(response.body.data.createJobExperience.role.id).toBe(referenceData.roleId); 63 - expect(response.body.data.createJobExperience.level.id).toBe(referenceData.levelId); 68 + expect(response.body.data.createJobExperience.company.id).toBe( 69 + referenceData.companyId, 70 + ); 71 + expect(response.body.data.createJobExperience.role.id).toBe( 72 + referenceData.roleId, 73 + ); 74 + expect(response.body.data.createJobExperience.level.id).toBe( 75 + referenceData.levelId, 76 + ); 64 77 expect(response.body.data.createJobExperience.skills).toHaveLength(1); 65 - expect(response.body.data.createJobExperience.skills[0].id).toBe(referenceData.skillId); 78 + expect(response.body.data.createJobExperience.skills[0].id).toBe( 79 + referenceData.skillId, 80 + ); 66 81 }); 67 82 68 83 it("should retrieve user's employment history", async () => { 69 84 // First create a job experience 70 - const createJobExperienceMutation = ` 71 - mutation CreateJobExperience( 72 - $companyId: String! 73 - $roleId: String! 74 - $levelId: String! 75 - $startDate: DateTime! 76 - ) { 77 - createJobExperience( 78 - companyId: $companyId 79 - roleId: $roleId 80 - levelId: $levelId 81 - startDate: $startDate 82 - ) { 83 - id 84 - } 85 - } 86 - `; 87 - 88 85 await makeAuthenticatedRequest(app, testUser.accessToken) 89 86 .send({ 90 - query: createJobExperienceMutation, 87 + query: CREATE_JOB_EXPERIENCE_MUTATION, 91 88 variables: { 92 89 companyId: referenceData.companyId, 93 90 roleId: referenceData.roleId, ··· 107 104 108 105 expect(response.body.data.myEmploymentHistory).toBeDefined(); 109 106 expect(Array.isArray(response.body.data.myEmploymentHistory)).toBe(true); 110 - expect(response.body.data.myEmploymentHistory.length).toBeGreaterThanOrEqual(1); 111 - 107 + expect( 108 + response.body.data.myEmploymentHistory.length, 109 + ).toBeGreaterThanOrEqual(1); 110 + 112 111 // Find the experience created in the previous test 113 112 const experience = response.body.data.myEmploymentHistory.find( 114 - (exp: any) => exp.company.id === referenceData.companyId 113 + (exp: { 114 + id: string; 115 + company: { id: string }; 116 + role: { id: string }; 117 + level: { id: string }; 118 + }) => exp.company.id === referenceData.companyId, 115 119 ); 116 120 expect(experience).toBeDefined(); 117 121 expect(experience.id).toBeDefined(); ··· 122 126 123 127 it("should update a job experience", async () => { 124 128 // First create a job experience 125 - const createResponse = await makeAuthenticatedRequest(app, testUser.accessToken) 129 + const createResponse = await makeAuthenticatedRequest( 130 + app, 131 + testUser.accessToken, 132 + ) 126 133 .send({ 127 134 query: CREATE_JOB_EXPERIENCE_MUTATION, 128 135 variables: { ··· 137 144 const experienceId = createResponse.body.data.createJobExperience.id; 138 145 139 146 // Create a new company for update 140 - const createNewCompanyMutation = ` 141 - mutation CreateCompany($name: String!) { 142 - createCompany(name: $name) { 143 - id 144 - name 145 - } 146 - } 147 - `; 148 - 149 147 const newCompanyResponse = await makeUnauthenticatedRequest(app) 150 148 .send({ 151 - query: createNewCompanyMutation, 149 + query: CREATE_COMPANY_MUTATION, 152 150 variables: { 153 151 name: `Updated Company ${Date.now()}`, 154 152 }, ··· 158 156 const newCompanyId = newCompanyResponse.body.data.createCompany.id; 159 157 160 158 // Update the job experience 161 - const updateJobExperienceMutation = ` 162 - mutation UpdateJobExperience( 163 - $id: String! 164 - $companyId: String 165 - $description: String 166 - ) { 167 - updateJobExperience( 168 - id: $id 169 - companyId: $companyId 170 - description: $description 171 - ) { 172 - id 173 - description 174 - company { 175 - id 176 - name 177 - } 178 - } 179 - } 180 - `; 181 - 182 159 const response = await makeAuthenticatedRequest(app, testUser.accessToken) 183 160 .send({ 184 - query: updateJobExperienceMutation, 161 + query: UPDATE_JOB_EXPERIENCE_DETAILED_MUTATION, 185 162 variables: { 186 163 id: experienceId, 187 164 companyId: newCompanyId, ··· 192 169 193 170 expect(response.body.data.updateJobExperience).toBeDefined(); 194 171 expect(response.body.data.updateJobExperience.id).toBe(experienceId); 195 - expect(response.body.data.updateJobExperience.company.id).toBe(newCompanyId); 196 - expect(response.body.data.updateJobExperience.description).toBe("Updated description"); 172 + expect(response.body.data.updateJobExperience.company.id).toBe( 173 + newCompanyId, 174 + ); 175 + expect(response.body.data.updateJobExperience.description).toBe( 176 + "Updated description", 177 + ); 197 178 }); 198 179 199 180 it("should delete a job experience", async () => { 200 181 // First create a job experience 201 - const createJobExperienceMutation = ` 202 - mutation CreateJobExperience( 203 - $companyId: String! 204 - $roleId: String! 205 - $levelId: String! 206 - $startDate: DateTime! 207 - ) { 208 - createJobExperience( 209 - companyId: $companyId 210 - roleId: $roleId 211 - levelId: $levelId 212 - startDate: $startDate 213 - ) { 214 - id 215 - } 216 - } 217 - `; 218 - 219 - const createResponse = await makeAuthenticatedRequest(app, testUser.accessToken) 182 + const createResponse = await makeAuthenticatedRequest( 183 + app, 184 + testUser.accessToken, 185 + ) 220 186 .send({ 221 187 query: CREATE_JOB_EXPERIENCE_MUTATION, 222 188 variables: { ··· 231 197 const experienceId = createResponse.body.data.createJobExperience.id; 232 198 233 199 // Delete the job experience 234 - const deleteJobExperienceMutation = ` 235 - mutation DeleteJobExperience($id: String!) { 236 - deleteJobExperience(id: $id) 237 - } 238 - `; 239 - 240 200 const response = await makeAuthenticatedRequest(app, testUser.accessToken) 241 201 .send({ 242 - query: deleteJobExperienceMutation, 202 + query: DELETE_JOB_EXPERIENCE_MUTATION, 243 203 variables: { 244 204 id: experienceId, 245 205 }, ··· 249 209 expect(response.body.data.deleteJobExperience).toBe(true); 250 210 251 211 // Verify it's deleted by checking employment history 252 - const myEmploymentHistoryQuery = ` 253 - query MeJobExperience { 254 - myEmploymentHistory { 255 - id 256 - } 257 - } 258 - `; 259 - 260 - const historyResponse = await makeAuthenticatedRequest(app, testUser.accessToken) 212 + const historyResponse = await makeAuthenticatedRequest( 213 + app, 214 + testUser.accessToken, 215 + ) 261 216 .send({ 262 - query: myEmploymentHistoryQuery, 217 + query: MY_EMPLOYMENT_HISTORY_MINIMAL, 263 218 }) 264 219 .expect(200); 265 220 266 221 // Check that the specific experience was deleted 267 - const deletedExperience = historyResponse.body.data.myEmploymentHistory.find( 268 - (exp: any) => exp.id === experienceId 269 - ); 222 + const deletedExperience = 223 + historyResponse.body.data.myEmploymentHistory.find( 224 + (exp: { id: string }) => exp.id === experienceId, 225 + ); 270 226 expect(deletedExperience).toBeUndefined(); 271 227 }); 272 228 }); 273 229 274 230 describe("Reference Data Queries", () => { 275 231 it("should retrieve all companies", async () => { 276 - const companiesQuery = ` 277 - query Companies { 278 - companies { 279 - id 280 - name 281 - description 282 - website 283 - createdAt 284 - updatedAt 285 - } 286 - } 287 - `; 288 - 289 232 const response = await makeUnauthenticatedRequest(app) 290 233 .send({ 291 - query: companiesQuery, 234 + query: ALL_COMPANIES_QUERY, 292 235 }) 293 236 .expect(200); 294 237 ··· 297 240 }); 298 241 299 242 it("should retrieve all skills", async () => { 300 - const skillsQuery = ` 301 - query Skills { 302 - skills { 303 - id 304 - name 305 - description 306 - createdAt 307 - updatedAt 308 - } 309 - } 310 - `; 311 - 312 243 const response = await makeUnauthenticatedRequest(app) 313 244 .send({ 314 - query: skillsQuery, 245 + query: ALL_SKILLS_QUERY, 315 246 }) 316 247 .expect(200); 317 248 ··· 320 251 }); 321 252 322 253 it("should retrieve all roles", async () => { 323 - const rolesQuery = ` 324 - query Roles { 325 - roles { 326 - id 327 - name 328 - description 329 - createdAt 330 - updatedAt 331 - } 332 - } 333 - `; 334 - 335 254 const response = await makeUnauthenticatedRequest(app) 336 255 .send({ 337 - query: rolesQuery, 256 + query: ALL_ROLES_QUERY, 338 257 }) 339 258 .expect(200); 340 259 ··· 343 262 }); 344 263 345 264 it("should retrieve all levels", async () => { 346 - const levelsQuery = ` 347 - query Levels { 348 - levels { 349 - id 350 - name 351 - description 352 - createdAt 353 - updatedAt 354 - } 355 - } 356 - `; 357 - 358 265 const response = await makeUnauthenticatedRequest(app) 359 266 .send({ 360 - query: levelsQuery, 267 + query: ALL_LEVELS_QUERY, 361 268 }) 362 269 .expect(200); 363 270 ··· 368 275 369 276 describe("Error Handling", () => { 370 277 it("should handle authentication errors for protected endpoints", async () => { 371 - const myEmploymentHistoryQuery = ` 372 - query MeJobExperience { 373 - myEmploymentHistory { 374 - id 375 - } 376 - } 377 - `; 378 - 379 278 const response = await makeUnauthenticatedRequest(app) 380 279 .send({ 381 - query: myEmploymentHistoryQuery, 280 + query: MY_EMPLOYMENT_HISTORY_MINIMAL, 382 281 }) 383 282 .expect(200); 384 283 ··· 387 286 }); 388 287 389 288 it("should handle invalid job experience creation", async () => { 390 - const createJobExperienceMutation = ` 391 - mutation CreateJobExperience( 392 - $companyId: String! 393 - $roleId: String! 394 - $levelId: String! 395 - $startDate: DateTime! 396 - ) { 397 - createJobExperience( 398 - companyId: $companyId 399 - roleId: $roleId 400 - levelId: $levelId 401 - startDate: $startDate 402 - ) { 403 - id 404 - } 405 - } 406 - `; 407 - 408 289 const response = await makeAuthenticatedRequest(app, testUser.accessToken) 409 290 .send({ 410 - query: createJobExperienceMutation, 291 + query: CREATE_JOB_EXPERIENCE_MUTATION, 411 292 variables: { 412 293 companyId: "invalid-id", 413 294 roleId: "invalid-id",