Skip to content

Commit

Permalink
feat: add integration tests and generate migration schema
Browse files Browse the repository at this point in the history
  • Loading branch information
Mohmn committed Nov 2, 2024
1 parent b1ec1c8 commit c6b5d49
Show file tree
Hide file tree
Showing 17 changed files with 350 additions and 92 deletions.
8 changes: 7 additions & 1 deletion apps/like/__test__/object.spec.ts
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
// This file contains integration tests for the Object Module.
describe.skip('Object Module Integration Tests', () => {
// Tests will be added here in the future.

it('should have tests', () => {
expect(true).toBe(true);
});
});
8 changes: 7 additions & 1 deletion apps/like/__test__/type.spec.ts
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
// This file contains integration tests for the Type module.
describe.skip('Type Module Integration Tests', () => {
// Tests will be added here in the future.

it('should have tests', () => {
expect(true).toBe(true);
});
});
98 changes: 97 additions & 1 deletion apps/like/__test__/user.spec.ts
Original file line number Diff line number Diff line change
@@ -1 +1,97 @@
// This file contains integration tests for the User Module.
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { UserModule } from '../src/user/user.module';
import { PrismaService } from '../src/prisma/prisma.service';
import { DeepMockProxy, mockDeep } from 'jest-mock-extended';
import * as request from 'supertest';
import { randomUUID } from 'crypto';

describe('UserModule (Integration with Prisma Mock)', () => {
let app: INestApplication;
let prismaMock: DeepMockProxy<PrismaService>;
const port = 3000;

beforeAll(async () => {
prismaMock = mockDeep<PrismaService>();

// Inject
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [UserModule],
})
.overrideProvider(PrismaService)
.useValue(prismaMock)
.compile();

app = moduleFixture.createNestApplication();
await app.init();
await app.listen(port)
});

afterAll(async () => {
await app.close();
});

