import ElementPlus from 'element-plus' import { readFileSync } from 'node:fs' import { resolve } from 'node:path' import { flushPromises, mount } from '@vue/test-utils' import { beforeEach, describe, expect, it, vi } from 'vitest' import { listOutbounds } from '../api/outbounds' import OutboundsView from './OutboundsView.vue' const canPermission = vi.hoisted(() => vi.fn((_code: string) => true)) const routerPush = vi.hoisted(() => vi.fn()) vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: canPermission }) })) vi.mock('vue-router', () => ({ useRouter: () => ({ push: routerPush }) })) vi.mock('../api/outbounds', () => ({ listOutbounds: vi.fn(), cancelOutbound: vi.fn(), createOneClickDropshipOutbound: vi.fn() })) vi.mock('../api/inventory', () => ({ listInventoryBalances: vi.fn(), listInventoryPositions: vi.fn() })) class ResizeObserverStub { observe() {} unobserve() {} disconnect() {} } describe('OutboundsView permissions and navigation', () => { beforeEach(() => { vi.stubGlobal('ResizeObserver', ResizeObserverStub) vi.stubGlobal('localStorage', { getItem: () => null, setItem: () => undefined, removeItem: () => undefined }) vi.mocked(listOutbounds).mockReset().mockResolvedValue({ records: [{ id: '1', outboundNo: 'OUT-1', dispatchNo: 'PC-1', status: 'PICKED', palletCount: 1, packageCount: 2 }], page: 1, size: 20, total: 1, pages: 1 }) canPermission.mockReset().mockReturnValue(true) routerPush.mockReset() }) it('uses list access for detail and independent create/cancel permissions', async () => { canPermission.mockImplementation((code: string) => code.endsWith(':list')) const wrapper = mount(OutboundsView, { global: { plugins: [ElementPlus] } }) await flushPromises() expect(wrapper.text()).toContain('详情') expect(wrapper.text()).not.toContain('一件代发出库') expect(wrapper.text()).not.toContain('取消') expect(OutboundsView.__file).toContain('OutboundsView.vue') wrapper.unmount() }) it('shows one-click creation and cancellation only with their exact permissions', async () => { canPermission.mockImplementation((code: string) => ['platform:overseas-warehouse:outbound:create', 'platform:overseas-warehouse:outbound:cancel'].includes(code)) const wrapper = mount(OutboundsView, { global: { plugins: [ElementPlus] } }) await flushPromises() expect(wrapper.text()).toContain('一件代发出库') expect(wrapper.text()).toContain('取消') wrapper.unmount() }) it('requires an explicit customer selection before choosing customer inventory', async () => { const source = readFileSync(resolve(process.cwd(), 'src/modules/overseas-warehouse/pages/OutboundsView.vue'), 'utf8') expect(source).toContain('v-model="selectedCustomerId"') expect(source).toContain('availablePositionOptions') expect(source).toContain('createOneClickDropshipOutbound(selectedCustomerId.value') }) })