Skip to content

Commit

Permalink
test: CRUD unit tests for availability
Browse files Browse the repository at this point in the history
  • Loading branch information
markdeluk authored and AlbertoBaroso committed Apr 9, 2024
1 parent f39f041 commit 789e246
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 43 deletions.
52 changes: 51 additions & 1 deletion api/src/availability/availability.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { testDate } from '@mocks/data';
import { mockAvailability, testDate } from '@mocks/data';
import { AvailabilityController } from './availability.controller';
import { AvailabilityService } from './availability.service';
import { TestBed } from '@automock/jest';
Expand Down Expand Up @@ -26,4 +26,54 @@ describe('AvailabilityController', () => {
expect(controller).toBeDefined();
expect(service).toBeDefined();
});

// CRUD OPERATIONS

describe('createAvailability', () => {
it('should allow creating a valid availability', async () => {
const availability = {
state: mockAvailability.state,
lastModified: mockAvailability.lastModified,
timeSlot: mockAvailability.timeSlot,
user: mockAvailability.user,
};

jest
.spyOn(service, 'createAvailability')
.mockResolvedValue(mockAvailability);

const result = await controller.createAvailability(availability);

expect(result).toEqual(mockAvailability);
});
});

// Read an availability
describe('findAvailabilityById', () => {
it('should allow finding an availability by id', async () => {
jest
.spyOn(service, 'findAvailabilityById')
.mockResolvedValue(mockAvailability);

const result = await controller.findAvailabilityById(mockAvailability.id);

expect(result).toEqual(mockAvailability);
});
});

