diff --git a/packages/core/manifest/e2e/assets/handlers/basicEndpoint.js b/packages/core/manifest/e2e/assets/handlers/basicEndpoint.js new file mode 100644 index 00000000..7fd2f982 --- /dev/null +++ b/packages/core/manifest/e2e/assets/handlers/basicEndpoint.js @@ -0,0 +1,3 @@ +module.exports = async (req, res) => { + res.json({ hello: 'OK' }) +} diff --git a/packages/core/manifest/e2e/assets/handlers/createDog.js b/packages/core/manifest/e2e/assets/handlers/createDog.js new file mode 100644 index 00000000..bded19e6 --- /dev/null +++ b/packages/core/manifest/e2e/assets/handlers/createDog.js @@ -0,0 +1,5 @@ +module.exports = async (req, res, manifest) => { + const dog = await manifest.from('dogs').create(req.body) + + res.json(dog) +} diff --git a/packages/core/manifest/e2e/assets/mock-backend.yml b/packages/core/manifest/e2e/assets/mock-backend.yml index fbfd44ad..a74d55d6 100644 --- a/packages/core/manifest/e2e/assets/mock-backend.yml +++ b/packages/core/manifest/e2e/assets/mock-backend.yml @@ -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: @@ -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 } @@ -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 diff --git a/packages/core/manifest/e2e/jest.setup.ts b/packages/core/manifest/e2e/jest.setup.ts index 26a736df..48249fa4 100644 --- a/packages/core/manifest/e2e/jest.setup.ts +++ b/packages/core/manifest/e2e/jest.setup.ts @@ -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 @@ -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({ @@ -32,6 +38,10 @@ beforeAll(async () => { ) ) }) + // .overrideProvider(HandlerService) + // .useValue({ + // trigger: jest.fn() + // }) .compile() app = moduleFixture.createNestApplication() diff --git a/packages/core/manifest/e2e/tests/endpoint.e2e-spec.ts b/packages/core/manifest/e2e/tests/endpoint.e2e-spec.ts new file mode 100644 index 00000000..1aa6cd7a --- /dev/null +++ b/packages/core/manifest/e2e/tests/endpoint.e2e-spec.ts @@ -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' }) + }) +}) diff --git a/packages/core/manifest/e2e/tests/open-api.e2e-spec.ts b/packages/core/manifest/e2e/tests/open-api.e2e-spec.ts index a4ab8691..5350d0ba 100644 --- a/packages/core/manifest/e2e/tests/open-api.e2e-spec.ts +++ b/packages/core/manifest/e2e/tests/open-api.e2e-spec.ts @@ -5,19 +5,4 @@ describe('Open API (e2e)', () => { expect(response.status).toBe(200) expect(response.text).toContain('') }) - - 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 - }) }) diff --git a/packages/core/manifest/manifest/backend.yml b/packages/core/manifest/manifest/backend.yml index 6ad44a52..307c7f5c 100644 --- a/packages/core/manifest/manifest/backend.yml +++ b/packages/core/manifest/manifest/backend.yml @@ -52,10 +52,3 @@ endpoints: path: /cats method: GET handler: createCat - policies: - - access: 🔒 - - upvoteCat: - path: /cats/:id/upvote - method: POST - handler: upvoteCat diff --git a/packages/core/manifest/src/endpoint/endpoint.controller.ts b/packages/core/manifest/src/endpoint/endpoint.controller.ts index 26bdf544..ffd86315 100644 --- a/packages/core/manifest/src/endpoint/endpoint.controller.ts +++ b/packages/core/manifest/src/endpoint/endpoint.controller.ts @@ -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 { 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 { 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 { 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 { 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 { 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 { // If no endpoint is found, return 404. if (!req['endpoint']) { throw new HttpException('Route not found', 404) diff --git a/packages/core/manifest/src/endpoint/middlewares/match-endpoint.middleware.ts b/packages/core/manifest/src/endpoint/middlewares/match-endpoint.middleware.ts index bae49011..78ccfd5d 100644 --- a/packages/core/manifest/src/endpoint/middlewares/match-endpoint.middleware.ts +++ b/packages/core/manifest/src/endpoint/middlewares/match-endpoint.middleware.ts @@ -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 })