feat: 支持导入不同项目测试用例

This commit is contained in:
gaoxiaolin.gao 2018-05-16 20:04:54 +08:00
parent 854badbedc
commit be4e449190
12 changed files with 380 additions and 213 deletions

View File

@ -3,7 +3,12 @@ import PropTypes from 'prop-types'
import { Row, Col, Tabs } from 'antd'
const TabPane = Tabs.TabPane;
function json_format(json) {
return JSON.stringify(json, null, ' ')
// console.log('json',json)
if(json && typeof json === 'object'){
return JSON.stringify(json, null, ' ')
}
return json;
}
const CaseReport = function (props) {

View File

@ -1,49 +1,85 @@
import React, { PureComponent as Component } from 'react'
import PropTypes from 'prop-types'
import React, { PureComponent as Component } from 'react';
import PropTypes from 'prop-types';
// import { connect } from 'react-redux'
import { Table } from 'antd'
import { Table, Select } from 'antd';
import variable from '../../../../constants/variable';
import { connect } from 'react-redux';
const Option = Select.Option;
import { fetchInterfaceListMenu } from '../../../../reducer/modules/interface.js';
@connect(
state => {
return {
projectList: state.project.projectList,
list: state.inter.list
};
},
{
fetchInterfaceListMenu
}
)
export default class ImportInterface extends Component {
constructor(props) {
super(props)
super(props);
}
state = {
selectedRowKeys: [],
categoryCount: {}
}
categoryCount: {},
project: this.props.currProjectId
};
static propTypes = {
list: PropTypes.array,
onChange: PropTypes.func
selectInterface: PropTypes.func,
projectList: PropTypes.array,
currProjectId: PropTypes.string,
fetchInterfaceListMenu: PropTypes.func
};
async componentDidMount() {
// console.log(this.props.currProjectId)
await this.props.fetchInterfaceListMenu(this.props.currProjectId);
}
// 切换项目
onChange = async val => {
this.setState({
project: val,
selectedRowKeys: [],
categoryCount: {}
});
await this.props.fetchInterfaceListMenu(val);
};
render() {
const { list } = this.props;
const { list, projectList } = this.props;
// const { selectedRowKeys } = this.state;
const data = list.map(item => {
return {
key: 'category_' + item._id,
title: item.name,
isCategory: true,
children: item.list ? item.list.map(e => {
e.key = e._id
e.categoryKey = 'category_' + item._id
e.categoryLength = item.list.length
return e
}) : []
}
children: item.list
? item.list.map(e => {
e.key = e._id;
e.categoryKey = 'category_' + item._id;
e.categoryLength = item.list.length;
return e;
})
: []
};
});
const self = this;
const rowSelection = {
// onChange: (selectedRowKeys) => {
// console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
// if (selectedRows.isCategory) {
// const selectedRowKeys = selectedRows.children.map(item => item._id)
// this.setState({ selectedRowKeys })
// }
// this.props.onChange(selectedRowKeys.filter(id => ('' + id).indexOf('category') === -1));
// console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
// if (selectedRows.isCategory) {
// const selectedRowKeys = selectedRows.children.map(item => item._id)
// this.setState({ selectedRowKeys })
// }
// this.props.onChange(selectedRowKeys.filter(id => ('' + id).indexOf('category') === -1));
// },
onSelect: (record, selected) => {
// console.log(record, selected, selectedRows);
@ -53,85 +89,137 @@ export default class ImportInterface extends Component {
const categoryLength = record.categoryLength;
let selectedRowKeys = [];
if (record.isCategory) {
selectedRowKeys = record.children.map(item => item._id).concat(record.key)
selectedRowKeys = record.children.map(item => item._id).concat(record.key);
if (selected) {
selectedRowKeys = selectedRowKeys.filter(id => oldSelecteds.indexOf(id) === -1).concat(oldSelecteds)
selectedRowKeys = selectedRowKeys
.filter(id => oldSelecteds.indexOf(id) === -1)
.concat(oldSelecteds);
categoryCount[categoryKey] = categoryLength;
} else {
selectedRowKeys = oldSelecteds.filter(id => selectedRowKeys.indexOf(id) === -1)
selectedRowKeys = oldSelecteds.filter(id => selectedRowKeys.indexOf(id) === -1);
categoryCount[categoryKey] = 0;
}
} else {
if (selected) {
selectedRowKeys = oldSelecteds.concat(record._id)
selectedRowKeys = oldSelecteds.concat(record._id);
if (categoryCount[categoryKey]) {
categoryCount[categoryKey] += 1;
} else {
categoryCount[categoryKey] = 1;
}
if (categoryCount[categoryKey] === record.categoryLength) {
selectedRowKeys.push(categoryKey)
selectedRowKeys.push(categoryKey);
}
} else {
selectedRowKeys = oldSelecteds.filter(id => id !== record._id)
selectedRowKeys = oldSelecteds.filter(id => id !== record._id);
if (categoryCount[categoryKey]) {
categoryCount[categoryKey] -= 1;
}
selectedRowKeys = selectedRowKeys.filter(id => id !== categoryKey)
selectedRowKeys = selectedRowKeys.filter(id => id !== categoryKey);
}
}
self.setState({ selectedRowKeys, categoryCount })
self.props.onChange(selectedRowKeys.filter(id => ('' + id).indexOf('category') === -1));
self.setState({ selectedRowKeys, categoryCount });
self.props.selectInterface(
selectedRowKeys.filter(id => ('' + id).indexOf('category') === -1),
self.state.project
);
},
onSelectAll: (selected) => {
onSelectAll: selected => {
// console.log(selected, selectedRows, changeRows);
let selectedRowKeys = [];
let categoryCount = self.state.categoryCount;
if (selected) {
data.forEach(item => {
if(item.children) {
if (item.children) {
categoryCount['category_' + item._id] = item.children.length;
selectedRowKeys = selectedRowKeys.concat(item.children.map(item => item._id))
selectedRowKeys = selectedRowKeys.concat(item.children.map(item => item._id));
}
});
selectedRowKeys = selectedRowKeys.concat(data.map(item => item.key))
selectedRowKeys = selectedRowKeys.concat(data.map(item => item.key));
} else {
categoryCount = {};
selectedRowKeys = [];
}
self.setState({ selectedRowKeys, categoryCount })
self.props.onChange(selectedRowKeys.filter(id => ('' + id).indexOf('category') === -1));
self.setState({ selectedRowKeys, categoryCount });
self.props.selectInterface(
selectedRowKeys.filter(id => ('' + id).indexOf('category') === -1),
self.state.project
);
},
selectedRowKeys: self.state.selectedRowKeys
};
const columns = [{
title: '接口名称',
dataIndex: 'title',
width: '30%'
}, {
title: '接口路径',
dataIndex: 'path',
width: '40%'
}, {
title: '请求方法',
dataIndex: 'method',
render: (item) => {
let methodColor = variable.METHOD_COLOR[item ? item.toLowerCase() : 'get'];
return <span style={{color: methodColor.color, backgroundColor: methodColor.bac, borderRadius: 4}} className="colValue">{item}</span>
const columns = [
{
title: '接口名称',
dataIndex: 'title',
width: '30%'
},
{
title: '接口路径',
dataIndex: 'path',
width: '40%'
},
{
title: '请求方法',
dataIndex: 'method',
render: item => {
let methodColor = variable.METHOD_COLOR[item ? item.toLowerCase() : 'get'];
return (
<span
style={{
color: methodColor.color,
backgroundColor: methodColor.bac,
borderRadius: 4
}}
className="colValue"
>
{item}
</span>
);
}
},
{
title: '状态',
dataIndex: 'status',
render: text => {
return (
text &&
(text === 'done' ? (
<span className="tag-status done">已完成</span>
) : (
<span className="tag-status undone">未完成</span>
))
);
}
}
}, {
title: '状态',
dataIndex: 'status',
render: (text) => {
return text && (text === 'done' ? <span className="tag-status done">已完成</span> : <span className="tag-status undone"></span>)
}
}];
];
return (
<div>
{/* <RadioGroup onChange={this.onChange} value={this.state.project}>
{projectList.map(item => {
return (
<Radio value={`${item._id}`} key={item._id}>
{item.name}
</Radio>
);
})}
</RadioGroup> */}
<div className="select-project">
<span>选择要导入的项目 </span>
<Select value={this.state.project} style={{ width: 200 }} onChange={this.onChange}>
{projectList.map(item => {
return (
<Option value={`${item._id}`} key={item._id}>
{item.name}
</Option>
);
})}
</Select>
</div>
<Table columns={columns} rowSelection={rowSelection} dataSource={data} pagination={false} />
</div>
)
);
}
}
}

View File

@ -171,7 +171,7 @@ export default class InterfaceCaseContent extends Component {
after_script: currProject.after_script
}, { _id: currCase._id });
return (
<div style={{ padding: '6px 0' }} className="case-content">
<div className="case-title">
@ -183,7 +183,7 @@ export default class InterfaceCaseContent extends Component {
<Input value={editCasename} onChange={e => this.setState({ editCasename: e.target.value })} style={{ fontSize: 18 }} />
</div>}
<span className="inter-link" style={{ margin: '0px 8px 0px 6px', fontSize: 12 }}>
<Link className="text" to={`/project/${currProject._id}/interface/api/${currCase.interface_id}`}>对应接口</Link>
<Link className="text" to={`/project/${currCase.project_id}/interface/api/${currCase.interface_id}`}>对应接口</Link>
</span>
</div>
<div>

View File

@ -474,7 +474,8 @@ class InterfaceColContent extends Component {
}
render() {
// console.log('rows',this.state.rows);
// console.log('rows',this.props.currProject);
const currProjectId = this.props.currProject._id
const columns = [{
property: 'casename',
header: {
@ -489,7 +490,7 @@ class InterfaceColContent extends Component {
formatters: [
(text, { rowData }) => {
let record = rowData;
return <Link to={"/project/" + record.project_id + "/interface/case/" + record._id}>{record.casename.length > 23 ? record.casename.substr(0, 20) + '...' : record.casename}</Link>
return <Link to={"/project/" + currProjectId + "/interface/case/" + record._id}>{record.casename.length > 23 ? record.casename.substr(0, 20) + '...' : record.casename}</Link>
}
]
}

View File

@ -3,7 +3,8 @@ import { connect } from 'react-redux';
import { withRouter } from 'react-router'
import PropTypes from 'prop-types'
import { fetchInterfaceColList, fetchInterfaceCaseList, setColData, fetchCaseList } from '../../../../reducer/modules/interfaceCol'
import { fetchInterfaceListMenu } from '../../../../reducer/modules/interface.js';
// import { fetchInterfaceListMenu } from '../../../../reducer/modules/interface.js';
import { fetchProjectList } from '../../../../reducer/modules/project'
import axios from 'axios';
// import { Input, Icon, Button, Modal, message, Tooltip, Tree, Dropdown, Menu, Form } from 'antd';
import ImportInterface from './ImportInterface'
@ -52,15 +53,19 @@ const ColModalForm = Form.create()((props) => {
currCase: state.interfaceCol.currCase,
isRander: state.interfaceCol.isRander,
currCaseId: state.interfaceCol.currCaseId,
list: state.inter.list
// list: state.inter.list,
// 当前项目的信息
curProject: state.project.currProject
// projectList: state.project.projectList
}
},
{
fetchInterfaceColList,
fetchInterfaceCaseList,
fetchInterfaceListMenu,
// fetchInterfaceListMenu,
fetchCaseList,
setColData
setColData,
fetchProjectList
}
)
@withRouter
@ -71,15 +76,18 @@ export default class InterfaceColMenu extends Component {
interfaceColList: PropTypes.array,
fetchInterfaceColList: PropTypes.func,
fetchInterfaceCaseList: PropTypes.func,
fetchInterfaceListMenu: PropTypes.func,
// fetchInterfaceListMenu: PropTypes.func,
fetchCaseList: PropTypes.func,
setColData: PropTypes.func,
currCaseId: PropTypes.number,
history: PropTypes.object,
isRander: PropTypes.bool,
list: PropTypes.array,
// list: PropTypes.array,
router: PropTypes.object,
currCase: PropTypes.object
currCase: PropTypes.object,
curProject: PropTypes.object,
fetchProjectList: PropTypes.func
// projectList: PropTypes.array
}
state = {
@ -92,7 +100,8 @@ export default class InterfaceColMenu extends Component {
importColId: 0,
expands: null,
list: [],
delIcon: null
delIcon: null,
selectedProject: null
}
constructor(props) {
@ -279,18 +288,21 @@ export default class InterfaceColMenu extends Component {
this.form = form;
}
selectInterface = (importInterIds) => {
// console.log(importInterIds)
this.setState({ importInterIds })
selectInterface = (importInterIds, selectedProject) => {
this.setState({ importInterIds, selectedProject })
}
showImportInterfaceModal = async (colId) => {
const projectId = this.props.match.params.id;
await this.props.fetchInterfaceListMenu(projectId)
// const projectId = this.props.match.params.id;
// console.log('project', this.props.curProject)
const groupId = this.props.curProject.group_id
await this.props.fetchProjectList(groupId)
// await this.props.fetchInterfaceListMenu(projectId)
this.setState({ importInterVisible: true, importColId: colId })
}
handleImportOk = async () => {
const project_id = this.props.match.params.id;
const project_id = this.state.selectedProject || this.props.match.params.id;
const { importColId, importInterIds } = this.state;
const res = await axios.post('/api/col/add_case_list', {
interface_list: importInterIds,
@ -367,7 +379,7 @@ export default class InterfaceColMenu extends Component {
render() {
// const { currColId, currCaseId, isShowCol } = this.props;
const { colModalType, colModalVisible, importInterVisible } = this.state;
const currProjectId = this.props.match.params.id;
// const menu = (col) => {
// return (
// <Menu>
@ -540,7 +552,7 @@ export default class InterfaceColMenu extends Component {
className="import-case-modal"
width={800}
>
<ImportInterface onChange={this.selectInterface} list={this.props.list} />
<ImportInterface currProjectId={currProjectId} selectInterface={this.selectInterface} />
</Modal>
</div>
)

View File

@ -137,6 +137,10 @@
max-height: 800px;
overflow-y: scroll;
}
.select-project {
margin-bottom: 16px;
}
}
.autoTestsModal{

View File

@ -55,6 +55,22 @@ export default class Project extends Component {
}]);
}
async componentWillReceiveProps(nextProps) {
const currProjectId = this.props.match.params.id;
const nextProjectId = nextProps.match.params.id;
if(currProjectId !== nextProjectId) {
await this.props.getProject(nextProjectId);
this.props.setBreadcrumb([{
name: this.props.currGroup.group_name,
href: '/group/' + this.props.currGroup._id
}, {
name: this.props.curProject.name
}]);
}
}
render() {
const { match, location } = this.props;
let routers = {

View File

@ -9,7 +9,7 @@ const PROJECT_DEL = 'yapi/project/PROJECT_DEL';
const PROJECT_UPDATE = 'yapi/project/PROJECT_UPDATE';
const PROJECT_UPDATE_ENV = 'yapi/project/PROJECT_UPDATE_ENV';
const PROJECT_UPSET = 'yapi/project/PROJECT_UPSET';
const GET_CURR_PROJECT = 'yapi/project/GET_CURR_PROJECT'
const GET_CURR_PROJECT = 'yapi/project/GET_CURR_PROJECT';
const GET_PEOJECT_MEMBER = 'yapi/project/GET_PEOJECT_MEMBER';
const ADD_PROJECT_MEMBER = 'yapi/project/ADD_PROJECT_MEMBER';
const DEL_PROJECT_MEMBER = 'yapi/project/DEL_PROJECT_MEMBER';
@ -19,7 +19,6 @@ const UPDATE_TOKEN = 'yapi/project/UPDATE_TOKEN';
const CHECK_PROJECT_NAME = 'yapi/project/CHECK_PROJECT_NAME';
const COPY_PROJECT_MSG = 'yapi/project/COPY_PROJECT_MSG';
// Reducer
const initialState = {
isUpdateModalShow: false,
@ -31,18 +30,16 @@ const initialState = {
total: 0,
currPage: 1,
token: '',
currProject: {
}
currProject: {}
};
export default (state = initialState, action) => {
switch (action.type) {
case GET_CURR_PROJECT: {
return {
...state,
currProject: action.payload.data.data
}
};
}
case FETCH_PROJECT_LIST: {
@ -65,25 +62,24 @@ export default (state = initialState, action) => {
return {
...state,
token: action.payload.data.data
}
};
}
case UPDATE_TOKEN: {
return {
...state,
token: action.payload.data.data.token
}
};
}
case CHECK_PROJECT_NAME: {
return{
return {
...state
}
};
}
case COPY_PROJECT_MSG: {
return {
...state
}
};
}
default:
return state;
@ -117,7 +113,7 @@ export function addMember(param) {
return {
type: ADD_PROJECT_MEMBER,
payload: axios.post('/api/project/add_member', param)
}
};
}
// 删除项目成员
@ -125,7 +121,7 @@ export function delMember(param) {
return {
type: DEL_PROJECT_MEMBER,
payload: axios.post('/api/project/del_member', param)
}
};
}
// 修改项目成员权限
@ -133,7 +129,7 @@ export function changeMemberRole(param) {
return {
type: CHANGE_PROJECT_MEMBER,
payload: axios.post('/api/project/change_member_role', param)
}
};
}
// 获取项目成员列表
@ -143,7 +139,7 @@ export function getProjectMemberList(id) {
payload: axios.get('/api/project/get_member_list', {
params: { id }
})
}
};
}
// export function changeTableLoading(data) {
@ -154,7 +150,18 @@ export function getProjectMemberList(id) {
// }
export function addProject(data) {
const { name, prd_host, basepath, desc, group_id, group_name, protocol, icon, color, project_type } = data;
const {
name,
prd_host,
basepath,
desc,
group_id,
group_name,
protocol,
icon,
color,
project_type
} = data;
const param = {
name,
prd_host,
@ -221,7 +228,6 @@ export function upsetProject(param) {
};
}
// 删除项目
export function delProject(id) {
const param = { id };
@ -236,34 +242,32 @@ export async function getProject(id) {
return {
type: GET_CURR_PROJECT,
payload: result
}
};
}
export async function getToken(project_id){
export async function getToken(project_id) {
return {
type: GET_TOKEN,
payload: axios.get('/api/project/token', {
params: { project_id }
})
}
};
}
export async function updateToken(project_id){
export async function updateToken(project_id) {
return {
type: UPDATE_TOKEN,
payload: axios.get('/api/project/update_token', {
params: { project_id }
})
}
};
}
export async function checkProjectName(name, group_id){
export async function checkProjectName(name, group_id) {
return {
type: CHECK_PROJECT_NAME,
payload: axios.get('/api/project/check_project_name', {
params: { name, group_id }
})
}
};
}

View File

@ -1,7 +1,7 @@
const { isJson5, json_parse, handleJson, joinPath, safeArray } = require('./utils')
const constants = require('../client/constants/variable.js')
const _ = require("underscore")
const URL = require('url')
const { isJson5, json_parse, handleJson, joinPath, safeArray } = require('./utils');
const constants = require('../client/constants/variable.js');
const _ = require('underscore');
const URL = require('url');
const utils = require('./power-string.js').utils;
const HTTP_METHOD = constants.HTTP_METHOD;
const axios = require('axios');
@ -11,19 +11,21 @@ const isNode = typeof global == 'object' && global.global === global;
const ContentTypeMap = {
'application/json': 'json',
'application/xml': 'xml',
'other': 'text',
other: 'text',
'application/html': 'html'
}
};
async function httpRequestByNode(options) {
function handleRes(response){
if(!response || typeof response !== 'object'){
function handleRes(response) {
if (!response || typeof response !== 'object') {
return {
res: {
status: 500,
body: isNode ? '请求出错, 内网服务器自动化测试无法访问到,请检查是否为内网服务器!': '请求出错'
body: isNode
? '请求出错, 内网服务器自动化测试无法访问到,请检查是否为内网服务器!'
: '请求出错'
}
}
};
}
return {
res: {
@ -31,47 +33,54 @@ async function httpRequestByNode(options) {
status: response.status,
body: response.data
}
}
};
}
function handleData(){
function handleData() {
let contentTypeItem;
if(!options) return;
if(typeof options.headers === 'object' && options.headers ){
if (!options) return;
if (typeof options.headers === 'object' && options.headers) {
Object.keys(options.headers).forEach(key => {
if (/content-type/i.test(key)) {
if(options.headers[key]){
contentTypeItem = options.headers[key].split(";")[0].trim().toLowerCase();
}
if (options.headers[key]) {
contentTypeItem = options.headers[key]
.split(';')[0]
.trim()
.toLowerCase();
}
}
if(!options.headers[key]) delete options.headers[key];
})
if (!options.headers[key]) delete options.headers[key];
});
if(contentTypeItem === 'application/x-www-form-urlencoded' && typeof options.data === 'object' && options.data){
options.data = qs.stringify(options.data);
if (
contentTypeItem === 'application/x-www-form-urlencoded' &&
typeof options.data === 'object' &&
options.data
) {
options.data = qs.stringify(options.data);
}
}
}
try{
try {
handleData(options);
let response=await axios({
let response = await axios({
method: options.method,
url: options.url,
headers: options.headers,
timeout: 5000,
data: options.data
})
return handleRes(response)
}catch(err){
if(err.response === undefined){
});
return handleRes(response);
} catch (err) {
if (err.response === undefined) {
handleRes({
headers: {},
status: null,
data: err.message
})
});
}
return handleRes(err.response)
return handleRes(err.response);
}
}
@ -81,18 +90,25 @@ function handleContentType(headers) {
try {
Object.keys(headers).forEach(key => {
if (/content-type/i.test(key)) {
contentTypeItem = headers[key].split(";")[0].trim().toLowerCase();
contentTypeItem = headers[key]
.split(';')[0]
.trim()
.toLowerCase();
}
})
});
return ContentTypeMap[contentTypeItem] ? ContentTypeMap[contentTypeItem] : ContentTypeMap.other;
} catch (err) {
return ContentTypeMap.other
return ContentTypeMap.other;
}
}
function checkRequestBodyIsRaw(method, reqBodyType) {
if (reqBodyType && reqBodyType !== 'file' && reqBodyType !== 'form' && HTTP_METHOD[method].request_body) {
if (
reqBodyType &&
reqBodyType !== 'file' &&
reqBodyType !== 'form' &&
HTTP_METHOD[method].request_body
) {
return reqBodyType;
}
return false;
@ -103,14 +119,13 @@ function checkNameIsExistInArray(name, arr) {
for (let i = 0; i < arr.length; i++) {
let item = arr[i];
if (item.name === name) {
isRepeat = true
isRepeat = true;
break;
}
}
return isRepeat;
}
function handleCurrDomain(domains, case_env) {
let currDomain = _.find(domains, item => item.name === case_env);
if (!currDomain) {
@ -119,7 +134,7 @@ function handleCurrDomain(domains, case_env) {
return currDomain;
}
function sandboxByNode(sandbox={}, script){
function sandboxByNode(sandbox = {}, script) {
const vm = require('vm');
script = new vm.Script(script);
const context = new vm.createContext(sandbox);
@ -129,35 +144,32 @@ function sandboxByNode(sandbox={}, script){
return sandbox;
}
async function sandbox(context={}, script){
if(isNode){
try{
async function sandbox(context = {}, script) {
if (isNode) {
try {
context.context = context;
context.console = console;
context.Promise = Promise;
context.setTimeout = setTimeout;
context = sandboxByNode(context, script)
}catch(err){
context = sandboxByNode(context, script);
} catch (err) {
err.message = `Script: ${script}
message: ${err.message}`
message: ${err.message}`;
throw err;
}
}else{
context = sandboxByBrowser(context, script)
} else {
context = sandboxByBrowser(context, script);
}
if(context.promise && typeof context.promise === 'object' && context.promise.then){
try{
await context.promise
}catch(err){
if (context.promise && typeof context.promise === 'object' && context.promise.then) {
try {
await context.promise;
} catch (err) {
err.message = `Script: ${script}
message: ${err.message}`
message: ${err.message}`;
throw err;
}
}
return context;
}
function sandboxByBrowser(context = {}, script) {
@ -171,40 +183,60 @@ function sandboxByBrowser(context = {}, script) {
try {
eval(beginScript + script);
} catch (err) {
console.log('----CodeBegin----: ')
console.log(beginScript + script)
console.log('----CodeEnd----')
console.log(err);
return context;
let message = `Script:
----CodeBegin----:
${beginScript}
${script}
----CodeEnd----
`;
err.message = `Script: ${message}
message: ${err.message}`;
throw err;
}
return context;
}
async function crossRequest(defaultOptions, preScript, afterScript) {
let options = Object.assign({}, defaultOptions);
let urlObj = URL.parse(options.url, true), query = {};
let urlObj = URL.parse(options.url, true),
query = {};
query = Object.assign(query, urlObj.query);
let context = {
get href() {
return urlObj.href;
},
set href(val){
throw new Error('context.href 不能被赋值')
},
get hostname() {
return urlObj.hostname;
},
set hostname(val){
throw new Error('context.hostname 不能被赋值')
},
method: options.method,
pathname: urlObj.pathname,
query: query,
requestHeader: options.headers || {},
requestBody: options.data,
promise: false,
utils: {
_: _,
base64: utils.base64,
md5: utils.md5,
sha1: utils.sha1,
sha224: utils.sha224,
sha256: utils.sha256,
sha384: utils.sha384,
sha512: utils.sha512,
unbase64: utils.unbase64,
axios: axios
}
promise: false
};
context.utils = Object.freeze({
_: _,
base64: utils.base64,
md5: utils.md5,
sha1: utils.sha1,
sha224: utils.sha224,
sha256: utils.sha256,
sha384: utils.sha384,
sha512: utils.sha512,
unbase64: utils.unbase64,
axios: axios
})
if (preScript) {
context = await sandbox(context, preScript);
defaultOptions.url = options.url = URL.format({
@ -212,22 +244,21 @@ async function crossRequest(defaultOptions, preScript, afterScript) {
host: urlObj.host,
query: context.query,
pathname: context.pathname
})
});
defaultOptions.headers = options.headers = context.requestHeader;
defaultOptions.data = options.data = context.requestBody;
}
let data;
if(isNode){
data = await httpRequestByNode(options)
if (isNode) {
data = await httpRequestByNode(options);
data.req = options;
}else{
data = await (new Promise((resolve, reject) => {
options.error = options.success = function (res, header, data) {
} else {
data = await new Promise((resolve, reject) => {
options.error = options.success = function(res, header, data) {
let message = '';
if(res && typeof res === 'string'){
if (res && typeof res === 'string') {
res = json_parse(data.res.body);
data.res.body = res;
}
@ -237,14 +268,14 @@ async function crossRequest(defaultOptions, preScript, afterScript) {
body: res || message,
header,
message
})
});
}
resolve(data);
}
};
window.crossRequest(options);
}))
});
}
if (afterScript) {
context.responseData = data.res.body;
context.responseHeader = data.res.header;
@ -259,7 +290,6 @@ async function crossRequest(defaultOptions, preScript, afterScript) {
return data;
}
function handleParams(interfaceData, handleValue, requestParams) {
function paramsToObjectWithEnable(arr) {
const obj = {};
@ -270,7 +300,7 @@ function handleParams(interfaceData, handleValue, requestParams) {
requestParams[item.name] = obj[item.name];
}
}
})
});
return obj;
}
@ -283,13 +313,14 @@ function handleParams(interfaceData, handleValue, requestParams) {
requestParams[item.name] = obj[item.name];
}
}
})
});
return obj;
}
let { case_env, path, env } = interfaceData;
let currDomain, requestBody, requestOptions = {};
let currDomain,
requestBody,
requestOptions = {};
interfaceData.req_params = interfaceData.req_params || [];
interfaceData.req_params.forEach(item => {
@ -301,7 +332,6 @@ function handleParams(interfaceData, handleValue, requestParams) {
path = path.replace(`{${item.name}}`, val || `{${item.name}}`);
});
currDomain = handleCurrDomain(env, case_env);
const urlObj = URL.parse(joinPath(currDomain.domain, path), true);
const url = URL.format({
@ -309,7 +339,6 @@ function handleParams(interfaceData, handleValue, requestParams) {
host: urlObj.host,
pathname: urlObj.pathname,
query: Object.assign(urlObj.query, paramsToObjectWithEnable(interfaceData.req_query))
});
requestOptions = {
@ -317,13 +346,15 @@ function handleParams(interfaceData, handleValue, requestParams) {
method: interfaceData.method,
headers: paramsToObjectUnWithEnable(interfaceData.req_headers),
timeout: 82400000
}
};
if (HTTP_METHOD[interfaceData.method].request_body) {
if (interfaceData.req_body_type === 'form') {
requestBody = paramsToObjectWithEnable(safeArray(interfaceData.req_body_form).filter(item => {
return item.type == 'text'
}));
requestBody = paramsToObjectWithEnable(
safeArray(interfaceData.req_body_form).filter(item => {
return item.type == 'text';
})
);
} else if (interfaceData.req_body_type === 'json') {
let reqBody = isJson5(interfaceData.req_body_other);
if (reqBody === false) {
@ -339,16 +370,17 @@ function handleParams(interfaceData, handleValue, requestParams) {
}
requestOptions.data = requestBody;
if (interfaceData.req_body_type === 'form') {
requestOptions.files = paramsToObjectWithEnable(safeArray(interfaceData.req_body_form).filter(item => {
return item.type == 'file'
}))
requestOptions.files = paramsToObjectWithEnable(
safeArray(interfaceData.req_body_form).filter(item => {
return item.type == 'file';
})
);
} else if (interfaceData.req_body_type === 'file') {
requestOptions.file = 'single-file'
requestOptions.file = 'single-file';
}
}
return requestOptions;
}
exports.checkRequestBodyIsRaw = checkRequestBodyIsRaw;

View File

@ -135,7 +135,7 @@ context = {
context.responseBody.a = 2;
```
> v1.3.16+新增context.href和context.hostname
### 工具函数
```
context.utils = {
@ -172,6 +172,8 @@ context.promise = new Promise(function(resolve){
> 处理完成后,不要忘记 `resolve()`,不然会一直处于挂起状态
## token配置
每个项目都有唯一的标识token用户可以使用这个token值来请求项目的所有资源数据。目前用到的地方是接口的<a href="./case.md">自动化测试</a>,用户不需要登录就可以访问接口测试结果信息。

View File

@ -59,7 +59,7 @@ class interfaceCase extends baseModel {
}
list(col_id, select) {
select = select || 'casename uid col_id _id index interface_id'
select = select || 'casename uid col_id _id index interface_id project_id'
if (select === 'all') {
return this.model.find({
col_id: col_id
@ -67,7 +67,7 @@ class interfaceCase extends baseModel {
}
return this.model.find({
col_id: col_id
}).select("casename uid col_id _id index interface_id").exec();
}).select(select).exec();
}
del(id) {

View File

@ -1,7 +1,10 @@
const defaultTheme = require("./defaultTheme.js");
function json_format(json) {
return JSON.stringify(json, null, ' ')
if(json && typeof json === 'object'){
return JSON.stringify(json, null, ' ')
}
return json;
}
module.exports = function renderToHtml(reports){