Files
admin-web/src/modules/overseas-master-data/components/TransportRouteDialog.test.ts
T

68 lines
4.9 KiB
TypeScript
Raw Normal View History

2026-10-09 17:36:32 +08:00
import { flushPromises, mount } from '@vue/test-utils'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import TransportRouteDialog from './TransportRouteDialog.vue'
import { resolveRouteLocation, routeLocation, RouteAddressError, type RouteLocation } from '../routeLocations'
vi.mock('../routeLocations', async importOriginal => ({ ...await importOriginal<object>(), resolveRouteLocation: vi.fn() }))
const global = { stubs: {
AppDialog: { template: '<div><slot /></div>' }, ElButton: { template: '<button><slot /></button>' }, ElLink: { template: '<a><slot /></a>' },
LoadErrorState: { props: ['message'], template: '<p role="alert">{{ message }}</p>' }, ApiErrorMeta: true,
ElSelect: { props: ['modelValue'], emits: ['update:modelValue'], template: '<select :value="modelValue" @change="$emit(\'update:modelValue\', Number($event.target.value))"><slot /></select>' },
ElOption: { props: ['label', 'value'], template: '<option :value="value">{{ label }}</option>' },
} }
const endpoints = { origin: { kind: 'warehouse', label: '洛杉矶仓', warehouseId: '123' } as RouteLocation, destinations: [routeLocation('ABE3'), routeLocation('ONT8')] }
const addresses: Record<string, string> = { '洛杉矶仓': '100 Example Street, Los Angeles, CA, US', ABE3: '200 Example Road, Example City, PA, 18000, US', ONT8: '300 Example Avenue, Ontario, CA, US' }
beforeEach(() => { vi.mocked(resolveRouteLocation).mockReset().mockImplementation(async location => location.kind === 'address' ? location.address : addresses[location.label]!) })
describe('transport route address resolution', () => {
it('does not query until opened and sends full addresses to both map URLs', async () => {
const wrapper = mount(TransportRouteDialog, { props: { ...endpoints, modelValue: false }, global })
expect(resolveRouteLocation).not.toHaveBeenCalled()
await wrapper.setProps({ modelValue: true }); await flushPromises()
const embedded = new URL(wrapper.get('iframe').attributes('src')!)
const external = new URL(wrapper.get('a').attributes('href')!)
expect(embedded.searchParams.get('saddr')).toBe(addresses['洛杉矶仓'])
expect(embedded.searchParams.get('daddr')).toBe(addresses.ABE3)
expect(external.searchParams.get('destination')).toBe(addresses.ABE3)
expect(wrapper.text()).toContain('目的地地址:' + addresses.ABE3)
expect(resolveRouteLocation).toHaveBeenCalledTimes(2)
const iframe = wrapper.get('iframe').element
await wrapper.get('button').trigger('click')
expect(wrapper.get('iframe').element).not.toBe(iframe)
expect(resolveRouteLocation).toHaveBeenCalledTimes(2)
await wrapper.setProps({ modelValue: false })
expect(wrapper.find('iframe').exists()).toBe(false)
wrapper.unmount()
})
it('resolves only the selected warehouse and reuses the origin for another destination', async () => {
const wrapper = mount(TransportRouteDialog, { props: { ...endpoints, modelValue: true }, global }); await flushPromises()
await wrapper.get('select').setValue('1'); await flushPromises()
expect(new URL(wrapper.get('iframe').attributes('src')!).searchParams.get('daddr')).toBe(addresses.ONT8)
expect(resolveRouteLocation).toHaveBeenCalledTimes(3)
wrapper.unmount()
})
it('never leaves the previous map visible while resolving a new destination, and ignores late results', async () => {
let finish!: (value: string) => void
vi.mocked(resolveRouteLocation).mockImplementation(location => location.label === 'ABE3' ? new Promise(resolve => { finish = resolve }) : Promise.resolve(addresses[location.label]!))
const wrapper = mount(TransportRouteDialog, { props: { ...endpoints, modelValue: true }, global })
expect(wrapper.find('iframe').exists()).toBe(false)
await wrapper.get('select').setValue('1'); await flushPromises()
finish('stale address'); await flushPromises()
expect(new URL(wrapper.get('iframe').attributes('src')!).searchParams.get('daddr')).toBe(addresses.ONT8)
await wrapper.setProps({ modelValue: false }); await flushPromises()
expect(wrapper.find('iframe').exists()).toBe(false)
wrapper.unmount()
})
it('shows missing address errors instead of falling back to a warehouse code', async () => {
vi.mocked(resolveRouteLocation).mockRejectedValue(new RouteAddressError('ABE3缺少完整仓库地址'))
const wrapper = mount(TransportRouteDialog, { props: { ...endpoints, modelValue: true }, global }); await flushPromises()
expect(wrapper.text()).toContain('ABE3缺少完整仓库地址')
expect(wrapper.find('iframe').exists()).toBe(false); expect(wrapper.find('a').exists()).toBe(false)
wrapper.unmount()
})
it('does not request missing endpoints', async () => {
const wrapper = mount(TransportRouteDialog, { props: { origin: routeLocation(''), destinations: [], modelValue: true }, global }); await flushPromises()
expect(resolveRouteLocation).not.toHaveBeenCalled()
expect(wrapper.text()).toContain('缺少起点或目的地')
wrapper.unmount()
})
})