mirror of
https://github.com/YMFE/yapi.git
synced 2025-02-17 13:49:43 +08:00
Merge branch 'dev-mock' into dev
This commit is contained in:
commit
474658c3b7
@ -194,6 +194,23 @@ function handleMockWord(word) {
|
||||
return Mock.mock(word);
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并后新的对象属性与 Obj 一致,nextObj 有对应属性则取 nextObj 属性值,否则取 Obj 属性值
|
||||
* @param {Object} Obj 旧对象
|
||||
* @param {Object} nextObj 新对象
|
||||
* @return {Object} 合并后的对象
|
||||
*/
|
||||
exports.safeAssign = (Obj, nextObj) => {
|
||||
let keys = Object.keys(nextObj);
|
||||
return Object.keys(Obj).reduce((result, value) => {
|
||||
if (keys.indexOf(value) >= 0) {
|
||||
result[value] = nextObj[value];
|
||||
} else {
|
||||
result[value] = Obj[value];
|
||||
}
|
||||
return result;
|
||||
}, {});
|
||||
};
|
||||
|
||||
exports.simpleJsonPathParse = simpleJsonPathParse;
|
||||
exports.handleMockWord = handleMockWord;
|
||||
|
30
client/reducer/modules/mockCol.js
Normal file
30
client/reducer/modules/mockCol.js
Normal file
@ -0,0 +1,30 @@
|
||||
import axios from 'axios'
|
||||
|
||||
// Actions
|
||||
const FETCH_MOCK_COL = 'yapi/mockCol/FETCH_MOCK_COL';
|
||||
|
||||
// Reducer
|
||||
const initialState = {
|
||||
list: []
|
||||
}
|
||||
|
||||
export default (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case FETCH_MOCK_COL:
|
||||
return {
|
||||
...state,
|
||||
list: action.payload.data.data
|
||||
}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
// Action Creators
|
||||
export async function fetchMockCol(interfaceId) {
|
||||
let result = await axios.get('/api/plugin/advmock/case/list?interface_id=' + interfaceId);
|
||||
return {
|
||||
type: FETCH_MOCK_COL,
|
||||
payload: result.data
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import news from './news.js'
|
||||
import addInterface from './addInterface.js'
|
||||
import menu from './menu.js'
|
||||
import follow from './follow.js'
|
||||
import mockCol from './mockCol.js'
|
||||
|
||||
export default combineReducers({
|
||||
group,
|
||||
@ -18,5 +19,6 @@ export default combineReducers({
|
||||
news,
|
||||
addInterface,
|
||||
menu,
|
||||
follow
|
||||
follow,
|
||||
mockCol
|
||||
})
|
||||
|
249
exts/yapi-plugin-advanced-mock/MockCol/CaseDesModal.js
Normal file
249
exts/yapi-plugin-advanced-mock/MockCol/CaseDesModal.js
Normal file
@ -0,0 +1,249 @@
|
||||
import React, { Component } from 'react'
|
||||
// import axios from 'axios'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Button, Form, Input, Switch, Select, Icon, Modal } from 'antd';
|
||||
import { safeAssign } from '../../../client/common.js';
|
||||
import { httpCodes } from '../index.js';
|
||||
|
||||
const Option = Select.Option;
|
||||
const FormItem = Form.Item;
|
||||
const formItemLayout = {
|
||||
labelCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 5 }
|
||||
},
|
||||
wrapperCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 12 }
|
||||
}
|
||||
};
|
||||
|
||||
@Form.create()
|
||||
export default class CaseDesModal extends Component {
|
||||
static propTypes = {
|
||||
form: PropTypes.object,
|
||||
caseData: PropTypes.object,
|
||||
onCancel: PropTypes.func,
|
||||
onOk: PropTypes.func,
|
||||
isAdd: PropTypes.bool,
|
||||
visible: PropTypes.bool
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
preProcess = caseData => {
|
||||
// const a = {
|
||||
// interface_id: { type: Number, required: true },
|
||||
// project_id: {type: Number, required: true},
|
||||
// ip: {type: String},
|
||||
// ip_enable: {type: Boolean, default: false},
|
||||
// name: {type: String, required: true},
|
||||
// code: {type: Number, default: 200},
|
||||
// deplay: {type: Number, default: 0},
|
||||
// headers: [{
|
||||
// name: {type: String, required: true},
|
||||
// value: {type: String}
|
||||
// }],
|
||||
// params: mongoose.Schema.Types.Mixed,
|
||||
// uid: String,
|
||||
// up_time: Number,
|
||||
// res_body: {type: String, required: true}
|
||||
// }
|
||||
const initCaseData = {
|
||||
ip: '',
|
||||
ip_enable: false,
|
||||
name: '',
|
||||
code: '200',
|
||||
deplay: 0,
|
||||
headers: [{name: '', value: ''}],
|
||||
paramsArr: [{name: '', value: ''}],
|
||||
res_body: ''
|
||||
}
|
||||
caseData.paramsArr = caseData.params && caseData.params.length ? Object.keys(caseData.params).map(key => {
|
||||
return { name: key, value: caseData.params[key] }
|
||||
}) : [{name: '', value: ''}];
|
||||
caseData.headers = caseData.headers && caseData.headers.length ? caseData.headers : [{name: '', value: ''}];
|
||||
caseData = safeAssign(initCaseData, caseData);
|
||||
return caseData;
|
||||
}
|
||||
|
||||
endProcess = caseData => {
|
||||
const headers = [];
|
||||
const params = {};
|
||||
caseData.headers.forEach(item => {
|
||||
if (item.name) {
|
||||
headers.push({
|
||||
name: item.name,
|
||||
value: item.value
|
||||
})
|
||||
}
|
||||
});
|
||||
caseData.paramsArr.forEach(item => {
|
||||
if (item.name) {
|
||||
params[item.name] = item.value
|
||||
}
|
||||
})
|
||||
caseData.headers = headers;
|
||||
caseData.params = params;
|
||||
delete caseData.paramsArr;
|
||||
return caseData;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.form.setFieldsValue(this.preProcess(this.props.caseData))
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (this.props.caseData !== nextProps.caseData) {
|
||||
this.props.form.setFieldsValue(this.preProcess(this.props.caseData))
|
||||
}
|
||||
}
|
||||
|
||||
handleOk = () => {
|
||||
const form = this.props.form;
|
||||
this.props.onOk(this.endProcess(form.getFieldsValue()));
|
||||
}
|
||||
|
||||
render() {
|
||||
const { getFieldDecorator, getFieldValue } = this.props.form;
|
||||
const { isAdd, visible, onCancel } = this.props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={isAdd ? '添加期望' : '编辑期望'}
|
||||
visible={visible}
|
||||
maskClosable={false}
|
||||
onOk={this.handleOk}
|
||||
onCancel={() => onCancel()}
|
||||
>
|
||||
<Form>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="期望名称"
|
||||
>
|
||||
{getFieldDecorator('name', {
|
||||
rules: [{ required: true, message: '请输入期望名称!' }]
|
||||
})(
|
||||
<Input placeholder="请输入期望名称" />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="IP 过滤">
|
||||
{getFieldDecorator('ip_enable', {
|
||||
valuePropName: 'checked',
|
||||
rules: [{ type: 'boolean' }]
|
||||
})(
|
||||
<Switch />
|
||||
)}
|
||||
{getFieldDecorator('ip')(
|
||||
<Input placeholder="请输入过滤的 IP 地址" />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="HTTP CODE"
|
||||
>
|
||||
{getFieldDecorator('code')(
|
||||
<Select search>
|
||||
{
|
||||
httpCodes.map(code => <Option key={''+code} value={''+code}>{''+code}</Option>)
|
||||
}
|
||||
</Select>
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="延时"
|
||||
>
|
||||
{getFieldDecorator('deplay', {
|
||||
initialValue: 0,
|
||||
rules: [{ required: true, message: '请输入延时时间!', type: 'integer' }]
|
||||
})(
|
||||
<Input placeholder="请输入延时时间" />
|
||||
)}
|
||||
</FormItem>
|
||||
{
|
||||
getFieldDecorator('headers', { initialValue: [] }) &&
|
||||
getFieldValue('headers').map((item, index) => (
|
||||
<div key={index}>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label={index ? '' : 'HTTP 头'}
|
||||
>
|
||||
{getFieldDecorator(`headers[${index}].name`)(
|
||||
<Input />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
>
|
||||
{getFieldDecorator(`headers[${index}].value`)(
|
||||
<Input />
|
||||
)}
|
||||
{getFieldValue('headers').length > 1 ? (
|
||||
<Icon
|
||||
className="dynamic-delete-button"
|
||||
type="minus-circle-o"
|
||||
onClick={() => this.removeHeaders(index)}
|
||||
/>
|
||||
) : null}
|
||||
</FormItem>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
<FormItem>
|
||||
<Button type="dashed" onClick={this.addHeaders} style={{ width: '60%' }}>
|
||||
<Icon type="plus" /> 添加 HTTP 头
|
||||
</Button>
|
||||
</FormItem>
|
||||
|
||||
{
|
||||
getFieldDecorator('paramsArr', { initialValue: [] }) &&
|
||||
getFieldValue('paramsArr').map((item, index) => (
|
||||
<div key={index}>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label={index ? '' : '参数'}
|
||||
>
|
||||
{getFieldDecorator(`paramsArr[${index}].name`)(
|
||||
<Input />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
>
|
||||
{getFieldDecorator(`paramsArr[${index}].value`)(
|
||||
<Input />
|
||||
)}
|
||||
{getFieldValue('paramsArr').length > 1 ? (
|
||||
<Icon
|
||||
className="dynamic-delete-button"
|
||||
type="minus-circle-o"
|
||||
onClick={() => this.removeParams(index)}
|
||||
/>
|
||||
) : null}
|
||||
</FormItem>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
<FormItem>
|
||||
<Button type="dashed" onClick={this.addParams} style={{ width: '60%' }}>
|
||||
<Icon type="plus" /> 添加参数
|
||||
</Button>
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="返回 JSON"
|
||||
>
|
||||
{getFieldDecorator('res_body', {
|
||||
rules: [{ required: true, message: '请输入期望名称!' }]
|
||||
})(
|
||||
<Input placeholder="返回 JSON" />
|
||||
)}
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
}
|
111
exts/yapi-plugin-advanced-mock/MockCol/MockCol.js
Normal file
111
exts/yapi-plugin-advanced-mock/MockCol/MockCol.js
Normal file
@ -0,0 +1,111 @@
|
||||
import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import axios from 'axios'
|
||||
import PropTypes from 'prop-types'
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { Table, Button, message } from 'antd';
|
||||
import { fetchMockCol } from '../../../client/reducer/modules/mockCol'
|
||||
import { formatTime } from '../../../client/common.js';
|
||||
import CaseDesModal from './CaseDesModal';
|
||||
|
||||
@connect(
|
||||
state => {
|
||||
return {
|
||||
list: state.mockCol.list
|
||||
}
|
||||
},
|
||||
{
|
||||
fetchMockCol
|
||||
}
|
||||
)
|
||||
@withRouter
|
||||
export default class MockCol extends Component {
|
||||
static propTypes = {
|
||||
list: PropTypes.array,
|
||||
match: PropTypes.object,
|
||||
fetchMockCol: PropTypes.func
|
||||
}
|
||||
|
||||
state = {
|
||||
caseData: {},
|
||||
caseDesModalVisible: false,
|
||||
isAdd: false
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
const interfaceId = this.props.match.params.actionId
|
||||
this.props.fetchMockCol(interfaceId);
|
||||
}
|
||||
|
||||
handleOk = async (caseData) => {
|
||||
const interface_id = this.props.match.params.action;
|
||||
const project_id = this.props.match.params.id;
|
||||
caseData = Object.assign({
|
||||
...caseData,
|
||||
interface_id: interface_id,
|
||||
project_id: project_id
|
||||
})
|
||||
if (!this.state.isAdd) {
|
||||
caseData.id = 0;
|
||||
}
|
||||
axios.post('/api/plugin/advmock/case/save', caseData).then(res => {
|
||||
if (res.data.errcode === 0) {
|
||||
message.success(this.state.isAdd ? '添加成功' : '保存成功');
|
||||
} else {
|
||||
message.error(res.data.errmsg);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
saveFormRef = (form) => {
|
||||
this.form = form;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const data = this.props.list;
|
||||
const { isAdd, caseData, caseDesModalVisible } = this.state;
|
||||
|
||||
const columns = [{
|
||||
title: '期望名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
render: text => <a href="#">{text}</a>
|
||||
}, {
|
||||
title: 'ip',
|
||||
dataIndex: 'ip',
|
||||
key: 'ip'
|
||||
}, {
|
||||
title: '创建人',
|
||||
dataIndex: 'username',
|
||||
key: 'username'
|
||||
}, {
|
||||
title: '编辑时间',
|
||||
key: 'action',
|
||||
render: text => formatTime(text)
|
||||
}, {
|
||||
title: '操作',
|
||||
dataIndex: 'address',
|
||||
key: 'address'
|
||||
}];
|
||||
|
||||
return (
|
||||
<div style={{ padding: '20px 10px' }}>
|
||||
<Button type="primary" onClick={() => this.setState({isAdd: true, caseDesModalVisible: true})}>添加期望</Button>
|
||||
<Table columns={columns} dataSource={data} />
|
||||
<CaseDesModal
|
||||
visible={caseDesModalVisible}
|
||||
isAdd={isAdd}
|
||||
caseData={caseData}
|
||||
onOk={this.handleOk}
|
||||
onCancel={() => this.setState({caseDesModalVisible: false})}
|
||||
ref={this.saveFormRef}
|
||||
></CaseDesModal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
@ -25,13 +25,13 @@ class advMockModel extends baseModel {
|
||||
}
|
||||
|
||||
delByInterfaceId(interface_id) {
|
||||
return this.model.deleteOne({
|
||||
return this.model.remove({
|
||||
interface_id: interface_id
|
||||
});
|
||||
}
|
||||
|
||||
delByProjectId(project_id){
|
||||
return this.model.deleteMany({
|
||||
return this.model.remove({
|
||||
project_id: project_id
|
||||
})
|
||||
}
|
75
exts/yapi-plugin-advanced-mock/caseModel.js
Normal file
75
exts/yapi-plugin-advanced-mock/caseModel.js
Normal file
@ -0,0 +1,75 @@
|
||||
const yapi = require('yapi.js');
|
||||
const baseModel = require('models/base.js');
|
||||
const mongoose = require('mongoose');
|
||||
|
||||
class caseModel extends baseModel {
|
||||
getName() {
|
||||
return 'adv_mock_case';
|
||||
}
|
||||
|
||||
getSchema() {
|
||||
return {
|
||||
interface_id: { type: Number, required: true },
|
||||
project_id: {type: Number, required: true},
|
||||
ip: {type: String},
|
||||
ip_enable: {type: Boolean, default: false},
|
||||
name: {type: String, required: true},
|
||||
code: {type: Number, default: 200},
|
||||
delay: {type: Number, default: 0},
|
||||
headers: [{
|
||||
name: {type: String, required: true},
|
||||
value: {type: String}
|
||||
}],
|
||||
params: mongoose.Schema.Types.Mixed,
|
||||
uid: String,
|
||||
up_time: Number,
|
||||
res_body: {type: String, required: true}
|
||||
};
|
||||
}
|
||||
|
||||
get(data) {
|
||||
return this.model.findOne(data);
|
||||
}
|
||||
|
||||
list(id){
|
||||
return this.model.find({
|
||||
interface_id: id
|
||||
})
|
||||
}
|
||||
|
||||
delByInterfaceId(interface_id) {
|
||||
return this.model.remove({
|
||||
interface_id: interface_id
|
||||
});
|
||||
}
|
||||
|
||||
delByProjectId(project_id){
|
||||
return this.model.remove({
|
||||
project_id: project_id
|
||||
})
|
||||
}
|
||||
|
||||
save(data) {
|
||||
data.up_time = yapi.commons.time();
|
||||
let m = new this.model(data);
|
||||
return m.save();
|
||||
}
|
||||
|
||||
up(data) {
|
||||
let id = data.id;
|
||||
delete data.id;
|
||||
data.up_time = yapi.commons.time();
|
||||
return this.model.update({
|
||||
_id: id
|
||||
}, data)
|
||||
}
|
||||
|
||||
del(id){
|
||||
return this.model.remove({
|
||||
_id: id
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = caseModel;
|
@ -1,4 +1,4 @@
|
||||
import AdvMock from './AdvMock.js'
|
||||
import AdvMock from './MockCol/MockCol.js'
|
||||
|
||||
module.exports = function(){
|
||||
this.bindHook('interface_tab', function(tabs){
|
||||
|
@ -1,11 +1,14 @@
|
||||
const baseController = require('controllers/base.js');
|
||||
const advModel = require('./model.js');
|
||||
const advModel = require('./advMockModel.js');
|
||||
const yapi = require('yapi.js');
|
||||
const caseModel = require('./caseModel.js');
|
||||
const config = require('./index.js');
|
||||
|
||||
class advMockController extends baseController{
|
||||
constructor(ctx){
|
||||
super(ctx);
|
||||
this.Model = yapi.getInst(advModel);
|
||||
this.caseModel = yapi.getInst(caseModel);
|
||||
}
|
||||
|
||||
async getMock(ctx){
|
||||
@ -27,7 +30,6 @@ class advMockController extends baseController{
|
||||
return ctx.body =yapi.commons.resReturn(null, 408, '缺少project_id');
|
||||
}
|
||||
|
||||
|
||||
let data = {
|
||||
interface_id: params.interface_id,
|
||||
mock_script: params.mock_script || '',
|
||||
@ -47,6 +49,99 @@ class advMockController extends baseController{
|
||||
return ctx.body = yapi.commons.resReturn(null, 400, e.message);
|
||||
}
|
||||
}
|
||||
|
||||
async list(ctx){
|
||||
let id = ctx.query.interface_id;
|
||||
if(!id){
|
||||
return ctx.body = yapi.commons.resReturn(null, 400, '缺少 interface_id');
|
||||
}
|
||||
let result = await this.caseModel.list(id);
|
||||
|
||||
ctx.body = yapi.commons.resReturn(result);
|
||||
}
|
||||
|
||||
async getCase(ctx){
|
||||
let id = ctx.query.id;
|
||||
if(!id){
|
||||
return ctx.body = yapi.commons.resReturn(null, 400, '缺少 id');
|
||||
}
|
||||
let result = await this.caseModel.get({
|
||||
_id: id
|
||||
})
|
||||
ctx.body = yapi.commons.resReturn(result);
|
||||
}
|
||||
|
||||
async saveCase(ctx){
|
||||
let params = ctx.request.body;
|
||||
if(!params.interface_id){
|
||||
return ctx.body =yapi.commons.resReturn(null, 408, '缺少interface_id');
|
||||
}
|
||||
if(!params.project_id){
|
||||
return ctx.body =yapi.commons.resReturn(null, 408, '缺少project_id');
|
||||
}
|
||||
let data = {
|
||||
interface_id: params.interface_id,
|
||||
project_id: params.project_id,
|
||||
ip_enable: params.ip_enable,
|
||||
name: params.name,
|
||||
params: params.params || [],
|
||||
uid: this.getUid(),
|
||||
code: params.code || 200,
|
||||
delay: params.delay || 0,
|
||||
headers: params.headers || [],
|
||||
up_time: yapi.commons.time(),
|
||||
res_body: params.res_body || '',
|
||||
ip: params.ip
|
||||
}
|
||||
|
||||
data.code = isNaN(data.code) ? 200 : +data.code;
|
||||
data.delay = isNaN(data.delay) ? 0 : +data.delay;
|
||||
if(config.httpCodes.indexOf(data.code) === -1){
|
||||
return ctx.body =yapi.commons.resReturn(null, 408, '非法的 httpCode');
|
||||
}
|
||||
|
||||
let findRepeat, findRepeatParams;
|
||||
findRepeatParams = {
|
||||
project_id: data.project_id,
|
||||
interface_id: data.interface_id,
|
||||
ip_enable: data.ip_enable
|
||||
}
|
||||
|
||||
if(data.params && typeof data.params === 'object'){
|
||||
for(let i in data.params){
|
||||
findRepeatParams['params.' + i] = data.params[i];
|
||||
}
|
||||
}
|
||||
|
||||
if(data.ip_enable){
|
||||
findRepeatParams.ip = data.ip;
|
||||
}
|
||||
|
||||
findRepeat = await this.caseModel.get(findRepeatParams);
|
||||
|
||||
if(findRepeat){
|
||||
return ctx.body = yapi.commons.resReturn(null,400, '已存在的期望');
|
||||
}
|
||||
|
||||
let result;
|
||||
if(params.id && !isNaN(params.id)){
|
||||
data.id = +params.id;
|
||||
result = await this.caseModel.up(data);
|
||||
}else{
|
||||
result = await this.caseModel.save(data);
|
||||
}
|
||||
return ctx.body = yapi.commons.resReturn(result);
|
||||
}
|
||||
|
||||
async delCase(ctx){
|
||||
let id = ctx.request.body.id;
|
||||
if(!id){
|
||||
return ctx.body =yapi.commons.resReturn(null, 408, '缺少 id');
|
||||
}
|
||||
ctx.body = await this.caseModel.del(id);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
module.exports = advMockController;
|
@ -1,4 +1,7 @@
|
||||
module.exports = {
|
||||
server: true,
|
||||
client: true
|
||||
client: true,
|
||||
httpCodes: [
|
||||
100,101,102,200,201,202,203,204,205,206,207,208,226,300,301,302,303,304,305,307,308,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,422,423,424,426,428,429,431,500,501,502,503,504,505,506,507,508,510,511
|
||||
]
|
||||
}
|
@ -1,19 +1,84 @@
|
||||
const controller = require('./controller');
|
||||
const advModel = require('./model.js');
|
||||
const advModel = require('./advMockModel.js');
|
||||
const caseModel = require('./caseModel.js');
|
||||
const yapi = require('yapi.js');
|
||||
const mongoose = require('mongoose');
|
||||
const _ = require('underscore');
|
||||
|
||||
function arrToObj(arr){
|
||||
let obj = {};
|
||||
arr.forEach(item=>{
|
||||
obj[item.name] = item.value;
|
||||
})
|
||||
return obj;
|
||||
}
|
||||
|
||||
module.exports = function(){
|
||||
yapi.connect.then(function () {
|
||||
let Col = mongoose.connection.db.collection('adv_mock')
|
||||
Col.ensureIndex({
|
||||
Col.createIndex({
|
||||
interface_id: 1
|
||||
})
|
||||
Col.ensureIndex({
|
||||
Col.createIndex({
|
||||
project_id: 1
|
||||
})
|
||||
|
||||
let caseCol = mongoose.connection.db.collection('adv_mock_case')
|
||||
caseCol.createIndex({
|
||||
interface_id: 1
|
||||
})
|
||||
caseCol.createIndex({
|
||||
project_id: 1
|
||||
})
|
||||
})
|
||||
|
||||
async function checkCase(ctx, interfaceId){
|
||||
let reqParams = Object.assign({}, ctx.query, ctx.body);
|
||||
let caseInst = yapi.getInst(caseModel);
|
||||
let ip = ctx.ip.match(/\d+.\d+.\d+.\d+/)[0];
|
||||
let listWithIp =await caseInst.model.find({
|
||||
interface_id: interfaceId,
|
||||
ip_enable: true,
|
||||
ip: ip
|
||||
}).select('_id params');
|
||||
let matchList = [];
|
||||
listWithIp.forEach(item=>{
|
||||
let params = item.params;
|
||||
if(_.isMatch(reqParams, params)){
|
||||
matchList.push(item);
|
||||
}
|
||||
})
|
||||
if(matchList.length === 0){
|
||||
let list =await caseInst.model.find({
|
||||
interface_id: interfaceId,
|
||||
ip_enable: false
|
||||
}).select('_id params')
|
||||
list.forEach(item=>{
|
||||
let params = item.params;
|
||||
if(_.isMatch(reqParams, item.params)){
|
||||
matchList.push(item);
|
||||
}
|
||||
})
|
||||
}
|
||||
if(matchList.length > 0){
|
||||
let maxItem = _.max(matchList, item=> Object.keys(item.params).length);
|
||||
return maxItem;
|
||||
}
|
||||
return null;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
async function handleByCase(caseData, context){
|
||||
let caseInst = yapi.getInst(caseModel);
|
||||
let result = await caseInst.get({
|
||||
_id: caseData._id
|
||||
})
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
this.bindHook('add_router', function(addRouter){
|
||||
addRouter({
|
||||
controller: controller,
|
||||
@ -27,6 +92,45 @@ module.exports = function(){
|
||||
path: 'advmock/save',
|
||||
action: 'upMock'
|
||||
})
|
||||
addRouter({
|
||||
/**
|
||||
* 保存期望
|
||||
*/
|
||||
controller: controller,
|
||||
method: 'post',
|
||||
path: 'advmock/case/save',
|
||||
action: 'saveCase'
|
||||
})
|
||||
|
||||
addRouter({
|
||||
/**
|
||||
* 保存期望
|
||||
*/
|
||||
controller: controller,
|
||||
method: 'get',
|
||||
path: 'advmock/case/get',
|
||||
action: 'getCase'
|
||||
})
|
||||
|
||||
addRouter({
|
||||
/**
|
||||
* 获取期望列表
|
||||
*/
|
||||
controller: controller,
|
||||
method: 'get',
|
||||
path: 'advmock/case/list',
|
||||
action: 'list'
|
||||
})
|
||||
|
||||
addRouter({
|
||||
/**
|
||||
* 获取期望列表
|
||||
*/
|
||||
controller: controller,
|
||||
method: 'post',
|
||||
path: 'advmock/case/del',
|
||||
action: 'delCase'
|
||||
})
|
||||
})
|
||||
this.bindHook('interface_del', async function(id){
|
||||
let inst = yapi.getInst(advModel);
|
||||
@ -46,6 +150,15 @@ module.exports = function(){
|
||||
*/
|
||||
this.bindHook('mock_after', async function(context){
|
||||
let interfaceId = context.interfaceData._id;
|
||||
let caseData = await checkCase(context.ctx, interfaceId);
|
||||
if(caseData){
|
||||
let data = await handleByCase(caseData, context);
|
||||
context.mockJson = data.res_body;
|
||||
context.resHeader = arrToObj(data.headers);
|
||||
context.httpCode = data.code;
|
||||
context.delay = data.delay;
|
||||
return true;
|
||||
}
|
||||
let inst = yapi.getInst(advModel);
|
||||
let data = await inst.get(interfaceId);
|
||||
if(!data || !data.enable || !data.mock_script){
|
||||
@ -56,7 +169,11 @@ module.exports = function(){
|
||||
header: context.ctx.header,
|
||||
query: context.ctx.query,
|
||||
body: context.ctx.request.body,
|
||||
mockJson: context.mockJson
|
||||
mockJson: context.mockJson,
|
||||
params: Object.assign({}, context.ctx.query, context.ctx.request.body),
|
||||
resHeader: context.resHeader,
|
||||
httpCode: context.httpCode,
|
||||
delay: context.httpCode
|
||||
}
|
||||
sandbox.cookie = {};
|
||||
|
||||
@ -65,6 +182,11 @@ module.exports = function(){
|
||||
sandbox.cookie[ parts[ 0 ].trim() ] = ( parts[ 1 ] || '' ).trim();
|
||||
});
|
||||
sandbox = yapi.commons.sandbox(sandbox, script);
|
||||
sandbox.delay = isNaN(sandbox.delay) ? 0 : +sandbox.delay;
|
||||
|
||||
context.mockJson = sandbox.mockJson;
|
||||
context.resHeader = sandbox.resHeader;
|
||||
context.httpCode = sandbox.httpCode;
|
||||
context.delay = sandbox.delay;
|
||||
})
|
||||
}
|
23
package.json
23
package.json
@ -8,11 +8,12 @@
|
||||
"install-server": " node server/install.js",
|
||||
"dev-client": "ykit s -p 4000",
|
||||
"dev": "npm run dev-server & npm run dev-client",
|
||||
"start": " node server/app.js"
|
||||
"start": " node server/app.js",
|
||||
"test": "ava"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@gitlab.corp.qunar.com:mfe/yapi.git"
|
||||
"url": "git@github.com:YMFE/yapi.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "Apache2.0",
|
||||
@ -25,6 +26,7 @@
|
||||
"json-schema-ref-parser": "^4.0.0",
|
||||
"json5": "^0.5.1",
|
||||
"jsonwebtoken": "^7.4.1",
|
||||
"kerberos": "0.0.23",
|
||||
"koa": "^2.0.0",
|
||||
"koa-bodyparser": "^3.2.0",
|
||||
"koa-multer": "^1.0.2",
|
||||
@ -37,7 +39,7 @@
|
||||
"koa-websocket": "^4.0.0",
|
||||
"mockjs": "^1.0.1-beta3",
|
||||
"moment": "^2.18.1",
|
||||
"mongoose": "^4.7.0",
|
||||
"mongoose": "^4.12.3",
|
||||
"mongoose-auto-increment": "^5.0.1",
|
||||
"nodemailer": "^4.0.1",
|
||||
"ora": "^1.3.0",
|
||||
@ -50,11 +52,8 @@
|
||||
"url": "^0.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"happypack": "^4.0.0-beta.5",
|
||||
"prop-types": "^15.5.10",
|
||||
"rc-queue-anim": "^1.2.0",
|
||||
"rc-scroll-anim": "^1.0.7",
|
||||
"assets-webpack-plugin": "^3.5.1",
|
||||
"ava": "^0.22.0",
|
||||
"babel": "^6.5.2",
|
||||
"babel-core": "^6.8.0",
|
||||
"babel-eslint": "^7.2.3",
|
||||
@ -81,10 +80,14 @@
|
||||
"extract-text-webpack-plugin": "2.0.0",
|
||||
"fast-sass-loader-china": "^1.2.5",
|
||||
"ghooks": "^2.0.0",
|
||||
"happypack": "^4.0.0-beta.5",
|
||||
"less": "^2.7.2",
|
||||
"less-loader": "^4.0.5",
|
||||
"node-sass-china": "^4.5.0",
|
||||
"nodemon": "^1.11.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"rc-queue-anim": "^1.2.0",
|
||||
"rc-scroll-anim": "^1.0.7",
|
||||
"react": "^15.6.1",
|
||||
"react-dnd": "^2.5.1",
|
||||
"react-dnd-html5-backend": "^2.5.1",
|
||||
@ -100,6 +103,7 @@
|
||||
"redux-devtools-log-monitor": "^1.3.0",
|
||||
"redux-promise": "^0.5.3",
|
||||
"redux-thunk": "^2.2.0",
|
||||
"rewire": "^2.5.2",
|
||||
"string-replace-webpack-plugin": "^0.1.3",
|
||||
"style-loader": "^0.18.2",
|
||||
"table-resolver": "^3.2.0",
|
||||
@ -135,5 +139,10 @@
|
||||
"engines": {
|
||||
"node": ">= 7.6.0",
|
||||
"npm": ">= 4.1.2"
|
||||
},
|
||||
"ava": {
|
||||
"files": [
|
||||
"test/**/*.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -178,20 +178,6 @@ class groupController extends baseController {
|
||||
}
|
||||
}
|
||||
|
||||
// params.role = ['owner', 'dev', 'guest'].find(v => v === params.role) || 'dev';
|
||||
|
||||
// var check = await groupInst.checkMemberRepeat(params.id, params.member_uid);
|
||||
// if (check > 0) {
|
||||
// return ctx.body = yapi.commons.resReturn(null, 400, '成员已存在');
|
||||
// }
|
||||
// let groupUserdata = await this.getUserdata(params.member_uid, params.role);
|
||||
// if (groupUserdata === null) {
|
||||
// return ctx.body = yapi.commons.resReturn(null, 400, '组长uid不存在')
|
||||
// }
|
||||
// if (groupUserdata._role === 'admin') {
|
||||
// return ctx.body = yapi.commons.resReturn(null, 400, '不能邀请管理员')
|
||||
// }
|
||||
// delete groupUserdata._role;
|
||||
try {
|
||||
let result = await groupInst.addMember(params.id, add_members);
|
||||
let username = this.getUsername();
|
||||
@ -448,10 +434,14 @@ class groupController extends baseController {
|
||||
await interfaceCaseInst.delByProjectId(p._id)
|
||||
await interfaceColInst.delByProjectId(p._id)
|
||||
})
|
||||
await projectInst.delByGroupid(id);
|
||||
if(projectList.length > 0){
|
||||
await projectInst.delByGroupid(id);
|
||||
}
|
||||
|
||||
let result = await groupInst.del(id);
|
||||
ctx.body = yapi.commons.resReturn(result);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
ctx.body = yapi.commons.resReturn(null, 402, err.message);
|
||||
}
|
||||
}
|
||||
|
@ -300,6 +300,9 @@ class interfaceController extends baseController {
|
||||
}
|
||||
|
||||
let project = await this.projectModel.getBaseInfo(project_id);
|
||||
if(!project){
|
||||
return ctx.body = yapi.commons.resReturn(null, 406, '不存在的项目');
|
||||
}
|
||||
if (project.project_type === 'private') {
|
||||
if (await this.checkAuth(project._id, 'project', 'view') !== true) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 406, '没有权限');
|
||||
|
@ -34,93 +34,93 @@ function setupSql() {
|
||||
|
||||
yapi.connect.then(function () {
|
||||
let userCol = mongoose.connection.db.collection('user')
|
||||
userCol.ensureIndex({
|
||||
userCol.createIndex({
|
||||
username: 1
|
||||
})
|
||||
userCol.ensureIndex({
|
||||
userCol.createIndex({
|
||||
email: 1
|
||||
}, {
|
||||
unique: true
|
||||
})
|
||||
|
||||
let projectCol = mongoose.connection.db.collection('project')
|
||||
projectCol.ensureIndex({
|
||||
projectCol.createIndex({
|
||||
uid: 1
|
||||
})
|
||||
projectCol.ensureIndex({
|
||||
projectCol.createIndex({
|
||||
name: 1
|
||||
})
|
||||
projectCol.ensureIndex({
|
||||
projectCol.createIndex({
|
||||
group_id: 1
|
||||
})
|
||||
|
||||
let logCol = mongoose.connection.db.collection('log')
|
||||
logCol.ensureIndex({
|
||||
logCol.createIndex({
|
||||
uid: 1
|
||||
})
|
||||
|
||||
logCol.ensureIndex({
|
||||
logCol.createIndex({
|
||||
typeid: 1,
|
||||
type: 1
|
||||
})
|
||||
|
||||
let interfaceColCol = mongoose.connection.db.collection('interface_col')
|
||||
interfaceColCol.ensureIndex({
|
||||
interfaceColCol.createIndex({
|
||||
uid: 1
|
||||
})
|
||||
interfaceColCol.ensureIndex({
|
||||
interfaceColCol.createIndex({
|
||||
project_id: 1
|
||||
})
|
||||
|
||||
let interfaceCatCol = mongoose.connection.db.collection('interface_cat')
|
||||
interfaceCatCol.ensureIndex({
|
||||
interfaceCatCol.createIndex({
|
||||
uid: 1
|
||||
})
|
||||
interfaceCatCol.ensureIndex({
|
||||
interfaceCatCol.createIndex({
|
||||
project_id: 1
|
||||
})
|
||||
|
||||
let interfaceCaseCol = mongoose.connection.db.collection('interface_case')
|
||||
interfaceCaseCol.ensureIndex({
|
||||
interfaceCaseCol.createIndex({
|
||||
uid: 1
|
||||
})
|
||||
interfaceCaseCol.ensureIndex({
|
||||
interfaceCaseCol.createIndex({
|
||||
col_id: 1
|
||||
})
|
||||
interfaceCaseCol.ensureIndex({
|
||||
interfaceCaseCol.createIndex({
|
||||
project_id: 1
|
||||
})
|
||||
|
||||
let interfaceCol = mongoose.connection.db.collection('interface')
|
||||
interfaceCol.ensureIndex({
|
||||
interfaceCol.createIndex({
|
||||
uid: 1
|
||||
})
|
||||
interfaceCol.ensureIndex({
|
||||
interfaceCol.createIndex({
|
||||
path: 1,
|
||||
method: 1
|
||||
})
|
||||
interfaceCol.ensureIndex({
|
||||
interfaceCol.createIndex({
|
||||
project_id: 1
|
||||
})
|
||||
|
||||
let groupCol = mongoose.connection.db.collection('group')
|
||||
groupCol.ensureIndex({
|
||||
groupCol.createIndex({
|
||||
uid: 1
|
||||
})
|
||||
groupCol.ensureIndex({
|
||||
groupCol.createIndex({
|
||||
group_name: 1
|
||||
})
|
||||
|
||||
let avatarCol = mongoose.connection.db.collection('avatar')
|
||||
avatarCol.ensureIndex({
|
||||
avatarCol.createIndex({
|
||||
uid: 1
|
||||
})
|
||||
|
||||
let followCol = mongoose.connection.db.collection('follow')
|
||||
followCol.ensureIndex({
|
||||
followCol.createIndex({
|
||||
uid: 1
|
||||
})
|
||||
followCol.ensureIndex({
|
||||
followCol.createIndex({
|
||||
project_id: 1
|
||||
})
|
||||
|
||||
|
@ -5,7 +5,11 @@ const mockExtra = require('../../common/mock-extra.js');
|
||||
const _ = require('underscore');
|
||||
const Mock = require('mockjs');
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} apiPath /user/tom
|
||||
* @param {*} apiRule /user/:username
|
||||
*/
|
||||
function matchApi(apiPath, apiRule) {
|
||||
let apiRules = apiRule.split("/");
|
||||
let apiPaths = apiPath.split("/");
|
||||
@ -61,13 +65,12 @@ module.exports = async (ctx, next) => {
|
||||
return ctx.body = yapi.commons.resReturn(null, 403, e.message);
|
||||
}
|
||||
|
||||
if (project === false) {
|
||||
if (!project) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 400, '不存在的项目');
|
||||
}
|
||||
|
||||
let interfaceData, newpath;
|
||||
let interfaceInst = yapi.getInst(interfaceModel);
|
||||
|
||||
try {
|
||||
newpath = path.substr(project.basepath.length);
|
||||
interfaceData = await interfaceInst.getByPath(project._id, newpath, ctx.method);
|
||||
@ -149,9 +152,25 @@ module.exports = async (ctx, next) => {
|
||||
projectData: project,
|
||||
interfaceData: interfaceData,
|
||||
ctx: ctx,
|
||||
mockJson: res
|
||||
mockJson: res,
|
||||
resHeader: {},
|
||||
httpCode: 200,
|
||||
delay: 0
|
||||
}
|
||||
await yapi.emitHook('mock_after', context);
|
||||
let handleMock = new Promise(resolve=>{
|
||||
setTimeout(()=>{
|
||||
resolve(true)
|
||||
}, context.delay)
|
||||
})
|
||||
await handleMock;
|
||||
if(context.resHeader && typeof context.resHeader === 'object'){
|
||||
for(let i in context.resHeader){
|
||||
ctx.set(i, context.resHeader[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.status = context.httpCode;
|
||||
return ctx.body = context.mockJson;
|
||||
} catch (e) {
|
||||
yapi.commons.log(e, 'error')
|
||||
|
@ -35,7 +35,7 @@ class followModel extends baseModel {
|
||||
}
|
||||
|
||||
del(projectid, uid){
|
||||
return this.model.deleteOne({
|
||||
return this.model.remove({
|
||||
projectid: projectid,
|
||||
uid: uid
|
||||
});
|
||||
|
@ -114,7 +114,7 @@ class groupModel extends baseModel {
|
||||
}
|
||||
|
||||
del(id) {
|
||||
return this.model.deleteOne({
|
||||
return this.model.remove({
|
||||
_id: id
|
||||
});
|
||||
}
|
||||
|
@ -140,19 +140,19 @@ class interfaceModel extends baseModel {
|
||||
}
|
||||
|
||||
del(id) {
|
||||
return this.model.deleteOne({
|
||||
return this.model.remove({
|
||||
_id: id
|
||||
});
|
||||
}
|
||||
|
||||
delByCatid(id){
|
||||
return this.model.deleteMany({
|
||||
return this.model.remove({
|
||||
catid: id
|
||||
})
|
||||
}
|
||||
|
||||
delByProjectId(id){
|
||||
return this.model.deleteMany({
|
||||
return this.model.remove({
|
||||
project_id: id
|
||||
})
|
||||
}
|
||||
|
@ -63,25 +63,25 @@ class interfaceCase extends baseModel {
|
||||
}
|
||||
|
||||
del(id) {
|
||||
return this.model.deleteOne({
|
||||
return this.model.remove({
|
||||
_id: id
|
||||
});
|
||||
}
|
||||
|
||||
delByProjectId(id) {
|
||||
return this.model.deleteMany({
|
||||
return this.model.remove({
|
||||
project_id: id
|
||||
})
|
||||
}
|
||||
|
||||
delByInterfaceId(id){
|
||||
return this.model.deleteMany({
|
||||
return this.model.remove({
|
||||
interface_id: id
|
||||
})
|
||||
}
|
||||
|
||||
delByCol(id) {
|
||||
return this.model.deleteMany({
|
||||
return this.model.remove({
|
||||
col_id: id
|
||||
})
|
||||
}
|
||||
|
@ -44,13 +44,13 @@ class interfaceCat extends baseModel {
|
||||
}
|
||||
|
||||
del(id) {
|
||||
return this.model.deleteOne({
|
||||
return this.model.remove({
|
||||
_id: id
|
||||
});
|
||||
}
|
||||
|
||||
delByProjectId(id){
|
||||
return this.model.deleteMany({
|
||||
return this.model.remove({
|
||||
project_id: id
|
||||
})
|
||||
}
|
||||
|
@ -41,13 +41,13 @@ class interfaceCol extends baseModel {
|
||||
}
|
||||
|
||||
del(id) {
|
||||
return this.model.deleteOne({
|
||||
return this.model.remove({
|
||||
_id: id
|
||||
});
|
||||
}
|
||||
|
||||
delByProjectId(id){
|
||||
return this.model.deleteMany({
|
||||
return this.model.remove({
|
||||
project_id: id
|
||||
})
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ class logModel extends baseModel {
|
||||
}
|
||||
|
||||
del(id) {
|
||||
return this.model.deleteOne({
|
||||
return this.model.remove({
|
||||
_id: id
|
||||
});
|
||||
}
|
||||
|
@ -115,13 +115,13 @@ class projectModel extends baseModel {
|
||||
}
|
||||
|
||||
del(id) {
|
||||
return this.model.deleteOne({
|
||||
return this.model.remove({
|
||||
_id: id
|
||||
});
|
||||
}
|
||||
|
||||
delByGroupid(groupId){
|
||||
return this.model.deleteMany({
|
||||
return this.model.remove({
|
||||
group_id: groupId
|
||||
})
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ class userModel extends baseModel {
|
||||
}
|
||||
|
||||
del(id) {
|
||||
return this.model.deleteOne({
|
||||
return this.model.remove({
|
||||
_id: id
|
||||
});
|
||||
}
|
||||
|
@ -160,6 +160,10 @@ exports.filterRes = (list, rules) => {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 验证一个 path 是否合法
|
||||
* path第一位必需为 /, path只容许由 字母数字-/_:. 组成, 最后一位不容许为 /
|
||||
*/
|
||||
exports.verifyPath = (path) => {
|
||||
if (/^\/[a-zA-Z0-9\-\/_:\.]+$/.test(path)) {
|
||||
if (path[path.length - 1] === '/') {
|
||||
@ -172,6 +176,15 @@ exports.verifyPath = (path) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 沙盒执行 js 代码
|
||||
* @sandbox Object context
|
||||
* @script String script
|
||||
* @return sandbox
|
||||
*
|
||||
* @example let a = sandbox({a: 1}, 'a=2')
|
||||
* a = {a: 2}
|
||||
*/
|
||||
exports.sandbox = (sandbox, script) => {
|
||||
const vm = require('vm');
|
||||
sandbox = sandbox || {};
|
||||
@ -215,6 +228,12 @@ exports.trim = trim;
|
||||
exports.ltrim = ltrim;
|
||||
exports.rtrim = rtrim;
|
||||
|
||||
/**
|
||||
* 处理请求参数类型,String 字符串去除两边空格,Number 使用parseInt 转换为数字
|
||||
* @params Object {a: ' ab ', b: ' 123 '}
|
||||
* @keys Object {a: 'string', b: 'number'}
|
||||
* @return Object {a: 'ab', b: 123}
|
||||
*/
|
||||
exports.handleParams = (params, keys) => {
|
||||
if (!params || typeof params !== 'object' || !keys || typeof keys !== 'object') {
|
||||
return false;
|
||||
@ -226,7 +245,7 @@ exports.handleParams = (params, keys) => {
|
||||
switch (filter) {
|
||||
case 'string': params[key] = trim(params[key] + '');
|
||||
break;
|
||||
case 'number': params[key] = parseInt(params[key], 10);
|
||||
case 'number': params[key] =!isNaN(params[key])? parseInt(params[key], 10) : 0;
|
||||
break;
|
||||
default: params[key] = trim(params + '');
|
||||
}
|
||||
|
49
test/server/commons.test.js
Normal file
49
test/server/commons.test.js
Normal file
@ -0,0 +1,49 @@
|
||||
import test from 'ava';
|
||||
import {
|
||||
ltrim,
|
||||
rtrim,
|
||||
trim,
|
||||
handleParams,
|
||||
verifyPath,
|
||||
sandbox
|
||||
} from '../../server/utils/commons.js';
|
||||
|
||||
test('trim', t => {
|
||||
t.is(trim(" a b ksjdfk "), 'a b ksjdfk');
|
||||
t.is(trim(1), '1')
|
||||
});
|
||||
|
||||
test('ltrim', t => {
|
||||
t.is(ltrim(" a b ksjdfk "), 'a b ksjdfk ');
|
||||
t.is(ltrim(1), '1')
|
||||
});
|
||||
|
||||
test('rtrim', t => {
|
||||
t.is(rtrim(" a b ksjdfk "), ' a b ksjdfk');
|
||||
t.is(rtrim(1), '1')
|
||||
});
|
||||
|
||||
test('handleParams', t=>{
|
||||
t.deepEqual(handleParams({
|
||||
a: ' s k ',
|
||||
b: " a123456 "
|
||||
}, {
|
||||
a: 'string',
|
||||
b: 'number'
|
||||
}), {
|
||||
a: 's k',
|
||||
b: 0
|
||||
})
|
||||
})
|
||||
|
||||
test('verifyPath', t=>{
|
||||
t.false(verifyPath('a/b'));
|
||||
t.true(verifyPath('/a:b/t/.api/k_-/tt'))
|
||||
t.false(verifyPath('/a:b/t/.api/k_-/tt/'))
|
||||
})
|
||||
|
||||
test('sandbox', t=>{
|
||||
t.deepEqual(sandbox({
|
||||
a: 1
|
||||
}, 'a=2'), {a : 2});
|
||||
})
|
23
test/server/mockServer.test.js
Normal file
23
test/server/mockServer.test.js
Normal file
@ -0,0 +1,23 @@
|
||||
import test from 'ava';
|
||||
const rewire = require("rewire");
|
||||
const mockServer = rewire('../../server/middleware/mockServer.js');
|
||||
const matchApi = mockServer.__get__('matchApi');
|
||||
|
||||
test('matchApi', t => {
|
||||
const apiRule = '/user/:username';
|
||||
t.true(matchApi('/user/tom', apiRule));
|
||||
t.true(matchApi('/user/111$$%#$##$#2222222222!!!!!!!', apiRule))
|
||||
t.false(matchApi('/user/a/', apiRule))
|
||||
t.false(matchApi('/use/a', apiRule))
|
||||
|
||||
const apiRule_2 = '/user/:username/kk';
|
||||
t.true(matchApi('/user/aa/kk', apiRule_2));
|
||||
t.true(matchApi('/user/!!!###kksdjfks***/kk', apiRule_2));
|
||||
t.false(matchApi('/user/aa/aa', apiRule_2));
|
||||
|
||||
const apiRule_3 = '/user/:sdfsdfj/ttt/:sdkfjkj';
|
||||
t.true(matchApi('/user/a/ttt/b', apiRule_3));
|
||||
t.false(matchApi('/user/a/ttt2/b', apiRule_3))
|
||||
|
||||
|
||||
});
|
Loading…
Reference in New Issue
Block a user