/
routes.spec.ts
298 lines (273 loc) 路 10.1 KB
/
routes.spec.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
import { expect } from 'chai';
import * as request from 'supertest';
import { createApp } from './app';
import * as apiSpec from './resources/openapi.json';
const app = createApp({ apiSpecPath: './openapi.yaml' }, 3001);
const app2 = createApp({ apiSpec }, 3002);
const packageJson = require('../package.json');
const basePath = (<any>app).basePath;
[app, app2].forEach(app => {
describe(packageJson.name, () => {
after(() => {
(<any>app).server.close();
});
describe(`GET ${basePath}/pets`, () => {
it('should throw 400 on missing required query parameter', async () =>
request(app)
.get(`${basePath}/pets`)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(400)
.then(r => {
const e = r.body.errors;
expect(e).to.have.length(2);
expect(e[0].path).to.equal('limit');
expect(e[1].path).to.equal('test');
}));
it('should respond with json on proper get call', async () =>
request(app)
.get(`${basePath}/pets`)
.query({
test: 'one',
limit: 10,
})
.set('Accept', 'application/json')
// .expect('Content-Type', /json/)
.expect(200));
it('should return 200 with unknown query parameter', async () =>
request(app)
.get(`${basePath}/pets`)
.query({
test: 'one',
limit: 10,
bad_param: 'test',
})
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200));
it('should return 400 when improper range specified', async () =>
request(app)
.get(`${basePath}/pets`)
.query({
test: 'one',
limit: 2,
})
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(400)
.then(r => {
const e = r.body.errors;
expect(e).to.have.length(1);
expect(e[0].path).to.contain('limit');
expect(e[0].message).to.equal('should be >= 5');
}));
it('should return 200 when JSON in query param', async () =>
request(app)
.get(`${basePath}/pets`)
.query(`limit=10&test=one&testJson={"foo": "bar"}`)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200));
it('should return 400 when improper JSON in query param', async () =>
request(app)
.get(`${basePath}/pets`)
.query(`limit=10&test=one&testJson={"foo": "test"}`)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(400)
.then(r => {
const e = r.body.errors;
expect(e).to.have.length(1);
expect(e[0].path).to.contain('testJson');
expect(e[0].message).to.equal('should be equal to one of the allowed values');
}));
it('should return 200 when separated array in query param', async () =>
request(app)
.get(`${basePath}/pets`)
.query(`limit=10&test=one&testArray=foo,bar,baz`)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200));
it('should return 400 when improper separated array in query param', async () =>
request(app)
.get(`${basePath}/pets`)
.query(`limit=10&test=one&testArray=foo,bar,test`)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(400)
.then(r => {
const e = r.body.errors;
expect(e).to.have.length(1);
expect(e[0].path).to.contain('testArray');
expect(e[0].message).to.equal('should be equal to one of the allowed values');
}));
});
describe('POST /pets', () => {
it('should return 400 if required body is missing', async () =>
request(app)
.post(`${basePath}/pets`)
.set('content-type', 'application/json')
.expect(400)
.then(r => {
const e = r.body.errors;
expect(e[0].message).to.equal(
"should have required property 'name'",
);
}));
it('should return 400 if required "name" property is missing', async () =>
request(app)
.post(`${basePath}/pets`)
.send({})
.expect(400)
.then(r => {
const e = r.body.errors;
expect(e[0].message).to.equal(
"should have required property 'name'",
);
}));
it('should return 200 when post props are met', async () =>
request(app)
.post(`${basePath}/pets`)
.send({
name: 'test',
})
.expect(200)
.then(r => {
expect(r.body.id).to.equal('new-id');
}));
});
describe('when a route defined either in express or openapi, but not both', () => {
it('should not validate a route defined in express, but not under an openapi basepath', async () =>
request(app)
.get('/not_under_an_openapi_basepath')
.expect(200)
.then(r => {
expect(r.body.id).to.equal('/not_under_an_openapi_basepath');
}));
it('should return 400 if route is defined in openapi but not express and is called with invalid parameters', async () =>
request(app)
.get(`${basePath}/route_not_defined_within_express`)
.expect(400)
.then(r => {
const e = r.body.errors;
expect(e[0].message).to.equal(
"should have required property 'name'",
);
}));
it('should return 404 if route is defined in swagger but not express', async () =>
request(app)
.get(`${basePath}/route_not_defined_within_express`)
.query({ name: 'test' })
.expect(404)
.then(r => {
const e = r.body;
// There is no route defined by express, hence the validator verifies parameters,
// then it fails over to the express error handler. In this case returns empty
expect(e).to.be.empty;
}));
it('should throw 404 on a route defined in express, but not documented in the openapi spec', async () =>
request(app)
.get(`${basePath}/router_1/10`)
.set('Accept', 'application/json')
.expect(404)
.then(r => {
const e = r.body.errors[0];
expect(e.message).to.equal('not found');
expect(e.path).to.equal(`${basePath}/router_1/10`);
}));
it('should return 405 if route is defined in swagger but not express and the method is invalid', async () =>
request(app)
.post(`${basePath}/route_not_defined_within_express`)
.send()
.expect(405)
.then(r => {
const e = r.body.errors;
expect(e[0].message).to.equal('POST method not allowed');
expect(e[0].path).to.equal(
`${basePath}/route_not_defined_within_express`,
);
}));
it('should return 404 for route not defined in openapi or express', async () =>
request(app)
.post(`${basePath}/unknown_route`)
.send({
name: 'test',
})
.expect(404)
.then(r => {
const e = r.body.errors;
expect(e[0].message).to.equal('not found');
expect(e[0].path).to.equal(`${basePath}/unknown_route`);
}));
it('should return 404 for a route defined in express, but not documented in openapi', async () =>
request(app)
.post(`${basePath}/route_defined_in_express_not_openapi`)
.send({
name: 'test',
})
.expect(404)
.then(r => {
const e = r.body.errors;
expect(e[0].message).to.equal('not found');
expect(e[0].path).to.equal(
`${basePath}/route_defined_in_express_not_openapi`,
);
}));
it('should return 415 when media type is not supported', async () =>
request(app)
.post(`${basePath}/pets`)
.send('<xml>stuff</xml>')
.set('content-type', 'application/xml')
.expect(415)
.then(r => {
const e = r.body.errors;
expect(e[0].message).to.equal(
'unsupported media type application/xml',
);
}));
it('should return 405 when method is not allows', async () =>
request(app)
.patch(`${basePath}/pets`)
.send({ name: 'test' })
.expect(405)
.then(r => {
const e = r.body.errors;
expect(e[0].message).to.equal('PATCH method not allowed');
}));
// TODO write test when route exists, but doc does not
});
describe(`GET ${basePath}/pets/:id`, () => {
it('should return 400 when path param should be int, but instead is string', async () => {
const id = 'my_id';
return request(app)
.get(`${basePath}/pets/${id}`)
.expect(400)
.then(r => {
const e = r.body.errors;
expect(e[0].path).contains('id');
expect(e[0].message).equals('should be integer');
});
});
it('should handle multiple path params with coereion', async () => {
const id = '10';
const attributeId = '12';
return request(app)
.get(`${basePath}/pets/${id}/attributes/${attributeId}`)
.expect(200)
.then(r => {
expect(r.body.id).equals(Number.parseInt(id));
expect(r.body.attribute_id).equals(Number.parseInt(attributeId));
});
});
it('should return 200 and get the id from the response', async () => {
const id = 10;
return request(app)
.get(`${basePath}/pets/${id}`)
.expect(200)
.then(r => {
expect(r.body.id).equals(id);
});
});
});
});
});