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(), resolveRouteLocation: vi.fn() })) const global = { stubs: { AppDialog: { template: '
' }, ElButton: { template: '' }, ElLink: { template: '' }, LoadErrorState: { props: ['message'], template: '

{{ message }}

' }, ApiErrorMeta: true, ElSelect: { props: ['modelValue'], emits: ['update:modelValue'], template: '' }, ElOption: { props: ['label', 'value'], template: '' }, } } const endpoints = { origin: { kind: 'warehouse', label: '洛杉矶仓', warehouseId: '123' } as RouteLocation, destinations: [routeLocation('ABE3'), routeLocation('ONT8')] } const addresses: Record = { '洛杉矶仓': '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.findAll('button').find(button => button.text() === '重新加载地图')!.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() }) })