UNPKG

fastman

Version:

快速api测试及文档生成

359 lines 13.2 kB
"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