fix(drivers): refresh cached list and summary when returning from details
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { flushPromises, shallowMount, type VueWrapper } from '@vue/test-utils'
|
||||
import { defineComponent, h, KeepAlive, ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ApiResponseError } from '@/shared/api/http'
|
||||
import * as api from '../api/drivers'
|
||||
@@ -44,6 +45,47 @@ beforeEach(() => {
|
||||
afterEach(() => { wrappers.splice(0).forEach(wrapper => wrapper.unmount()); vi.unstubAllGlobals() })
|
||||
|
||||
describe('driver page workflows', () => {
|
||||
it('refreshes a cached list once on return and retains applied filters and pagination', async () => {
|
||||
const showingList = ref(true)
|
||||
const host = defineComponent({ setup: () => () => h(KeepAlive, null, { default: () => showingList.value ? h(DriversView) : h('div', '司机详情') }) })
|
||||
const wrapper = shallowMount(host, { global: { stubs: { ...stubs, KeepAlive: false, DriversView: false }, directives: { loading: () => undefined } } })
|
||||
wrappers.push(wrapper)
|
||||
await flushPromises()
|
||||
expect(api.listDrivers).toHaveBeenCalledTimes(1)
|
||||
const list = wrapper.findComponent(DriversView)
|
||||
const toolbar = list.findComponent({ name: 'QueryToolbar' })
|
||||
toolbar.vm.$emit('update:modelValue', { keyword: 'DR-TEST', licenseState: 'EXPIRING' })
|
||||
toolbar.vm.$emit('search'); await flushPromises()
|
||||
list.findComponent({ name: 'DataTable' }).vm.$emit('update:page', 2); await flushPromises()
|
||||
expect(api.listDrivers).toHaveBeenCalledTimes(3)
|
||||
showingList.value = false; await flushPromises()
|
||||
const refreshed = { ...structuredClone(driver), recordVersion: 3, reviewStatus: 'APPROVED' as const }
|
||||
vi.mocked(api.listDrivers).mockResolvedValueOnce({ records: [refreshed], page: 2, size: 20, total: 1, pages: 1, summary: { total: 1, owned: 1, dispatched: 0, expiringSoon: 1, expired: 0 } })
|
||||
showingList.value = true; await flushPromises()
|
||||
expect(api.listDrivers).toHaveBeenCalledTimes(4)
|
||||
expect(api.listDrivers).toHaveBeenLastCalledWith({ keyword: 'DR-TEST', licenseState: 'EXPIRING', region: undefined, ownership: undefined, active: undefined, reviewStatus: undefined, page: 2, size: 20 })
|
||||
expect(wrapper.findComponent({ name: 'DataTable' }).props('data')).toEqual([refreshed])
|
||||
expect(wrapper.text()).toContain('司机总数1')
|
||||
expect(api.getDriver).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('ignores a list response that arrives while its cached page is deactivated', async () => {
|
||||
let resolveList!: (value: Awaited<ReturnType<typeof api.listDrivers>>) => void
|
||||
vi.mocked(api.listDrivers).mockReturnValueOnce(new Promise(resolve => { resolveList = resolve }))
|
||||
const showingList = ref(true)
|
||||
const host = defineComponent({ setup: () => () => h(KeepAlive, null, { default: () => showingList.value ? h(DriversView) : h('div', '司机详情') }) })
|
||||
const wrapper = shallowMount(host, { global: { stubs: { ...stubs, KeepAlive: false, DriversView: false }, directives: { loading: () => undefined } } })
|
||||
wrappers.push(wrapper)
|
||||
await flushPromises()
|
||||
const list = wrapper.findComponent(DriversView)
|
||||
showingList.value = false; await flushPromises()
|
||||
resolveList({ records: [driver], page: 1, size: 20, total: 24, pages: 2, summary: { total: 24, owned: 20, dispatched: 4, expiringSoon: 3, expired: 1 } }); await flushPromises()
|
||||
expect(list.findComponent({ name: 'DataTable' }).props('data')).toEqual([])
|
||||
showingList.value = true; await flushPromises()
|
||||
expect(api.listDrivers).toHaveBeenCalledTimes(2)
|
||||
expect(wrapper.findComponent({ name: 'DataTable' }).props('data')).toEqual([driver])
|
||||
})
|
||||
|
||||
it('loads one paged request with server summary and does not request each driver or file', async () => {
|
||||
const wrapper = mount(DriversView)
|
||||
await flushPromises()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import '@/styles/adminDensity.css'
|
||||
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
import { onActivated, onBeforeUnmount, onDeactivated, onMounted, ref, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus } from '@lucide/vue'
|
||||
@@ -26,6 +26,7 @@ const rows = ref<DriverDetail[]>([]), total = ref(0), page = ref(1), pageSize =
|
||||
const error = ref<ApiErrorDetails | null>(null), summary = ref<DriverSummary | null>(null)
|
||||
const filters = ref<QueryModel>({ keyword: '', region: '', ownership: '', active: '', reviewStatus: '', licenseState: '' })
|
||||
let applied: Omit<DriverQuery, 'page' | 'size'> = {}, request = 0
|
||||
let refreshOnReturn = false
|
||||
const editorOpen = ref(false), editing = ref<DriverDetail | null>(null), actionId = ref('')
|
||||
const previewOpen = ref(false), preview = ref<DriverDetail | null>(null)
|
||||
const fields: QueryField[] = [
|
||||
@@ -101,6 +102,10 @@ function saved(row: DriverDetail) {
|
||||
watch(editorOpen, (value, previous) => { if (!value && previous) void load() })
|
||||
watch([page, pageSize], () => void load())
|
||||
onMounted(load)
|
||||
onDeactivated(() => { request++; refreshOnReturn = true })
|
||||
onActivated(() => {
|
||||
if (refreshOnReturn) { refreshOnReturn = false; void load() }
|
||||
})
|
||||
onBeforeUnmount(() => { request++ })
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user