loopback-swagger
Version:
Integration between LoopBack and Swagger API specs
215 lines (201 loc) • 6.65 kB
JavaScript
// Copyright IBM Corp. 2015,2019. All Rights Reserved.
// Node module: loopback-swagger
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var schemaBuilder = require('../../lib/specgen/schema-builder');
var TypeRegistry = require('../../lib/specgen/type-registry');
var format = require('util').format;
var _defaults = require('lodash').defaults;
var loopback = require('loopback');
var expect = require('chai').expect;
var ANY_TYPE = {$ref: '#/definitions/x-any'};
describe('schema-builder', function() {
describeTestCases('for constructor types', [
{in: String, out: {type: 'string'}},
{in: Number, out: {type: 'number', format: 'double'}},
{in: Date, out: {type: 'string', format: 'date-time'}},
{in: Boolean, out: {type: 'boolean'}},
{in: Buffer, out: {type: 'string', format: 'byte'}},
]);
describeTestCases('for string types', [
{in: 'string', out: {type: 'string'}},
{in: 'number', out: {type: 'number', format: 'double'}},
{in: 'date', out: {type: 'string', format: 'date-time'}},
{in: 'boolean', out: {type: 'boolean'}},
{in: 'buffer', out: {type: 'string', format: 'byte'}},
]);
describeTestCases('for array definitions', [
{in: [String],
out: {type: 'array', items: {type: 'string'}}},
{in: ['string'],
out: {type: 'array', items: {type: 'string'}}},
{in: [{type: 'string', maxLength: 64}],
out: {type: 'array', items: {type: 'string', maxLength: 64}}},
{in: [{type: 'date'}],
out: {type: 'array', items: {type: 'string', format: 'date-time'}}},
{in: [],
out: {type: 'array', items: ANY_TYPE}},
// This value is somehow provided by loopback-boot called from
// loopback-workspace.
{in: [undefined],
out: {type: 'array', items: ANY_TYPE}},
{in: 'array',
out: {type: 'array', items: ANY_TYPE}},
]);
describeTestCases('for complex types', [
// Note: User is a built-in loopback model
{in: loopback.User,
out: {$ref: '#/definitions/User'}},
{in: {type: 'User'},
out: {$ref: '#/definitions/User'}},
{in: {type: 'user'},
out: {$ref: '#/definitions/user'}},
// Anonymous type
{in: {
type: {
foo: 'string',
bar: 'number',
quux: {
type: {
quuux: 'date',
},
},
},
},
out: {
type: 'object',
properties: {
foo: {
type: 'string',
},
bar: {
type: 'number',
format: 'double',
},
quux: {
properties: {
quuux: {
format: 'date-time',
type: 'string',
},
},
type: 'object',
},
},
}},
{in: {
type: {
foo: 'string',
bar: 'number',
},
example: {
foo: 'something',
bar: 'something else',
},
},
out: {
type: 'object',
properties: {
foo: {
type: 'string',
},
bar: {
type: 'number',
format: 'double',
},
},
example: {
foo: 'something',
bar: 'something else',
},
}},
{in: {
type: {
foo: {
type: 'string',
example: 'hello world',
},
},
},
out: {
type: 'object',
properties: {
foo: {
type: 'string',
example: 'hello world',
},
},
}},
]);
describeTestCases('for extra metadata', [
{in: {type: String, doc: 'a-description'},
out: {type: 'string', description: 'a-description'}},
{in: {type: String, doc: ['line1', 'line2']},
out: {type: 'string', description: 'line1\nline2'}},
{in: {type: String, description: 'a-description'},
out: {type: 'string', description: 'a-description'}},
{in: {type: String, description: ['line1', 'line2']},
out: {type: 'string', description: 'line1\nline2'}},
{in: {type: String, required: true},
out: {type: 'string'}}, // the flag required is handled specially
{in: {type: String, length: 10},
out: {type: 'string', maxLength: 10}},
{in: {type: String, length: null},
out: {type: 'string'}},
{in: {type: String, default: 'default-value'},
out: {type: 'string', default: 'default-value'}},
{in: {type: String, default: null},
out: {type: 'string'}},
{in: {type: String, default: {aaa: 'default-key-val'}},
out: {type: 'string', default: {aaa: 'default-key-val'}}},
{in: {type: String,
default: {
aaa: 'default-key-val',
bbb: null,
ccc: {ddd: 'val', eee: null}}},
out: {type: 'string', default: {aaa: 'default-key-val', ccc: {ddd: 'val'}}}},
]);
describeTestCases('for built-in LoopBack types', [
{in: {type: 'ObjectID', doc: 'a-description'},
out: {$ref: '#/definitions/ObjectID', description: 'a-description'}},
{in: {type: 'objectid', doc: 'a-description'},
out: {$ref: '#/definitions/ObjectID', description: 'a-description'}},
{in: {type: 'OBJECTID', doc: 'a-description'},
out: {$ref: '#/definitions/ObjectID', description: 'a-description'}},
{in: {type: 'GeoPoint', doc: '{lng: 10, lat: 20}'},
out: {$ref: '#/definitions/GeoPoint', description: '{lng: 10, lat: 20}'}},
{in: {type: 'geopoint', doc: '{lng: 10, lat: 20}'},
out: {$ref: '#/definitions/GeoPoint', description: '{lng: 10, lat: 20}'}},
{in: {type: 'GEOPOINT', doc: '{lng: 10, lat: 20}'},
out: {$ref: '#/definitions/GeoPoint', description: '{lng: 10, lat: 20}'}},
{in: {type: 'DateString'},
out: {$ref: '#/definitions/DateString'}},
{in: {type: 'datestring'},
out: {$ref: '#/definitions/DateString'}},
{in: {type: 'DATESTRING'},
out: {$ref: '#/definitions/DateString'}},
]);
function describeTestCases(name, testCases) {
describe(name, function() {
testCases.forEach(function(tc) {
var inStr = formatType(tc.in);
var outStr = formatType(tc.out);
it(format('converts %s to %s', inStr, outStr), function() {
var registry = new TypeRegistry();
var schema = schemaBuilder.buildFromLoopBackType(tc.in, registry);
expect(schema).to.eql(tc.out);
});
});
});
}
function formatType(type) {
if (Array.isArray(type))
return '[' + type.map(formatType) + ']';
if (typeof type === 'function')
return type.modelName ?
'model ' + type.modelName :
'ctor ' + type.name;
return format(type);
}
});