# Conflicts:
#	frontend/src/business/components/api/test/ApiTestConfig.vue
This commit is contained in:
fit2-zhao 2020-09-07 13:44:40 +08:00
commit 20f89c0017
20 changed files with 852 additions and 506 deletions

View File

@ -19,6 +19,7 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.List;
@RestController
@ -44,6 +45,11 @@ public class APITestController {
return PageUtils.setPageInfo(page, apiTestService.list(request));
}
@PostMapping("/list/ids")
public List<ApiTest> listByIds(@RequestBody QueryAPITestRequest request) {
return apiTestService.listByIds(request);
}
@GetMapping("/list/{projectId}")
public List<ApiTest> list(@PathVariable String projectId) {
return apiTestService.getApiTestByProjectId(projectId);
@ -94,6 +100,7 @@ public class APITestController {
public String runDebug(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
return apiTestService.runDebug(request, file, bodyFiles);
}
@PostMapping(value = "/checkName")
public void checkName(@RequestBody SaveAPITestRequest request) {
apiTestService.checkName(request);

View File

@ -12,6 +12,7 @@ import java.util.Map;
public class QueryAPITestRequest {
private String id;
private String excludeId;
private String projectId;
private String name;
private String workspaceId;
@ -19,4 +20,5 @@ public class QueryAPITestRequest {
private List<OrderRequest> orders;
private Map<String, List<String>> filters;
private Map<String, Object> combine;
private List<String> ids;
}

View File

@ -7,6 +7,7 @@ import java.util.List;
@Data
public class Scenario {
private String id;
private String name;
private String url;
private String environmentId;

View File

@ -23,6 +23,8 @@ public class DubboRequest implements Request {
// type 必须放最前面以便能够转换正确的类
private String type = RequestType.DUBBO;
@JSONField(ordinal = 1)
private String id;
@JSONField(ordinal = 1)
private String name;
@JSONField(ordinal = 2)
private String protocol;

View File

@ -20,6 +20,8 @@ public class HttpRequest implements Request {
// type 必须放最前面以便能够转换正确的类
private String type = RequestType.HTTP;
@JSONField(ordinal = 1)
private String id;
@JSONField(ordinal = 1)
private String name;
@JSONField(ordinal = 2)
private String url;

View File

@ -74,12 +74,16 @@ public class APITestService {
return extApiTestMapper.list(request);
}
public List<ApiTest> listByIds(QueryAPITestRequest request) {
return extApiTestMapper.listByIds(request.getIds());
}
public void create(SaveAPITestRequest request, MultipartFile file, List<MultipartFile> bodyFiles) {
if (file == null) {
throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
}
checkQuota();
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds()) ;
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
request.setBodyUploadIds(null);
ApiTest test = createTest(request);
createBodyFiles(test, bodyUploadIds, bodyFiles);
@ -92,7 +96,7 @@ public class APITestService {
}
deleteFileByTestId(request.getId());
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds()) ;
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
request.setBodyUploadIds(null);
ApiTest test = updateTest(request);
createBodyFiles(test, bodyUploadIds, bodyFiles);
@ -245,6 +249,7 @@ public class APITestService {
MSException.throwException(Translator.get("load_test_already_exists"));
}
}
public void checkName(SaveAPITestRequest request) {
ApiTestExample example = new ApiTestExample();
example.createCriteria().andNameEqualTo(request.getName()).andProjectIdEqualTo(request.getProjectId());
@ -411,7 +416,7 @@ public class APITestService {
}
updateTest(request);
APITestResult apiTest = get(request.getId());
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds()) ;
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
request.setBodyUploadIds(null);
createBodyFiles(apiTest, bodyUploadIds, bodyFiles);
if (SessionUtils.getUser() == null) {

View File

@ -11,4 +11,6 @@ public interface ExtApiTestMapper {
List<APITestResult> list(@Param("request") QueryAPITestRequest request);
List<ApiTest> getApiTestByProjectId(String projectId);
List<ApiTest> listByIds(@Param("ids") List<String> ids);
}

View File

@ -105,6 +105,9 @@
</include>
</if>
<if test="request.excludeId != null">
and api_test.id != #{request.excludeId}
</if>
<if test="request.name != null">
and api_test.name like CONCAT('%', #{request.name},'%')
</if>
@ -143,4 +146,17 @@
where project_id = #{projectId}
</select>
<select id="listByIds" resultType="io.metersphere.base.domain.ApiTest">
select *
from api_test
<where>
<if test="ids != null and ids.size() > 0">
id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</if>
</where>
</select>
</mapper>

@ -1 +1 @@
Subproject commit b86032cbbda9a9e6028308aa95a887cff2192f1c
Subproject commit ecb30d83c575c6ed14adb1a1ebea389730f410a9

View File

@ -57,7 +57,8 @@
</el-row>
</el-header>
<ms-api-scenario-config :debug-report-id="debugReportId" @runDebug="runDebug" :is-read-only="isReadOnly"
:scenarios="test.scenarioDefinition" :project-id="test.projectId" ref="config"/>
:test-id="test.id" :scenarios="test.scenarioDefinition" :project-id="test.projectId"
ref="config"/>
</el-container>
</el-card>
</ms-main-container>
@ -65,19 +66,18 @@
</template>
<script>
import MsApiScenarioConfig from "./components/ApiScenarioConfig";
import {Test} from "./model/ScenarioModel"
import MsApiReportStatus from "../report/ApiReportStatus";
import MsApiReportDialog from "./ApiReportDialog";
import {checkoutTestManagerOrTestUser, downloadFile} from "@/common/js/utils";
import MsScheduleConfig from "../../common/components/MsScheduleConfig";
import ApiImport from "./components/import/ApiImport";
import {getUUID} from "../../../../common/js/utils";
import {ApiEvent, LIST_CHANGE} from "@/business/components/common/head/ListEvent";
import MsContainer from "@/business/components/common/components/MsContainer";
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
import MsApiScenarioConfig from "./components/ApiScenarioConfig";
import {Test, Scenario} from "./model/ScenarioModel"
import MsApiReportStatus from "../report/ApiReportStatus";
import MsApiReportDialog from "./ApiReportDialog";
import {checkoutTestManagerOrTestUser, downloadFile, getUUID} from "@/common/js/utils";
import MsScheduleConfig from "../../common/components/MsScheduleConfig";
import ApiImport from "./components/import/ApiImport";
import {ApiEvent, LIST_CHANGE} from "@/business/components/common/head/ListEvent";
import MsContainer from "@/business/components/common/components/MsContainer";
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
export default {
export default {
name: "MsApiTestConfig",
components: {
@ -134,6 +134,39 @@
if (projectId) this.test.projectId = projectId;
})
},
updateReference() {
let updateIds = [];
this.test.scenarioDefinition.forEach(scenario => {
if (scenario.isReference()) {
updateIds.push(scenario.id.split("#")[0]);
}
})
if (updateIds.length === 0) return;
//
this.result = this.$post("/api/list/ids", {ids: updateIds}, response => {
let scenarioMap = {};
if (response.data) {
response.data.forEach(test => {
JSON.parse(test.scenarioDefinition).forEach(options => {
let referenceId = test.id + "#" + options.id;
scenarioMap[referenceId] = new Scenario(options);
scenarioMap[referenceId].id = referenceId;
})
})
}
let scenarios = [];
this.test.scenarioDefinition.forEach(scenario => {
if (scenario.isReference()) {
if (scenarioMap[scenario.id]) scenarios.push(scenarioMap[scenario.id]);
} else {
scenarios.push(scenario);
}
})
this.test.scenarioDefinition = scenarios;
})
},
getTest(id) {
this.result = this.$get("/api/get/" + id, response => {
if (response.data) {
@ -147,6 +180,8 @@
scenarioDefinition: JSON.parse(item.scenarioDefinition),
schedule: item.schedule ? item.schedule : {},
});
this.updateReference();
this.$refs.config.reset();
}
});
@ -163,7 +198,7 @@
let jmx = this.test.toJMX();
let blob = new Blob([jmx.xml], {type: "application/octet-stream"});
let file = new File([blob], jmx.name);
this.result = this.$fileUpload(url, file, bodyFiles, this.test, response => {
this.result = this.$fileUpload(url, file, bodyFiles, this.test, () => {
if (callback) callback();
this.create = false;
this.resetBodyFile();
@ -339,26 +374,26 @@
created() {
this.init();
}
}
}
</script>
<style scoped>
.test-container {
.test-container {
height: calc(100vh - 155px);
min-height: 600px;
}
}
.test-name {
.test-name {
width: 600px;
margin-left: -20px;
margin-right: 20px;
}
}
.test-project {
.test-project {
min-width: 150px;
}
}
.test-container .more {
.test-container .more {
margin-left: 10px;
}
}
</style>

View File

@ -8,44 +8,60 @@
:title="scenario.name" :name="index" :class="{'disable-scenario': !scenario.enable}">
<template slot="title">
<div class="scenario-name">
{{scenario.name}}
<el-tag type="info" size="small" v-if="scenario.isReference()">{{
$t('api_test.scenario.reference')
}}
</el-tag>
{{ scenario.name }}
<span id="hint" v-if="!scenario.name">
{{$t('api_test.scenario.config')}}
{{ $t('api_test.scenario.config') }}
</span>
</div>
<el-dropdown trigger="click" @command="handleCommand">
<span class="el-dropdown-link el-icon-more scenario-btn"/>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :disabled="isReadOnly" :command="{type: 'copy', index: index}">
{{$t('api_test.scenario.copy')}}
{{ $t('api_test.scenario.copy') }}
</el-dropdown-item>
<el-dropdown-item :disabled="isReadOnly" :command="{type:'delete', index:index}">
{{$t('api_test.scenario.delete')}}
{{ $t('api_test.scenario.delete') }}
</el-dropdown-item>
<el-dropdown-item v-if="scenario.enable" :disabled="isReadOnly" :command="{type:'disable', index:index}">
{{$t('api_test.scenario.disable')}}
<el-dropdown-item v-if="scenario.enable" :disabled="isReadOnly"
:command="{type:'disable', index:index}">
{{ $t('api_test.scenario.disable') }}
</el-dropdown-item>
<el-dropdown-item v-if="!scenario.enable" :disabled="isReadOnly" :command="{type:'enable', index:index}">
{{$t('api_test.scenario.enable')}}
<el-dropdown-item v-if="!scenario.enable" :disabled="isReadOnly"
:command="{type:'enable', index:index}">
{{ $t('api_test.scenario.enable') }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<ms-api-request-config :is-read-only="isReadOnly" :scenario="scenario" @select="select"/>
<ms-api-request-config :is-read-only="disable" :scenario="scenario" @select="select"/>
</ms-api-collapse-item>
</draggable>
</ms-api-collapse>
</div>
<el-button :disabled="isReadOnly" class="scenario-create" type="primary" size="mini" icon="el-icon-plus" plain @click="createScenario"/>
<el-popover placement="top" v-model="visible">
<el-radio-group v-model="type" @change="createScenario">
<el-radio :label="types.CREATE">{{ $t('api_test.scenario.create_scenario') }}</el-radio>
<el-radio :label="types.SELECT">{{ $t('api_test.scenario.select_scenario') }}</el-radio>
</el-radio-group>
<el-button slot="reference" :disabled="isReadOnly" class="scenario-create" type="primary" size="mini"
icon="el-icon-plus" plain/>
</el-popover>
</el-aside>
<el-main class="scenario-main">
<div class="scenario-form">
<ms-api-scenario-form :is-read-only="isReadOnly" :scenario="selected" :project-id="projectId" v-if="isScenario"/>
<ms-api-request-form :debug-report-id="debugReportId" @runDebug="runDebug" :is-read-only="isReadOnly"
<ms-api-scenario-form :is-read-only="disable" :scenario="selected" :project-id="projectId"
v-if="isScenario"/>
<ms-api-request-form :debug-report-id="debugReportId" @runDebug="runDebug"
:is-read-only="disable"
:request="selected" :scenario="currentScenario" v-if="isRequest"/>
</div>
</el-main>
<ms-api-scenario-select :exclude-id="testId" @select="selectScenario" ref="selectDialog"/>
</el-container>
</template>
@ -58,11 +74,13 @@ import MsApiRequestForm from "./request/ApiRequestForm";
import MsApiScenarioForm from "./ApiScenarioForm";
import {Request, Scenario} from "../model/ScenarioModel";
import draggable from 'vuedraggable';
import MsApiScenarioSelect from "@/business/components/api/test/components/ApiScenarioSelect";
export default {
name: "MsApiScenarioConfig",
components: {
MsApiScenarioSelect,
MsApiRequestConfig,
MsApiScenarioForm,
MsApiRequestForm,
@ -72,17 +90,21 @@ export default {
},
props: {
testId: String,
scenarios: Array,
projectId: String,
isReadOnly: {
type: Boolean,
default: false
},
debugReportId: String
debugReportId: String,
},
data() {
return {
visible: false,
types: {CREATE: "create", SELECT: "select"},
type: "",
activeName: 0,
selected: [Scenario, Request],
currentScenario: {}
@ -100,30 +122,49 @@ export default {
},
methods: {
createScenario: function () {
notContainsScenario(item) {
for (let scenario of this.scenarios) {
if (item.id === scenario.id) {
return false;
}
}
return true;
},
selectScenario(selection) {
selection.filter(this.notContainsScenario).forEach(item => {
this.scenarios.push(item);
})
},
createScenario() {
if (this.type === this.types.CREATE) {
this.scenarios.push(new Scenario());
} else {
this.$refs.selectDialog.open();
}
this.visible = false;
this.type = "";
},
copyScenario: function (index) {
copyScenario(index) {
let scenario = this.scenarios[index];
this.scenarios.push(new Scenario(scenario));
this.scenarios.push(scenario.clone());
},
deleteScenario: function (index) {
deleteScenario(index) {
this.scenarios.splice(index, 1);
if (this.scenarios.length === 0) {
this.createScenario();
this.select(this.scenarios[0]);
}
},
disableScenario: function (index) {
disableScenario(index) {
this.scenarios[index].enable = false;
},
enableScenario: function (index) {
enableScenario(index) {
this.scenarios[index].enable = true;
},
handleChange: function (index) {
handleChange(index) {
this.select(this.scenarios[index]);
},
handleCommand: function (command) {
handleCommand(command) {
switch (command.type) {
case "copy":
this.copyScenario(command.index);
@ -139,7 +180,7 @@ export default {
break;
}
},
select: function (obj, scenario) {
select(obj, scenario) {
this.selected = null;
this.$nextTick(function () {
if (obj instanceof Scenario) {
@ -150,13 +191,13 @@ export default {
this.selected = obj;
});
},
reset: function () {
reset() {
this.$nextTick(function () {
this.activeName = 0;
this.select(this.scenarios[0]);
});
},
initScenarioEnvironment: function () {
initScenarioEnvironment() {
if (this.projectId) {
this.result = this.$get('/api/environment/list/' + this.projectId, response => {
let environments = response.data;
@ -192,62 +233,74 @@ export default {
},
isRequest() {
return this.selected instanceof Request;
},
isReference() {
if (this.selected instanceof Scenario) {
return this.selected.isReference();
}
if (this.selected instanceof Request) {
return this.currentScenario.isReference();
}
return false;
},
disable() {
return this.isReadOnly || this.isReference;
},
},
created() {
this.select(this.scenarios[0]);
}
}
}
</script>
<style scoped>
.scenario-aside {
.scenario-aside {
position: relative;
border-radius: 4px;
border: 1px solid #EBEEF5;
box-sizing: border-box;
}
}
.scenario-list {
.scenario-list {
overflow-y: auto;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 28px;
}
}
.scenario-name {
.scenario-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 14px;
width: 100%;
}
}
/*.scenario-name > #hint {*/
/*color: #8a8b8d;*/
/*}*/
/*.scenario-name > #hint {*/
/*color: #8a8b8d;*/
/*}*/
.scenario-btn {
.scenario-btn {
text-align: center;
padding: 13px;
}
}
.scenario-create {
.scenario-create {
position: absolute;
bottom: 0;
width: 100%;
}
}
.scenario-main {
.scenario-main {
position: relative;
margin-left: 20px;
border: 1px solid #EBEEF5;
}
}
.scenario-form {
.scenario-form {
padding: 20px;
overflow-y: auto;
position: absolute;
@ -255,18 +308,18 @@ export default {
left: 0;
right: 0;
bottom: 0;
}
}
.scenario-ghost {
.scenario-ghost {
opacity: 0.5;
}
}
.scenario-draggable {
.scenario-draggable {
background-color: #909399;
}
}
.disable-scenario >>> .el-collapse-item__header {
.disable-scenario >>> .el-collapse-item__header {
border-right: 2px solid #909399;
color: #8a8b8d;
}
}
</style>

View File

@ -1,5 +1,6 @@
<template>
<el-form :model="scenario" :rules="rules" ref="scenario" label-width="100px" v-loading="result.loading">
<el-form :model="scenario" :rules="rules" ref="scenario" label-width="100px" v-loading="result.loading"
:disabled="isReadOnly">
<el-form-item :label="$t('api_test.scenario.name')" prop="name">
<el-input :disabled="isReadOnly" v-model="scenario.name" maxlength="100" show-word-limit/>
</el-form-item>
@ -26,7 +27,7 @@
</el-form-item>
</el-form-item>
<el-tabs v-model="activeName">
<el-tabs v-model="activeName" :disabled="isReadOnly">
<el-tab-pane :label="$t('api_test.scenario.variables')" name="parameters">
<ms-api-scenario-variables :is-read-only="isReadOnly" :items="scenario.variables"
:description="$t('api_test.scenario.kv_description')"/>
@ -38,11 +39,11 @@
</el-tab-pane>
<el-tab-pane :label="$t('api_test.scenario.dubbo')" name="dubbo">
<div class="dubbo-config-title">Config Center</div>
<ms-dubbo-config-center :config="scenario.dubboConfig.configCenter"/>
<ms-dubbo-config-center :config="scenario.dubboConfig.configCenter" :is-read-only="isReadOnly"/>
<div class="dubbo-config-title">Registry Center</div>
<ms-dubbo-registry-center :registry="scenario.dubboConfig.registryCenter"/>
<ms-dubbo-registry-center :registry="scenario.dubboConfig.registryCenter" :is-read-only="isReadOnly"/>
<div class="dubbo-config-title">Consumer & Service</div>
<ms-dubbo-consumer-service :consumer="scenario.dubboConfig.consumerAndService"/>
<ms-dubbo-consumer-service :consumer="scenario.dubboConfig.consumerAndService" :is-read-only="isReadOnly"/>
</el-tab-pane>
</el-tabs>

View File

@ -0,0 +1,128 @@
<template>
<el-dialog :title="$t('api_test.scenario.select_scenario')" :visible.sync="visible" width="70%">
<el-table stripe :data="tableData" size="small" @expand-change="expand">
<el-table-column type="expand" width="50">
<template v-slot:default="{row}">
<ms-api-scenario-select-sub-table :row="row" v-model="row.selected"/>
</template>
</el-table-column>
<el-table-column prop="name" :label="$t('api_test.scenario.test_name')" width="400" show-overflow-tooltip/>
<el-table-column prop="sr" :label="$t('api_test.scenario.scenario_request')" width="150" show-overflow-tooltip/>
<el-table-column prop="userName" :label="$t('api_test.creator')" width="150" show-overflow-tooltip/>
<el-table-column prop="enable" :label="$t('api_test.scenario.enable_disable')" width="150"/>
<el-table-column>
<template v-slot:header>
<div class="search-header">
<ms-table-search-bar :condition.sync="condition" @change="search" class="search-bar"
:tip="$t('commons.search_by_name')"/>
<ms-table-adv-search-bar :condition.sync="condition" @search="search"/>
</div>
</template>
<template v-slot:default="{row}">
{{ row.reference }}
<el-button type="text" size="small" @click="reference(row)">
{{ $t('api_test.scenario.reference') }}
</el-button>
<el-button type="text" size="small" @click="clone(row)">{{ $t('api_test.scenario.clone') }}</el-button>
</template>
</el-table-column>
</el-table>
<ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize" :total="total"/>
<div class="dialog-footer">
<el-button @click="close">{{ $t('commons.cancel') }}</el-button>
</div>
</el-dialog>
</template>
<script>
import MsTableHeader from "@/business/components/common/components/MsTableHeader";
import {TEST_CONFIGS} from "@/business/components/common/components/search/search-components";
import MsTablePagination from "@/business/components/common/pagination/TablePagination";
import MsTableSearchBar from "@/business/components/common/components/MsTableSearchBar";
import MsTableAdvSearchBar from "@/business/components/common/components/search/MsTableAdvSearchBar";
import MsApiScenarioSelectSubTable from "@/business/components/api/test/components/ApiScenarioSelectSubTable";
import {Scenario} from "@/business/components/api/test/model/ScenarioModel";
export default {
name: "MsApiScenarioSelect",
components: {
MsApiScenarioSelectSubTable,
MsTableAdvSearchBar, MsTableSearchBar, MsTablePagination, MsTableHeader
},
props: {
excludeId: String
},
data() {
return {
visible: false,
condition: {
components: TEST_CONFIGS
},
tableData: [],
currentPage: 1,
pageSize: 5,
total: 0,
selection: false,
}
},
methods: {
search() {
this.condition.excludeId = this.excludeId;
let url = "/api/list/" + this.currentPage + "/" + this.pageSize;
this.result = this.$post(url, this.condition, response => {
let data = response.data;
this.total = data.itemCount;
this.tableData = data.listObject;
this.tableData.forEach(row => {
row.selected = [];
})
});
},
reference(row) {
let scenarios = [];
for (let options of row.selected) {
if (!options.id) {
this.$warning(this.$t('api_test.scenario.cant_reference'));
return;
}
let scenario = new Scenario(options);
if (!scenario.isReference()) {
scenario.id = row.id + "#" + options.id;
} else {
scenario.id = options.id;
}
scenarios.push(scenario);
}
this.$emit('select', scenarios);
},
clone(row) {
let scenarios = [];
row.selected.forEach(options => {
scenarios.push(new Scenario(options));
})
this.$emit('select', scenarios);
},
open() {
this.search();
this.visible = true;
},
close() {
this.visible = false;
},
expand(row) {
row.selected = [];
}
}
}
</script>
<style scoped>
.search-header {
text-align: right;
}
.search-bar {
width: 200px
}
</style>

View File

@ -0,0 +1,58 @@
<template>
<el-table stripe :data="scenarios" class="adjust-table" @select-all="select" @select="select" size="small"
:show-header="false" ref="table" v-loading="result.loading">
<el-table-column type="selection" width="50"/>
<el-table-column prop="name" width="350" show-overflow-tooltip/>
<el-table-column width="150">
<template v-slot:default="{row}">
1 / {{ row.requests.length }}
</template>
</el-table-column>
<el-table-column prop="null" width="150">
{{ row.userName }}
</el-table-column>
<el-table-column prop="enable">
<template v-slot:default="{row}">
<el-tag type="success" size="small" v-if="row.enable !== false">{{ $t('api_test.scenario.enable') }}</el-tag>
<el-tag type="info" size="small" v-else>{{ $t('api_test.scenario.disable') }}</el-tag>
</template>
</el-table-column>
<el-table-column/>
</el-table>
</template>
<script>
export default {
name: "MsApiScenarioSelectSubTable",
props: {
row: Object
},
data() {
return {
result: {loading: true},
scenarios: [],
}
},
methods: {
getTest() {
this.result = this.$get("/api/get/" + this.row.id, response => {
if (response.data) {
this.scenarios = JSON.parse(response.data.scenarioDefinition);
}
});
},
select(selection) {
this.$emit('input', selection);
}
},
mounted() {
this.getTest();
}
}
</script>
<style scoped>
</style>

View File

@ -1,5 +1,5 @@
<template>
<el-form :model="request" :rules="rules" ref="request" label-width="100px">
<el-form :model="request" :rules="rules" ref="request" label-width="100px" :disabled="isReadOnly">
<el-form-item :label="$t('api_test.request.name')" prop="name">
<el-input :disabled="isReadOnly" v-model="request.name" maxlength="300" show-word-limit/>
@ -41,7 +41,9 @@
<el-checkbox class="follow-redirects-item" v-model="request.followRedirects">{{$t('api_test.request.follow_redirects')}}</el-checkbox>
</el-form-item>
<el-button :disabled="!request.enable || !scenario.enable || isReadOnly" class="debug-button" size="small" type="primary" @click="runDebug">{{ $t('api_test.request.debug') }}</el-button>
<el-button :disabled="!request.enable || !scenario.enable || isReadOnly" class="debug-button" size="small"
type="primary" @click="runDebug">{{ $t('api_test.request.debug') }}
</el-button>
<el-tabs v-model="activeName">
<el-tab-pane :label="$t('api_test.request.parameters')" name="parameters">

View File

@ -106,7 +106,6 @@ export class BaseConfig {
set(options) {
options = this.initOptions(options)
for (let name in options) {
if (options.hasOwnProperty(name)) {
if (!(this[name] instanceof Array)) {
@ -142,7 +141,7 @@ export class Test extends BaseConfig {
constructor(options) {
super();
this.type = "MS API CONFIG";
this.version = '1.1.0';
this.version = '1.3.0';
this.id = uuid();
this.name = undefined;
this.projectId = undefined;
@ -201,6 +200,7 @@ export class Test extends BaseConfig {
export class Scenario extends BaseConfig {
constructor(options = {}) {
super();
this.id = undefined;
this.name = undefined;
this.url = undefined;
this.variables = [];
@ -216,15 +216,17 @@ export class Scenario extends BaseConfig {
this.sets({variables: KeyValue, headers: KeyValue, requests: RequestFactory}, options);
}
initOptions(options) {
options = options || {};
initOptions(options = {}) {
options.id = options.id || uuid();
options.requests = options.requests || [new RequestFactory()];
options.dubboConfig = new DubboConfig(options.dubboConfig);
return options;
}
clone() {
return new Scenario(this);
let clone = new Scenario(this);
clone.id = uuid();
return clone;
}
isValid() {
@ -238,6 +240,10 @@ export class Scenario extends BaseConfig {
}
return {isValid: true};
}
isReference() {
return this.id.indexOf("#") !== -1
}
}
class DubboConfig extends BaseConfig {
@ -296,6 +302,7 @@ export class Request extends BaseConfig {
export class HttpRequest extends Request {
constructor(options) {
super(RequestFactory.TYPES.HTTP);
this.id = undefined;
this.name = undefined;
this.url = undefined;
this.path = undefined;
@ -321,8 +328,8 @@ export class HttpRequest extends Request {
this.sets({parameters: KeyValue, headers: KeyValue}, options);
}
initOptions(options) {
options = options || {};
initOptions(options = {}) {
options.id = options.id || uuid();
options.method = options.method || "GET";
options.body = new Body(options.body);
options.assertions = new Assertions(options.assertions);
@ -381,6 +388,7 @@ export class DubboRequest extends Request {
constructor(options = {}) {
super(RequestFactory.TYPES.DUBBO);
this.id = options.id || uuid();
this.name = options.name;
this.protocol = options.protocol || DubboRequest.PROTOCOLS.DUBBO;
this.interface = options.interface;

@ -1 +1 @@
Subproject commit 7e4d80cc2b870a8cac6dbb9fe6711ab6041faf6d
Subproject commit 390943d21e7d0196e0d7d5faa66f0131cb631614

View File

@ -414,7 +414,15 @@ export default {
copy: "Copy scenario",
delete: "Delete scenario",
disable: "Disable",
enable: "Enable"
enable: "Enable",
create_scenario: "Create scenario",
select_scenario: "Select scenario",
scenario_request: "Scenario/Request",
enable_disable: "Enable/Disable",
test_name: "Test Name",
reference: "Reference",
clone: "Copy",
cant_reference:'Historical test files, can be referenced after re-saving'
},
request: {
debug: "Debug",
@ -484,7 +492,7 @@ export default {
xpath_expression: "XPath expression",
},
processor: {
pre_exec_script : "PreProcessor",
pre_exec_script: "PreProcessor",
post_exec_script: "PostProcessor",
code_template: "Code template",
bean_shell_processor_tip: "Currently only BeanShell scripts are supported",
@ -716,7 +724,7 @@ export default {
result_distribution: "Result distribution",
custom_component: "Custom",
create_report: "Create report",
defect_list:"Defect list",
defect_list: "Defect list",
view_report: "View report",
component_library: "Component library",
component_library_tip: "Drag and drop the component from the component library, add to the right, preview the report effect, only one can be added per system component.",

View File

@ -414,7 +414,15 @@ export default {
copy: "复制场景",
delete: "删除场景",
disable: "禁用",
enable: "启用"
enable: "启用",
create_scenario: "创建新场景",
select_scenario: "选择已有场景",
scenario_request: "场景/请求",
enable_disable: "启用/禁用",
test_name: "测试名称",
reference: "引用",
clone: "复制",
cant_reference: '历史测试文件,重新保存后才可被引用'
},
request: {
debug: "调试",
@ -485,7 +493,7 @@ export default {
xpath_expression: "XPath表达式",
},
processor: {
pre_exec_script : "预执行脚本",
pre_exec_script: "预执行脚本",
post_exec_script: "后执行脚本",
code_template: "代码模版",
bean_shell_processor_tip: "仅支持 BeanShell 脚本",
@ -505,7 +513,7 @@ export default {
get_provider_success: "获取成功",
check_registry_center: "获取失败请检查Registry Center",
form_description: "如果当前配置项无值,则取场景配置项的值",
}
},
},
api_import: {
label: "导入",
@ -718,7 +726,7 @@ export default {
test_result: "测试结果",
result_distribution: "测试结果分布",
custom_component: "自定义模块",
defect_list:"缺陷列表",
defect_list: "缺陷列表",
create_report: "创建测试报告",
view_report: "查看测试报告",
component_library: "组件库",

View File

@ -413,7 +413,15 @@ export default {
copy: "複製場景",
delete: "删除場景",
disable: "禁用",
enable: "啟用"
enable: "啟用",
create_scenario: "創建新場景",
select_scenario: "選擇已有場景",
scenario_request: "場景/請求",
enable_disable: "啟用/禁用",
test_name: "測試名稱",
reference: "引用",
clone: "複製",
cant_reference: '歷史測試文件,重新保存後才可被引用'
},
request: {
debug: "調試",