Skip to content

Commit

Permalink
[M1_TR-198] Backend for M1_TR-8
Browse files Browse the repository at this point in the history
  • Loading branch information
NiloJr-sun committed Sep 22, 2023
1 parent 4c6b7d1 commit c51181b
Show file tree
Hide file tree
Showing 23 changed files with 898 additions and 81 deletions.
1 change: 1 addition & 0 deletions server/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ lerna-debug.log*

# Keep environment variables out of version control
.env
/test
23 changes: 19 additions & 4 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/swagger": "^7.1.10",
"@prisma/client": "^5.1.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"dotenv": "^16.3.1",
"jest-junit": "^16.0.0",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1"
"rxjs": "^7.8.1",
"typeorm": "^0.3.17"
},
"devDependencies": {
"@nestjs/cli": "^10.0.0",
Expand Down Expand Up @@ -70,14 +73,26 @@
"**/*.{js,ts}"
],
"coverageDirectory": "../test/coverage",
"coverageReporters": ["clover", "json", "lcov", "text"],
"coverageReporters": [
"clover",
"json",
"lcov",
"text"
],
"testEnvironment": "node",
"reporters": [
"default",
["jest-junit", {"outputDirectory": "./test/result", "outputName": "report.xml"}]
[
"jest-junit",
{
"outputDirectory": "./test/result",
"outputName": "report.xml"
}
]
]
},
"prisma": {
"schema": "./src/models/schema.prisma"
"schema": "./src/models/schema.prisma",
"seed": "ts-node ./src/models/seeder.ts"
}
}
71 changes: 71 additions & 0 deletions server/src/api/jobs/dto/update-job.dto.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { validate } from "class-validator";
import { plainToClass } from "class-transformer";
import { UpdateJobDto } from "./update-job.dto";
import { PaymentMethod } from "../../../utils/constants/enums/paymentMethodEnums";

describe("UpdateJobDto", () => {
describe("Validation", () => {
it("should validate a valid UpdateJobDto", async () => {
const validData: UpdateJobDto = {
customer_registration: {
firstName: "John",
lastName: "Cena",
contact: "1234567890",
email: "[email protected]",
address: "123 Main St",
},
job_information: {
title: "Fix Plumbing",
type: "Plumbing",
tags: ["TAG_A", "TAG_B", "TAG_C"],
remarks: "Fix leaky faucet",
customerId: 19,
paymentMethod: PaymentMethod.CARD,
userId: 5,
},
work_schedule: [
{
id: 1,
startDate: "2024-10-01T00:00:00Z",
startTime: "2023-09-01T08:32:22.345Z",
endDate: "2024-09-01T00:00:00Z",
endTime: "2023-09-01T08:32:22.345Z",
},
],
};

const dto = plainToClass(UpdateJobDto, validData);
const errors = await validate(dto);
expect(errors.length).toEqual(0);
});

it("should not validate an invalid CreateJobDto", async () => {
const invalidData = {
customer_registration: {
firstName: "",
lastNam: "Doe",
contact: "1234567890",
email: "[email protected]",
address: "123 Main St",
},
job_information: {
title: "Software Engineer",
type: "Full-time",
personInChargeId: 1,
tagId: 2,
paymentMethodId: "2",
},
work_schedule: {
startDate: "2023-09-01",
startTime: "09:00 AM",
endDate: "2023-09-01",
endTime: "05:00 PM",
},
};

const dto = plainToClass(UpdateJobDto, invalidData);
const errors = await validate(dto);
expect(errors.length).toBeGreaterThan(0);
});
});
});
121 changes: 121 additions & 0 deletions server/src/api/jobs/dto/update-job.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { ApiProperty } from "@nestjs/swagger";
import {
IsInt,
IsEnum,
IsEmail,
IsArray,
IsString,
IsNotEmpty,
IsOptional,
IsDateString,
ValidateNested,
IsMobilePhone,
} from "class-validator";
import {
JobInfoDetails,
CustomerInfoDetails,
WorkscheduleInfoDetails,
} from "../../../utils/constants/apiPropertyValues";
import { Type } from "class-transformer";
import { PaymentMethod } from "../../../utils/constants/enums/paymentMethodEnums";
import { Tag } from "@prisma/client";

export class CustomerRegistration {
@IsNotEmpty()
@IsString()
firstName: string;

@IsNotEmpty()
@IsString()
lastName: string;

@IsNotEmpty()
@IsString()
@IsMobilePhone()
contact: string;

@IsNotEmpty()
@IsEmail()
email: string;

@IsNotEmpty()
@IsString()
address: string;
}

export class JobInformation {
@IsNotEmpty()
@IsInt()
customerId: number;

@IsNotEmpty()
@IsString()
title: string;

@IsNotEmpty()
@IsString()
type: string;

@IsNotEmpty()
@IsInt()
userId: number;

@ApiProperty({ enum: Tag })
@IsArray()
@IsEnum(Tag, { each: true })
readonly tags: Tag[];

@IsOptional()
@IsString()
remarks: string;

@ApiProperty({ enum: PaymentMethod })
@IsEnum(PaymentMethod)
readonly paymentMethod: PaymentMethod;
}

