mirror of
https://github.com/YMFE/yapi.git
synced 2024-12-09 05:00:30 +08:00
feat: 增加自动化测试弹窗
This commit is contained in:
parent
ae9c3cfa86
commit
2da67b618b
@ -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' }}>测试集合 <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>
|
||||
)
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -27,7 +27,7 @@ class tokenModel extends baseModel {
|
||||
findId(token){
|
||||
return this.model.findOne({
|
||||
token: token
|
||||
});
|
||||
}).select('project_id').exec();
|
||||
}
|
||||
|
||||
up(project_id, token){
|
||||
|
@ -1,3 +1,4 @@
|
||||
module.exports = function renderToHtml(reports){
|
||||
// console.log("reports",reports)
|
||||
return reports;
|
||||
}
|
Loading…
Reference in New Issue
Block a user