feat: 增加自动化测试弹窗

This commit is contained in:
gaoxiaolin.gao 2018-02-11 17:24:14 +08:00
parent ae9c3cfa86
commit 2da67b618b
9 changed files with 174 additions and 20 deletions

View File

@ -4,9 +4,10 @@ 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, Button, Spin, Modal, message, Select, Switch } from 'antd'
import { Tooltip, Icon, Button, Row, Col, Spin, Modal, message, Select, Switch } from 'antd'
import { fetchInterfaceColList, fetchCaseList, setColData } from '../../../../reducer/modules/interfaceCol'
import HTML5Backend from 'react-dnd-html5-backend';
import { getToken } from '../../../../reducer/modules/project';
import { DragDropContext } from 'react-dnd';
import AceEditor from 'client/components/AceEditor/AceEditor';
import * as Table from 'reactabular-table';
@ -21,6 +22,8 @@ const { handleParams, crossRequest, handleCurrDomain, checkNameIsExistInArray }
const {handleParamsValue, json_parse} = require('common/utils.js')
const Option = Select.Option;
import copy from 'copy-to-clipboard';
function handleReport(json) {
@ -41,13 +44,16 @@ function handleReport(json) {
isShowCol: state.interfaceCol.isShowCol,
isRander: state.interfaceCol.isRander,
currCaseList: state.interfaceCol.currCaseList,
currProject: state.project.currProject
currProject: state.project.currProject,
token: state.project.token,
curProjectRole: state.project.currProject.role
}
},
{
fetchInterfaceColList,
fetchCaseList,
setColData
setColData,
getToken
}
)
@withRouter
@ -66,7 +72,10 @@ class InterfaceColContent extends Component {
currCaseId: PropTypes.number,
isShowCol: PropTypes.bool,
isRander: PropTypes.bool,
currProject: PropTypes.object
currProject: PropTypes.object,
getToken: PropTypes.func,
token: PropTypes.string,
curProjectRole: PropTypes.string
}
constructor(props) {
@ -82,7 +91,9 @@ class InterfaceColContent extends Component {
currColEnv: '',
advVisible: false,
curScript: '',
enableScript: false
enableScript: false,
autoVisible: false,
mode: 'html'
};
this.onRow = this.onRow.bind(this);
this.onMoveRow = this.onMoveRow.bind(this);
@ -90,7 +101,8 @@ class InterfaceColContent extends Component {
}
async componentWillMount() {
const result = await this.props.fetchInterfaceColList(this.props.match.params.id)
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;
@ -402,11 +414,35 @@ class InterfaceColContent extends Component {
}
colEnvChange = (envName) => {
this.setState({
currColEnv: envName
}, () => this.handleColdata(this.props.currCaseList));
}
autoTests = () =>{
this.setState({
autoVisible: true
})
}
handleAuto = () =>{
this.setState({
autoVisible: false
})
}
copyUrl =(url) =>{
console.log('url',url);
copy(url)
message.success('已经成功复制到剪切板');
}
modeChange =(mode)=>{
this.setState({
mode
})
}
@ -537,6 +573,8 @@ class InterfaceColContent extends Component {
method: resolve.nested
})(rows);
let colEnv = this.props.currProject.env || [];
const localUrl = location.protocol + '//' + location.hostname + (location.port !== "" ? ":" + location.port : "");
const autoTestsUrl = `/api/open/run_auto_test?id=${this.props.currColId}&token=${this.props.token}${this.state.currColEnv ? '&env_name='+this.state.currColEnv: ''}&mode=${this.state.mode}`;
return (
<div className="interface-col">
<h2 className="interface-title" style={{ display: 'inline-block', margin: "0 20px", marginBottom: '16px' }}>测试集合&nbsp;<a target="_blank" rel="noopener noreferrer" href="https://yapi.ymfe.org/case.html" >
@ -553,7 +591,11 @@ class InterfaceColContent extends Component {
</Select>
</div>
{this.state.hasPlugin ?
<Button type="primary" style={{ float: 'right' }} onClick={this.executeTests}>开始测试</Button> :
<div style={{ float: 'right' }}>
{this.props.curProjectRole !=='guest'? <Button style={{ marginRight: '8px' }} onClick={this.autoTests}>自动化测试</Button>:null}
<Button type="primary" onClick={this.executeTests}>开始测试</Button>
</div>
:
<Tooltip title="请安装 cross-request Chrome 插件">
<Button disabled type="primary" style={{ float: 'right' }} >开始测试</Button>
</Tooltip>
@ -603,6 +645,51 @@ class InterfaceColContent extends Component {
<AceEditor className="case-script" data={this.state.curScript} onChange={this.handleScriptChange} />
</Modal>
<Modal
title="自动化测试"
width="780px"
style={{ minHeight: '500px' }}
visible={this.state.autoVisible}
onCancel={this.handleAuto}
className="autoTestsModal"
footer={null}
>
<Row type="flex" justify="space-around" className="row" align="middle">
<Col span={3} className="label">选择环境</Col>
<Col span={21}>
<Select value={currColEnv} style={{ width: "320px" }} onChange={this.colEnvChange}>
<Option key="default" value="" >默认使用 case 详情页面保存的 domain</Option>
{
colEnv.map((item) => {
return <Option key={item._id} value={item.name}>{item.name + ": " + item.domain}</Option>;
})
}
</Select>
</Col>
</Row>
<Row type="flex" justify="space-around" className="row" align="middle">
<Col span={3} className="label">输出样式</Col>
<Col span={21}>
<Select value={this.state.mode} onChange={this.modeChange}>
<Option key="html" value="html" >默认展示 html 页面</Option>
<Option key="json" value="json" >展示 json 页面</Option>
</Select>
</Col>
</Row>
<Row type="flex" justify="space-around" className="row" align="middle">
<Col span={21} className="autoTestUrl"><a href={localUrl+autoTestsUrl} target="_blank">{autoTestsUrl}</a></Col>
<Col span={3}>
<Button className="copy-btn" onClick={()=>this.copyUrl(localUrl+autoTestsUrl)}>复制</Button>
</Col>
</Row>
<div className="autoTestMsg">
访问该URL可以测试所有用例
</div>
</Modal>
</div>
)
}

View File

@ -128,6 +128,8 @@
padding: 5px 10px;
max-width: 90px;
}
}
.import-case-modal{
@ -137,3 +139,39 @@
}
}
.autoTestsModal{
.autoTestUrl{
background-color: #f5f5f5;
border: 1px solid #f1f1f1ce;
padding: 16px;
}
.autoTestMsg{
padding: 8px 0 16px;
font-size: 12px;
}
.copy-btn{
margin-left: 16px;
height: 50px;
font-size: 14px;
width: 70px;
}
.ant-modal-body{
padding-top: 32px;
}
.row{
margin-bottom: .24rem;
}
.label{
text-align: left;
}
}