export class WorkSchedule {
@IsNotEmpty()
@IsInt()
id: number;

@IsNotEmpty()
@IsDateString()
startDate: string;

@IsNotEmpty()
@IsString()
startTime: string;

@IsNotEmpty()
@IsDateString()
endDate: string;

@IsNotEmpty()
@IsString()
endTime: string;
}
[];

export class UpdateJobDto {
@ApiProperty({
example: CustomerInfoDetails,
})
@ValidateNested()
@Type(() => CustomerRegistration)
customer_registration: CustomerRegistration;

@ApiProperty({
example: JobInfoDetails,
})
@ValidateNested()
@Type(() => JobInformation)
job_information: JobInformation;

@ApiProperty({
example: WorkscheduleInfoDetails,
})
@ValidateNested()
@Type(() => WorkSchedule)
work_schedule: WorkSchedule[];
}
100 changes: 100 additions & 0 deletions server/src/api/jobs/jobs.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { NotFoundException } from "@nestjs/common";
import { JobsController } from "./jobs.controller";
import { UpdateJobDto } from "./dto/update-job.dto";
import { Test, TestingModule } from "@nestjs/testing";
import { JobsService } from "../../services/jobs/jobs.service";
import { Tag } from "../../utils/constants/enums/tagEnums";
import { PrismaService } from "../../database/connection.service";
import { PaymentMethod } from "../../utils/constants/enums/paymentMethodEnums";

describe("JobsController", () => {
let jobsController: JobsController;
let jobsService: JobsService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [JobsController],
providers: [JobsService, PrismaService],
}).compile();

jobsController = module.get<JobsController>(JobsController);
jobsService = module.get<JobsService>(JobsService);
});
describe("update", () => {
it("should update a job and return success message", async () => {
// Arrange
const id = 1;
const successMessage = "Updated job information";
const updateJobDto: UpdateJobDto = {
customer_registration: {
firstName: "John",
lastName: "Cena",
contact: "1234567890",
email: "[email protected]",
address: "123 Main St",
},
job_information: {
title: "Fix Plumbing",
type: "Plumbing",
tags: ["TAG_A", "TAG_B", "TAG_C"],
remarks: "Fix leaky faucet",
customerId: 19,
paymentMethod: PaymentMethod.CARD,
userId: 5,
},
work_schedule: [
{
id: 1,
startDate: "2024-10-01T00:00:00Z",
startTime: "2023-09-01T08:32:22.345Z",
endDate: "2024-09-01T00:00:00Z",
endTime: "2023-09-01T08:32:22.345Z",
},
],
};

// Mock the update method of the jobsService to resolve with success message
jest.spyOn(jobsService, "update").mockResolvedValue(successMessage);

// Act
const result = await jobsController.update(id, updateJobDto);

// Assert
expect(result).toEqual(successMessage);
expect(jobsService.update).toHaveBeenCalledWith(id, updateJobDto);
});

it("should handle job not found and throw NotFoundException", async () => {
// Arrange
const id = 1;
const updateJobDto: UpdateJobDto = {
customer_registration: {
firstName: "",
lastName: "",
contact: "",
email: "",
address: "",
},
job_information: {
customerId: 0,
title: "",
type: "",
userId: 0,
tags: [Tag.TAG_A],
remarks: "",
paymentMethod: PaymentMethod.CARD,
},
work_schedule: [],
};
// Mock the update method to reject with NotFoundException
jest
.spyOn(jobsService, "update")
.mockRejectedValue(new NotFoundException("Job not found"));

// Act & Assert
await expect(
jobsController.update(id, updateJobDto),
).rejects.toThrowError(NotFoundException);
expect(jobsService.update).toHaveBeenCalledWith(id, updateJobDto);
});
});
});
16 changes: 16 additions & 0 deletions server/src/api/jobs/jobs.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { UpdateJobDto } from "./dto/update-job.dto";
import { ApiCreatedResponse, ApiTags } from "@nestjs/swagger";
import { Controller, Body, Patch, Param } from "@nestjs/common";
import { JobsService } from "../../services/jobs/jobs.service";

@Controller("jobs")
@ApiTags("jobs")
export class JobsController {
constructor(private readonly jobsService: JobsService) {}

@Patch(":id")
@ApiCreatedResponse()
update(@Param("id") id: number, @Body() updateJobDto: UpdateJobDto) {
return this.jobsService.update(+id, updateJobDto);
}
}
10 changes: 10 additions & 0 deletions server/src/api/jobs/jobs.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Module } from "@nestjs/common";
import { JobsController } from "./jobs.controller";
import { JobsService } from "src/services/jobs/jobs.service";
import { PrismaService } from "src/database/connection.service";

@Module({
controllers: [JobsController],
providers: [JobsService, PrismaService],
})
export class JobsModule {}
18 changes: 0 additions & 18 deletions server/src/api/sample/sample.controller.spec.ts

This file was deleted.

Loading

0 comments on commit c51181b

Please sign in to comment.