describe('GET /user/:user_uuid/types/:type_uuid', () => {
it('should return mocked user likes', async () => {
const typeId = randomUUID();
const likeId = randomUUID();
const userId = randomUUID();
const objectId = randomUUID()
const mockLikes = [
{
id: likeId,
type_id: typeId,
object_id: objectId,
user_id: userId,
time: new Date(),
active: true,
Type: { id: typeId, name: 'like1' },
},
];

prismaMock.like.findMany.mockResolvedValue(mockLikes);

const response = await request(app.getHttpServer())
.get(`/user/${userId}/types/${typeId}`)
.expect(200);

expect(response.body).toEqual(
mockLikes.map((like) => ({
...like,
time: like.time.toISOString(),
})),
);

expect(prismaMock.like.findMany).toHaveBeenCalledWith({
where: { user_id: userId, type_id: typeId },
include: { Type: true },
});
});

it('should get 400', async () => {
const typeId = randomUUID();
const userId = randomUUID();
const likeId = randomUUID();
const objectId = randomUUID();
const mockLikes = [
{
id: likeId,
type_id: typeId,
object_id: objectId,
user_id: userId,
time: new Date(),
active: true,
Type: { id: typeId, name: 'like1' },
},
];


prismaMock.like.findMany.mockResolvedValue(mockLikes);

await request(app.getHttpServer())
.get(`/user/${userId}/types/${'44'}`)
.expect(400);
});

});
});
11 changes: 10 additions & 1 deletion apps/like/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import { Logger } from '@nestjs/common';
import { Logger, ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { setupSwagger } from '../../../libs/utils/swagger';

async function bootstrap() {
const app = await NestFactory.create(AppModule);
const port = process.env.PORT || 3006;

app.useGlobalPipes(
new ValidationPipe({
whitelist: true, // Strips properties that are not in the DTO
forbidNonWhitelisted: true, // Throws error if any unknown property is present
transform: true, // Automatically transforms query and param strings into appropriate types (like numbers, UUIDs)
}),
);

if (process.env.NODE_ENV !== 'production') {
setupSwagger(app);
}
Expand Down
64 changes: 6 additions & 58 deletions apps/like/src/object/object.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,7 @@
// This file contains the unit tests of the ObjectController class.
describe.skip('Object Module unit test', () => {
// Tests will be added here in the future.

import { Test, TestingModule } from '@nestjs/testing';
import { ObjectController } from './object.controller';
import { ObjectService } from './object.service';

// describe('ObjectController', () => {
// let controller: ObjectController;
// let service: ObjectService;

// beforeEach(async () => {
// const module: TestingModule = await Test.createTestingModule({
// controllers: [ObjectController],
// providers: [ObjectService],
// }).compile();

// controller = module.get<ObjectController>(ObjectController);
// service = module.get<ObjectService>(ObjectService);
// });

// describe('handleGetObjectLikes', () => {
// it('should call the service method to get object likes', async () => {
// const type_id = '1';
// const object_id = '2';

// const serviceSpy = jest.spyOn(service, 'getObjectLikes');

// await controller.handleGetObjectLikes(type_id, object_id);

// expect(serviceSpy).toHaveBeenCalledWith(type_id, object_id);
// });
// });

// describe('handleLikeObject', () => {
// it('should call the service method to like an object', async () => {
// const type_id = '1';
// const object_id = '2';

// const serviceSpy = jest.spyOn(service, 'likeObject');

// await controller.handleLikeObject(type_id, object_id);

// expect(serviceSpy).toHaveBeenCalledWith(type_id, object_id);
// });
// });

// describe('handleUnlikeObject', () => {
// it('should call the service method to unlike an object', async () => {
// const type_id = '1';
// const object_id = '2';

// const serviceSpy = jest.spyOn(service, 'unlikeObject');

// await controller.handleUnlikeObject(type_id, object_id);

// expect(serviceSpy).toHaveBeenCalledWith(type_id, object_id);
// });
// });
// });
it('should have tests', () => {
expect(true).toBe(true);
});
});
12 changes: 10 additions & 2 deletions apps/like/src/prisma/prisma.service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Injectable } from '@nestjs/common';
import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient {
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
constructor(config: ConfigService) {
super({
datasources: {
Expand All @@ -13,4 +13,12 @@ export class PrismaService extends PrismaClient {
},
});
}

async onModuleInit() {
await this.$connect();
}

async onModuleDestroy() {
await this.$disconnect();
}
}
8 changes: 7 additions & 1 deletion apps/like/src/type/type.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
// This file contains unit tests for the TypeController class.
describe.skip('Type Module unit test', () => {
// Tests will be added here in the future.

it('should have tests', () => {
expect(true).toBe(true);
});
});
18 changes: 18 additions & 0 deletions apps/like/src/user/dto/get-user-likes-dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { IsUUID } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';

export class GetUserLikesDto {
@ApiProperty({
description: 'UUID of the user',
example: '550e8400-e29b-41d4-a716-446655440000',
})
@IsUUID()
userUUID: string;

@ApiProperty({
description: 'UUID of the type',
example: 'a65e8400-bf2d-42e1-b723-678655440111',
})
@IsUUID()
typeUUID: string;
}
58 changes: 57 additions & 1 deletion apps/like/src/user/user.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -1 +1,57 @@
// This file contains the unit tests for the UserController class.
import { Test, TestingModule } from '@nestjs/testing';
import { UserController } from './user.controller';
import { UserService } from './user.service';
import { DeepMockProxy, mockDeep } from 'jest-mock-extended'
import { PrismaClient } from '@prisma/client';
import { PrismaService } from '../prisma/prisma.service';
import { randomUUID } from 'crypto';

describe('UserController', () => {
let userController: UserController;
let userService: UserService;
let prismaMock: DeepMockProxy<PrismaClient>;

beforeEach(async () => {
prismaMock = mockDeep<PrismaClient>();
const module: TestingModule = await Test.createTestingModule({
controllers: [UserController],
providers: [
UserService,
{
provide: PrismaService,
useValue: prismaMock,
},
],
}).compile();

userController = module.get<UserController>(UserController);
userService = module.get<UserService>(UserService);
});

describe('handleGetUserLikes', () => {
it('should return user likes', async () => {
const userUUID = randomUUID();
const typeUUID = randomUUID();
const objectUUId = randomUUID()
const result = [
{
id: randomUUID(),
type_id: typeUUID,
object_id: objectUUId,
user_id: userUUID,
time: new Date(),
active: true,
Type: {
id: typeUUID,
name: 'like1',
},
},
];

jest.spyOn(userService, 'getUserLikesOnType').mockResolvedValue(result);

expect(await userController.handleGetUserLikes({ userUUID, typeUUID })).toBe(result);
expect(userService.getUserLikesOnType).toHaveBeenCalledWith({ userUUID, typeUUID });
});
});
});
12 changes: 5 additions & 7 deletions apps/like/src/user/user.controller.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import {
Body,
Controller,
Post,
Get,
Param,
ParseIntPipe,
ValidationPipe,
} from '@nestjs/common';
import { UserService } from './user.service';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { GetUserLikesDto } from './dto/get-user-likes-dto';

@Controller('user')
@ApiTags('user')

export class UserController {
constructor(private userService: UserService) {}

@Get(':user_uuid/types/:type_uuid')
@Get(':userUUID/types/:typeUUID')
@ApiOperation({ summary: 'Get user likes on type by user id' })
@ApiResponse({
status: 200,
Expand All @@ -26,9 +25,8 @@ export class UserController {
description: 'Not Found',
})
async handleGetUserLikes(
@Param('user_uuid') user_uuid: string,
@Param('type_uuid') type_uuid: string
@Param(ValidationPipe) params: GetUserLikesDto,
) {
return this.userService.getUserLikesOnType(user_uuid, type_uuid);
return this.userService.getUserLikesOnType(params);
}
}
Loading

0 comments on commit c6b5d49

Please sign in to comment.