优化
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
import { effectScope, ref } from 'vue'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { useActiveCustomerOptions } from './useActiveCustomerOptions'
|
||||
import type { PlatformTenantPage, PlatformTenantQuery, PlatformTenantResource } from './api/platformIam'
|
||||
|
||||
const scopes: ReturnType<typeof effectScope>[] = []
|
||||
afterEach(() => { scopes.splice(0).forEach(scope => scope.stop()) })
|
||||
function customer(id: string, tenantName = `客户${id}`, status = 'ACTIVE') {
|
||||
return { id, tenantName, status } as PlatformTenantResource
|
||||
}
|
||||
function page(records: PlatformTenantResource[], current = 1, pages = 1): PlatformTenantPage {
|
||||
return { records, page: current, size: 50, pages, total: pages * 50 }
|
||||
}
|
||||
function deferred<T>() {
|
||||
let resolve!: (value: T) => void
|
||||
let reject!: (cause: Error) => void
|
||||
const promise = new Promise<T>((yes, no) => { resolve = yes; reject = no })
|
||||
return { promise, resolve, reject }
|
||||
}
|
||||
function setup() {
|
||||
const selectedId = ref<string | null>(null)
|
||||
const load = vi.fn<(query: PlatformTenantQuery) => Promise<PlatformTenantPage>>()
|
||||
const scope = effectScope(); scopes.push(scope)
|
||||
const options = scope.run(() => useActiveCustomerOptions(() => selectedId.value, load))!
|
||||
return { ...options, load, selectedId, scope }
|
||||
}
|
||||
|
||||
describe('active customer remote options', () => {
|
||||
it('searches the complete customer directory by keyword instead of filtering the first page', async () => {
|
||||
const view = setup()
|
||||
view.load.mockResolvedValueOnce(page([customer('1', '跨客户车次-测试客户')], 1, 10))
|
||||
.mockResolvedValueOnce(page([customer('9007199254740999', '柏悦物流')]))
|
||||
await view.search()
|
||||
await view.search(' 柏悦 ')
|
||||
expect(view.load.mock.calls.map(([query]) => query)).toEqual([
|
||||
{ page: 1, size: 50, status: 'ACTIVE' },
|
||||
{ page: 1, size: 50, status: 'ACTIVE', keyword: '柏悦' },
|
||||
])
|
||||
expect(view.customers.value.map(row => row.tenantName)).toEqual(['柏悦物流'])
|
||||
expect(view.customers.value[0]!.id).toBe('9007199254740999')
|
||||
})
|
||||
|
||||
it('continues beyond 200 customers, deduplicates pages, and stops at the final page', async () => {
|
||||
const view = setup()
|
||||
view.load.mockImplementation(async query => page([customer('shared'), customer(String(query.page))], query.page, 5))
|
||||
await view.search('物流')
|
||||
for (let index = 0; index < 6; index++) await view.endReached('bottom')
|
||||
expect(view.load.mock.calls.map(([query]) => query.page)).toEqual([1, 2, 3, 4, 5])
|
||||
expect(view.load.mock.calls.every(([query]) => query.keyword === '物流')).toBe(true)
|
||||
expect(view.customers.value.map(row => row.id)).toEqual(['shared', '1', '2', '3', '4', '5'])
|
||||
})
|
||||
|
||||
it('ignores late pages and errors from an earlier keyword', async () => {
|
||||
const view = setup(), old = deferred<PlatformTenantPage>(), latest = deferred<PlatformTenantPage>()
|
||||
view.load.mockResolvedValueOnce(page([customer('1')], 1, 2)).mockReturnValueOnce(old.promise).mockReturnValueOnce(latest.promise)
|
||||
await view.search('旧')
|
||||
const oldRequest = view.endReached('bottom')
|
||||
const current = view.search('柏悦')
|
||||
old.reject(new Error('旧查询失败')); await oldRequest
|
||||
expect(view.loading.value).toBe(true); expect(view.error.value).toBeNull()
|
||||
latest.resolve(page([customer('2', '柏悦物流')])); await current
|
||||
expect(view.customers.value.map(row => row.tenantName)).toEqual(['柏悦物流'])
|
||||
expect(view.loading.value).toBe(false)
|
||||
})
|
||||
|
||||
it('does not let a late successful search overwrite a newer result', async () => {
|
||||
const view = setup(), old = deferred<PlatformTenantPage>()
|
||||
view.load.mockReturnValueOnce(old.promise).mockResolvedValueOnce(page([customer('2', '柏悦物流')]))
|
||||
const first = view.search('旧'); await view.search('柏悦')
|
||||
old.resolve(page([customer('1', '旧客户')])); await first
|
||||
expect(view.customers.value.map(row => row.tenantName)).toEqual(['柏悦物流'])
|
||||
})
|
||||
|
||||
it('retains selection and loaded pages after an append failure and retries that page once', async () => {
|
||||
const view = setup(), next = deferred<PlatformTenantPage>()
|
||||
view.load.mockResolvedValueOnce(page([customer('1', '已选客户')], 1, 2)).mockReturnValueOnce(next.promise)
|
||||
.mockResolvedValueOnce(page([customer('2')], 2, 2))
|
||||
await view.search(); view.selectedId.value = '1'
|
||||
const pending = view.endReached('bottom'); await view.endReached('bottom')
|
||||
expect(view.load).toHaveBeenCalledTimes(2)
|
||||
next.reject(new Error('客户目录暂不可用')); await pending
|
||||
expect(view.error.value?.message).toContain('客户选项加载失败')
|
||||
expect(view.customers.value.map(row => row.id)).toEqual(['1'])
|
||||
await view.endReached('bottom'); expect(view.load).toHaveBeenCalledTimes(2)
|
||||
await view.retry()
|
||||
expect(view.load.mock.calls.map(([query]) => query.page)).toEqual([1, 2, 2])
|
||||
expect(view.selectedId.value).toBe('1'); expect(view.error.value).toBeNull()
|
||||
expect(view.customers.value.map(row => row.id)).toEqual(['1', '2'])
|
||||
})
|
||||
|
||||
it('keeps the selected label across searches and clears it when selection is cleared', async () => {
|
||||
const view = setup()
|
||||
view.load.mockResolvedValueOnce(page([customer('1', '柏悦物流')])).mockResolvedValueOnce(page([customer('2')]))
|
||||
await view.search('柏悦'); view.selectedId.value = '1'; await view.search('其他')
|
||||
expect(view.customers.value[0]!.tenantName).toBe('柏悦物流')
|
||||
view.selectedId.value = null
|
||||
expect(view.customers.value.map(row => row.id)).toEqual(['2'])
|
||||
})
|
||||
|
||||
it('shows initial errors, retries the same keyword, and excludes inactive customers', async () => {
|
||||
const view = setup()
|
||||
view.load.mockRejectedValueOnce(new Error('加载失败')).mockResolvedValueOnce(page([customer('1'), customer('2', '停用客户', 'DISABLED')]))
|
||||
await view.search('客户'); expect(view.error.value).not.toBeNull()
|
||||
await view.retry()
|
||||
expect(view.load.mock.calls[1]![0]).toEqual({ page: 1, size: 50, status: 'ACTIVE', keyword: '客户' })
|
||||
expect(view.customers.value.map(row => row.id)).toEqual(['1'])
|
||||
})
|
||||
|
||||
it('ignores disposal and non-bottom scroll events', async () => {
|
||||
const view = setup(), pending = deferred<PlatformTenantPage>()
|
||||
view.load.mockReturnValueOnce(pending.promise)
|
||||
await view.endReached('top'); expect(view.load).not.toHaveBeenCalled()
|
||||
const request = view.search('柏悦'); view.scope.stop()
|
||||
pending.resolve(page([customer('1')])); await request
|
||||
expect(view.customers.value).toEqual([])
|
||||
await view.search('其他'); await view.retry(); expect(view.load).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user