42 lines
3.6 KiB
TypeScript
42 lines
3.6 KiB
TypeScript
import { defineComponent, h } from 'vue'
|
|
import { flushPromises, mount } from '@vue/test-utils'
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import OwnerPicker from './OwnerPicker.vue'
|
|
import type { QueryContext } from '../types'
|
|
|
|
const owners = vi.hoisted(() => vi.fn())
|
|
vi.mock('../api/analytics', () => ({ analyticsApi: { owners } }))
|
|
const context: QueryContext = { salesRunId: '11', inventoryRunId: '12', salesScopeHash: 'sales', inventoryScopeHash: 'stock', queryAsOf: '2026-10-12T01:00:00Z', queryExpiresAt: '2026-10-12T01:30:00Z', businessTimezone: 'Asia/Shanghai', anchorDate: '2026-10-12' }
|
|
const select = defineComponent({ props: ['remoteMethod'], setup(props, { slots }) { return () => h('div', [h('button', { onClick: () => props.remoteMethod('Ab_') }, '前缀搜索'), slots.default?.()]) } })
|
|
const button = defineComponent({ props: ['disabled'], emits: ['click'], setup(props, { slots, emit }) { return () => h('button', { disabled: props.disabled, onClick: () => emit('click') }, slots.default?.()) } })
|
|
const option = defineComponent({ props: ['label'], setup(props) { return () => h('span', props.label) } })
|
|
const global = { stubs: { 'el-select': select, 'el-button': button, 'el-option': option } }
|
|
const wrappers: ReturnType<typeof mount>[] = []
|
|
beforeEach(() => { owners.mockReset(); owners.mockResolvedValue({ context, records: [{ customerCode: 'OWNER-A', customerName: '货主甲' }], total: 25 }) })
|
|
afterEach(() => wrappers.splice(0).forEach(wrapper => wrapper.unmount()))
|
|
describe('fixed-context owner selector', () => {
|
|
it('uses backend pagination and prefix search without changing the pinned context', async () => {
|
|
const wrapper = mount(OwnerPicker, { props: { modelValue: '', sourceAccount: 'lingxing-primary', warehouseCode: 'WH-A', context }, global }); wrappers.push(wrapper)
|
|
await flushPromises()
|
|
await wrapper.findAll('button').find(node => node.text() === '下一页货主')!.trigger('click'); await flushPromises()
|
|
expect(owners.mock.calls.at(-1)?.[0]).toMatchObject({ current: 2, size: 20, salesRunId: '11', inventoryRunId: '12', queryAsOf: context.queryAsOf })
|
|
await wrapper.findAll('button').find(node => node.text() === '前缀搜索')!.trigger('click'); await flushPromises()
|
|
expect(owners.mock.calls.at(-1)?.[0]).toMatchObject({ keyword: 'Ab_', current: 1, queryAsOf: context.queryAsOf })
|
|
expect(wrapper.text()).toContain('OWNER-A · 货主甲')
|
|
})
|
|
it('ignores late options from the old warehouse and rejects mixed-version choices', async () => {
|
|
let resolve!: (value: object) => void
|
|
owners.mockImplementationOnce(() => new Promise(done => { resolve = done })).mockResolvedValue({ context, records: [{ customerCode: 'OWNER-B', customerName: null }], total: 1 })
|
|
const wrapper = mount(OwnerPicker, { props: { modelValue: '', sourceAccount: 'lingxing-primary', warehouseCode: 'WH-A', context }, global }); wrappers.push(wrapper)
|
|
await wrapper.setProps({ warehouseCode: 'WH-B' }); await flushPromises()
|
|
resolve({ context, records: [{ customerCode: 'OLD-OWNER', customerName: null }], total: 1 }); await flushPromises()
|
|
expect(wrapper.text()).toContain('OWNER-B')
|
|
expect(wrapper.text()).not.toContain('OLD-OWNER')
|
|
expect(owners.mock.calls[0]?.[1].aborted).toBe(true)
|
|
owners.mockResolvedValue({ context: { ...context, inventoryRunId: '99' }, records: [{ customerCode: 'WRONG-VERSION' }], total: 1 })
|
|
await wrapper.findAll('button').find(node => node.text() === '前缀搜索')!.trigger('click'); await flushPromises()
|
|
expect(wrapper.text()).not.toContain('WRONG-VERSION')
|
|
expect(wrapper.text()).toContain('货主选项版本已变化')
|
|
})
|
|
})
|