From b681a5b45e4863ae87b5896488580fa143db1d1e Mon Sep 17 00:00:00 2001 From: Hanabi <317387557+Hanabi9248@users.noreply.github.com> Date: Tue, 22 Sep 2026 15:43:15 +0800 Subject: [PATCH 1/2] fix: keep the latest instance search results --- src/components/SearchBox/index.vue | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/components/SearchBox/index.vue b/src/components/SearchBox/index.vue index dfcb030..a7200d9 100644 --- a/src/components/SearchBox/index.vue +++ b/src/components/SearchBox/index.vue @@ -46,6 +46,7 @@ export default { filter: '' }, resultList: [], + requestId: 0, isTimerContinue: false } }, @@ -79,6 +80,7 @@ export default { }, btnSearch() { const _this = this + const requestId = ++this.requestId _this.searchForm.clusterId = _this.cluster.id _this.searchForm.filter = _this.keyword this.axios.get('/instances/1/1000', { @@ -87,17 +89,20 @@ export default { filter: _this.searchForm.filter } }).then((response) => { + if (requestId !== this.requestId) return _this.listLoading = false _this.list = response.data.data _this.isTimerContinue = false this.$emit('resultList', _this.list, _this.isTimerContinue) // console.log(_this.isTimerContinue) }).catch((error) => { + if (requestId !== this.requestId) return this.$message.error(error) }) }, btnReset() { const _this = this + const requestId = ++this.requestId _this.cluster.id = '' _this.cluster.name = '' _this.keyword = '' @@ -108,12 +113,14 @@ export default { } this.axios.get('/instances/list/' + userId, {}) .then((response) => { + if (requestId !== this.requestId) return _this.listLoading = false _this.list = response.data _this.isTimerContinue = true this.$emit('resultList', _this.list, _this.isTimerContinue) // console.log(_this.isTimerContinue) }).catch((error) => { + if (requestId !== this.requestId) return this.$message.error(error) }) }, From 6e9dfbae8832d86e8f51c1123589c7eb22bdcbaf Mon Sep 17 00:00:00 2001 From: Hanabi <317387557+Hanabi9248@users.noreply.github.com> Date: Tue, 22 Sep 2026 15:44:18 +0800 Subject: [PATCH 2/2] test: cover out-of-order instance searches and resets --- tests/unit/components/SearchBox.spec.js | 56 +++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 tests/unit/components/SearchBox.spec.js diff --git a/tests/unit/components/SearchBox.spec.js b/tests/unit/components/SearchBox.spec.js new file mode 100644 index 0000000..b926a28 --- /dev/null +++ b/tests/unit/components/SearchBox.spec.js @@ -0,0 +1,56 @@ +import { shallowMount } from '@vue/test-utils' +import SearchBox from '@/components/SearchBox/index' + +const flush = () => new Promise(resolve => setImmediate(resolve)) + +describe('SearchBox request ordering', () => { + let wrapper + let requests + let reportError + + beforeEach(() => { + requests = [] + reportError = jest.fn() + wrapper = shallowMount(SearchBox, { + stubs: ['el-row', 'el-select', 'el-option', 'el-input', 'el-button'], + mocks: { + axios: { + get: url => url === '/clusters' + ? Promise.resolve({ data: [] }) + : new Promise((resolve, reject) => requests.push({ resolve, reject })) + }, + $message: { error: reportError } + } + }) + }) + + afterEach(() => wrapper.destroy()) + + it.each([ + ['btnSearch', 'btnSearch'], + ['btnSearch', 'btnReset'], + ['btnReset', 'btnSearch'] + ])('keeps the latest result for %s followed by %s', async(first, second) => { + wrapper.vm[first]() + wrapper.vm[second]() + const latest = [{ id: 'latest' }] + requests[1].resolve({ data: second === 'btnSearch' ? { data: latest } : latest }) + await flush() + const stale = [{ id: 'stale' }] + requests[0].resolve({ data: first === 'btnSearch' ? { data: stale } : stale }) + await flush() + expect(wrapper.emitted('resultList')).toEqual([[latest, second === 'btnReset']]) + }) + + it('ignores an old error but reports the current request error', async() => { + wrapper.vm.btnSearch() + wrapper.vm.btnReset() + requests[0].reject(new Error('old request')) + await flush() + expect(reportError).not.toHaveBeenCalled() + const currentError = new Error('current request') + requests[1].reject(currentError) + await flush() + expect(reportError).toHaveBeenCalledWith(currentError) + }) +})