mirror of
https://github.com/YMFE/yapi.git
synced 2024-11-27 04:40:08 +08:00
feat: add autotest
This commit is contained in:
parent
3c9941c9f3
commit
3c70917b93
@ -254,8 +254,6 @@ class InterfaceColContent extends Component {
|
||||
statusText: data.message,
|
||||
code: 400
|
||||
}
|
||||
|
||||
result.code = 400;
|
||||
}
|
||||
|
||||
result.params = requestParams;
|
||||
|
@ -4,8 +4,10 @@ const _ = require("underscore")
|
||||
const URL = require('url')
|
||||
const utils = require('./power-string.js').utils;
|
||||
const HTTP_METHOD = constants.HTTP_METHOD;
|
||||
let httpRequest = () => { };
|
||||
const axios = require('axios');
|
||||
const qs = require('qs');
|
||||
|
||||
const isNode = typeof global == 'object' && global.global === global;
|
||||
const ContentTypeMap = {
|
||||
'application/json': 'json',
|
||||
'application/xml': 'xml',
|
||||
@ -13,7 +15,50 @@ const ContentTypeMap = {
|
||||
'application/html': 'html'
|
||||
}
|
||||
|
||||
const isNode = typeof global == 'object' && global.global === global;
|
||||
async function httpRequestByNode(options) {
|
||||
function handleRes(response){
|
||||
return {
|
||||
res: {
|
||||
header: response.headers,
|
||||
status: response.status,
|
||||
body: response.data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleData(){
|
||||
let contentTypeItem;
|
||||
if(!options) return;
|
||||
if(typeof options.headers === 'object' && options.headers ){
|
||||
Object.keys(options.headers).forEach(key => {
|
||||
if (/content-type/i.test(key)) {
|
||||
contentTypeItem = options.headers[key].split(";")[0].trim().toLowerCase();
|
||||
}
|
||||
})
|
||||
if(contentTypeItem === 'application/x-www-form-urlencoded' && typeof options.data === 'object' && options.data){
|
||||
options.data = qs.stringify(options.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try{
|
||||
handleData(options);
|
||||
let response=await axios({
|
||||
method: options.method,
|
||||
url: options.url,
|
||||
headers: options.headers,
|
||||
timeout: 5000,
|
||||
data: options.data
|
||||
})
|
||||
return handleRes(response)
|
||||
}catch(response){
|
||||
console.log('--------')
|
||||
|
||||
console.log(response)
|
||||
console.log('--------')
|
||||
return handleRes(response.response)
|
||||
}
|
||||
}
|
||||
|
||||
function handleContentType(headers) {
|
||||
if (!headers || typeof headers !== 'object') return ContentTypeMap.other;
|
||||
@ -79,12 +124,9 @@ function sandbox(context = {}, script) {
|
||||
return context;
|
||||
}
|
||||
|
||||
function crossRequest(defaultOptions, preScript, afterScript) {
|
||||
async function crossRequest(defaultOptions, preScript, afterScript) {
|
||||
let options = Object.assign({}, defaultOptions);
|
||||
let urlObj = URL.parse(options.url, true), query = {};
|
||||
if (!isNode) {
|
||||
httpRequest = window.crossRequest
|
||||
}
|
||||
query = Object.assign(query, urlObj.query);
|
||||
let context = {
|
||||
pathname: urlObj.pathname,
|
||||
@ -116,37 +158,49 @@ function crossRequest(defaultOptions, preScript, afterScript) {
|
||||
defaultOptions.data = options.data = context.requestBody;
|
||||
|
||||
}
|
||||
|
||||
let data;
|
||||
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
options.error = options.success = function (res, header, data) {
|
||||
let message = '请求异常,请检查 chrome network 错误信息...';
|
||||
if (isNaN(data.res.status)) {
|
||||
reject({
|
||||
body: res || message,
|
||||
header,
|
||||
message
|
||||
})
|
||||
if(isNode){
|
||||
data = await httpRequestByNode(options)
|
||||
data.req = options;
|
||||
}else{
|
||||
data = await (new Promise((resolve, reject) => {
|
||||
options.error = options.success = function (res, header, data) {
|
||||
let message = '';
|
||||
if(res && typeof res === 'string'){
|
||||
res = json_parse(res);
|
||||
data.res.body = res;
|
||||
}
|
||||
if (!isNode) message = '请求异常,请检查 chrome network 错误信息...';
|
||||
if (isNaN(data.res.status)) {
|
||||
reject({
|
||||
body: res || message,
|
||||
header,
|
||||
message
|
||||
})
|
||||
}
|
||||
resolve(data);
|
||||
}
|
||||
|
||||
if (afterScript) {
|
||||
context.responseData = json_parse(data.res.body);
|
||||
context.responseHeader = data.res.header;
|
||||
context.responseStatus = data.res.status;
|
||||
context.runTime = data.runTime;
|
||||
context = sandbox(context, afterScript);
|
||||
data.res.body = context.responseData;
|
||||
data.res.header = context.responseHeader;
|
||||
}
|
||||
resolve(data);
|
||||
}
|
||||
httpRequest(options);
|
||||
})
|
||||
window.crossRequest(options);
|
||||
}))
|
||||
}
|
||||
|
||||
if (afterScript) {
|
||||
context.responseData = data.res.body;
|
||||
context.responseHeader = data.res.header;
|
||||
context.responseStatus = data.res.status;
|
||||
context.runTime = data.runTime;
|
||||
context = sandbox(context, afterScript);
|
||||
data.res.body = context.responseData;
|
||||
data.res.header = context.responseHeader;
|
||||
data.res.status = context.responseStatus;
|
||||
data.runTime = context.runTime;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function handleParams(interfaceData, handleValue, requestParams) {
|
||||
function paramsToObjectWithEnable(arr) {
|
||||
const obj = {};
|
||||
@ -191,7 +245,6 @@ function handleParams(interfaceData, handleValue, requestParams) {
|
||||
|
||||
currDomain = handleCurrDomain(env, case_env);
|
||||
const urlObj = URL.parse(joinPath(currDomain.domain, path), true);
|
||||
|
||||
const url = URL.format({
|
||||
protocol: urlObj.protocol || 'http',
|
||||
host: urlObj.host,
|
||||
|
@ -725,48 +725,9 @@ class interfaceColController extends baseController {
|
||||
}
|
||||
}
|
||||
|
||||
convertString(variable) {
|
||||
if (variable instanceof Error) {
|
||||
return variable.name + ': ' + variable.message;
|
||||
}
|
||||
try {
|
||||
return JSON.stringify(variable, null, ' ');
|
||||
} catch (err) {
|
||||
return variable || '';
|
||||
}
|
||||
}
|
||||
|
||||
async runCaseScript(ctx) {
|
||||
let params = ctx.request.body;
|
||||
let script = params.script;
|
||||
if (!script) {
|
||||
return ctx.body = yapi.commons.resReturn('ok');
|
||||
}
|
||||
|
||||
let logs = [];
|
||||
|
||||
let result = {
|
||||
assert: require('assert'),
|
||||
status: params.response.status,
|
||||
body: params.response.body,
|
||||
header: params.response.header,
|
||||
records: params.records,
|
||||
params: params.params,
|
||||
log: (msg) => {
|
||||
logs.push('log: ' + this.convertString(msg))
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
result = yapi.commons.sandbox(result, script);
|
||||
result.logs = logs;
|
||||
return ctx.body = yapi.commons.resReturn(result);
|
||||
} catch (err) {
|
||||
logs.push(this.convertString(err));
|
||||
result.logs = logs;
|
||||
return ctx.body = yapi.commons.resReturn(result, 400, err.name + ": " + err.message)
|
||||
}
|
||||
|
||||
ctx.body = await yapi.commons.runCaseScript(params);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ const interfaceModel = require('../models/interface.js');
|
||||
const yapi = require('../yapi.js');
|
||||
const baseController = require('./base.js');
|
||||
const { handleParams, crossRequest, handleCurrDomain, checkNameIsExistInArray } = require('../../common/postmanLib')
|
||||
|
||||
const {handleParamsValue, json_parse} = require('../../common/utils.js')
|
||||
|
||||
|
||||
class openController extends baseController{
|
||||
@ -15,10 +15,11 @@ class openController extends baseController{
|
||||
this.interfaceColModel = yapi.getInst(interfaceColModel)
|
||||
this.interfaceCaseModel = yapi.getInst(interfaceCaseModel)
|
||||
this.interfaceModel = yapi.getInst(interfaceModel)
|
||||
|
||||
this.handleValue = this.handleValue.bind(this)
|
||||
this.schemaMap = {
|
||||
runAutoTest: {
|
||||
'*id': 'number'
|
||||
'*id': 'number',
|
||||
'env_name': 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -27,7 +28,14 @@ class openController extends baseController{
|
||||
ctx.body = 'projectInterfaceData'
|
||||
}
|
||||
|
||||
handleValue(val){
|
||||
return handleParamsValue(val, this.records);
|
||||
}
|
||||
|
||||
async runAutoTest(ctx){
|
||||
const records = this.records = {};
|
||||
const reports = this.reports = {};
|
||||
const testList = []
|
||||
let id = ctx.params.id;
|
||||
let curEnv = ctx.params.env_name;
|
||||
let colData = await this.interfaceColModel.get(id);
|
||||
@ -39,17 +47,146 @@ class openController extends baseController{
|
||||
ctx.body = caseList
|
||||
}
|
||||
caseList = caseList.data;
|
||||
caseList = caseList.map(item=>{
|
||||
for(let i=0, l= caseList.length; i< l; i++){
|
||||
let item = caseList[i];
|
||||
item.id = item._id;
|
||||
item.case_env = curEnv || item.case_env;
|
||||
item.req_headers = this.handleReqHeader(item.req_headers, projectData.env, curEnv)
|
||||
return item;
|
||||
})
|
||||
|
||||
item.pre_script = projectData.pre_script;
|
||||
item.after_script = projectData.after_script;
|
||||
item.env= projectData.env;
|
||||
let result;
|
||||
try{
|
||||
result = await this.handleTest(item);
|
||||
}catch(err){
|
||||
result = err;
|
||||
}
|
||||
|
||||
result.body = result.data;
|
||||
reports[item.id] = result;
|
||||
records[item.id] = {
|
||||
params: result.params,
|
||||
body: result.res_body
|
||||
}
|
||||
testList.push(result)
|
||||
}
|
||||
|
||||
function getMessage(testList){
|
||||
let successNum = 0, failedNum = 0, len = 0;
|
||||
testList.forEach(item=>{
|
||||
len++;
|
||||
if(item.code ===0) successNum++;
|
||||
else failedNum++;
|
||||
})
|
||||
if(failedNum === 0){
|
||||
return `一共 ${len} 测试用例,全部验证通过`
|
||||
}
|
||||
return `一共 ${len} 测试用例,${successNum} 个验证通过, ${failedNum} 个未通过。`
|
||||
}
|
||||
|
||||
ctx.body = {
|
||||
message: getMessage(testList),
|
||||
caseNumber: testList.length,
|
||||
list: testList
|
||||
}
|
||||
}
|
||||
|
||||
async handleTest(interfaceData){
|
||||
let requestParams = {};
|
||||
let options;
|
||||
options = handleParams(interfaceData, this.handleValue, requestParams)
|
||||
let result = {
|
||||
id: interfaceData.id,
|
||||
code: 400,
|
||||
validRes: []
|
||||
};
|
||||
try {
|
||||
let data = await crossRequest(options, interfaceData.pre_script, interfaceData.after_script)
|
||||
let res= data.res;
|
||||
|
||||
result = Object.assign(
|
||||
result,
|
||||
{
|
||||
status: res.status,
|
||||
statusText: res.statusText,
|
||||
url: data.req.url,
|
||||
method: data.req.url,
|
||||
data: data.req.data,
|
||||
headers: data.req.headers,
|
||||
res_header: res.header,
|
||||
res_body: res.body
|
||||
}
|
||||
)
|
||||
if (options.data && typeof options.data === 'object') {
|
||||
requestParams = Object.assign(
|
||||
requestParams,
|
||||
options.data
|
||||
)
|
||||
}
|
||||
|
||||
let validRes = [];
|
||||
|
||||
let responseData = Object.assign({}, {
|
||||
status: res.status,
|
||||
body: res.body,
|
||||
header: res.header,
|
||||
statusText: res.statusText
|
||||
})
|
||||
|
||||
await this.handleScriptTest(interfaceData, responseData, validRes, requestParams);
|
||||
result.params = requestParams;
|
||||
if (validRes.length === 0) {
|
||||
result.code = 0;
|
||||
result.validRes = [{ message: '验证通过' }];
|
||||
} else if (validRes.length > 0) {
|
||||
result.code = 1;
|
||||
result.validRes = validRes;
|
||||
}
|
||||
|
||||
}catch(data){
|
||||
result = Object.assign(options,
|
||||
result,
|
||||
{
|
||||
res_header: data.header,
|
||||
res_body: data.body || data.message,
|
||||
status: null,
|
||||
statusText: data.message,
|
||||
code: 400
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
async handleScriptTest (interfaceData, response, validRes, requestParams){
|
||||
if (interfaceData.enable_script !== true) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
let test = await yapi.commons.runCaseScript({
|
||||
response: response,
|
||||
records: this.records,
|
||||
script: interfaceData.test_script,
|
||||
params: requestParams
|
||||
})
|
||||
if (test.errcode !== 0) {
|
||||
test.data.logs.forEach(item => {
|
||||
validRes.push({
|
||||
message: item
|
||||
})
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
validRes.push({
|
||||
message: 'Error: ' + err.message
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleReqHeader(req_header, envData, curEnvName){
|
||||
// console.log('env', env);
|
||||
let currDomain = handleCurrDomain(envData, curEnvName);
|
||||
let header = currDomain.header;
|
||||
header.forEach(item => {
|
||||
|
@ -443,4 +443,47 @@ function handleParamsValue (params, val){
|
||||
let ctxBody = yapi.commons.resReturn(resultList);
|
||||
ctxBody.colData = colData;
|
||||
return ctxBody;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function convertString(variable) {
|
||||
if (variable instanceof Error) {
|
||||
return variable.name + ': ' + variable.message;
|
||||
}
|
||||
try {
|
||||
return JSON.stringify(variable, null, ' ');
|
||||
} catch (err) {
|
||||
return variable || '';
|
||||
}
|
||||
}
|
||||
|
||||
exports.runCaseScript = async function runCaseScript(params){
|
||||
let script = params.script;
|
||||
if (!script) {
|
||||
return yapi.commons.resReturn('ok');
|
||||
}
|
||||
const logs = [];
|
||||
const context = {
|
||||
assert: require('assert'),
|
||||
status: params.response.status,
|
||||
body: params.response.body,
|
||||
header: params.response.header,
|
||||
records: params.records,
|
||||
params: params.params,
|
||||
log: (msg) => {
|
||||
logs.push('log: ' + convertString(msg))
|
||||
}
|
||||
}
|
||||
|
||||
let result = {};
|
||||
try {
|
||||
result = yapi.commons.sandbox(context, script);
|
||||
result.logs = logs;
|
||||
return yapi.commons.resReturn(result);
|
||||
} catch (err) {
|
||||
logs.push(convertString(err));
|
||||
result.logs = logs;
|
||||
return yapi.commons.resReturn(result, 400, err.name + ": " + err.message)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user