feat(接口自动化): 跨项目添加场景步骤

This commit is contained in:
shiziyuan9527 2021-02-23 18:06:12 +08:00
parent 354892fd9c
commit 0a997065dd
12 changed files with 256 additions and 57 deletions

View File

@ -6,6 +6,7 @@ import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.Map;
@Setter
@Getter
@ -34,4 +35,6 @@ public class RunDefinitionRequest {
private Response response;
private List<String> bodyUploadIds;
private Map<String, String> environmentMap;
}

View File

@ -50,6 +50,7 @@ import org.apache.jorphan.collections.ListedHashTree;
import java.io.ByteArrayOutputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
@ -104,6 +105,8 @@ public abstract class MsTestElement {
private boolean customizeReq;
@JSONField(ordinal = 12)
private String projectId;
@JSONField(ordinal = 13)
private Map<String, String> environmentMap;
private MsTestElement parent;
@ -181,9 +184,10 @@ public abstract class MsTestElement {
return null;
}
protected EnvironmentConfig getEnvironmentConfig(String environmentId) {
protected EnvironmentConfig getEnvironmentConfig(String projectId) {
String env = environmentMap.get(projectId);
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
ApiTestEnvironmentWithBLOBs environment = environmentService.get(environmentId);
ApiTestEnvironmentWithBLOBs environment = environmentService.get(env);
if (environment != null && environment.getConfig() != null) {
return JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
}

View File

@ -0,0 +1,130 @@
<template>
<el-dialog
title="环境选择"
:visible.sync="dialogVisible"
width="30%"
:before-close="handleClose">
<div v-for="pe in data" :key="pe.id">
<div>
{{ getProjectName(pe.id) }}
<el-select v-model="pe['selectEnv']" placeholder="请选择环境" style="margin-left:10px; margin-top: 10px;" size="small">
<el-option v-for="(environment, index) in pe.envs" :key="index"
:label="environment.name + (environment.config.httpConfig.socket ? (': ' + environment.config.httpConfig.protocol + '://' + environment.config.httpConfig.socket) : '')"
:value="environment.id"/>
<el-button class="ms-scenario-button" size="mini" type="primary" @click="openEnvironmentConfig">
{{ $t('api_test.environment.environment_config') }}
</el-button>
<template v-slot:empty>
<div class="empty-environment">
<el-button class="ms-scenario-button" size="mini" type="primary" @click="openEnvironmentConfig">
{{ $t('api_test.environment.environment_config') }}
</el-button>
</div>
</template>
</el-select>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false" size="small"> </el-button>
<el-button type="primary" @click="handleConfirm" size="small"> </el-button>
</span>
</el-dialog>
</template>
<script>
import {parseEnvironment} from "@/business/components/api/test/model/EnvironmentModel";
export default {
name: "ApiScenarioEnv",
props: {
projectIds: Set
},
data() {
return {
dialogVisible: false,
projects: [],
data: [],
environmentId: '',
environments: []
}
},
created() {
this.getWsProjects();
},
methods: {
handleClose(done) {
this.$confirm('确认关闭?')
.then(_ => {
done();
})
.catch(_ => {
});
},
init() {
this.projectIds.forEach(id => {
this.result = this.$get('/api/environment/list/' + id, res => {
let envs = res.data;
envs.forEach(environment => {
parseEnvironment(environment);
});
let item = {};
item.id = id;
item.envs = envs;
item.selectEnv = '';
this.data.push(item)
})
})
},
open() {
this.data = [];
this.dialogVisible = true;
this.init();
},
getWsProjects() {
this.$get("/project/listAll", res => {
this.projects = res.data;
})
},
getProjectName(id) {
const project = this.projects.find(p => p.id === id);
if (project) {
return project.name;
}
return '';
},
openEnvironmentConfig() {
if (!this.projectId) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs.environmentConfig.open(this.projectId);
},
getProjectEnvMap() {
},
handleConfirm() {
let map = new Map();
let sign = true;
this.data.forEach(dt => {
if (!dt.selectEnv) {
sign = false;
return;
}
map.set(dt.id, dt.selectEnv);
})
if (!sign) {
this.$warning("请为每个项目选择一个运行环境!");
return;
}
this.$emit('setProjectEnvMap', map);
this.dialogVisible = false;
}
}
}
</script>
<style scoped>
</style>

View File

@ -363,7 +363,7 @@
this.changeSelectDataRangeAll();
this.search();
},
search() {
search(projectId) {
this.selectRows = new Set();
this.getLabel()
this.condition.moduleIds = this.selectNodeIds;
@ -372,7 +372,10 @@
this.condition.moduleIds = [];
}
if (this.projectId != null) {
// todo
if (projectId != null) {
this.condition.projectId = projectId;
} else if (this.projectId != null) {
this.condition.projectId = this.projectId;
}

View File

@ -9,7 +9,7 @@
name: 'MsDebugRun',
components: {},
props: {
environment: String,
environment: Map,
debug: Boolean,
reportId: String,
runData: Object,
@ -112,9 +112,12 @@
threadGroup.hashTree = [];
threadGroup.name = this.reportId;
threadGroup.enableCookieShare = this.runData.enableCookieShare;
let map = this.environment;
this.runData.environmentMap = this.strMapToObj(map);
threadGroup.hashTree.push(this.runData);
testPlan.hashTree.push(threadGroup);
let reqObj = {id: this.reportId, reportId: this.reportId, scenarioName: this.runData.name, scenarioId: this.runData.id, environmentId: this.environment, testElement: testPlan, projectId: getCurrentProjectID()};
let reqObj = {id: this.reportId, reportId: this.reportId, scenarioName: this.runData.name,
scenarioId: this.runData.id, testElement: testPlan, projectId: getCurrentProjectID(), environmentMap: this.strMapToObj(map)};
let bodyFiles = this.getBodyUploadFiles(reqObj);
let url = "/api/automation/run/debug";
this.$fileUpload(url, null, bodyFiles, reqObj, response => {
@ -122,6 +125,13 @@
this.$emit('runRefresh', {});
}, erro => {
});
},
strMapToObj(strMap){
let obj= Object.create(null);
for (let[k,v] of strMap) {
obj[k] = v;
}
return obj;
}
}
}

View File

@ -111,24 +111,26 @@
<el-col :span="3" class="ms-col-one ms-font">
<el-checkbox v-model="enableCookieShare">共享cookie</el-checkbox>
</el-col>
<el-col :span="7" class="ms-font">
<el-select v-model="currentEnvironmentId" size="small" class="ms-htt-width"
:placeholder="$t('api_test.definition.request.run_env')"
clearable>
<el-option v-for="(environment, index) in environments" :key="index"
:label="environment.name + (environment.config.httpConfig.socket ? (': ' + environment.config.httpConfig.protocol + '://' + environment.config.httpConfig.socket) : '')"
:value="environment.id"/>
<el-button class="ms-scenario-button" size="mini" type="primary" @click="openEnvironmentConfig">
{{ $t('api_test.environment.environment_config') }}
</el-button>
<template v-slot:empty>
<div class="empty-environment">
<el-button class="ms-scenario-button" size="mini" type="primary" @click="openEnvironmentConfig">
{{ $t('api_test.environment.environment_config') }}
</el-button>
</div>
</template>
</el-select>
<el-col :span="7" class="ms-col-one ms-font">
<el-link type="primary" @click="handleEnv">环境配置</el-link>
<!-- <el-select v-model="currentEnvironmentId" size="small" class="ms-htt-width"-->
<!-- :placeholder="$t('api_test.definition.request.run_env')"-->
<!-- clearable>-->
<!-- <el-option v-for="(environment, index) in environments" :key="index"-->
<!-- :label="environment.name + (environment.config.httpConfig.socket ? (': ' + environment.config.httpConfig.protocol + '://' + environment.config.httpConfig.socket) : '')"-->
<!-- :value="environment.id"/>-->
<!-- <el-button class="ms-scenario-button" size="mini" type="primary" @click="openEnvironmentConfig">-->
<!-- {{ $t('api_test.environment.environment_config') }}-->
<!-- </el-button>-->
<!-- <template v-slot:empty>-->
<!-- <div class="empty-environment">-->
<!-- <el-button class="ms-scenario-button" size="mini" type="primary" @click="openEnvironmentConfig">-->
<!-- {{ $t('api_test.environment.environment_config') }}-->
<!-- </el-button>-->
<!-- </div>-->
<!-- </template>-->
<!-- </el-select>-->
</el-col>
<el-col :span="2">
<el-button :disabled="scenarioDefinition.length < 1" size="small" type="primary" @click="runDebug">{{$t('api_test.request.debug')}}</el-button>
@ -184,11 +186,13 @@
<!--场景导入 -->
<scenario-relevance @save="addScenario" ref="scenarioRelevance"/>
<api-scenario-env :project-ids="projectIds" ref="apiScenarioEnv" @setProjectEnvMap="setProjectEnvMap"/>
<!-- 环境 -->
<api-environment-config ref="environmentConfig" @close="environmentConfigClose"/>
<!--执行组件-->
<ms-run :debug="true" :environment="currentEnvironmentId" :reportId="reportId" :run-data="debugData"
<ms-run :debug="true" :environment="projectEnvMap" :reportId="reportId" :run-data="debugData"
@runRefresh="runRefresh" ref="runTest"/>
<!-- 调试结果 -->
<el-drawer :visible.sync="debugVisible" :destroy-on-close="true" direction="ltr" :withHeader="true" :modal="false" size="90%">
@ -230,6 +234,8 @@ import ScenarioApiRelevance from "./api/ApiRelevance";
import ScenarioRelevance from "./api/ScenarioRelevance";
import MsComponentConfig from "./component/ComponentConfig";
import {handleCtrlSEvent} from "../../../../../common/js/utils";
import {getProject} from "@/business/components/api/automation/scenario/event";
import ApiScenarioEnv from "@/business/components/api/automation/scenario/ApiScenarioEnv";
export default {
name: "EditApiScenario",
@ -238,6 +244,7 @@ export default {
currentScenario: {},
},
components: {
ApiScenarioEnv,
MsVariableList,
ScenarioRelevance,
ScenarioApiRelevance,
@ -291,7 +298,9 @@ export default {
globalOptions: {
spacing: 30
},
response: {}
response: {},
projectIds: new Set,
projectEnvMap: new Map
}
},
created() {
@ -304,7 +313,13 @@ export default {
this.getApiScenario();
this.addListener(); // ctrl s
},
directives: {OutsideClick},
mounted() {
getProject.$on('addProjectEnv', (projectId, projectEnv) => {
this.projectIds.add(projectId);
this.projectEnvMap.set(projectId, projectEnv);
})
},
directives: {OutsideClick},
computed: {
buttons() {
let buttons = [
@ -679,9 +694,16 @@ export default {
},
runDebug() {
/*触发执行操作*/
if (!this.currentEnvironmentId) {
this.$error(this.$t('api_test.environment.select_environment'));
return;
// if (!this.currentEnvironmentId) {
// this.$error(this.$t('api_test.environment.select_environment'));
// return;
// }
let iter = this.projectEnvMap.values();
for (let i of iter) {
if (!i) {
this.$warning("请为每个项目选择一个运行环境!");
return;
}
}
this.$refs['currentScenario'].validate((valid) => {
if (valid) {
@ -694,7 +716,7 @@ export default {
referenced: 'Created',
enableCookieShare: this.enableCookieShare,
headers: this.currentScenario.headers,
environmentId: this.currentEnvironmentId,
environmentMap: this.projectEnvMap,
hashTree: this.scenarioDefinition
};
this.reportId = getUUID().substring(0, 8);
@ -933,7 +955,7 @@ export default {
variables: this.currentScenario.variables,
headers: this.currentScenario.headers,
referenced: 'Created',
environmentId: this.currentEnvironmentId,
environmentMap: this.projectEnvMap,
hashTree: this.scenarioDefinition,
projectId: this.projectId
};
@ -973,6 +995,15 @@ export default {
size += this.currentScenario.headers.length - 1;
}
return size;
},
beforeDestroy() {
getProject.$off('addProjectEnv');
},
handleEnv() {
this.$refs.apiScenarioEnv.open();
},
setProjectEnvMap(projectEnvMap) {
this.projectEnvMap = projectEnvMap;
}
}
}

View File

@ -1,6 +1,7 @@
<template>
<relevance-dialog :title="$t('api_test.automation.scenario_import')" ref="relevanceDialog">
<test-case-relevance-base
@setProject="setProject"
ref="baseRelevance">
<template v-slot:aside>
<ms-api-scenario-module
@nodeSelectEvent="nodeChange"
@ -22,8 +23,7 @@
<el-button type="primary" @click="copy" @keydown.enter.native.prevent>{{$t('commons.copy')}}</el-button>
<el-button type="primary" @click="reference" @keydown.enter.native.prevent> {{ $t('api_test.scenario.reference') }}</el-button>
</template>
</relevance-dialog>
</test-case-relevance-base>
</template>
<script>
@ -37,10 +37,12 @@
import MsApiScenarioList from "../ApiScenarioList";
import {getUUID} from "../../../../../../common/js/utils";
import RelevanceDialog from "../../../../track/plan/view/comonents/base/RelevanceDialog";
import TestCaseRelevanceBase from "@/business/components/track/plan/view/comonents/base/TestCaseRelevanceBase";
export default {
name: "ScenarioRelevance",
components: {
TestCaseRelevanceBase,
RelevanceDialog,
MsApiScenarioList,
MsApiScenarioModule,
@ -55,6 +57,12 @@
isApiListEnable: true,
currentScenario: [],
currentScenarioIds: [],
projectId: ''
}
},
watch: {
projectId() {
this.$refs.apiScenarioList.search(this.projectId);
}
},
methods: {
@ -69,7 +77,7 @@
scenarios.push(obj);
});
this.$emit('save', scenarios);
this.close();
this.$refs.baseRelevance.close();
},
copy() {
let scenarios = [];
@ -87,7 +95,7 @@
}
});
this.$emit('save', scenarios);
this.close();
this.$refs.baseRelevance.close();
}
})
},
@ -96,9 +104,9 @@
this.$refs.relevanceDialog.close();
},
open() {
this.$refs.relevanceDialog.open();
this.$refs.baseRelevance.open();
if (this.$refs.apiScenarioList) {
this.$refs.apiScenarioList.search();
this.$refs.apiScenarioList.search(this.projectId);
}
},
nodeChange(node, nodeIds, pNodes) {
@ -117,6 +125,9 @@
this.currentScenario = Array.from(data).map(row => row);
this.currentScenarioIds = Array.from(data).map(row => row.id);
},
setProject(projectId) {
this.projectId = projectId;
},
}
}
</script>

