Skip to content

Commit

Permalink
tests(e2e): endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
brunobuddy committed Jan 31, 2025
1 parent c57af2c commit 8812a33
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 31 deletions.
3 changes: 3 additions & 0 deletions packages/core/manifest/e2e/assets/handlers/basicEndpoint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = async (req, res) => {
res.json({ hello: 'OK' })
}
5 changes: 5 additions & 0 deletions packages/core/manifest/e2e/assets/handlers/createDog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = async (req, res, manifest) => {
const dog = await manifest.from('dogs').create(req.body)

res.json(dog)
}
18 changes: 16 additions & 2 deletions packages/core/manifest/e2e/assets/mock-backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#
# Please do not modify it unless you know what you are doing.

name: 'mock-backend-for-e2e-tests'
name: "mock-backend-for-e2e-tests"
entities:
Owner:
properties:
Expand Down Expand Up @@ -100,7 +100,7 @@ entities:
- brand
- { name: year, type: number, validation: { min: 2000 } }
validation:
model: { contains: 'turbo' }
model: { contains: "turbo" }
brand: { minLength: 3, maxLength: 20 }
year: { min: 2023, max: 2024, isOptional: true }

Expand Down Expand Up @@ -201,3 +201,17 @@ entities:
- { name: content, type: text }
validation:
title: { required: true }

# Testing endpoints
endpoints:
basicEndpoint:
path: /basic
description: A basic endpoint that returns a simple message.
method: GET
handler: basicEndpoint

createDog:
path: /create-dog
description: A basic endpoint that creates a dog with the backend SDK.
method: POST
handler: createDog
10 changes: 10 additions & 0 deletions packages/core/manifest/e2e/jest.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import fs from 'fs'
import { SwaggerModule } from '@nestjs/swagger'
import { OpenApiService } from '../src/open-api/services/open-api.service'
import { SeederService } from '../src/seed/services/seeder.service'
import path from 'path'

let app: INestApplication

Expand All @@ -17,6 +18,11 @@ beforeAll(async () => {
process.env.DB_DATABASE = ':memory:'
process.env.DB_DROP_SCHEMA = 'true'
process.env.TOKEN_SECRET_KEY = 'test'
process.env.MANIFEST_HANDLERS_FOLDER = path.join(
__dirname,
'assets',
'handlers'
)

// Start the NestJS application mocking some services.
const moduleFixture: TestingModule = await Test.createTestingModule({
Expand All @@ -32,6 +38,10 @@ beforeAll(async () => {
)
)
})
// .overrideProvider(HandlerService)
// .useValue({
// trigger: jest.fn()
// })
.compile()

app = moduleFixture.createNestApplication()
Expand Down
24 changes: 24 additions & 0 deletions packages/core/manifest/e2e/tests/endpoint.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
describe('Endpoints (e2e)', () => {
beforeEach(() => {})

it('should trigger an endpoint', async () => {
const response = await global.request
.get('/endpoints/basic')
.expect(JSON.stringify({ hello: 'OK' }))

expect(response.status).toBe(200)
})

it('should throw a 404 if no endpoint is found', async () => {
await global.request.get('/endpoints/unknown').expect(404)
})

it('should integrate the backend SDK into handlers', async () => {
const response = await global.request
.post('/endpoints/create-dog')
.send({ name: 'Rex' })

expect(response.status).toBe(201)
expect(response.body).toMatchObject({ name: 'Rex' })
})
})
15 changes: 0 additions & 15 deletions packages/core/manifest/e2e/tests/open-api.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,4 @@ describe('Open API (e2e)', () => {
expect(response.status).toBe(200)
expect(response.text).toContain('<html lang="en">')
})

it('Should generate a doc for each entity', async () => {
// TODO: Implement.
return false
})

it('Should generate an auth system for admins', async () => {
// TODO: Implement.
return false
})

it('Should generate an auth system for authenticable entities', async () => {
// TODO: Implement.
return false
})
})
7 changes: 0 additions & 7 deletions packages/core/manifest/manifest/backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,3 @@ endpoints:
path: /cats
method: GET
handler: createCat
policies:
- access: 🔒

upvoteCat:
path: /cats/:id/upvote
method: POST
handler: upvoteCat
27 changes: 21 additions & 6 deletions packages/core/manifest/src/endpoint/endpoint.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,38 +23,53 @@ export class EndpointController {

@Get('*')
@Rule('dynamic-endpoint') // The dynamic-endpoint rule is based on policies individually set for each endpoint.
triggerGetEndpoint(@Req() req: Request, @Res() res: Response): unknown {
triggerGetEndpoint(
@Req() req: Request,
@Res() res: Response
): Promise<unknown> {
return this.handleRoute(req, res)
}

@Post('*')
@Rule('dynamic-endpoint')
triggerPostEndpoint(@Req() req: Request, @Res() res: Response): unknown {
triggerPostEndpoint(
@Req() req: Request,
@Res() res: Response
): Promise<unknown> {
return this.handleRoute(req, res)
}

@Put('*')
@Rule('dynamic-endpoint')
triggerPutEndpoint(@Req() req: Request, @Res() res: Response): unknown {
triggerPutEndpoint(
@Req() req: Request,
@Res() res: Response
): Promise<unknown> {
return this.handleRoute(req, res)
}

@Patch('*')
@Rule('dynamic-endpoint')
triggerPatchEndpoint(@Req() req: Request, @Res() res: Response): unknown {
triggerPatchEndpoint(
@Req() req: Request,
@Res() res: Response
): Promise<unknown> {
return this.handleRoute(req, res)
}

@Delete('*')
@Rule('dynamic-endpoint')
triggerDeleteEndpoint(@Req() req: Request, @Res() res: Response): unknown {
triggerDeleteEndpoint(
@Req() req: Request,
@Res() res: Response
): Promise<unknown> {
return this.handleRoute(req, res)
}

/**
* All the routes lead to Rome.
*/
private handleRoute(req: Request, res: Response): unknown {
private async handleRoute(req: Request, res: Response): Promise<unknown> {
// If no endpoint is found, return 404.
if (!req['endpoint']) {
throw new HttpException('Route not found', 404)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ export class MatchEndpointMiddleware implements NestMiddleware {

use(req: Request, res: Response, next: () => void) {
const { endpoint, params } = this.endpointService.matchRoutePath({
path: req.path.replace(`/${API_PATH}/${ENDPOINTS_PATH}`, ''),
path: req.path
.replace(`/${API_PATH}`, '')
.replace(`/${ENDPOINTS_PATH}`, ''),
method: req.method as HttpMethod,
endpoints: this.manifestService.getAppManifest().endpoints
})
Expand Down

0 comments on commit 8812a33

Please sign in to comment.