Skip to content

Commit 13d8c0e

Browse files
author
nikkegg
committed
test: add test cases for new feature
1 parent 01950b7 commit 13d8c0e

File tree

1 file changed

+261
-0
lines changed

1 file changed

+261
-0
lines changed

test/user-original-url.router.spec.ts

+261
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
import { expect } from 'chai';
2+
import type {
3+
Express,
4+
IRouter,
5+
Response,
6+
NextFunction,
7+
Request,
8+
} from 'express';
9+
import * as express from 'express';
10+
import { OpenAPIV3 } from '../src/framework/types';
11+
import * as request from 'supertest';
12+
import { createApp } from './common/app';
13+
14+
import * as OpenApiValidator from '../src';
15+
import { Server } from 'http';
16+
17+
interface HTTPError extends Error {
18+
status: number;
19+
text: string;
20+
method: string;
21+
path: string;
22+
}
23+
24+
describe('when useRequestUrl is set to "true" on the child router', async () => {
25+
let app: Express & { server?: Server };
26+
27+
before(async () => {
28+
const router = makeRouter({ useRequestUrl: true });
29+
app = await makeMainApp();
30+
app.use(router);
31+
});
32+
33+
after(() => app?.server?.close());
34+
35+
it('should apply parent app schema to requests', async () => {
36+
const result = await request(app).get('/api/pets/1');
37+
const error = result.error as HTTPError;
38+
expect(result.statusCode).to.equal(400);
39+
expect(error.path).to.equal('/api/pets/1');
40+
expect(error.text).to.contain(
41+
'Bad Request: request/params/petId must NOT have fewer than 3 characters',
42+
);
43+
});
44+
45+
it('should apply child router schema to requests', async () => {
46+
const result = await request(app).get('/api/pets/not-uuid');
47+
const error = result.error as HTTPError;
48+
expect(result.statusCode).to.equal(400);
49+
expect(error.path).to.equal('/api/pets/not-uuid');
50+
expect(error.text).to.contain(
51+
'Bad Request: request/params/petId must match format "uuid&quot',
52+
);
53+
});
54+
});
55+
56+
describe('when useRequestUrl is set to "false" on the child router', async () => {
57+
let app: Express & { server?: Server };
58+
59+
before(async () => {
60+
const router = makeRouter({ useRequestUrl: false });
61+
app = await makeMainApp();
62+
app.use(router);
63+
});
64+
65+
after(() => app?.server?.close());
66+
67+
it('should throw not found', async () => {
68+
const result = await request(app).get('/api/pets/valid-pet-id');
69+
const error = result.error as HTTPError;
70+
expect(result.statusCode).to.equal(404);
71+
expect(error.path).to.equal('/api/pets/valid-pet-id');
72+
expect(error.text).to.contain('Not Found');
73+
});
74+
});
75+
76+
function defaultResponse(): OpenAPIV3.ResponseObject {
77+
return {
78+
description: 'unexpected error',
79+
content: {
80+
'application/json': {
81+
schema: {
82+
type: 'object',
83+
required: ['code', 'message'],
84+
properties: {
85+
code: {
86+
type: 'integer',
87+
format: 'int32',
88+
},
89+
message: {
90+
type: 'string',
91+
},
92+
},
93+
},
94+
},
95+
},
96+
};
97+
}
98+
99+
/*
100+
represents spec of the "public" entrypoint to our application e.g gateway. The
101+
type of id in path and id in the response here defined as simple string
102+
with minLength
103+
*/
104+
const gatewaySpec: OpenAPIV3.Document = {
105+
openapi: '3.0.0',
106+
info: { version: '1.0.0', title: 'test bug OpenApiValidator' },
107+
servers: [{ url: 'http://localhost:3000/api' }],
108+
paths: {
109+
'/pets/{petId}': {
110+
get: {
111+
summary: 'Info for a specific pet',
112+
operationId: 'showPetById',
113+
tags: ['pets'],
114+
parameters: [
115+
{
116+
name: 'petId',
117+
in: 'path',
118+
required: true,
119+
description: 'The id of the pet to retrieve',
120+
schema: {
121+
type: 'string',
122+
minLength: 3,
123+
},
124+
},
125+
],
126+
responses: {
127+
'200': {
128+
description: 'Expected response to a valid request',
129+
content: {
130+
'application/json': {
131+
schema: {
132+
type: 'object',
133+
required: ['id', 'name'],
134+
properties: {
135+
id: {
136+
type: 'string',
137+
},
138+
name: {
139+
type: 'string',
140+
},
141+
tag: {
142+
type: 'string',
143+
},
144+
},
145+
},
146+
},
147+
},
148+
},
149+
default: defaultResponse(),
150+
},
151+
},
152+
},
153+
},
154+
};
155+
156+
/*
157+
represents spec of the child router. We route request from main app (gateway) to this router.
158+
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.
159+
*/
160+
const childRouterSpec: OpenAPIV3.Document = {
161+
openapi: '3.0.0',
162+
info: { version: '1.0.0', title: 'test bug OpenApiValidator' },
163+
servers: [{ url: 'http://localhost:3000/' }],
164+
paths: {
165+
'/internal/api/pets/{petId}': {
166+
get: {
167+
summary: 'Info for a specific pet',
168+
operationId: 'showPetById',
169+
tags: ['pets'],
170+
parameters: [
171+
{
172+
name: 'petId',
173+
in: 'path',
174+
required: true,
175+
description: 'The id of the pet to retrieve',
176+
schema: {
177+
type: 'string',
178+
format: 'uuid',
179+
},
180+
},
181+
],
182+
responses: {
183+
'200': {
184+
description: 'Expected response to a valid request',
185+
content: {
186+
'application/json': {
187+
schema: {
188+
type: 'object',
189+
required: ['id', 'name'],
190+
properties: {
191+
id: {
192+
type: 'string',
193+
format: 'uuid',
194+
},
195+
name: {
196+
type: 'string',
197+
},
198+
tag: {
199+
type: 'string',
200+
},
201+
},
202+
},
203+
},
204+
},
205+
},
206+
},
207+
},
208+
},
209+
},
210+
};
211+
212+
function redirectToInternalService(
213+
req: Request,
214+
_res: Response,
215+
next: NextFunction,
216+
): void {
217+
req.url = `/internal${req.originalUrl}`;
218+
next();
219+
}
220+
221+
function makeMainApp(): ReturnType<typeof createApp> {
222+
return createApp(
223+
{
224+
apiSpec: gatewaySpec,
225+
validateResponses: true,
226+
validateRequests: true,
227+
},
228+
3000,
229+
(app) => {
230+
app
231+
.get(
232+
'/api/pets/:petId',
233+
function (_req: Request, _res: Response, next: NextFunction) {
234+
next();
235+
},
236+
)
237+
.use(redirectToInternalService);
238+
},
239+
false,
240+
);
241+
}
242+
243+
function makeRouter({ useRequestUrl }: { useRequestUrl: boolean }): IRouter {
244+
return express
245+
.Router()
246+
.use(
247+
OpenApiValidator.middleware({
248+
apiSpec: childRouterSpec,
249+
validateRequests: true,
250+
validateResponses: true,
251+
useRequestUrl,
252+
}),
253+
)
254+
.get('/internal/api/pets/:petId', function (req, res) {
255+
res.json({
256+
id: req.params.petId,
257+
name: 'Mr Sparky',
258+
tag: "Ain't nobody tags me",
259+
});
260+
});
261+
}

0 commit comments

Comments
 (0)