View File

@ -71,6 +71,7 @@ import {getUUID} from "@/common/js/utils";
import ApiBaseComponent from "../common/ApiBaseComponent";
import ApiResponseComponent from "./ApiResponseComponent";
import CustomizeReqInfo from "@/business/components/api/automation/scenario/common/CustomizeReqInfo";
import {getProject} from "@/business/components/api/automation/scenario/event";
export default {
name: "MsApiComponent",
@ -118,6 +119,7 @@ export default {
}
}
}
getProject.$emit('addProjectEnv', this.request.projectId, this.currentEnvironmentId);
},
computed: {
displayColor() {

View File

@ -29,6 +29,7 @@
import MsDubboBasisParameters from "../../../definition/components/request/dubbo/BasisParameters";
import MsApiRequestForm from "../../../definition/components/request/http/ApiHttpRequestForm";
import ApiBaseComponent from "../common/ApiBaseComponent";
import {getProject} from "@/business/components/api/automation/scenario/event";
export default {
name: "ApiScenarioComponent",
@ -39,6 +40,7 @@
type: Boolean,
default: false,
},
currentEnvironmentId: String,
},
watch: {},
created() {
@ -56,7 +58,8 @@
this.scenario.disabled = true;
this.scenario.name = response.data.name;
const project = this.projects.find(p => p.id === this.scenario.projectId);
this.scenario.projectName = project.name;
getProject.$emit('addProjectEnv', this.scenario.projectId, this.currentEnvironmentId);
this.scenario.projectName = project ? project.name : '';
this.$emit('refReload');
} else {
this.scenario.referenced = "Deleted";

View File

@ -0,0 +1,2 @@
import Vue from 'vue';
export const getProject = new Vue();

View File

@ -223,6 +223,7 @@ export class Scenario extends BaseConfig {
this.headers = [];
this.requests = [];
this.environmentId = undefined;
this.environmentMap = undefined;
this.dubboConfig = undefined;
this.environment = undefined;
this.enableCookieShare = false;

View File

@ -14,11 +14,12 @@
<slot></slot>
<template v-slot:footer>
<ms-dialog-footer @cancel="close" @confirm="save"/>
</template>
<template v-slot:footer>
<ms-dialog-footer @cancel="close" @confirm="save"/>
<div v-if="$slots.footer">
<slot name="footer"></slot>
</div>
<div v-else>
<ms-dialog-footer @cancel="close" @confirm="save"/>
</div>
</template>
</relevance-dialog>
@ -75,17 +76,15 @@
},
getProject() {
if (this.planId) {
this.result = this.$post("/test/plan/project/", {planId: this.planId}, res => {
let data = res.data;
if (data) {
this.projects = data;
this.projectId = data[0].id;
this.projectName = data[0].name;
this.changeProject(data[0]);
}
})
}
this.result = this.$get("/project/listAll", res => {
let data = res.data;
if (data) {
this.projects = data;
this.projectId = data[0].id;
this.projectName = data[0].name;
this.changeProject(data[0]);
}
})
},
changeProject(project) {