优化
This commit is contained in:
@@ -0,0 +1,317 @@
|
||||
import ElementPlus from 'element-plus'
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { enableAutoUnmount, flushPromises, mount, type VueWrapper } from '@vue/test-utils'
|
||||
import { afterAll, afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||||
import { useAuthStore } from '@/core/auth/auth'
|
||||
import { listPlatformTenants as listPlatformCustomers, type PlatformTenantResource as PlatformCustomerResource } from '@/modules/iam'
|
||||
import { listPlatformWarehouses, type PlatformWarehouseResource } from '@/modules/warehouses'
|
||||
import DataTable from '@/shared/components/DataTable.vue'
|
||||
import QueryToolbar from '@/shared/components/QueryToolbar.vue'
|
||||
import {
|
||||
createPlatformPallet,
|
||||
getPlatformPallet,
|
||||
listPlatformPallets,
|
||||
type PlatformPalletResource,
|
||||
} from '../api/platformPallets'
|
||||
import PalletsView from './PalletsView.vue'
|
||||
|
||||
vi.mock('@/modules/iam', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('@/modules/iam')>()
|
||||
const listPlatformTenants = vi.fn<typeof actual.listPlatformTenants>()
|
||||
return { ...actual, listPlatformTenants }
|
||||
})
|
||||
vi.mock('@/modules/warehouses', () => ({ listPlatformWarehouses: vi.fn() }))
|
||||
vi.mock('../api/platformPallets', () => ({
|
||||
listPlatformPallets: vi.fn(),
|
||||
getPlatformPallet: vi.fn(),
|
||||
createPlatformPallet: vi.fn(),
|
||||
updatePlatformPallet: vi.fn(),
|
||||
deletePlatformPallet: vi.fn(),
|
||||
}))
|
||||
|
||||
class ResizeObserverStub implements ResizeObserver {
|
||||
observe() {}
|
||||
unobserve() {}
|
||||
disconnect() {}
|
||||
}
|
||||
|
||||
function createMemoryStorage(): Storage {
|
||||
const values = new Map<string, string>()
|
||||
return {
|
||||
get length() { return values.size },
|
||||
clear: () => values.clear(),
|
||||
getItem: (key) => values.get(key) ?? null,
|
||||
key: (index) => [...values.keys()][index] ?? null,
|
||||
removeItem: (key) => values.delete(key),
|
||||
setItem: (key, value) => values.set(key, value),
|
||||
}
|
||||
}
|
||||
|
||||
const customer = (id: number | string, tenantName: string): PlatformCustomerResource => ({
|
||||
id, tenantCode: String(id), tenantName, status: 'ACTIVE', legalName: tenantName,
|
||||
legalRepresentative: null, unifiedSocialCreditCode: null, contactName: null,
|
||||
contactPhone: null, contactEmail: null, servicePackage: null, contactWechat: null,
|
||||
salesOwnerName: null, paymentTermDays: null, enterpriseType: null, establishedDate: null,
|
||||
registeredCapital: null, registeredCapitalCurrency: null, registeredAddress: null,
|
||||
internalRemark: null, createdAt: null, approvedAt: null,
|
||||
})
|
||||
|
||||
const warehouse: PlatformWarehouseResource = {
|
||||
id: '19001', tenantId: 10001, warehouseCode: 'CN-YW-01', warehouseName: '义乌收货仓',
|
||||
warehouseType: 'DOMESTIC', countryCode: 'CN', timezone: 'Asia/Shanghai', contactName: null,
|
||||
contactPhone: null, contactEmail: null, status: 'ACTIVE', remark: null,
|
||||
}
|
||||
|
||||
const pallet: PlatformPalletResource = {
|
||||
id: '20001', tenantId: 10001, warehouseId: '19001', palletCode: 'TP-001', palletType: '木托盘',
|
||||
capacityCbm: '1.200000', remark: '标准川字托盘', createdAt: '2026-08-04T09:00:00', updatedAt: '2026-08-04T10:00:00',
|
||||
}
|
||||
|
||||
async function mountView(permissions = [
|
||||
'platform:pallet:list', 'platform:pallet:create', 'platform:pallet:edit', 'platform:pallet:delete',
|
||||
]) {
|
||||
vi.stubGlobal('localStorage', createMemoryStorage())
|
||||
vi.stubGlobal('sessionStorage', createMemoryStorage())
|
||||
const pinia = createPinia()
|
||||
setActivePinia(pinia)
|
||||
const auth = useAuthStore()
|
||||
auth.token = 'token'
|
||||
auth.permissions = permissions
|
||||
useAccessPreviewStore().initializeAfterLogin()
|
||||
const wrapper = mount(PalletsView, { attachTo: document.body, global: { plugins: [pinia, ElementPlus] } })
|
||||
await flushPromises()
|
||||
return wrapper
|
||||
}
|
||||
|
||||
async function setFilterContext(wrapper: VueWrapper, customerId = '10001', warehouseId = '') {
|
||||
wrapper.findComponent(QueryToolbar).vm.$emit('update:modelValue', {
|
||||
customerId,
|
||||
warehouseId: '',
|
||||
palletCode: '',
|
||||
palletType: '',
|
||||
})
|
||||
await flushPromises()
|
||||
if (!warehouseId) return
|
||||
wrapper.findComponent(QueryToolbar).vm.$emit('update:modelValue', {
|
||||
customerId,
|
||||
warehouseId,
|
||||
palletCode: '',
|
||||
palletType: '',
|
||||
})
|
||||
await flushPromises()
|
||||
}
|
||||
|
||||
async function loadRows(wrapper: VueWrapper, warehouseId = '') {
|
||||
await setFilterContext(wrapper, '10001', warehouseId)
|
||||
wrapper.findComponent(QueryToolbar).vm.$emit('search', {
|
||||
customerId: '10001',
|
||||
warehouseId,
|
||||
palletCode: '',
|
||||
palletType: '',
|
||||
})
|
||||
await flushPromises()
|
||||
}
|
||||
|
||||
enableAutoUnmount(afterEach)
|
||||
afterAll(() => vi.unstubAllGlobals())
|
||||
|
||||
describe('PalletsView', () => {
|
||||
beforeEach(() => {
|
||||
vi.stubGlobal('ResizeObserver', ResizeObserverStub)
|
||||
document.body.innerHTML = ''
|
||||
vi.mocked(listPlatformCustomers).mockReset().mockResolvedValue({
|
||||
records: [customer(10001, '默认企业'), customer('9223372036854775806', '雪花企业')], page: 1, size: 200, total: 2, pages: 1,
|
||||
})
|
||||
vi.mocked(listPlatformWarehouses).mockReset().mockResolvedValue({ records: [warehouse], page: 1, size: 200, total: 1, pages: 1 })
|
||||
vi.mocked(listPlatformPallets).mockReset().mockResolvedValue({ records: [pallet], page: 1, size: 20, total: 1, pages: 1 })
|
||||
vi.mocked(getPlatformPallet).mockReset().mockResolvedValue(pallet)
|
||||
vi.mocked(createPlatformPallet).mockReset().mockResolvedValue('20002')
|
||||
})
|
||||
|
||||
it('starts with all customers and uses compact semantic filter widths', async () => {
|
||||
const wrapper = await mountView()
|
||||
const toolbar = wrapper.findComponent(QueryToolbar)
|
||||
const fields = toolbar.props('fields')
|
||||
|
||||
expect(toolbar.props('modelValue')).toMatchObject({ customerId: '', warehouseId: '' })
|
||||
expect(fields.map((field) => [field.key, field.width])).toEqual([
|
||||
['customerId', 260],
|
||||
['warehouseId', 240],
|
||||
['palletCode', 240],
|
||||
['palletType', 180],
|
||||
])
|
||||
expect(wrapper.find('.pallet-filter-toolbar').exists()).toBe(true)
|
||||
expect(fields.find((field) => field.key === 'customerId')?.placeholder).toBe('全部客户')
|
||||
expect(listPlatformWarehouses).not.toHaveBeenCalled()
|
||||
expect(listPlatformPallets).toHaveBeenCalledWith({
|
||||
page: 1, size: 20,
|
||||
})
|
||||
})
|
||||
|
||||
it('loads warehouses after customer selection and omits an empty warehouse id when searching', async () => {
|
||||
const wrapper = await mountView()
|
||||
await loadRows(wrapper)
|
||||
|
||||
expect(listPlatformWarehouses).toHaveBeenCalledWith(10001, 1, 200)
|
||||
expect(listPlatformPallets).toHaveBeenCalledWith({
|
||||
page: 1, size: 20, tenantId: 10001,
|
||||
})
|
||||
expect(wrapper.text()).toContain('TP-001')
|
||||
expect(wrapper.text()).toContain('木托盘')
|
||||
expect(wrapper.text()).toContain('1.2 m³')
|
||||
expect(wrapper.text()).toContain('义乌收货仓')
|
||||
expect(wrapper.text()).toContain('托盘列表')
|
||||
expect(wrapper.text()).not.toContain('启停托盘')
|
||||
expect(wrapper.text()).not.toContain('全部状态')
|
||||
expect(wrapper.text()).toContain('全部托盘类型')
|
||||
expect(wrapper.find('input[aria-label="所属企业"]').exists()).toBe(true)
|
||||
expect(wrapper.find('input[aria-label="所属仓库"]').exists()).toBe(true)
|
||||
expect(wrapper.find('.platform-tenant-selector').exists()).toBe(false)
|
||||
expect(wrapper.text()).not.toContain('租户')
|
||||
expect(wrapper.find('.data-table').exists()).toBe(true)
|
||||
expect(wrapper.find('.table-actions.pallet-row-actions').exists()).toBe(true)
|
||||
expect(wrapper.findAll('thead th').map((item) => item.text().trim())[0]).toBe('操作')
|
||||
})
|
||||
|
||||
it('queries all customers explicitly without adding a customer id', async () => {
|
||||
vi.mocked(listPlatformPallets).mockResolvedValue({ records: [pallet], page: 1, size: 20, total: 41, pages: 3 })
|
||||
const wrapper = await mountView()
|
||||
const toolbar = wrapper.findComponent(QueryToolbar)
|
||||
|
||||
toolbar.vm.$emit('search', { customerId: '', warehouseId: '', palletCode: '', palletType: '' })
|
||||
await flushPromises()
|
||||
expect(listPlatformPallets).toHaveBeenLastCalledWith({
|
||||
page: 1, size: 20,
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
it('resets customer and dependent warehouse filters without sending an empty id', async () => {
|
||||
const wrapper = await mountView()
|
||||
await setFilterContext(wrapper, '10001', '19001')
|
||||
const toolbar = wrapper.findComponent(QueryToolbar)
|
||||
|
||||
toolbar.vm.reset()
|
||||
await flushPromises()
|
||||
|
||||
expect(toolbar.props('modelValue')).toMatchObject({ customerId: '', warehouseId: '' })
|
||||
expect(listPlatformPallets).toHaveBeenCalledTimes(2)
|
||||
expect(listPlatformPallets).toHaveBeenLastCalledWith({
|
||||
page: 1, size: 20,
|
||||
})
|
||||
expect(toolbar.props('fields').find((field) => field.key === 'customerId')?.placeholder).toBe('全部客户')
|
||||
})
|
||||
|
||||
it('preserves a snowflake customer id when switching the enterprise filter', async () => {
|
||||
const wrapper = await mountView()
|
||||
const snowflakeId = '9223372036854775806'
|
||||
|
||||
wrapper.findComponent(QueryToolbar).vm.$emit('update:modelValue', {
|
||||
customerId: snowflakeId,
|
||||
warehouseId: '',
|
||||
palletCode: '',
|
||||
palletType: '',
|
||||
})
|
||||
await flushPromises()
|
||||
|
||||
expect(listPlatformWarehouses).toHaveBeenLastCalledWith(snowflakeId, 1, 200)
|
||||
})
|
||||
|
||||
it('applies pallet filters only after search', async () => {
|
||||
const wrapper = await mountView()
|
||||
await setFilterContext(wrapper, '10001', '19001')
|
||||
await wrapper.find('input[placeholder="托盘编码(模糊查询)"]').setValue('TP-00')
|
||||
expect(listPlatformPallets).toHaveBeenCalledTimes(1)
|
||||
|
||||
wrapper.findComponent(QueryToolbar).vm.$emit('search', {
|
||||
customerId: '10001', warehouseId: '19001', palletCode: 'TP-00', palletType: '木托盘',
|
||||
})
|
||||
await flushPromises()
|
||||
|
||||
expect(listPlatformPallets).toHaveBeenLastCalledWith({
|
||||
page: 1, size: 20, tenantId: 10001, warehouseId: 19001, palletCode: 'TP-00', palletType: '木托盘',
|
||||
})
|
||||
})
|
||||
|
||||
it('creates a pallet in the selected warehouse with the real request fields', async () => {
|
||||
const wrapper = await mountView()
|
||||
await setFilterContext(wrapper, '10001', '19001')
|
||||
const createButton = wrapper.findAll('button').find((button) => button.text().trim() === '新增托盘')
|
||||
await createButton?.trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
await wrapper.find('input[placeholder="例如 TP-001"]').setValue('TP-002')
|
||||
const palletTypeItem = wrapper.findAll('.el-form-item').find((item) => item.text().includes('托盘类型'))
|
||||
palletTypeItem?.findComponent({ name: 'ElSelect' }).vm.$emit('update:modelValue', '塑料托盘')
|
||||
const capacity = wrapper.findComponent({ name: 'ElInputNumber' })
|
||||
capacity.vm.$emit('update:modelValue', 1.5)
|
||||
await wrapper.find('textarea[placeholder="可填写规格、材质或现场识别说明"]').setValue('蓝色标准托盘')
|
||||
const saveButton = wrapper.findAll('button').find((button) => button.text().trim() === '保存托盘')
|
||||
await saveButton?.trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(createPlatformPallet).toHaveBeenCalledWith(10001, {
|
||||
warehouseId: 19001, palletCode: 'TP-002', palletType: '塑料托盘', capacityCbm: 1.5, remark: '蓝色标准托盘',
|
||||
})
|
||||
})
|
||||
|
||||
it('hides all write actions without write permissions', async () => {
|
||||
const wrapper = await mountView(['platform:pallet:list'])
|
||||
|
||||
expect(wrapper.find('.panel-heading button').exists()).toBe(false)
|
||||
const actions = wrapper.find('.pallet-row-actions').text()
|
||||
expect(actions).not.toContain('编辑')
|
||||
expect(actions).not.toContain('删除')
|
||||
expect(actions).toContain('查看')
|
||||
})
|
||||
|
||||
it('shows a recoverable list failure instead of demo data', async () => {
|
||||
vi.mocked(listPlatformPallets).mockRejectedValueOnce(new Error('Gateway unavailable'))
|
||||
const wrapper = await mountView()
|
||||
|
||||
expect(wrapper.text()).toContain('托盘列表暂时无法加载')
|
||||
expect(wrapper.text()).toContain('Gateway unavailable')
|
||||
expect(wrapper.text()).toContain('重新加载')
|
||||
expect(wrapper.text()).not.toContain('TP-001')
|
||||
})
|
||||
|
||||
it('stops dependent requests when the enterprise filter cannot load', async () => {
|
||||
vi.mocked(listPlatformCustomers).mockRejectedValueOnce(new Error('Gateway unavailable'))
|
||||
const wrapper = await mountView()
|
||||
|
||||
expect(wrapper.text()).toContain('所属企业列表暂时无法加载')
|
||||
expect(wrapper.text()).toContain('重新加载')
|
||||
expect(listPlatformWarehouses).not.toHaveBeenCalled()
|
||||
expect(listPlatformPallets).toHaveBeenCalledWith({
|
||||
page: 1, size: 20,
|
||||
})
|
||||
})
|
||||
|
||||
it('shows only the pallet fields exposed by the backend contract', async () => {
|
||||
const crossCustomerPallet = { ...pallet, tenantId: '9223372036854775806' }
|
||||
vi.mocked(listPlatformPallets).mockResolvedValue({ records: [crossCustomerPallet], page: 1, size: 20, total: 1, pages: 1 })
|
||||
vi.mocked(getPlatformPallet).mockResolvedValue(crossCustomerPallet)
|
||||
const wrapper = await mountView()
|
||||
await loadRows(wrapper)
|
||||
expect(wrapper.findComponent(DataTable).props('data')).toEqual([crossCustomerPallet])
|
||||
const tableBody = wrapper.find('.el-table__body-wrapper')
|
||||
const viewButton = tableBody.findAll('.pallet-row-actions button').find((button) => button.text().trim() === '查看')
|
||||
await viewButton?.trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(getPlatformPallet).toHaveBeenCalledWith('9223372036854775806', 19001, '20001')
|
||||
expect(document.body.textContent).toContain('所属企业')
|
||||
expect(document.body.textContent).toContain('雪花企业(9223372036854775806)')
|
||||
expect(document.body.textContent).toContain('托盘编码')
|
||||
expect(document.body.textContent).toContain('托盘类型')
|
||||
expect(document.body.textContent).toContain('托盘容积')
|
||||
expect(document.body.textContent).toContain('归属信息')
|
||||
expect(document.body.textContent).toContain('托盘规格')
|
||||
expect(document.body.textContent).toContain('记录信息')
|
||||
expect(document.body.textContent).not.toContain('企业 ID')
|
||||
expect(document.body.textContent).not.toContain('租户')
|
||||
expect(document.body.textContent).not.toContain('托盘状态')
|
||||
expect(document.body.textContent).not.toContain('最大承重')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user