fastman
Version:
快速api测试及文档生成
359 lines • 13.2 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
var openapi_3_1 = require("./spec/openapi-3");
var newman_runner_1 = require("./runner/newman-runner");
var queryString = require("query-string");
var es6_promise_1 = require("es6-promise");
var fs = require("fs");
var _ = require("lodash");
var URL = require("url");
function getComponentRef(name, type) {
if (type === void 0) { type = "schemas"; }
return "#/components/" + type + "/" + name;
}
exports.getComponentRef = getComponentRef;
var Fastman = /** @class */ (function () {
function Fastman() {
this.state = {
passedCases: {},
globalHeader: {}
};
this.spceVersion = 3;
this.spec = null;
this.runner = null;
}
/**
* 指定使用openapi版本
* @param {number} version
*/
Fastman.prototype.openApiVersion = function (version) {
this.spceVersion = version;
if (this.spceVersion === 3) {
this.spec = new openapi_3_1.default();
}
else {
// this.spec = new OpenApi2Spec();
}
return this;
};
/**
* 将openapi文档写入字符串
* @returns {string}
*/
Fastman.prototype.writeSpec = function () {
return this.spec.write("yaml");
};
/**
* 设置openapi的info
*/
Fastman.prototype.info = function (info) {
this.spec.info(info);
return this;
};
Fastman.prototype.component = function (name, value, type) {
this.spec.component(name, value, type);
return this;
};
/**
* 从给定字符串或object中读取 文档
* @param {string | object} spec
* @returns {this}
*/
Fastman.prototype.load = function (spec) {
this.spec.load(spec);
var servers = this.spec.server();
this.state.url = servers[0].url || servers[0].basePath;
if (!this.state.url) {
throw new Error("文档中需要配置Server");
}
return this;
};
Fastman.prototype.response = function (status, response) {
if (typeof status === "number") {
status = status.toString();
}
this.spec.response(status, this.state.path, this.state.operation, response);
this.state.response = status;
return this;
};
/**
* 选择或新建一个资源
* @param name 资源名称
*/
Fastman.prototype.resource = function (name) {
this.state = __assign({}, this.state, {
resource: name,
path: null,
operation: null,
response: null
});
return this;
};
/**
* 选择或新建一个路径
* @param {string} path
*/
Fastman.prototype.path = function (path) {
this.spec.path(path);
this.state = __assign({}, this.state, {
path: path,
operation: null,
response: null
});
return this;
};
/**
* 设置全局的headers
* @param {object} headers
*/
Fastman.prototype.globalHeaders = function (headers) {
this.state.globalHeader = __assign({}, this.state.globalHeader, headers);
return this;
};
/**
* 配置Server
* @param {Server} server
*/
Fastman.prototype.server = function (server) {
this.spec.server(server);
this.state.url = server.url || server.basePath;
return this;
};
/**
* 选择或新建一个操作
* @param {string} method
* @param operation
*/
Fastman.prototype.operation = function (method, operation) {
if (operation) {
var tags = operation.tags || [];
tags.push(this.state.resource);
operation.tags = tags;
}
this.spec.operation(this.state.path, method, operation);
this.state = __assign({}, this.state, {
operation: method,
response: null
});
return this;
};
/**
* 准备测试用例
*/
Fastman.prototype.testCase = function (testCase) {
if (!this.state.url)
throw "没有找到server配置";
var url = URL.parse(this.state.url);
// 去掉path中的所有参数
var re = /\/\{\w+\}/g;
url.pathname += this.state.path.replace(re, "");
if (testCase.params) {
url.pathname += "/" + testCase.params.join("/");
}
var protocol = url.protocol.replace(":", "");
var postmanQuery;
if (testCase.query) {
url.query = queryString.stringify(testCase.query);
postmanQuery = Object.keys(testCase.query).map(function (k) {
return {
key: k,
value: testCase.query[k]
};
});
}
var raw = URL.format({
protocol: protocol,
hostname: url.hostname,
port: url.port,
query: testCase.query,
pathname: url.pathname
});
var postManUrl = {
raw: raw,
protocol: protocol,
port: url.port,
host: [url.hostname],
path: url.pathname.slice(1).split("/"),
query: postmanQuery
};
var testHeader = __assign({}, this.state.globalHeader.all, this.state.globalHeader[this.state.operation], testCase.header);
var postmanHeader = Object.keys(testHeader).map(function (k) {
return {
key: k,
value: testHeader[k]
};
});
// FIXME 目前只支持 json 格式的 body, 需要对多种类型的body进行处理
// 构建body
var postmanBody = testCase.body ?
{
mode: "raw",
raw: JSON.stringify(testCase.body, null, "\t")
} : {};
// 构建Request
testCase.request = {
url: postManUrl,
header: postmanHeader,
body: postmanBody,
method: this.state.operation
};
this.state.testCase = testCase;
this.state.except = null;
return this;
};
Fastman.prototype.except = function (expect) {
this.state.except = expect;
return this;
};
Fastman.prototype.getCaseKey = function (name) {
var _a = this.state, resource = _a.resource, path = _a.path, operation = _a.operation, response = _a.response;
return resource + ":" + path + ":" + operation + ":" + response + ":" + name;
};
/**
* 导出postman 结果,将测试的结果保存在postman的collection文件中
* 如果给出的file不存在,则会新建一个collection文件
* 如果file存在,则会在collection中按照 resource 分文件夹存放测试用例
*
* 同时,会自动将 host port bearer 等转换为postman的环境格式
* @param {string} file 保存文件的路径
*/
Fastman.prototype.exportPostman = function (file) {
var passedCases = this.state.passedCases;
var resources = Object.keys(passedCases)
.map(function (k) { return k.split(":")[0]; });
resources = _.uniq(resources);
var url = URL.parse(this.state.url);
var hostname = url.hostname;
var port = url.port;
var collection = fs.existsSync(file) ?
JSON.parse(fs.readFileSync(file).toString()) :
{
info: {
name: "FastmanAutoGen",
schema: "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
item: []
};
var _loop_1 = function (r) {
var resource = {
name: r,
item: []
};
var cases = Object
.keys(passedCases)
.filter(function (k) { return k.split(":")[0] === r; })
.map(function (k) { return passedCases[k]; })
.filter(function (k) { return !k.excludePostman; });
resource.item = cases.map(function (c) {
var url = __assign({}, c.request.url, {
raw: c.request.url.raw
.replace(hostname, "{{host}}")
.replace(port, "{{port}}"),
port: "{{port}}",
host: ["{{host}}"]
});
// 处理request下的header
c.request.header = c.request.header.map(function (h) {
if (h.key === "Authorization") {
if (h.value.indexOf("Bearer") !== -1) {
h["value"] = "Bearer {{bearer_token}}";
}
else {
// TODO 处理其他需要写成环境变量的token
return h;
}
}
return h;
});
var responseBody = {};
try {
responseBody = c.response["json"]();
}
catch (e) {
responseBody = {};
}
return {
name: c.name,
request: __assign({}, c.request, { url: url }),
response: [
{
name: c.name,
originalRequest: __assign({}, c.request, { url: url }),
status: c.response.status,
code: c.response.code,
header: c.response["headers"]["members"],
cookies: c.response["cookies"]["members"],
body: JSON.stringify(responseBody, null, "\t")
}
]
};
});
_.remove(collection.item, function (i) { return i["name"] === r; });
collection.item.push(resource);
};
for (var _i = 0, resources_1 = resources; _i < resources_1.length; _i++) {
var r = resources_1[_i];
_loop_1(r);
}
fs.writeFileSync(file, JSON.stringify(collection, null, 2));
};
/**
* 测试
*/
Fastman.prototype.run = function () {
var _this = this;
return new es6_promise_1.Promise(function (resolve, reject) {
if (!_this.runner) {
_this.runner = new newman_runner_1.default();
}
_this.runner.run(_this.state.testCase, _this.getCaseKey(_this.state.testCase.name))
.then(function (resp) {
try {
// 验证status 是否满足
if (resp.code != _this.state.response) {
reject(new Error("Response except " + _this.state.response + ", but receive " + resp.code));
}
// 验证是否通过
if (_this.state.except) {
_this.state.except(resp);
}
var testCase = _this.state.testCase;
testCase.response = resp;
// 将结果保存在文档的example中
if (testCase.save && resp.code !== 204) {
var example = {
value: resp.json()
};
_this.spec.example(testCase.name, example, _this.state.path, _this.state.operation, _this.state.response);
if (testCase.saveRequest && testCase.body) {
var requestExample = {
summary: testCase.name,
value: testCase.body
};
_this.spec.requestExample(testCase.name, requestExample, _this.state.path, _this.state.operation);
}
}
// 保存通过的testcase
_this.state.passedCases[_this.getCaseKey(testCase.name)]
= testCase;
resolve(resp);
}
catch (e) {
reject(e);
}
})
.catch(function (e) { return reject(e); });
});
};
return Fastman;
}());
exports.default = Fastman;
//# sourceMappingURL=fastman.js.map