View File

@ -825,7 +825,7 @@ class InterfaceEditForm extends Component {
</pre>}>
<Icon type="question-circle-o" style={{ color: "#086dbf" }} />
</Tooltip>
<span style={{ color: 'rgb(0, 168, 84)' }}>全局编辑 </span> 退 F9
全局编辑 退出全屏 请按 <span style={{fontWeight: '500'}}>F9</span>
</Col>
<Col id="req_body_json" style={{ minHeight: "300px" }}>
</Col>
@ -882,13 +882,13 @@ class InterfaceEditForm extends Component {
</Tabs>
<div>
<h3 style={{ padding: '10px 0' }}>基于 mockjs json5,使用注释方式写参数说明 <Tooltip title={<pre>
<div style={{ padding: '10px 0',fontSize: '15px' }}>基于 mockjs json5,使用注释方式写参数说明 <Tooltip title={<pre>
{Json5Example}
</pre>}>
<Icon type="question-circle-o" style={{ color: "#086dbf" }} />
</Tooltip> ,具体使用方法请 <span className="href" onClick={() => window.open('https://yapi.ymfe.org/mock.html', '_blank')}>查看文档</span>
<span style={{ color: 'rgb(0, 168, 84)' }}>全局编辑 </span> 退 F9
</h3>
全局编辑 退出全屏 请按 <span style={{fontWeight: '500'}}>F9</span>
</div>
<div id="res_body_json" style={{ minHeight: "300px", display: this.state.jsonType === 'tpl' ? 'block' : 'none' }} ></div>
<div id="mock-preview" style={{ backgroundColor: "#eee", lineHeight: "20px", minHeight: "300px", display: this.state.jsonType === 'preview' ? 'block' : 'none' }}></div>
</div>

View File

@ -59,11 +59,12 @@ class ProjectToken extends Component {
return (
<div className="project-token">
<h2 className="token-title">工具标识</h2>
<div className="message">
每个项目都有唯一的标识key用户可以使用这个key值来请求项目的所有资源数据
每个项目都有唯一的标识token用户可以使用这个token值来请求项目的所有资源数据
</div>
<div className="token">
<span>key值: <span className="token-message">{this.props.token}</span></span>
<span>token: <span className="token-message">{this.props.token}</span></span>
<Tooltip title="复制">
<Icon className="token-btn" type="copy" onClick={this.copyToken}/>
</Tooltip>
@ -72,7 +73,7 @@ class ProjectToken extends Component {
</Tooltip>
</div>
<div className="blockquote">
为确保项目内数据的安全性和私密性请勿轻易将该key暴露给项目组外用户
为确保项目内数据的安全性和私密性请勿轻易将该token暴露给项目组外用户
</div>
</div>

View File

@ -13,15 +13,26 @@
.token-message{
padding: 8px;
margin-right: 8px;
background-color: #f8f8f8;
background-color: #f5f5f5;
}
.message{
padding-left: 16px;
padding: 16px 0 0 16px;
font-size: 14px;
}
.token-title{
font-size: 16px;
// background-color: #eee;
// border-radius: 4px;
// margin-bottom: 15px;
font-weight: 400;
margin-bottom: 0.16rem;
border-left: 3px solid #2395f1;
padding-left: 8px;
}
.blockquote{
border-left: 4px solid #ff561b;
// background-color: #f8f8f8;

View File

@ -40,7 +40,7 @@ class Setting extends Component {
</TabPane>
{
(this.props.curProjectRole !== "guest") ?
<TabPane tab="key值配置" key="4">
<TabPane tab="token配置" key="4">
<ProjectToken projectId={+id} />
</TabPane> : null
}

View File

@ -2,6 +2,7 @@ const projectModel = require('../models/project.js');
const interfaceColModel = require('../models/interfaceCol.js');
const interfaceCaseModel = require('../models/interfaceCase.js');
const interfaceModel = require('../models/interface.js');
const tokenModel = require('../models/token.js');
const yapi = require('../yapi.js');
const baseController = require('./base.js');
const { handleParams, crossRequest, handleCurrDomain, checkNameIsExistInArray } = require('../../common/postmanLib')
@ -15,6 +16,7 @@ class openController extends baseController{
this.interfaceColModel = yapi.getInst(interfaceColModel)
this.interfaceCaseModel = yapi.getInst(interfaceCaseModel)
this.interfaceModel = yapi.getInst(interfaceModel)
this.tokenModel = yapi.getInst(tokenModel);
this.handleValue = this.handleValue.bind(this)
this.schemaMap = {
runAutoTest: {
@ -30,7 +32,8 @@ class openController extends baseController{
}
async getProjectIdByToken(token){
return '111'
let projectId = await this.tokenModel.findId(token);
return projectId.toObject().project_id
}
async projectInterfaceData(ctx){
@ -50,7 +53,20 @@ class openController extends baseController{
let token = ctx.params.token;
let curEnv = ctx.params.env_name;
let colData = await this.interfaceColModel.get(id);
if(!colData){
return ctx.body = yapi.commons.resReturn(null, 40022, 'id值不存在');
}
if(!token){
return ctx.body = yapi.commons.resReturn(null, 40033, '没有权限');
}
let checkId = await this.getProjectIdByToken(token);
let projectId = colData.project_id;
if(checkId !== projectId){
return ctx.body = yapi.commons.resReturn(null, 40033, '没有权限');
}
let projectData = await this.projectModel.get(projectId);
let caseList = await yapi.commons.getCaseList(id);

View File

@ -27,7 +27,7 @@ class tokenModel extends baseModel {
findId(token){
return this.model.findOne({
token: token
});
}).select('project_id').exec();
}
up(project_id, token){

View File

@ -1,3 +1,4 @@
module.exports = function renderToHtml(reports){
// console.log("reports",reports)
return reports;
}