Skip to content

Commit

Permalink
[M1_TR-214] Backend for M1_TR-211
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoleamber committed Sep 8, 2023
1 parent 4c6b7d1 commit 57d63ec
Show file tree
Hide file tree
Showing 25 changed files with 671 additions and 62 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
6 changes: 5 additions & 1 deletion server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
"test:e2e": "jest --config ./test/jest-e2e.json",
"seed": "ts-node src/models/seed.ts"
},
"dependencies": {
"@nestjs/common": "^10.0.0",
Expand All @@ -31,10 +32,13 @@
"rxjs": "^7.8.1"
},
"devDependencies": {
"@faker-js/faker": "^8.0.2",
"@nestjs/cli": "^10.0.0",
"@nestjs/schematics": "^10.0.0",
"@nestjs/swagger": "^7.1.10",
"@nestjs/testing": "^10.0.0",
"@types/express": "^4.17.17",
"@types/faker": "^6.6.9",
"@types/jest": "^29.5.2",
"@types/node": "^20.3.1",
"@types/supertest": "^2.0.12",
Expand Down
10 changes: 10 additions & 0 deletions server/src/api/jobs/dto/job-list.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ApiProperty } from '@nestjs/swagger';
import { Job } from '@prisma/client';

export class JobListDto {
@ApiProperty()
jobs: Job[];

@ApiProperty()
count: number;
}
16 changes: 16 additions & 0 deletions server/src/api/jobs/dto/job-query.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ApiProperty } from '@nestjs/swagger';
import { Transform } from 'class-transformer';
import { IsNumber, IsOptional } from 'class-validator';

export class JobQueryDto {
@ApiProperty()
@IsNumber()
@Transform(({ value }) => parseInt(value))
page: number;

@ApiProperty({ required: false})
@IsOptional()
@IsNumber()
@Transform(({ value }) => parseInt(value))
perPage?: number;
}
69 changes: 69 additions & 0 deletions server/src/api/jobs/jobs.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Test, TestingModule } from '@nestjs/testing';
import { JobsController } from './jobs.controller';
import { JobsService } from './jobs.service';

describe('JobsController', () => {
let jobController: JobsController;

const mockJobService = {
findAll: jest.fn()
};

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [JobsController],
providers: [
{
provide: JobsService,
useValue: mockJobService,
},
],
}).compile();

jobController = module.get<JobsController>(JobsController);
});

describe('findAll', () => {
it('should return a list of jobs with the total number of jobs', async () => {
const jobQuery = { page: 1, perPage: 2 };
const jobList = {
jobs: [
{
id: 1,
title: "Job A",
type: "Type A",
tags: [],
remarks: null,
customerId: 1,
paymentMethod: null,
userId: 1,
pipelinePhase: null,
createdAt: new Date("2023-09-07T09:38:42.296Z"),
updatedAt: new Date("2023-09-07T09:38:42.296Z"),
},
{
id: 2,
title: "Job B",
type: "Type B",
tags: [],
remarks: null,
customerId: 2,
paymentMethod: null,
userId: 2,
pipelinePhase: null,
createdAt: new Date("2023-09-07T09:38:42.296Z"),
updatedAt: new Date("2023-09-07T09:38:42.296Z"),
}
],
count: 2
};

jest.spyOn(mockJobService, 'findAll').mockResolvedValue(jobList);

const jobs = await jobController.findAll(jobQuery);

expect(mockJobService.findAll).toHaveBeenCalledWith(jobQuery);
expect(jobs).toEqual(jobList);
});
});
});
19 changes: 19 additions & 0 deletions server/src/api/jobs/jobs.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Controller, Get, Query, UsePipes, ValidationPipe } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { JobListDto } from './dto/job-list.dto';
import { JobQueryDto } from './dto/job-query.dto';
import { JobsService } from './jobs.service';

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

@Get()
@UsePipes(new ValidationPipe({ transform: true }))
async findAll(@Query() jobQuery: JobQueryDto): Promise<JobListDto> {
const jobs = await this.jobsService.findAll(jobQuery);

return jobs;
}
}
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 { PrismaService } from 'src/database/connection.service';
import { JobsController } from './jobs.controller';
import { JobsService } from './jobs.service';

