diff --git a/sample/10-fastify/e2e/cats.e2e-spec.ts b/sample/10-fastify/e2e/cats.e2e-spec.ts new file mode 100644 index 00000000000..66e6d6cc615 --- /dev/null +++ b/sample/10-fastify/e2e/cats.e2e-spec.ts @@ -0,0 +1,85 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { INestApplication } from '@nestjs/common'; +import * as request from 'supertest'; +import { CatsModule } from '../src/cats/cats.module'; +import { + FastifyAdapter, + NestFastifyApplication, +} from '@nestjs/platform-fastify'; +import { CreateCatDto } from '../src/cats/dto/create-cat.dto'; +import { RolesGuard } from '../src/common/guards/roles.guard'; + +describe('CatsController (e2e)', () => { + let app: INestApplication; + + const mockRolesGuard = { canActivate: () => true }; + + beforeAll(async () => { + const moduleFixture: TestingModule = await Test.createTestingModule({ + imports: [CatsModule], + }) + .overrideGuard(RolesGuard) + .useValue(mockRolesGuard) + .compile(); + + app = moduleFixture.createNestApplication( + new FastifyAdapter(), + ); + + await app.init(); + await app.getHttpAdapter().getInstance().ready(); + }); + + afterAll(async () => { + await app.close(); + }); + + it('/cats (GET) - initial state', () => { + return request(app.getHttpServer()) + .get('/cats') + .expect(200) + .expect([]); + }); + + it('/cats (POST) - create a cat', () => { + const newCatDto: CreateCatDto = { name: 'Milo', age: 2, breed: 'Tabby' }; + const expectedCat = { + id: 1, + ...newCatDto, + }; + + return request(app.getHttpServer()) + .post('/cats') + .send(newCatDto) + .expect(201) + .expect(expectedCat); + }); + + it('/cats (GET) - after create', () => { + const expectedCat = { + id: 1, + name: 'Milo', + age: 2, + breed: 'Tabby', + }; + + return request(app.getHttpServer()) + .get('/cats') + .expect(200) + .expect([expectedCat]); + }); + + it('/cats/:id (GET) - find one', () => { + const expectedCat = { + id: 1, + name: 'Milo', + age: 2, + breed: 'Tabby', + }; + + return request(app.getHttpServer()) + .get('/cats/1') + .expect(200) + .expect(expectedCat); + }); +}); \ No newline at end of file diff --git a/sample/10-fastify/e2e/jest-e2e.json b/sample/10-fastify/e2e/jest-e2e.json new file mode 100644 index 00000000000..ac432d937e1 --- /dev/null +++ b/sample/10-fastify/e2e/jest-e2e.json @@ -0,0 +1,9 @@ +{ + "moduleFileExtensions": ["js", "json", "ts"], + "rootDir": ".", + "testEnvironment": "node", + "testRegex": ".e2e-spec.ts$", + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + } +} \ No newline at end of file diff --git a/sample/10-fastify/jest.config.js b/sample/10-fastify/jest.config.js new file mode 100644 index 00000000000..e4ab2b3118a --- /dev/null +++ b/sample/10-fastify/jest.config.js @@ -0,0 +1,7 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + rootDir: 'src', + testRegex: '.*\\.spec\\.ts$', + moduleFileExtensions: ['js', 'json', 'ts'], +}; \ No newline at end of file diff --git a/sample/10-fastify/package.json b/sample/10-fastify/package.json index 0c938371a2c..e975d5900a0 100644 --- a/sample/10-fastify/package.json +++ b/sample/10-fastify/package.json @@ -16,7 +16,7 @@ "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": "echo 'No e2e tests implemented yet.'" + "test:e2e": "jest --config ./e2e/jest-e2e.json" }, "dependencies": { "@nestjs/common": "11.1.9", @@ -42,7 +42,7 @@ "jest": "30.2.0", "prettier": "3.6.2", "supertest": "7.1.4", - "ts-jest": "29.4.5", + "ts-jest": "^29.4.5", "ts-loader": "9.5.4", "ts-node": "10.9.2", "tsconfig-paths": "4.2.0", diff --git a/sample/10-fastify/src/cats/cats.controller.ts b/sample/10-fastify/src/cats/cats.controller.ts index 2008e3de796..05bdb4f6e0c 100644 --- a/sample/10-fastify/src/cats/cats.controller.ts +++ b/sample/10-fastify/src/cats/cats.controller.ts @@ -1,32 +1,40 @@ -import { Body, Controller, Get, Param, Post, UseGuards } from '@nestjs/common'; -import { Roles } from '../common/decorators/roles.decorator'; -import { RolesGuard } from '../common/guards/roles.guard'; -import { ParseIntPipe } from '../common/pipes/parse-int.pipe'; -import { CatsService } from './cats.service'; +import { + Controller, + Get, + Post, + Body, + Param, + UseGuards, + NotFoundException, +} from '@nestjs/common'; import { CreateCatDto } from './dto/create-cat.dto'; +import { CatsService } from './cats.service'; +import { RolesGuard } from '../common/guards/roles.guard'; +import { Roles } from '../common/decorators/roles.decorator'; import { Cat } from './interfaces/cat.interface'; -@UseGuards(RolesGuard) @Controller('cats') +@UseGuards(RolesGuard) export class CatsController { constructor(private readonly catsService: CatsService) {} @Post() @Roles('admin') - async create(@Body() createCatDto: CreateCatDto) { - this.catsService.create(createCatDto); + create(@Body() createCatDto: CreateCatDto): Cat { + return this.catsService.create(createCatDto); } @Get() - async findAll(): Promise { + findAll(): Cat[] { return this.catsService.findAll(); } @Get(':id') - findOne( - @Param('id', new ParseIntPipe()) - id: number, - ) { - // get by ID logic + findOne(@Param('id') id: string): Cat { + const cat = this.catsService.findOne(+id); + if (!cat) { + throw new NotFoundException(`Cat with ID ${id} not found`); + } + return cat; } -} +} \ No newline at end of file diff --git a/sample/10-fastify/src/cats/cats.service.spec.ts b/sample/10-fastify/src/cats/cats.service.spec.ts new file mode 100644 index 00000000000..177ba5dca0e --- /dev/null +++ b/sample/10-fastify/src/cats/cats.service.spec.ts @@ -0,0 +1,57 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { CatsService } from './cats.service'; +import { Cat } from './interfaces/cat.interface'; +import { CreateCatDto } from './dto/create-cat.dto'; + +describe('CatsService', () => { + let service: CatsService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [CatsService], + }).compile(); + + service = module.get(CatsService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); + + describe('create and findAll', () => { + it('should create a new cat, assign an ID, and return all cats', () => { + const catDto: CreateCatDto = { name: 'Milo', age: 2, breed: 'Tabby' }; + + const createdCat = service.create(catDto); + + expect(createdCat.id).toBe(1); + expect(createdCat.name).toBe('Milo'); + + const allCats = service.findAll(); + + expect(allCats).toHaveLength(1); + expect(allCats).toEqual([createdCat]); + + const catDto2: CreateCatDto = { name: 'Luna', age: 1, breed: 'Siamese' }; + const createdCat2 = service.create(catDto2); + expect(createdCat2.id).toBe(2); + }); + }); + + describe('findOne', () => { + it('should return a single cat by its id', () => { + const catDto: CreateCatDto = { name: 'Luna', age: 1, breed: 'Siamese' }; + const createdCat = service.create(catDto); + + const foundCat = service.findOne(1); + + expect(foundCat).toBeDefined(); + expect(foundCat).toEqual(createdCat); + }); + + it('should return undefined if cat is not found', () => { + const foundCat = service.findOne(999); + expect(foundCat).toBeUndefined(); + }); + }); +}); \ No newline at end of file diff --git a/sample/10-fastify/src/cats/cats.service.ts b/sample/10-fastify/src/cats/cats.service.ts index 2619cd7176d..ab265131cb7 100644 --- a/sample/10-fastify/src/cats/cats.service.ts +++ b/sample/10-fastify/src/cats/cats.service.ts @@ -1,15 +1,27 @@ import { Injectable } from '@nestjs/common'; import { Cat } from './interfaces/cat.interface'; +import { CreateCatDto } from './dto/create-cat.dto'; @Injectable() export class CatsService { private readonly cats: Cat[] = []; + private idCounter = 1; - create(cat: Cat) { - this.cats.push(cat); + create(createCatDto: CreateCatDto): Cat { + const newCat: Cat = { + id: this.idCounter++, + ...createCatDto, + }; + + this.cats.push(newCat); + return newCat; } findAll(): Cat[] { return this.cats; } -} + + findOne(id: number): Cat { + return this.cats.find((cat) => cat.id === id); + } +} \ No newline at end of file diff --git a/sample/10-fastify/src/cats/interfaces/cat.interface.ts b/sample/10-fastify/src/cats/interfaces/cat.interface.ts index b3e66c4b676..1374507c67b 100644 --- a/sample/10-fastify/src/cats/interfaces/cat.interface.ts +++ b/sample/10-fastify/src/cats/interfaces/cat.interface.ts @@ -1,4 +1,5 @@ export interface Cat { + readonly id: number; readonly name: string; readonly age: number; readonly breed: string;