// Delete an availability
describe('deleteAvailability', () => {
it('should allow deleting an availability', async () => {
jest
.spyOn(service, 'findAvailabilityById')
.mockResolvedValue(mockAvailability);
jest
.spyOn(service, 'deleteAvailability')
.mockResolvedValue(mockAvailability);

await expect(
controller.deleteAvailability(mockAvailability.id),
).resolves.toEqual(mockAvailability);
});
});
});
36 changes: 14 additions & 22 deletions api/src/availability/availability.controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {
BadRequestException,
Body,
Controller,
Delete,
Expand All @@ -12,7 +11,6 @@ import {
import { AvailabilityService } from './availability.service';
import {
Action,
checkAbility,
insertAvailabilitySchema,
updateAvailabilitySchema,
} from '@hkrecruitment/shared';
Expand All @@ -25,13 +23,13 @@ import {
ApiCreatedResponse,
ApiOkResponse,
ApiTags,
ApiConflictResponse,
ApiNoContentResponse,
ApiBadGatewayResponse,
} from '@nestjs/swagger';
import { CheckPolicies } from 'src/authorization/check-policies.decorator';
import { Availability } from './availability.entity';
import Joi from 'joi';
import { CreateAvailabilityDto } from './create-availability.dto';

@ApiBearerAuth()
@ApiTags('availability')
Expand Down Expand Up @@ -76,10 +74,12 @@ export class AvailabilityController {
@JoiValidate({
body: insertAvailabilitySchema,
})
async createAvailability(@Body() body: Availability): Promise<boolean> {
async createAvailability(
@Body() body: CreateAvailabilityDto,
): Promise<Availability> {
const res = await this.availabilityService.createAvailability(body);
if (res.identifiers.length > 0) {
return true;
if (res) {
return res;
} else {
throw new ForbiddenException();
}
Expand All @@ -95,16 +95,12 @@ export class AvailabilityController {
@JoiValidate({
body: updateAvailabilitySchema,
})
async updateAvailability(@Body() body: Availability): Promise<boolean> {
async updateAvailability(@Body() body: Availability): Promise<Availability> {
const test = await this.findAvailabilityById(body.id);
if (test) {
const res = await this.availabilityService.updateAvailability(body);
if (
res.affected != undefined &&
res.affected != null &&
res.affected > 0
) {
return true;
const res = await this.availabilityService.updateAvailability(test, body);
if (res) {
return res;
} else {
throw new ForbiddenException();
}
Expand All @@ -123,16 +119,12 @@ export class AvailabilityController {
@JoiValidate({
param: Joi.number().positive().integer().required(),
})
async deleteAvailability(@Param() id: number): Promise<boolean> {
async deleteAvailability(@Param() id: number): Promise<Availability> {
const test = await this.findAvailabilityById(id);
if (test) {
const res = await this.availabilityService.deleteAvailability(id);
if (
res.affected != undefined &&
res.affected != null &&
res.affected > 0
) {
return true;
const res = await this.availabilityService.deleteAvailability(test);
if (res) {
return res;
} else {
throw new ForbiddenException();
}
Expand Down
1 change: 0 additions & 1 deletion api/src/availability/availability.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
Entity,
JoinColumn,
ManyToOne,
OneToOne,
PrimaryGeneratedColumn,
} from 'typeorm';
import {
Expand Down
46 changes: 45 additions & 1 deletion api/src/availability/availability.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { testDate } from '@mocks/data';
import { mockAvailability, testDate } from '@mocks/data';
import { Test, TestingModule } from '@nestjs/testing';
import { AvailabilityService } from './availability.service';
import { Availability } from './availability.entity';
Expand Down Expand Up @@ -37,4 +37,48 @@ describe('AvailabilityService', () => {
it('should be defined', () => {
expect(service).toBeDefined();
});

// CRUD OPERATIONS

describe('createAvailability', () => {
it('should create a new availability', async () => {
jest.spyOn(mockedRepository, 'save').mockResolvedValue(mockAvailability);
const result = await service.createAvailability(mockAvailability);
expect(result).toEqual(mockAvailability);
expect(mockedRepository.save).toHaveBeenCalledTimes(1);
});
});

describe('deleteAvailability', () => {
it('should remove the specified availability from the database', async () => {
jest
.spyOn(mockedRepository, 'remove')
.mockResolvedValue(mockAvailability);
const result = await service.deleteAvailability(mockAvailability);
expect(result).toEqual(mockAvailability);
expect(mockedRepository.remove).toHaveBeenCalledTimes(1);
});
});

describe('listAvailabilities', () => {
it('should return all availabilities', async () => {
jest
.spyOn(mockedRepository, 'find')
.mockResolvedValue([mockAvailability]);
const result = await service.listAvailabilities();
expect(result).toEqual([mockAvailability]);
expect(mockedRepository.find).toHaveBeenCalledTimes(1);
});
});

describe('findAvailabilityById', () => {
it('should return the availability with the specified id', async () => {
jest
.spyOn(mockedRepository, 'findBy')
.mockResolvedValue([mockAvailability]);
const result = await service.findAvailabilityById(mockAvailability.id);
expect(result).toEqual(mockAvailability);
expect(mockedRepository.findBy).toHaveBeenCalledTimes(1);
});
});
});
24 changes: 14 additions & 10 deletions api/src/availability/availability.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { DeleteResult, InsertResult, Repository, UpdateResult } from 'typeorm';
import { Repository } from 'typeorm';
import { Availability } from './availability.entity';
import { CreateAvailabilityDto } from './create-availability.dto';

@Injectable()
export class AvailabilityService {
Expand All @@ -21,18 +22,21 @@ export class AvailabilityService {
return matches.length > 0 ? matches[0] : null;
}

async createAvailability(availability: Availability): Promise<InsertResult> {
return await this.availabilityRepository.insert(availability);
async createAvailability(
availability: CreateAvailabilityDto,
): Promise<Availability> {
return await this.availabilityRepository.save(availability);
}

async updateAvailability(availability: Availability): Promise<UpdateResult> {
return await this.availabilityRepository.update(
availability.id,
availability,
);
async updateAvailability(
oldAvailability: Availability,
newAvailability: Availability,
): Promise<Availability> {
await this.availabilityRepository.remove(oldAvailability);
return await this.availabilityRepository.save(newAvailability);
}

async deleteAvailability(id: number): Promise<DeleteResult> {
return await this.availabilityRepository.delete(id);
async deleteAvailability(availability: Availability): Promise<Availability> {
return await this.availabilityRepository.remove(availability);
}
}
18 changes: 18 additions & 0 deletions api/src/availability/create-availability.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {
Availability,
AvailabilityState,
TimeSlot,
} from '@hkrecruitment/shared';
import { ApiProperty } from '@nestjs/swagger';
import { User } from 'src/users/user.entity';

export class CreateAvailabilityDto implements Availability {
@ApiProperty()
state: AvailabilityState;
@ApiProperty()
lastModified: Date;
@ApiProperty()
timeSlot: TimeSlot;
@ApiProperty()
user: User;
}
9 changes: 9 additions & 0 deletions api/src/mocks/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
ApplicationState,
LangLevel,
Role,
AvailabilityState,
} from '@hkrecruitment/shared';
import {
BscApplication,
Expand Down Expand Up @@ -156,3 +157,11 @@ export const applicantId = 'abc123';
export const folderId = 'folder_abc123';
export const fileId = 'file_abc123';
export const today = '1/1/2023, 10:00:00';

export const mockAvailability = {
id: 1,
state: AvailabilityState.Confirmed,
lastModified: new Date(),
timeSlot: mockTimeSlot,
user: applicant,
};
7 changes: 1 addition & 6 deletions api/src/timeslots/timeslots.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { TestBed } from '@automock/jest';
import {
mockTimeSlot,
testDate,
testDateTimeEnd,
testDateTimeStart,
} from '@mocks/data';
import { mockTimeSlot, testDateTimeEnd, testDateTimeStart } from '@mocks/data';
import { TimeSlotsController } from './timeslots.controller';
import { TimeSlotsService } from './timeslots.service';
import { testDateTime10Minutes } from '@mocks/data';
Expand Down
2 changes: 0 additions & 2 deletions shared/src/availability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ export enum AvailabilityType {
}

export interface Availability {
id: number;
state: AvailabilityState;
lastModified: Date;
timeSlot: TimeSlot;
Expand All @@ -37,7 +36,6 @@ export const insertAvailabilitySchema = Joi.object<Availability>({
});

export const updateAvailabilitySchema = Joi.object<Availability>({
id: Joi.number().positive().integer().required(),
state: Joi.string()
.valid(...Object.values(AvailabilityType))
.required(),
Expand Down

0 comments on commit 789e246

Please sign in to comment.