@Module({
controllers: [JobsController],
providers: [JobsService, PrismaService],
})
export class JobsModule {}
70 changes: 70 additions & 0 deletions server/src/api/jobs/jobs.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Test, TestingModule } from '@nestjs/testing';
import { PrismaService } from '../../database/connection.service';
import { JobsService } from './jobs.service';

describe('JobsService', () => {
let jobService: JobsService;

const mockPrismaService = {
job: {
findMany: jest.fn(),
count: jest.fn(),
},
$transaction: jest.fn()
};

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
JobsService,
{
provide: PrismaService,
useValue: mockPrismaService
}
],
}).compile();

jobService = module.get<JobsService>(JobsService);
});

describe('findAll', () => {
it('should be return a list of jobs with the total number of jobs', async () => {
const jobQuery = { page: 1, perPage: 2 };
const mockJobList = [
{
id: 1,
title: "Job A",
type: "Type A",
tags: [],
remarks: null,
customerId: 1,
paymentMethod: null,
userId: 1,
pipelinePhase: null,
createdAt: new Date("2023-09-07T09:38:42.296Z"),
updatedAt: new Date("2023-09-07T09:38:42.296Z"),
},
{
id: 2,
title: "Job B",
type: "Type B",
tags: [],
remarks: null,
customerId: 2,
paymentMethod: null,
userId: 2,
pipelinePhase: null,
createdAt: new Date("2023-09-07T09:38:42.296Z"),
updatedAt: new Date("2023-09-07T09:38:42.296Z"),
}
];
const mockJobCount = 2;

mockPrismaService.$transaction.mockResolvedValue([ mockJobList, mockJobCount ]);

const jobs = await jobService.findAll(jobQuery);

expect(jobs).toEqual({ jobs: mockJobList, count: mockJobCount });
});
});
});
56 changes: 56 additions & 0 deletions server/src/api/jobs/jobs.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { BadRequestException, Injectable } from '@nestjs/common';
import { PrismaService } from '../../database/connection.service';
import { JobListDto } from './dto/job-list.dto';
import { JobQueryDto } from './dto/job-query.dto';

@Injectable()
export class JobsService {
constructor(private prisma: PrismaService){}

async findAll(query: JobQueryDto): Promise<JobListDto> {
try {
const { page, perPage = 12 } = query;
const skip = (page - 1) * perPage;

const [ jobs, count ] = await this.prisma.$transaction([
this.prisma.job.findMany({
take: perPage,
skip,
include: {
customer: {
select: {
firstName: true,
lastName: true,
}
},
schedules: {
select: {
startDate: true,
startTime: true,
endDate: true,
endTime: true
}
},
estimation: {
select: {
status: true,
totalCost: true,
}
},
personInCharge: {
select: {
firstName: true,
lastName: true
}
}
}
}),
this.prisma.job.count()
]);

return { jobs, count };
} catch (err) {
throw new BadRequestException('Something went wrong.');
}
}
}
18 changes: 0 additions & 18 deletions server/src/api/sample/sample.controller.spec.ts

This file was deleted.

9 changes: 0 additions & 9 deletions server/src/api/sample/sample.controller.ts

This file was deleted.

11 changes: 0 additions & 11 deletions server/src/api/sample/sample.dto.ts

This file was deleted.

7 changes: 0 additions & 7 deletions server/src/api/sample/sample.entities.ts

This file was deleted.

6 changes: 3 additions & 3 deletions server/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Module } from '@nestjs/common';
import { JobsModule } from './api/jobs/jobs.module';
import { DatabaseModule } from './database/database.module';
import { SampleController } from './api/sample/sample.controller';

@Module({
imports: [DatabaseModule],
controllers: [SampleController],
imports: [DatabaseModule, JobsModule],
controllers: [],
providers: [],
})
export class AppModule {}
11 changes: 11 additions & 0 deletions server/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import { NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app.module';

async function bootstrap() {
const app = await NestFactory.create(AppModule);

const config = new DocumentBuilder()
.setTitle('Sim-JMS')
.setDescription('This is the API documentation for sim-jms')
.setVersion('1.0')
.build();

const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);

await app.listen(4000);
}
bootstrap();
Loading

0 comments on commit 57d63ec

Please sign in to comment.