Skip to content

Commit

Permalink
test: add test cases for new feature
Browse files Browse the repository at this point in the history
  • Loading branch information
nikkegg committed Aug 14, 2023
1 parent 01950b7 commit 13d8c0e
Showing 1 changed file with 261 additions and 0 deletions.
261 changes: 261 additions & 0 deletions test/user-original-url.router.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
import { expect } from 'chai';
import type {
Express,
IRouter,
Response,
NextFunction,
Request,
} from 'express';
import * as express from 'express';
import { OpenAPIV3 } from '../src/framework/types';
import * as request from 'supertest';
import { createApp } from './common/app';

import * as OpenApiValidator from '../src';
import { Server } from 'http';

interface HTTPError extends Error {
status: number;
text: string;
method: string;
path: string;
}

describe('when useRequestUrl is set to "true" on the child router', async () => {
let app: Express & { server?: Server };

before(async () => {
const router = makeRouter({ useRequestUrl: true });
app = await makeMainApp();
app.use(router);
});

after(() => app?.server?.close());

it('should apply parent app schema to requests', async () => {
const result = await request(app).get('/api/pets/1');
const error = result.error as HTTPError;
expect(result.statusCode).to.equal(400);
expect(error.path).to.equal('/api/pets/1');
expect(error.text).to.contain(
'Bad Request: request/params/petId must NOT have fewer than 3 characters',
);
});

it('should apply child router schema to requests', async () => {
const result = await request(app).get('/api/pets/not-uuid');
const error = result.error as HTTPError;
expect(result.statusCode).to.equal(400);
expect(error.path).to.equal('/api/pets/not-uuid');
expect(error.text).to.contain(
'Bad Request: request/params/petId must match format "uuid&quot',
);
});
});

describe('when useRequestUrl is set to "false" on the child router', async () => {
let app: Express & { server?: Server };

before(async () => {
const router = makeRouter({ useRequestUrl: false });
app = await makeMainApp();
app.use(router);
});

after(() => app?.server?.close());

it('should throw not found', async () => {
const result = await request(app).get('/api/pets/valid-pet-id');
const error = result.error as HTTPError;
expect(result.statusCode).to.equal(404);
expect(error.path).to.equal('/api/pets/valid-pet-id');
expect(error.text).to.contain('Not Found');
});
});

function defaultResponse(): OpenAPIV3.ResponseObject {
return {
description: 'unexpected error',
content: {
'application/json': {
schema: {
type: 'object',
required: ['code', 'message'],
properties: {
code: {
type: 'integer',
format: 'int32',
},
message: {
type: 'string',
},
},
},
},
},
};
}

/*
represents spec of the "public" entrypoint to our application e.g gateway. The
type of id in path and id in the response here defined as simple string
with minLength
*/
const gatewaySpec: OpenAPIV3.Document = {
openapi: '3.0.0',
info: { version: '1.0.0', title: 'test bug OpenApiValidator' },
servers: [{ url: 'http://localhost:3000/api' }],
paths: {
'/pets/{petId}': {
get: {
summary: 'Info for a specific pet',
operationId: 'showPetById',
tags: ['pets'],
parameters: [
{
name: 'petId',
in: 'path',
required: true,
description: 'The id of the pet to retrieve',
schema: {
type: 'string',
minLength: 3,
},
},
],
responses: {
'200': {
description: 'Expected response to a valid request',
content: {
'application/json': {
schema: {
type: 'object',
required: ['id', 'name'],
properties: {
id: {
type: 'string',
},
name: {
type: 'string',
},
tag: {
type: 'string',
},
},
},
},
},
},
default: defaultResponse(),
},
},
},
},
};

/*
represents spec of the child router. We route request from main app (gateway) to this router.
This router has its own schema, routes and validation formats. In particular, we force id in the path and id in the response to be uuid.
*/
const childRouterSpec: OpenAPIV3.Document = {
openapi: '3.0.0',
info: { version: '1.0.0', title: 'test bug OpenApiValidator' },
servers: [{ url: 'http://localhost:3000/' }],
paths: {
'/internal/api/pets/{petId}': {
get: {
summary: 'Info for a specific pet',
operationId: 'showPetById',
tags: ['pets'],
parameters: [
{
name: 'petId',
in: 'path',
required: true,
description: 'The id of the pet to retrieve',
schema: {
type: 'string',
format: 'uuid',
},
},
],
responses: {
'200': {
description: 'Expected response to a valid request',
content: {
'application/json': {
schema: {
type: 'object',
required: ['id', 'name'],
properties: {
id: {
type: 'string',
format: 'uuid',
},
name: {
type: 'string',
},
tag: {
type: 'string',
},
},
},
},
},
},
},
},
},
},
};

function redirectToInternalService(
req: Request,
_res: Response,
next: NextFunction,
): void {
req.url = `/internal${req.originalUrl}`;
next();
}

function makeMainApp(): ReturnType<typeof createApp> {
return createApp(
{
apiSpec: gatewaySpec,
validateResponses: true,
validateRequests: true,
},
3000,
(app) => {
app
.get(
'/api/pets/:petId',
function (_req: Request, _res: Response, next: NextFunction) {
next();
},
)
.use(redirectToInternalService);
},
false,
);
}

function makeRouter({ useRequestUrl }: { useRequestUrl: boolean }): IRouter {
return express
.Router()
.use(
OpenApiValidator.middleware({
apiSpec: childRouterSpec,
validateRequests: true,
validateResponses: true,
useRequestUrl,
}),
)
.get('/internal/api/pets/:petId', function (req, res) {
res.json({
id: req.params.petId,
name: 'Mr Sparky',
tag: "Ain't nobody tags me",
});
});
}

0 comments on commit 13d8c0e

Please sign in to comment.