Skip to content

Instantly share code, notes, and snippets.

@xiaoyvr
Last active January 12, 2018 04:22
Show Gist options
  • Save xiaoyvr/5ec26fbd0f603d0ca312c2ab472d0920 to your computer and use it in GitHub Desktop.
Save xiaoyvr/5ec26fbd0f603d0ca312c2ab472d0920 to your computer and use it in GitHub Desktop.
const _ = require('lodash')
const Ajv = require('ajv')
const pathToRegexp = require('path-to-regexp')
const {expect} = require('chai')
const SwaggerParser = require('swagger-parser')
const request = require('supertest')
module.exports = {
create: async(specFile) => {
const parser = new SwaggerParser()
const spec = await parser.dereference(specFile)
const validations = [], ajv = new Ajv()
_.forIn(spec.paths, (pathSpec, path) => {
_.forIn(pathSpec, (methodSpec, method) => {
const bodyParameter = _.find(methodSpec.parameters, p => p.in === 'body')
let requestBody
if (bodyParameter) {
const inlineBody = {}
_.forIn(bodyParameter.schema.properties, (value, key) => {
inlineBody[key] = value.example
})
requestBody = Object.assign(inlineBody, bodyParameter.schema.example || {})
}
validations.push({
uriTemplate: spec.basePath + path,
method,
requestBody,
responses: methodSpec.responses
})
})
})
function match(uriTemplate, path) {
const routeStr = (uriTemplate.replace(/{(\w+)}/g, ':$1'))
const keys = []
const re = pathToRegexp(routeStr, keys)
const match = re.exec(path)
return !!match
}
function formatObjectSchema(obj) {
const properties = obj.properties || {}
for (let key in properties) {
const property = properties[key]
if (property.type === 'string' && property.format === 'byte') {
// remove properties[prop].format: byte
delete properties[key].format
}
if (property.type === 'number' && property.format === 'float') {
// remove properties[prop].format: byte
delete properties[key].format
}
if (property.type === 'object') {
formatObjectSchema(property)
}
}
}
function formatJSONSchema(schema) {
formatObjectSchema(schema)
}
function report(method, path, validate) {
return `${method} ${path}
${JSON.stringify(validate.errors, null, 2)}`
}
return {
getValidator: (method, path) => {
const validation = _.find(validations, v => match(v.uriTemplate, path) && v.method === method)
if ( !validation ) {
throw `No validation found for ${method} ${path}`
}
return {
validation,
validate: async(app, statusCode, headers, requestMap = (example => example)) => {
let req = request(app)[method](path)
_.forIn(headers, (value, key) => {
req = req.set(key, value)
})
if (validation.requestBody) {
requestMap(validation.requestBody)
req = req.send(validation.requestBody)
}
return await req
.expect(statusCode)
.expect(res => {
const schema = validation.responses['' + statusCode].schema
formatJSONSchema(schema)
const validate = ajv.compile(schema)
const result = validate(res.body)
const msg = report(method, path, validate)
expect(result, msg).to.be.true
})
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment