feat: add autotest

This commit is contained in:
suxiaoxin 2018-02-08 21:29:10 +08:00
parent 3c9941c9f3
commit 3c70917b93
5 changed files with 275 additions and 83 deletions

View File

@ -254,8 +254,6 @@ class InterfaceColContent extends Component {
statusText: data.message,
code: 400
}
result.code = 400;
}
result.params = requestParams;

View File

@ -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,

View File

@ -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);
}
}

View File

@ -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 => {

View File

@ -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)
}
}