1
0
Fork 0

Basic swagger tests

This commit is contained in:
Alan Plum 2016-02-02 14:59:05 +01:00
parent a71fc92c6f
commit a31bf33892
No known key found for this signature in database
GPG Key ID: 8ED72A9A323B6EFD
5 changed files with 264 additions and 112 deletions

View File

@ -158,7 +158,7 @@ module.exports = exports = class SwaggerContext {
}
this._bodyParam = {
model: model || null,
model: model,
multiple: multiple,
contentTypes: contentTypes,
description: description
@ -257,7 +257,7 @@ module.exports = exports = class SwaggerContext {
}
this._responses.set(statusCode, {
model: model || null,
model: model,
multiple: multiple,
contentTypes: contentTypes,
description: description

View File

@ -139,11 +139,6 @@ exports.routeApp = function (service, throwOnErrors) {
let error = null;
if (service.legacy) {
error = routeLegacyService(service, throwOnErrors);
} else {
service.routes = {
name: `foxx("${service.mount}")`,
routes: []
};
}
if (service.manifest.files) {

View File

@ -348,7 +348,10 @@ module.exports = class FoxxService {
this.main.context = new FoxxContext(this);
this.router = new Router();
this.types = new Map(defaultTypes);
this.routes = {
name: `foxx("${this.mount}")`,
routes: []
};
if (this.legacy) {
this.main.context.foxxFilename = this.main.context.fileName;

View File

@ -1,6 +1,5 @@
/*global describe, it, beforeEach */
'use strict';
const Router = require('@arangodb/foxx/router/router');
const Tree = require('@arangodb/foxx/router/tree');
const expect = require('chai').expect;
@ -407,106 +406,3 @@ describe('Tree', function () {
});
});
});
describe('Tree#buildSwaggerPaths', function () {
it('disambiguates duplicate path parameter names', function () {
const child = new Router();
child.get('/:x', function () {});
const router = new Router();
router.use('/:x', child);
const tree = new Tree({}, router);
const docs = tree.buildSwaggerPaths();
expect(docs).to.have.a.property('/:x/:x2')
.with.a.property('get').that.is.an('object');
});
it('sets the "consumes" info to the default body mime type', function () {
const router = new Router();
router.post('/data', function () {});
const tree = new Tree({}, router);
const docs = tree.buildSwaggerPaths();
expect(docs).to.have.a.property('/data')
.with.a.deep.property('post.consumes')
.that.is.eql(['application/json']);
});
it('sets the "consumes" info to the body mime type', function () {
const mimeType = 'banana';
const router = new Router();
const route = router.post('/data', function () {});
route._bodyParam.contentTypes[0] = mimeType;
const tree = new Tree({}, router);
const docs = tree.buildSwaggerPaths();
expect(docs).to.have.a.property('/data')
.with.a.deep.property('post.consumes')
.that.is.eql([mimeType]);
});
it('does not set the "consumes" info for body-free methods', function () {
const router = new Router();
router.get('/no-data', function () {});
const tree = new Tree({}, router);
const docs = tree.buildSwaggerPaths();
expect(docs).to.have.a.property('/no-data')
.with.not.a.deep.property('get.consumes'); // this may not work?
});
it('sets the "consumes" info to empty if explicitly forbidden', function () {
const router = new Router();
router.post('/no-data', function () {})
.body(null);
const tree = new Tree({}, router);
const docs = tree.buildSwaggerPaths();
expect(docs).to.have.a.property('/no-data')
.with.a.deep.property('post.consumes')
.that.is.eql([]);
});
it('sets the "produces" info to the default response mime type', function () {
const router = new Router();
router.get('/body', function () {});
const tree = new Tree({}, router);
const docs = tree.buildSwaggerPaths();
expect(docs).to.have.a.property('/body')
.with.a.deep.property('get.produces')
.that.is.eql(['application/json']);
});
it('sets the "produces" info to all response mime types', function () {
const mimeType = 'banana';
const router = new Router();
const route = router.get('/body', function () {});
route._responses.set(200, {contentTypes: [mimeType]});
const tree = new Tree({}, router);
const docs = tree.buildSwaggerPaths();
expect(docs).to.have.a.property('/body')
.with.a.deep.property('get.produces')
.that.is.eql([mimeType, 'application/json']);
});
it('only sets the "produces" info once per response mime type', function () {
const mimeType = 'banana';
const router = new Router();
const route = router.get('/body', function () {});
route._responses.set(200, {contentTypes: [mimeType]});
route._responses.set(400, {contentTypes: [mimeType]});
const tree = new Tree({}, router);
const docs = tree.buildSwaggerPaths();
expect(docs).to.have.a.property('/body')
.with.a.deep.property('get.produces')
.that.is.eql([mimeType, 'application/json']);
});
it.skip('sets the path parameters');
it.skip('sets the query parameters');
it.skip('sets the header parameters');
it.skip('sets the body parameter');
it.skip('uses the default body parameter if body is implied');
it.skip('omits the body parameter if no body is set');
it.skip('omits the body parameter if body is explicitly disabled');
it.skip('sets the default response');
it.skip('sets the response bodies');
it.skip('omits the response body if body is explicitly disabled');
it.skip('sets the form parameters if route consumes form type but not json');
});

View File

@ -0,0 +1,258 @@
/*global describe, it, beforeEach */
'use strict';
require('chai').config.truncateThreshold = 0;
const expect = require('chai').expect;
const Service = require('@arangodb/foxx/service');
const createRouter = require('@arangodb/foxx/router');
describe('Foxx Swagger', function () {
let service;
beforeEach(function () {
service = createService();
});
it('adds all the basic metadata', function () {
service.buildRoutes();
expect(service.docs).to.eql({
swagger: '2.0',
basePath: `/_db/_system${service.mount}`,
paths: {},
info: {
title: service.manifest.name,
description: service.manifest.description,
version: service.manifest.version,
license: {
name: service.manifest.license
}
}
});
});
describe('Route Info', function () {
it('formats path param names', function () {
service.router.get('/:x', noop());
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/{x}')
.with.a.property('get');
});
it('disambiguates duplicate path param names', function () {
const child = createRouter();
child.get('/:x', noop());
service.router.use('/:x', child);
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/{x}/{x2}')
.with.a.property('get');
});
it('supports multiple methods on the same path', function () {
service.router.get('/a', noop()).description('x');
service.router.post('/a', noop()).description('y');
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/a')
.with.a.deep.property('get.description', 'x');
expect(service.docs.paths).to.have.a.property('/a')
.with.a.deep.property('post.description', 'y');
});
describe('"deprecated"', function () {
it('is omitted by default', function () {
service.router.get('/hello', noop());
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/hello')
.with.not.a.deep.property('get.deprecated');
});
it('is set to true if the route is marked deprecated', function () {
service.router.get('/hello', noop()).deprecated();
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/hello')
.with.a.deep.property('get.deprecated')
.that.is.equal(true);
});
it('is set to true if a parent is marked deprecated', function () {
const child = createRouter();
child.get('/hello', noop()).deprecated(false);
service.router.use(child).deprecated();
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/hello')
.with.a.deep.property('get.deprecated')
.that.is.equal(true);
});
it('is omitted if the route is marked un-deprecated', function () {
service.router.get('/hello', noop()).deprecated(false);
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/hello')
.with.not.a.deep.property('get.deprecated');
});
});
['description', 'summary'].forEach(function (field) {
describe(`"${field}"`, function () {
it('is omitted by default', function () {
service.router.get('/hello', noop());
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/hello')
.with.not.a.deep.property(`get.${field}`);
});
it(`is set to the ${field} if provided`, function () {
const str = 'Hello World!';
service.router.get('/hello', noop())[field](str);
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/hello')
.with.a.deep.property(`get.${field}`)
.that.is.equal(str);
});
it(`is omitted if the ${field} is empty`, function () {
service.router.get('/hello', noop())[field]('');
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/hello')
.with.not.a.deep.property(`get.${field}`);
});
});
});
describe('"consumes"', function () {
['patch', 'post', 'put'].forEach(function (method) {
it(`defaults to JSON for ${method.toUpperCase()}`, function () {
service.router[method]('/hello', noop());
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/hello')
.with.a.deep.property(`${method}.consumes`)
.that.is.eql(['application/json']);
});
});
['get', 'head', 'delete'].forEach(function (method) {
it(`is omitted for ${method.toUpperCase()}`, function () {
service.router[method]('/hello', noop());
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/hello')
.with.not.a.deep.property(`${method}.consumes`);
});
});
it('is set to the body mime type', function () {
service.router.post('/hello', noop()).body(['text/plain']);
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/hello')
.with.a.deep.property('post.consumes')
.that.is.eql(['text/plain']);
});
['get', 'head', 'delete'].forEach(function (method) {
it(`is set for ${method.toUpperCase()} if explicitly defined`, function () {
service.router[method]('/hello', noop()).body(['text/plain']);
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/hello')
.with.a.deep.property(`${method}.consumes`)
.that.is.eql(['text/plain']);
});
});
['patch', 'post', 'put'].forEach(function (method) {
it(`is empty for ${method.toUpperCase()} if explicitly set to null`, function () {
service.router[method]('/hello', noop()).body(null);
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/hello')
.with.a.deep.property(`${method}.consumes`)
.that.is.eql([]);
});
});
});
describe('"produces"', function () {
it('defaults to JSON', function () {
service.router.get('/hello', noop());
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/hello')
.with.a.deep.property('get.produces')
.that.is.eql(['application/json']);
});
it('includes explicit response types', function () {
service.router.get('/hello', noop()).response(['text/plain']);
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/hello')
.with.a.deep.property('get.produces')
.that.is.eql(['text/plain', 'application/json']);
});
it('includes non-200 response types', function () {
service.router.get('/hello', noop())
.response(['text/plain'])
.response(499, ['text/html']);
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/hello')
.with.a.deep.property('get.produces')
.that.is.eql(['text/plain', 'text/html', 'application/json']);
});
});
describe('"responses"', function () {
it('provides a default response', function () {
service.router.get('/hello', noop());
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/hello')
.with.a.deep.property('get.responses.default')
.that.has.a.property('description', 'Unexpected error');
});
it('provides a default 200 response', function () {
service.router.get('/hello', noop());
service.buildRoutes();
expect(service.docs.paths).to.have.a.property('/hello')
.with.a.deep.property('get.responses.200')
.that.has.a.property('description', 'Undocumented response body');
});
it('TODO');
});
describe('"parameters"', function () {
describe('in:body', function () {
it('TODO');
});
describe('in:path', function () {
it('TODO');
});
describe('in:query', function () {
it('TODO');
});
describe('in:header', function () {
it('TODO');
});
});
});
});
function createService() {
return new Service({
path: '/tmp/$dummy$',
mount: '/__dummy__',
manifest: {
name: 'DUMMY APP',
version: '1.0.0',
license: 'The Unlicense',
description: 'Dummy app for Foxx.',
main: '$dummy$',
engines: {
arangodb: '^3.0.0'
}
},
options: {}
});
}
function noop() {
return noop;
}