Skip to content

Commit d108b0f

Browse files
authored
chore: improve the store manager ui (#518)
* chore: improve the store manager ui * improve the extension type selection * add more unit tests of ts --------- Co-authored-by: rick <[email protected]>
1 parent 6e0c70e commit d108b0f

File tree

10 files changed

+347
-64
lines changed

10 files changed

+347
-64
lines changed

console/atest-ui/src/App.vue

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,17 @@ import setAsDarkTheme from './theme'
2222
2323
const asDarkMode = ref(Cache.GetPreference().darkTheme)
2424
setAsDarkTheme(asDarkMode.value)
25-
watch(asDarkMode, Cache.WatchDarkTheme)
25+
watch(asDarkMode, Cache.WithDarkTheme)
2626
watch(asDarkMode, () => {
2727
setAsDarkTheme(asDarkMode.value)
2828
})
2929
3030
const appVersion = ref('')
3131
const appVersionLink = ref('https://github.com/LinuxSuRen/api-testing')
3232
API.GetVersion((d) => {
33-
appVersion.value = d.message
34-
const version = d.message.match('^v\\d*.\\d*.\\d*')
35-
const dirtyVersion = d.message.match('^v\\d*.\\d*.\\d*-\\d*-g')
33+
appVersion.value = d.version
34+
const version = d.version.match('^v\\d*.\\d*.\\d*')
35+
const dirtyVersion = d.version.match('^v\\d*.\\d*.\\d*-\\d*-g')
3636
3737
if (!version && !dirtyVersion) {
3838
return
@@ -65,8 +65,8 @@ const handleSelect = (key: string) => {
6565
const locale = ref(Cache.GetPreference().language)
6666
i18nLocale.value = locale.value
6767
68-
watch(locale, (value) =>{
69-
Cache.WatchLocale(value)
68+
watch(locale, (e) =>{
69+
Cache.WithLocale(e.value)
7070
i18nLocale.value = locale.value
7171
})
7272

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

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { FormInstance, FormRules } from 'element-plus'
66
import type { Pair } from './types'
77
import { API } from './net'
88
import { UIAPI } from './net-vue'
9-
import { SupportedExtensions } from './store'
9+
import { SupportedExtensions, SupportedExtension } from './store'
1010
import { useI18n } from 'vue-i18n'
1111
import { Magic } from './magicKeys'
1212
@@ -99,10 +99,6 @@ function setStoreForm(store: Store) {
9999
storeForm.disabled = store.disabled
100100
storeForm.readonly = store.readonly
101101
storeForm.properties = store.properties
102-
storeForm.properties.push({
103-
key: '',
104-
value: ''
105-
})
106102
}
107103
108104
function addStore() {
@@ -130,6 +126,40 @@ const submitForm = async (formEl: FormInstance | undefined) => {
130126
})
131127
}
132128
129+
watch(() => storeForm.kind.name, (name) => {
130+
const ext = SupportedExtension(name)
131+
if (ext) {
132+
let pro = storeForm.properties.slice()
133+
134+
for (var i = 0; i < pro.length;) {
135+
// remove it if the value or key is empty
136+
if (pro[i].key === '' || pro[i].value === '') {
137+
pro.splice(i, 1)
138+
} else {
139+
i++
140+
}
141+
}
142+
143+
// add extension related params
144+
ext.params.forEach(p => {
145+
const index = pro.findIndex(e => e.key === p.key)
146+
if (index === -1) {
147+
pro.push({
148+
key: p.key,
149+
value: '',
150+
defaultValue: p.defaultValue
151+
} as Pair)
152+
}
153+
})
154+
155+
// make sure there is always a empty pair for letting users input
156+
pro.push({
157+
key: '',
158+
value: ''
159+
} as Pair)
160+
storeForm.properties = pro
161+
}
162+
})
133163
watch(storeForm, (e) => {
134164
if (e.kind.name === '') {
135165
if (e.url.startsWith('https://github.com') || e.url.startsWith('https://gitee.com')) {
@@ -157,12 +187,11 @@ function storeVerify(formEl: FormInstance | undefined) {
157187
158188
function updateKeys() {
159189
const props = storeForm.properties
160-
let lastItem = props[props.length - 1]
161-
if (lastItem.key !== '') {
190+
if (props.findIndex(p => p.key === '') === -1) {
162191
storeForm.properties.push({
163192
key: '',
164193
value: ''
165-
})
194+
} as Pair)
166195
}
167196
}
168197
</script>
@@ -246,13 +275,12 @@ function updateKeys() {
246275
v-model="storeForm.kind.name"
247276
test-id="store-form-plugin-name"
248277
class="m-2"
249-
size="middle"
250278
>
251279
<el-option
252280
v-for="item in SupportedExtensions()"
253-
:key="item.value"
254-
:label="item.key"
255-
:value="item.value"
281+
:key="item.name"
282+
:label="item.name"
283+
:value="item.name"
256284
/>
257285
</el-select>
258286
</el-form-item>
@@ -272,7 +300,7 @@ function updateKeys() {
272300
<el-table-column label="Value">
273301
<template #default="scope">
274302
<div style="display: flex; align-items: center">
275-
<el-input v-model="scope.row.value" placeholder="Value" />
303+
<el-input v-model="scope.row.value" :placeholder="scope.row.defaultValue" />
276304
</div>
277305
</template>
278306
</el-table-column>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const emit = defineEmits(['updated'])
2626
2727
let querySuggestedAPIs = NewSuggestedAPIsQuery(Cache.GetCurrentStore().name!, props.suite!)
2828
const testResultActiveTab = ref(Cache.GetPreference().responseActiveTab)
29-
watch(testResultActiveTab, Cache.WatchResponseActiveTab)
29+
watch(testResultActiveTab, Cache.WithResponseActiveTab)
3030
Magic.Keys(() => {
3131
testResultActiveTab.value = 'output'
3232
}, ['Alt+KeyO'])
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/*
2+
Copyright 2024 API Testing Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import { describe } from 'node:test'
18+
import {Cache, SetPreference, TestCaseResponse, Store, Stores} from '../cache'
19+
20+
const localStorageMock = (() => {
21+
let store = {};
22+
23+
return {
24+
getItem(key) {
25+
return store[key] || null;
26+
},
27+
setItem(key, value) {
28+
store[key] = value.toString();
29+
},
30+
removeItem(key) {
31+
delete store[key];
32+
},
33+
clear() {
34+
store = {};
35+
}
36+
};
37+
})();
38+
39+
Object.defineProperty(global, 'sessionStorage', {
40+
value: localStorageMock
41+
});
42+
Object.defineProperty(global, 'localStorage', {
43+
value: localStorageMock
44+
});
45+
Object.defineProperty(global, 'navigator', {
46+
value: {
47+
language: 'en'
48+
}
49+
});
50+
51+
describe('TestCaseResponseCache', () => {
52+
test('should set and get test case response cache', () => {
53+
const id = 'test-case-id'
54+
const resp = {
55+
output: 'test-body',
56+
body: {},
57+
statusCode: 200,
58+
} as TestCaseResponse
59+
Cache.SetTestCaseResponseCache(id, resp)
60+
const result = Cache.GetTestCaseResponseCache(id)
61+
expect(result).toEqual(resp)
62+
})
63+
64+
test('get a non-existent test case response cache', () => {
65+
expect(Cache.GetTestCaseResponseCache('non-existent-id')).toEqual({})
66+
})
67+
})
68+
69+
describe('LastTestCaseLocation', () => {
70+
test('should get empty object when no last test case location', () => {
71+
expect(Cache.GetLastTestCaseLocation()).toEqual({})
72+
})
73+
74+
test('should set and get last test case location', () => {
75+
const suite = 'test-suite'
76+
const testcase = 'test-case'
77+
Cache.SetLastTestCaseLocation(suite, testcase)
78+
const result = Cache.GetLastTestCaseLocation()
79+
expect(result).toEqual({ suite, testcase })
80+
})
81+
})
82+
83+
describe('Preference', () => {
84+
test('get the default preference', () => {
85+
expect(Cache.GetPreference()).toEqual({
86+
darkTheme: false,
87+
requestActiveTab: 'body',
88+
responseActiveTab: 'body',
89+
language: 'en',
90+
})
91+
})
92+
93+
test('set and get preference', () => {
94+
const preference = {
95+
darkTheme: true,
96+
requestActiveTab: 'header',
97+
responseActiveTab: 'header',
98+
language: 'zh-cn',
99+
}
100+
SetPreference(preference)
101+
expect(Cache.GetPreference()).toEqual(preference)
102+
})
103+
104+
test('set and get dark theme', () => {
105+
Cache.WithDarkTheme(true)
106+
expect(Cache.GetPreference().darkTheme).toEqual(true)
107+
})
108+
109+
test('set and get request active tab', () => {
110+
Cache.WithRequestActiveTab('request')
111+
expect(Cache.GetPreference().requestActiveTab).toEqual('request')
112+
})
113+
114+
test('set and get response active tab', () => {
115+
Cache.WithResponseActiveTab('response')
116+
expect(Cache.GetPreference().responseActiveTab).toEqual('response')
117+
})
118+
119+
it('set and get language', () => {
120+
Cache.WithLocale('zh-cn')
121+
expect(Cache.GetPreference().language).toEqual('zh-cn')
122+
})
123+
})
124+
125+
describe('stores', () => {
126+
test('should get empty object when no stores', () => {
127+
expect(Cache.GetCurrentStore()).toEqual({})
128+
})
129+
130+
test('should set and get stores', () => {
131+
const stores = {
132+
current: 'test-store',
133+
items: [
134+
{
135+
name: 'test-store',
136+
readOnly: false,
137+
} as Store,
138+
{
139+
name: 'read-only-store',
140+
readOnly: true,
141+
} as Store,
142+
],
143+
}
144+
Cache.SetStores(stores)
145+
expect(Cache.GetCurrentStore()).toEqual({
146+
name: 'test-store',
147+
readOnly: false,
148+
})
149+
150+
Cache.SetCurrentStore('read-only-store')
151+
expect(Cache.GetCurrentStore()).toEqual({
152+
name: 'read-only-store',
153+
readOnly: true,
154+
})
155+
156+
Cache.SetStores({} as Stores)
157+
})
158+
})
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
Copyright 2024 API Testing Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import { describe } from "node:test";
18+
import {SupportedExtension, SupportedExtensions} from "../store";
19+
20+
describe("SupportedExtensions", () => {
21+
test('length check', () => {
22+
const extensions = SupportedExtensions()
23+
expect(extensions.length).toBe(5)
24+
})
25+
26+
for (const extension of SupportedExtensions()) {
27+
test(`${extension.name} check`, () => {
28+
expect(SupportedExtension(extension.name)).not.toBeUndefined()
29+
})
30+
}
31+
})

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

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
1+
/*
2+
Copyright 2023-2024 API Testing Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
117
import { describe } from 'node:test'
218
import { NewSuggestedAPIsQuery, CreateFilter, GetHTTPMethods, FlattenObject } from '../types'
319
import type { Pair } from '../types'
420

521
const fakeFetch: { [key:string]:string; } = {};
6-
function matchFake(url: string, data: string) {
7-
fakeFetch[url] = data
8-
}
922

1023
global.fetch = jest.fn((key: string) =>
1124
Promise.resolve({

0 commit comments

Comments
 (0)