Merge branch 'master' of https://github.com/metersphere/metersphere
This commit is contained in:
commit
fd0ee661a5
|
@ -10,4 +10,5 @@ public class ExtractCommon extends ExtractType {
|
|||
private String value; // value: ${variable}
|
||||
private String expression;
|
||||
private String description;
|
||||
private Boolean multipleMatching;
|
||||
}
|
||||
|
|
|
@ -11,5 +11,5 @@ public interface ExtTestReviewCaseMapper {
|
|||
|
||||
List<TestReviewCaseDTO> list(@Param("request") QueryCaseReviewRequest request);
|
||||
List<String> getStatusByReviewId(String reviewId);
|
||||
List<String> findRelateTestReviewId(String userId, String workspaceId);
|
||||
List<String> findRelateTestReviewId(@Param("userId") String userId, @Param("workspaceId") String workspaceId);
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ public class TestCaseController {
|
|||
}
|
||||
|
||||
@PostMapping("/file/download")
|
||||
public ResponseEntity<byte[]> downloadJmx(@RequestBody FileOperationRequest fileOperationRequest) {
|
||||
public ResponseEntity<byte[]> download(@RequestBody FileOperationRequest fileOperationRequest) {
|
||||
byte[] bytes = fileService.loadFileAsBytes(fileOperationRequest.getId());
|
||||
return ResponseEntity.ok()
|
||||
.contentType(MediaType.parseMediaType("application/octet-stream"))
|
||||
|
@ -175,4 +175,13 @@ public class TestCaseController {
|
|||
.body(bytes);
|
||||
}
|
||||
|
||||
@GetMapping("/file/preview/{fileId}")
|
||||
public ResponseEntity<byte[]> preview(@PathVariable String fileId) {
|
||||
byte[] bytes = fileService.loadFileAsBytes(fileId);
|
||||
return ResponseEntity.ok()
|
||||
.contentType(MediaType.parseMediaType("application/octet-stream"))
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileId + "\"")
|
||||
.body(bytes);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit cf6b06526324326a563d933e07118fac014a63b4
|
||||
Subproject commit ee74568be0beba46da19616f5832e83f9164c688
|
|
@ -35,7 +35,8 @@
|
|||
"jspdf": "^2.1.1",
|
||||
"yan-progress": "^1.0.3",
|
||||
"nprogress": "^0.2.0",
|
||||
"el-table-infinite-scroll": "^1.0.10"
|
||||
"el-table-infinite-scroll": "^1.0.10",
|
||||
"vue-pdf": "^4.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "^4.1.0",
|
||||
|
|
|
@ -29,6 +29,10 @@
|
|||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showCopyTipWithMultiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
|
@ -63,7 +67,7 @@
|
|||
|
||||
computed: {
|
||||
variable() {
|
||||
return "${" + this.value + "}";
|
||||
return "${" + (this.showCopyTipWithMultiple ? (this.value + "_n") : this.value) + "}";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,12 +8,17 @@
|
|||
</el-col>
|
||||
<el-col>
|
||||
<ms-api-variable-input :is-read-only="isReadOnly" v-model="common.variable" size="small" maxlength="60"
|
||||
@change="change" show-word-limit :placeholder="$t('api_test.variable_name')"/>
|
||||
@change="change" :show-copy-tip-with-multiple="common.multipleMatching" show-word-limit :placeholder="$t('api_test.variable_name')"/>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<el-input :disabled="isReadOnly" v-model="common.expression" size="small" show-word-limit
|
||||
:placeholder="expression"/>
|
||||
</el-col>
|
||||
<el-col class="multiple_checkbox">
|
||||
<el-checkbox v-model="common.multipleMatching" :disabled="isReadOnly">
|
||||
{{ $t('api_test.request.extract.multiple_matching') }}
|
||||
</el-checkbox>
|
||||
</el-col>
|
||||
<el-col class="extract-btn">
|
||||
<el-button :disabled="isReadOnly" type="danger" size="mini" icon="el-icon-delete" circle @click="remove"
|
||||
v-if="edit"/>
|
||||
|
@ -159,4 +164,10 @@
|
|||
.extract-btn {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.multiple_checkbox {
|
||||
text-align: center;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -49,43 +49,35 @@
|
|||
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="6">
|
||||
<el-form-item>
|
||||
<el-form-item :label="$t('api_test.request.refer_to_environment')">
|
||||
<el-switch
|
||||
v-model="request.useEnvironment"
|
||||
:active-text="$t('api_test.request.refer_to_environment')"
|
||||
@change="useEnvironmentChange">
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item>
|
||||
<el-switch
|
||||
v-model="request.reUseConnection"
|
||||
:active-text="$t('api_test.request.tcp.re_use_connection')">
|
||||
</el-switch>
|
||||
<el-form-item :label="$t('api_test.request.tcp.re_use_connection')">
|
||||
<el-checkbox v-model="request.reUseConnection"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item>
|
||||
<el-switch
|
||||
v-model="request.closeConnection"
|
||||
:active-text="$t('api_test.request.tcp.close_connection')">
|
||||
</el-switch>
|
||||
<el-form-item :label="$t('api_test.request.tcp.close_connection')">
|
||||
<el-checkbox v-model="request.closeConnection"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item>
|
||||
<el-switch
|
||||
v-model="request.nodelay"
|
||||
:active-text="$t('api_test.request.tcp.no_delay')">
|
||||
</el-switch>
|
||||
<el-form-item :label="$t('api_test.request.tcp.no_delay')">
|
||||
<el-checkbox v-model="request.nodelay"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item :label="$t('api_test.request.tcp.request')" prop="request">
|
||||
<el-input type="textarea" v-model="request.request" :autosize="{minRows: 4, maxRows: 6}">
|
||||
</el-input>
|
||||
<div class="send-request">
|
||||
<ms-code-edit mode="text" :read-only="isReadOnly" :data.sync="request.request"
|
||||
:modes="['text', 'json', 'xml', 'html']" theme="eclipse"/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-row :gutter="10">
|
||||
|
@ -128,10 +120,11 @@ import {Scenario, TCPConfig, TCPRequest} from "@/business/components/api/test/mo
|
|||
import MsApiAssertions from "@/business/components/api/test/components/assertion/ApiAssertions";
|
||||
import MsApiExtract from "@/business/components/api/test/components/extract/ApiExtract";
|
||||
import MsJsr233Processor from "@/business/components/api/test/components/processor/Jsr233Processor";
|
||||
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
|
||||
|
||||
export default {
|
||||
name: "MsApiTcpRequestForm",
|
||||
components: {MsJsr233Processor, MsApiExtract, MsApiAssertions},
|
||||
components: {MsCodeEdit, MsJsr233Processor, MsApiExtract, MsApiAssertions},
|
||||
props: {
|
||||
request: TCPRequest,
|
||||
scenario: Scenario,
|
||||
|
@ -144,15 +137,7 @@ export default {
|
|||
return {
|
||||
activeName: "assertions",
|
||||
classes: TCPConfig.CLASSES,
|
||||
rules: {
|
||||
server: [
|
||||
{
|
||||
required: true,
|
||||
message: this.$t('commons.required', [this.$t('api_test.request.tcp.server')]),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
}
|
||||
rules: {}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -175,4 +160,9 @@ export default {
|
|||
.tcp >>> .el-input-number {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.send-request {
|
||||
padding: 15px 0;
|
||||
height: 300px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -22,22 +22,25 @@
|
|||
</el-row>
|
||||
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="6">
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('api_test.request.tcp.connect')" prop="ctimeout">
|
||||
<el-input-number v-model="config.ctimeout" controls-position="right" :min="0" :step="1000" :controls="false"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('api_test.request.tcp.response')" prop="timeout">
|
||||
<el-input-number v-model="config.timeout" controls-position="right" :min="0" :step="1000" :controls="false"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('api_test.request.tcp.so_linger')" prop="soLinger">
|
||||
<el-input v-model="config.soLinger"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('api_test.request.tcp.eol_byte')" prop="eolByte">
|
||||
<el-input v-model="config.eolByte"/>
|
||||
</el-form-item>
|
||||
|
@ -46,27 +49,18 @@
|
|||
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="8">
|
||||
<el-form-item>
|
||||
<el-switch
|
||||
v-model="config.reUseConnection"
|
||||
:active-text="$t('api_test.request.tcp.re_use_connection')">
|
||||
</el-switch>
|
||||
<el-form-item :label="$t('api_test.request.tcp.re_use_connection')">
|
||||
<el-checkbox v-model="config.reUseConnection"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item>
|
||||
<el-switch
|
||||
v-model="config.closeConnection"
|
||||
:active-text="$t('api_test.request.tcp.close_connection')">
|
||||
</el-switch>
|
||||
<el-form-item :label="$t('api_test.request.tcp.close_connection')">
|
||||
<el-checkbox v-model="config.closeConnection"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item>
|
||||
<el-switch
|
||||
v-model="config.nodelay"
|
||||
:active-text="$t('api_test.request.tcp.no_delay')">
|
||||
</el-switch>
|
||||
<el-form-item :label="$t('api_test.request.tcp.no_delay')">
|
||||
<el-checkbox v-model="config.nodelay"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
|
|
@ -855,6 +855,7 @@ export class ExtractCommon extends ExtractType {
|
|||
this.value = ""; // ${variable}
|
||||
this.expression = undefined;
|
||||
this.description = undefined;
|
||||
this.multipleMatching = undefined;
|
||||
|
||||
this.set(options);
|
||||
}
|
||||
|
@ -1460,6 +1461,7 @@ class JMXGenerator {
|
|||
let props = {
|
||||
name: extractCommon.variable,
|
||||
expression: extractCommon.expression,
|
||||
match: extractCommon.multipleMatching ? -1 : undefined
|
||||
}
|
||||
let testName = props.name
|
||||
switch (extractCommon.type) {
|
||||
|
|
|
@ -252,6 +252,10 @@
|
|||
<el-table-column
|
||||
:label="$t('commons.operating')">
|
||||
<template v-slot:default="scope">
|
||||
<el-button @click="preview(scope.row)" :disabled="!scope.row.id || readOnly" type="primary"
|
||||
v-if="isPreview(scope.row)"
|
||||
icon="el-icon-view"
|
||||
size="mini" circle/>
|
||||
<el-button @click="handleDownload(scope.row)" :disabled="!scope.row.id || readOnly" type="primary"
|
||||
icon="el-icon-download"
|
||||
size="mini" circle/>
|
||||
|
@ -277,6 +281,7 @@
|
|||
|
||||
</el-dialog>
|
||||
|
||||
<test-case-file ref="testCaseFile"/>
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -289,10 +294,11 @@ import MsDialogFooter from '../../../common/components/MsDialogFooter'
|
|||
import {listenGoBack, removeGoBackListener} from "../../../../../common/js/utils";
|
||||
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
|
||||
import {Message} from "element-ui";
|
||||
import TestCaseFile from "@/business/components/track/case/components/TestCaseFile";
|
||||
|
||||
export default {
|
||||
name: "TestCaseEdit",
|
||||
components: {MsDialogFooter},
|
||||
components: {MsDialogFooter, TestCaseFile},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
|
@ -718,7 +724,13 @@ export default {
|
|||
/// todo: 是否需要对文件内容和大小做限制
|
||||
return file.size > 0;
|
||||
},
|
||||
|
||||
preview(row) {
|
||||
this.$refs.testCaseFile.open(row);
|
||||
},
|
||||
isPreview(row) {
|
||||
const fileType = row.type;
|
||||
return fileType === 'JPG' || fileType === 'JPEG' || fileType === 'PDF' || fileType === 'PNG';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
<template>
|
||||
<el-dialog :visible.sync="dialogVisible" width="80%" :destroy-on-close="true" :before-close="close">
|
||||
<div>
|
||||
<img :src="'/test/case/file/preview/' + file.id" alt="图片显示异常" style="width: 100%;height: 100%;"
|
||||
v-if="file.type === 'JPG' || file.type === 'JPEG' || file.type === 'PNG'">
|
||||
<div v-if="file.type === 'PDF'">
|
||||
<test-case-pdf :file-id="file.id"/>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import TestCasePdf from "@/business/components/track/case/components/TestCasePdf";
|
||||
|
||||
export default {
|
||||
name: "TestCaseFiles",
|
||||
components: {TestCasePdf},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
file: {
|
||||
id: '',
|
||||
type: ''
|
||||
},
|
||||
dialogVisible: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open(file) {
|
||||
this.file = file;
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
close() {
|
||||
this.file = {
|
||||
id: '',
|
||||
type: ''
|
||||
};
|
||||
this.dialogVisible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,38 @@
|
|||
<template>
|
||||
<div v-loading="loading">
|
||||
<pdf ref="pdf" v-for="i in numPages" :key="i" :src="loadingTask" :page="i"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pdf from "vue-pdf";
|
||||
export default {
|
||||
name: "TestCasePdf",
|
||||
components: {pdf},
|
||||
props: {
|
||||
fileId: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
numPages: null,
|
||||
loadingTask: null,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loading = true;
|
||||
this.loadingTask = pdf.createLoadingTask("/test/case/file/preview/" + this.fileId);
|
||||
this.loadingTask.promise.then(pdf => {
|
||||
this.numPages = pdf.numPages
|
||||
this.loading = false;
|
||||
}).catch(() => {
|
||||
this.loading = false;
|
||||
this.$error("pdf 加载失败");
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -1 +1 @@
|
|||
Subproject commit 06d935cd1d22ab36f09763745c2aff8ad3fb08c1
|
||||
Subproject commit cc38137a69a0f20fadece9c0f9f50a9468c4ace9
|
|
@ -554,6 +554,7 @@ export default {
|
|||
select_type: "Choose type",
|
||||
description: "Extract data from the response and store it in variables. Use the variables in subsequent requests.",
|
||||
regex: "Regex",
|
||||
multiple_matching: "Multiple matching",
|
||||
regex_expression: "Regular expression",
|
||||
json_path_expression: "JSONPath expression",
|
||||
xpath_expression: "XPath expression",
|
||||
|
|
|
@ -554,6 +554,7 @@ export default {
|
|||
},
|
||||
extract: {
|
||||
label: "提取",
|
||||
multiple_matching: "匹配多条",
|
||||
select_type: "请选择类型",
|
||||
description: "从响应结果中提取数据并将其存储在变量中,在后续请求中使用变量。",
|
||||
regex: "正则",
|
||||
|
|
|
@ -554,6 +554,7 @@ export default {
|
|||
},
|
||||
extract: {
|
||||
label: "提取",
|
||||
multiple_matching: "匹配多條",
|
||||
select_type: "請選擇類型",
|
||||
description: "從響應結果中提取數據並將其存儲在變量中,在後續請求中使用變量。",
|
||||
regex: "正則",
|
||||
|
|
Loading…
Reference in New Issue