import React, { PureComponent as Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router';
import { Link } from 'react-router-dom';
//import constants from '../../../../constants/variable.js'
import { Tooltip, Icon,Input, Button, Row, Col, Spin, Modal, message, Select, Switch } from 'antd';
import {
fetchInterfaceColList,
fetchCaseList,
setColData,
fetchCaseEnvList
} from '../../../../reducer/modules/interfaceCol';
import HTML5Backend from 'react-dnd-html5-backend';
import { getToken, getEnv } from '../../../../reducer/modules/project';
import { DragDropContext } from 'react-dnd';
import AceEditor from 'client/components/AceEditor/AceEditor';
import * as Table from 'reactabular-table';
import * as dnd from 'reactabular-dnd';
import * as resolve from 'table-resolver';
import axios from 'axios';
import CaseReport from './CaseReport.js';
import _ from 'underscore';
import { initCrossRequest } from 'client/components/Postman/CheckCrossInstall.js';
import produce from 'immer';
import {InsertCodeMap} from 'client/components/Postman/Postman.js'
const plugin = require('client/plugin.js');
const {
handleParams,
crossRequest,
handleCurrDomain,
checkNameIsExistInArray
} = require('common/postmanLib.js');
const { handleParamsValue, json_parse, ArrayToObject } = require('common/utils.js');
import CaseEnv from 'client/components/CaseEnv';
import Label from '../../../../components/Label/Label.js';
const Option = Select.Option;
const createContext = require('common/createContext')
import copy from 'copy-to-clipboard';
const defaultModalStyle = {
top: 10
}
function handleReport(json) {
try {
return JSON.parse(json);
} catch (e) {
return {};
}
}
@connect(
state => {
return {
interfaceColList: state.interfaceCol.interfaceColList,
currColId: state.interfaceCol.currColId,
currCaseId: state.interfaceCol.currCaseId,
isShowCol: state.interfaceCol.isShowCol,
isRander: state.interfaceCol.isRander,
currCaseList: state.interfaceCol.currCaseList,
currProject: state.project.currProject,
token: state.project.token,
envList: state.interfaceCol.envList,
curProjectRole: state.project.currProject.role,
projectEnv: state.project.projectEnv,
curUid: state.user.uid
};
},
{
fetchInterfaceColList,
fetchCaseList,
setColData,
getToken,
getEnv,
fetchCaseEnvList
}
)
@withRouter
@DragDropContext(HTML5Backend)
class InterfaceColContent extends Component {
static propTypes = {
match: PropTypes.object,
interfaceColList: PropTypes.array,
fetchInterfaceColList: PropTypes.func,
fetchCaseList: PropTypes.func,
setColData: PropTypes.func,
history: PropTypes.object,
currCaseList: PropTypes.array,
currColId: PropTypes.number,
currCaseId: PropTypes.number,
isShowCol: PropTypes.bool,
isRander: PropTypes.bool,
currProject: PropTypes.object,
getToken: PropTypes.func,
token: PropTypes.string,
curProjectRole: PropTypes.string,
getEnv: PropTypes.func,
projectEnv: PropTypes.object,
fetchCaseEnvList: PropTypes.func,
envList: PropTypes.array,
curUid: PropTypes.number
};
constructor(props) {
super(props);
this.reports = {};
this.records = {};
this.state = {
rows: [],
reports: {},
visible: false,
curCaseid: null,
hasPlugin: false,
advVisible: false,
curScript: '',
enableScript: false,
autoVisible: false,
mode: 'html',
email: false,
download: false,
currColEnvObj: {},
collapseKey: '1',
commonSettingModalVisible: false,
commonSetting: {
checkHttpCodeIs200: false,
checkResponseField: {
name: 'code',
value: '0',
enable: false
},
checkResponseSchema: false,
checkScript:{
enable: false,
content: ''
}
}
};
this.onRow = this.onRow.bind(this);
this.onMoveRow = this.onMoveRow.bind(this);
}
async handleColIdChange(newColId){
this.props.setColData({
currColId: +newColId,
isShowCol: true,
isRander: false
});
let result = await this.props.fetchCaseList(newColId);
if (result.payload.data.errcode === 0) {
this.reports = handleReport(result.payload.data.colData.test_report);
this.setState({
commonSetting:{
...this.state.commonSetting,
...result.payload.data.colData
}
})
}
await this.props.fetchCaseList(newColId);
await this.props.fetchCaseEnvList(newColId);
this.changeCollapseClose();
this.handleColdata(this.props.currCaseList);
}
async UNSAFE_componentWillMount() {
const result = await this.props.fetchInterfaceColList(this.props.match.params.id);
await this.props.getToken(this.props.match.params.id);
let { currColId } = this.props;
const params = this.props.match.params;
const { actionId } = params;
this.currColId = currColId = +actionId || result.payload.data.data[0]._id;
// this.props.history.push('/project/' + params.id + '/interface/col/' + currColId);
if (currColId && currColId != 0) {
await this.handleColIdChange(currColId)
}
this._crossRequestInterval = initCrossRequest(hasPlugin => {
this.setState({ hasPlugin: hasPlugin });
});
}
componentWillUnmount() {
clearInterval(this._crossRequestInterval);
}
// 更新分类简介
handleChangeInterfaceCol = (desc, name) => {
let params = {
col_id: this.props.currColId,
name: name,
desc: desc
};
axios.post('/api/col/up_col', params).then(async res => {
if (res.data.errcode) {
return message.error(res.data.errmsg);
}
let project_id = this.props.match.params.id;
await this.props.fetchInterfaceColList(project_id);
message.success('接口集合简介更新成功');
});
};
// 整合header信息
handleReqHeader = (project_id, req_header, case_env) => {
let envItem = _.find(this.props.envList, item => {
return item._id === project_id;
});
let currDomain = handleCurrDomain(envItem && envItem.env, case_env);
let header = currDomain.header;
header.forEach(item => {
if (!checkNameIsExistInArray(item.name, req_header)) {
// item.abled = true;
item = {
...item,
abled: true
};
req_header.push(item);
}
});
return req_header;
};
handleColdata = (rows, currColEnvObj = {}) => {
let that = this;
let newRows = produce(rows, draftRows => {
draftRows.map(item => {
item.id = item._id;
item._test_status = item.test_status;
if(currColEnvObj[item.project_id]){
item.case_env =currColEnvObj[item.project_id];
}
item.req_headers = that.handleReqHeader(item.project_id, item.req_headers, item.case_env);
return item;
});
});
this.setState({ rows: newRows });
};
executeTests = async () => {
for (let i = 0, l = this.state.rows.length, newRows, curitem; i < l; i++) {
let { rows } = this.state;
let envItem = _.find(this.props.envList, item => {
return item._id === rows[i].project_id;
});
curitem = Object.assign(
{},
rows[i],
{
env: envItem.env,
pre_script: this.props.currProject.pre_script,
after_script: this.props.currProject.after_script
},
{ test_status: 'loading' }
);
newRows = [].concat([], rows);
newRows[i] = curitem;
this.setState({ rows: newRows });
let status = 'error',
result;
try {
result = await this.handleTest(curitem);
if (result.code === 400) {
status = 'error';
} else if (result.code === 0) {
status = 'ok';
} else if (result.code === 1) {
status = 'invalid';
}
} catch (e) {
console.error(e);
status = 'error';
result = e;
}
//result.body = result.data;
this.reports[curitem._id] = result;
this.records[curitem._id] = {
status: result.status,
params: result.params,
body: result.res_body
};
curitem = Object.assign({}, rows[i], { test_status: status });
newRows = [].concat([], rows);
newRows[i] = curitem;
this.setState({ rows: newRows });
}
await axios.post('/api/col/up_col', {
col_id: this.props.currColId,
test_report: JSON.stringify(this.reports)
});
};
handleTest = async interfaceData => {
let requestParams = {};
let options = handleParams(interfaceData, this.handleValue, requestParams);
let result = {
code: 400,
msg: '数据异常',
validRes: []
};
await plugin.emitHook('before_col_request', Object.assign({}, options, {
type: 'col',
caseId: options.caseId,
projectId: interfaceData.project_id,
interfaceId: interfaceData.interface_id
}));
try {
let data = await crossRequest(options, interfaceData.pre_script, interfaceData.after_script, createContext(
this.props.curUid,
this.props.match.params.id,
interfaceData.interface_id
));
options.taskId = this.props.curUid;
let res = (data.res.body = json_parse(data.res.body));
result = {
...options,
...result,
res_header: data.res.header,
res_body: res,
status: data.res.status,
statusText: data.res.statusText
};
await plugin.emitHook('after_col_request', result, {
type: 'col',
caseId: options.caseId,
projectId: interfaceData.project_id,
interfaceId: interfaceData.interface_id
});
if (options.data && typeof options.data === 'object') {
requestParams = {
...requestParams,
...options.data
};
}
let validRes = [];
let responseData = Object.assign(
{},
{
status: data.res.status,
body: res,
header: data.res.header,
statusText: data.res.statusText
}
);
// 断言测试
await this.handleScriptTest(interfaceData, responseData, validRes, 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 = {
...options,
...result,
res_header: data.header,
res_body: data.body || data.message,
status: 0,
statusText: data.message,
code: 400,
validRes: [
{
message: data.message
}
]
};
}
result.params = requestParams;
return result;
};
//response, validRes
// 断言测试
handleScriptTest = async (interfaceData, response, validRes, requestParams) => {
// 是否启动断言
try {
let test = await axios.post('/api/col/run_script', {
response: response,
records: this.records,
script: interfaceData.test_script,
params: requestParams,
col_id: this.props.currColId,
interface_id: interfaceData.interface_id
});
if (test.data.errcode !== 0) {
test.data.data.logs.forEach(item => {
validRes.push({ message: item });
});
}
} catch (err) {
validRes.push({
message: 'Error: ' + err.message
});
}
};
handleValue = (val, global) => {
let globalValue = ArrayToObject(global);
let context = Object.assign({}, { global: globalValue }, this.records);
return handleParamsValue(val, context);
};
arrToObj = (arr, requestParams) => {
arr = arr || [];
const obj = {};
arr.forEach(item => {
if (item.name && item.enable && item.type !== 'file') {
obj[item.name] = this.handleValue(item.value);
if (requestParams) {
requestParams[item.name] = obj[item.name];
}
}
});
return obj;
};
onRow(row) {
return { rowId: row.id, onMove: this.onMoveRow, onDrop: this.onDrop };
}
onDrop = () => {
let changes = [];
this.state.rows.forEach((item, index) => {
changes.push({ id: item._id, index: index });
});
axios.post('/api/col/up_case_index', changes).then(() => {
this.props.fetchInterfaceColList(this.props.match.params.id);
});
};
onMoveRow({ sourceRowId, targetRowId }) {
let rows = dnd.moveRows({ sourceRowId, targetRowId })(this.state.rows);
if (rows) {
this.setState({ rows });
}
}
onChangeTest = d => {
this.setState({
commonSetting: {
...this.state.commonSetting,
checkScript: {
...this.state.commonSetting.checkScript,
content: d.text
}
}
});
};
handleInsertCode = code => {
this.aceEditor.editor.insertCode(code);
};
async UNSAFE_componentWillReceiveProps(nextProps) {
let newColId = !isNaN(nextProps.match.params.actionId) ? +nextProps.match.params.actionId : 0;
if (newColId && ((this.currColId && newColId !== this.currColId) || nextProps.isRander)) {
this.currColId = newColId;
this.handleColIdChange(newColId)
}
}
// 测试用例环境面板折叠
changeCollapseClose = key => {
if (key) {
this.setState({
collapseKey: key
});
} else {
this.setState({
collapseKey: '1',
currColEnvObj: {}
});
}
};
openReport = id => {
if (!this.reports[id]) {
return message.warn('还没有生成报告');
}
this.setState({ visible: true, curCaseid: id });
};
openAdv = id => {
let findCase = _.find(this.props.currCaseList, item => item.id === id);
this.setState({
enableScript: findCase.enable_script,
curScript: findCase.test_script,
advVisible: true,
curCaseid: id
});
};
handleScriptChange = d => {
this.setState({ curScript: d.text });
};
handleAdvCancel = () => {
this.setState({ advVisible: false });
};
handleAdvOk = async () => {
const { curCaseid, enableScript, curScript } = this.state;
const res = await axios.post('/api/col/up_case', {
id: curCaseid,
test_script: curScript,
enable_script: enableScript
});
if (res.data.errcode === 0) {
message.success('更新成功');
}
this.setState({ advVisible: false });
let currColId = this.currColId;
this.props.setColData({
currColId: +currColId,
isShowCol: true,
isRander: false
});
await this.props.fetchCaseList(currColId);
this.handleColdata(this.props.currCaseList);
};
handleCancel = () => {
this.setState({ visible: false });
};
currProjectEnvChange = (envName, project_id) => {
let currColEnvObj = {
...this.state.currColEnvObj,
[project_id]: envName
};
this.setState({ currColEnvObj });
// this.handleColdata(this.props.currCaseList, envName, project_id);
this.handleColdata(this.props.currCaseList,currColEnvObj);
};
autoTests = () => {
this.setState({ autoVisible: true, currColEnvObj: {}, collapseKey: '' });
};
handleAuto = () => {
this.setState({
autoVisible: false,
email: false,
download: false,
mode: 'html',
currColEnvObj: {},
collapseKey: ''
});
};
copyUrl = url => {
copy(url);
message.success('已经成功复制到剪切板');
};
modeChange = mode => {
this.setState({ mode });
};
emailChange = email => {
this.setState({ email });
};
downloadChange = download => {
this.setState({ download });
};
handleColEnvObj = envObj => {
let str = '';
for (let key in envObj) {
str += envObj[key] ? `&env_${key}=${envObj[key]}` : '';
}
return str;
};
handleCommonSetting = ()=>{
let setting = this.state.commonSetting;
let params = {
col_id: this.props.currColId,
...setting
};
console.log(params)
axios.post('/api/col/up_col', params).then(async res => {
if (res.data.errcode) {
return message.error(res.data.errmsg);
}
message.success('配置测试集成功');
});
this.setState({
commonSettingModalVisible: false
})
}
cancelCommonSetting = ()=>{
this.setState({
commonSettingModalVisible: false
})
}
openCommonSetting = ()=>{
this.setState({
commonSettingModalVisible: true
})
}
changeCommonFieldSetting = (key)=>{
return (e)=>{
let value = e;
if(typeof e === 'object' && e){
value = e.target.value;
}
let {checkResponseField} = this.state.commonSetting;
this.setState({
commonSetting: {
...this.state.commonSetting,
checkResponseField: {
...checkResponseField,
[key]: value
}
}
})
}
}
render() {
const currProjectId = this.props.currProject._id;
const columns = [
{
property: 'casename',
header: {
label: '用例名称'
},
props: {
style: {
width: '250px'
}
},
cell: {
formatters: [
(text, { rowData }) => {
let record = rowData;
return (
{record.casename.length > 23
? record.casename.substr(0, 20) + '...'
: record.casename}
);
}
]
}
},
{
header: {
label: 'key',
formatters: [
() => {
return (