Skip to content

Commit 834a28f

Browse files
authored
feat: support embed file upload (#538)
1 parent 344ed1b commit 834a28f

File tree

7 files changed

+88
-22
lines changed

7 files changed

+88
-22
lines changed

console/atest-ui/src/views/StoreManager.vue

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script setup lang="ts">
22
import { ElMessage } from 'element-plus'
33
import { reactive, ref, watch } from 'vue'
4-
import { Edit, Delete } from '@element-plus/icons-vue'
4+
import { Edit, Delete, QuestionFilled } from '@element-plus/icons-vue'
55
import type { FormInstance, FormRules } from 'element-plus'
66
import type { Pair } from './types'
77
import { API } from './net'
@@ -24,7 +24,8 @@ const emptyStore = function() {
2424
},
2525
properties: [{
2626
key: '',
27-
value: ''
27+
value: '',
28+
description: '',
2829
}],
2930
disabled: false,
3031
readonly: false
@@ -147,8 +148,11 @@ watch(() => storeForm.kind.name, (name) => {
147148
pro.push({
148149
key: p.key,
149150
value: '',
150-
defaultValue: p.defaultValue
151+
defaultValue: p.defaultValue,
152+
description: p.description,
151153
} as Pair)
154+
} else {
155+
pro[index].description = p.description
152156
}
153157
})
154158
@@ -205,20 +209,27 @@ function updateKeys() {
205209
<el-table :data="stores" style="width: 100%" v-loading=storesLoading>
206210
<el-table-column :label="t('field.name')" width="180">
207211
<template #default="scope">
208-
<el-input v-model="scope.row.name" placeholder="Name"/>
212+
{{ scope.row.name }}
209213
</template>
210214
</el-table-column>
211215
<el-table-column label="URL">
212216
<template #default="scope">
213217
<div style="display: flex; align-items: center">
214-
<el-input v-model="scope.row.url" placeholder="URL" />
218+
{{ scope.row.url }}
215219
</div>
216220
</template>
217221
</el-table-column>
218222
<el-table-column :label="t('field.plugin')">
219223
<template #default="scope">
220224
<div style="display: flex; align-items: center">
221-
<el-input v-model="scope.row.kind.url" placeholder="Plugin" />
225+
{{ scope.row.kind.name }}
226+
</div>
227+
</template>
228+
</el-table-column>
229+
<el-table-column label="Socket">
230+
<template #default="scope">
231+
<div style="display: flex; align-items: center">
232+
{{ scope.row.kind.url }}
222233
</div>
223234
</template>
224235
</el-table-column>
@@ -299,9 +310,17 @@ function updateKeys() {
299310
</el-table-column>
300311
<el-table-column label="Value">
301312
<template #default="scope">
302-
<div style="display: flex; align-items: center">
303-
<el-input v-model="scope.row.value" :placeholder="scope.row.defaultValue" />
304-
</div>
313+
<div style="display: flex; align-items: center">
314+
<el-input v-model="scope.row.value" :placeholder="scope.row.defaultValue">
315+
<template #append v-if="scope.row.description">
316+
<el-tooltip :content="scope.row.description">
317+
<el-icon>
318+
<QuestionFilled/>
319+
</el-icon>
320+
</el-tooltip>
321+
</template>
322+
</el-input>
323+
</div>
305324
</template>
306325
</el-table-column>
307326
</el-table>

console/atest-ui/src/views/TestCase.vue

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { ref, watch, reactive } from 'vue'
33
import { ElMessage } from 'element-plus'
44
import { Edit, Delete, Search, CopyDocument } from '@element-plus/icons-vue'
55
import JsonViewer from 'vue-json-viewer'
6-
import type { Pair, TestResult, TestCaseWithSuite } from './types'
6+
import type { Pair, TestResult, TestCaseWithSuite, TestCase } from './types'
77
import { NewSuggestedAPIsQuery, CreateFilter, GetHTTPMethods, FlattenObject } from './types'
88
import { Cache } from './cache'
99
import { API } from './net'
@@ -241,7 +241,8 @@ const emptyTestCaseWithSuite: TestCaseWithSuite = {
241241
query: [],
242242
cookie: [],
243243
form: [],
244-
body: ''
244+
body: '',
245+
filepath: ''
245246
},
246247
response: {
247248
statusCode: 0,
@@ -324,7 +325,7 @@ function formatDate(createTimeStr : string){
324325
return formattedDate
325326
}
326327
327-
function determineBodyType(e) {
328+
function determineBodyType(e: TestCase) {
328329
e.request.header.forEach(item => {
329330
if (item.key === "Content-Type") {
330331
switch (item.value) {
@@ -334,6 +335,15 @@ function determineBodyType(e) {
334335
case 'application/json':
335336
bodyType.value = 5
336337
break
338+
case 'multipart/form-data':
339+
bodyType.value = 6
340+
341+
e.request.form.forEach(fItem => {
342+
if (fItem.key !== '' && fItem.key !== '') {
343+
e.request.filepath = fItem.key + "=" + fItem.value
344+
}
345+
})
346+
break
337347
}
338348
}
339349
});
@@ -721,6 +731,17 @@ function bodyTypeChange(e: number) {
721731
case 5:
722732
contentType = 'application/json'
723733
break;
734+
case 6:
735+
contentType = 'multipart/form-data'
736+
737+
const items = testCaseWithSuite.value.data.request.filepath.split("=")
738+
if (items && items.length > 1) {
739+
testCaseWithSuite.value.data.request.form = [{
740+
key: items[0],
741+
value: items[1]
742+
} as Pair]
743+
}
744+
break;
724745
}
725746
726747
if (contentType !== "") {
@@ -732,7 +753,7 @@ function bodyTypeChange(e: number) {
732753
}
733754
734755
const lintingError = ref('')
735-
function jsonFormat(space) {
756+
function jsonFormat(space: number) {
736757
const jsonText = testCaseWithSuite.value.data.request.body
737758
if (bodyType.value !== 5 || jsonText === '') {
738759
return
@@ -987,10 +1008,14 @@ Magic.Keys(() => {
9871008
<el-radio :label="3">raw</el-radio>
9881009
<el-radio :label="4">x-www-form-urlencoded</el-radio>
9891010
<el-radio :label="5">JSON</el-radio>
1011+
<el-radio :label="6">EmbedFile</el-radio>
9901012
</el-radio-group>
9911013

9921014
<div style="flex-grow: 1;">
993-
<Codemirror v-if="bodyType === 3 || bodyType === 5"
1015+
<div v-if="bodyType === 6">
1016+
Filename: <el-input v-model="testCaseWithSuite.data.request.filepath" placeholder="file=sample.txt" />
1017+
</div>
1018+
<Codemirror v-if="bodyType === 3 || bodyType === 5 || bodyType === 6"
9941019
@blur="jsonFormat(-1)"
9951020
v-model="testCaseWithSuite.data.request.body"
9961021
:disabled="isHistoryTestCase"/>

console/atest-ui/src/views/store.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@ const storeExtensions = [
3232
}, {
3333
key: 'branch'
3434
}, {
35-
key: 'email'
35+
key: 'email',
36+
description: 'See also: git config --local user.email [email protected]'
3637
}, {
37-
key: 'name'
38+
key: 'name',
39+
description: 'See also: git config --local user.name xxx'
3840
}]
3941
},
4042
{
@@ -59,10 +61,15 @@ const storeExtensions = [
5961
name: 'atest-store-orm',
6062
params: [{
6163
key: 'driver',
62-
defaultValue: 'mysql'
64+
defaultValue: 'mysql',
65+
description: 'Supported: mysql, postgres'
6366
}, {
6467
key: 'database',
6568
defaultValue: 'atest'
69+
}, {
70+
key: 'historyLimit',
71+
defaultValue: '',
72+
description: 'Set the limit of the history record count'
6673
}]
6774
},
6875
{

console/atest-ui/src/views/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export interface Pair {
4545
key: string
4646
value: string
4747
defaultValue: string
48+
description: string
4849
}
4950

5051
export interface TestCaseWithSuite {
@@ -62,9 +63,11 @@ export interface TestCaseRequest {
6263
api: string
6364
method: string
6465
header: Pair[]
66+
cookie: Pair[]
6567
query: Pair[]
6668
form: Pair[]
6769
body: string
70+
filepath: string
6871
}
6972

7073
export interface TestCaseResponse {

pkg/runner/http.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,9 @@ func (r *simpleTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataConte
176176
Value: v,
177177
})
178178
}
179-
r.log.Info("start to send request to %s\n", testcase.Request.API)
179+
r.log.Info("request method: %s\n", request.Method)
180+
r.log.Info("request header %v\n", request.Header)
181+
r.log.Info("start to send request to %v\n", request.URL)
180182

181183
// TODO only do this for unit testing, should remove it once we have a better way
182184
if strings.HasPrefix(testcase.Request.API, "http://") {
@@ -189,7 +191,7 @@ func (r *simpleTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataConte
189191
return
190192
}
191193

192-
r.log.Debug("test case %q, test case info: %v, status code: %d\n", testcase.Name, testcase, resp.StatusCode)
194+
r.log.Debug("test case %q, status code: %d\n", testcase.Name, resp.StatusCode)
193195

194196
if err = testcase.Expect.Render(dataContext); err != nil {
195197
return
@@ -223,7 +225,7 @@ func (r *simpleTestCaseRunner) RunTestCase(testcase *testing.TestCase, dataConte
223225

224226
err = errors.Join(err, jsonSchemaValidation(testcase.Expect.Schema, responseBodyData))
225227
} else {
226-
r.log.Trace(fmt.Sprintf("skip to read the body due to it is not struct content: %q\n", respType))
228+
r.log.Debug("skip to read the body due to it is not struct content: %q\n", respType)
227229
}
228230

229231
r.cookies = append(r.cookies, resp.Cookies()...)

pkg/server/remote_server_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,10 @@ func TestRunTestCase(t *testing.T) {
148148
})
149149
assert.NoError(t, err)
150150
assert.Equal(t, sampleBody, result.Body)
151-
assert.Contains(t, result.Output, "start to run: 'get'\nstart to send request to http://foo\ntest case \"get\", test case info: &{ get <nil> <nil> {http://foo GET map[] map[key:value] map[] map[] } {0 map[] map[] [] [] }}, status code: 200\n")
151+
assert.Contains(t, result.Output, "request method: GET")
152+
assert.Contains(t, result.Output, "request header")
153+
assert.Contains(t, result.Output, "start to send request to http://foo")
154+
assert.Contains(t, result.Output, "test case \"get\", status code: 200")
152155
})
153156

154157
t.Run("text response", func(t *testing.T) {

pkg/testing/parser.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,14 @@ func (r *Request) GetBody() (reader io.Reader, err error) {
187187
writer.WriteField(key, val)
188188
}
189189

190-
_ = writer.Close()
190+
if f, ok := r.Form["file"]; ok && f != "" && r.Body.Value != "" {
191+
var part io.Writer
192+
if part, err = writer.CreateFormFile("file", r.Form["file"]); err == nil {
193+
part.Write([]byte(r.Body.Value))
194+
}
195+
}
196+
197+
err = writer.Close()
191198
reader = multiBody
192199
r.Header[util.ContentType] = writer.FormDataContentType()
193200
} else if r.Header[util.ContentType] == util.Form {

0 commit comments

Comments
 (0)