2026-08-12 12:19:02 +08:00
|
|
|
|
import ElementPlus from 'element-plus'
|
|
|
|
|
|
import { flushPromises, mount } from '@vue/test-utils'
|
|
|
|
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
|
|
import { listPlatformTenants, type PlatformTenantResource } from '../api/platformIam'
|
|
|
|
|
|
import PlatformTenantSelector from './PlatformTenantSelector.vue'
|
|
|
|
|
|
|
|
|
|
|
|
vi.mock('../api/platformIam', () => ({ listPlatformTenants: vi.fn() }))
|
|
|
|
|
|
|
|
|
|
|
|
const customer = {
|
|
|
|
|
|
id: '190000000000000008',
|
|
|
|
|
|
tenantCode: 'CUS-008',
|
|
|
|
|
|
tenantName: '柏悦物流',
|
|
|
|
|
|
status: 'ACTIVE',
|
|
|
|
|
|
} as PlatformTenantResource
|
|
|
|
|
|
|
|
|
|
|
|
function mountSelector(props: { modelValue?: string; label?: string } = {}) {
|
|
|
|
|
|
return mount(PlatformTenantSelector, {
|
|
|
|
|
|
props: { modelValue: props.modelValue ?? '', ...(props.label ? { label: props.label } : {}) },
|
|
|
|
|
|
global: { plugins: [ElementPlus] },
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
describe('PlatformTenantSelector customer labels', () => {
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
|
vi.clearAllMocks()
|
|
|
|
|
|
vi.mocked(listPlatformTenants).mockResolvedValue({ records: [customer], page: 1, size: 200, total: 1, pages: 1 })
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
it('shows business identity and status without exposing the internal id', async () => {
|
|
|
|
|
|
const wrapper = mountSelector({ modelValue: String(customer.id) })
|
|
|
|
|
|
await flushPromises()
|
|
|
|
|
|
|
2026-08-14 12:50:42 +08:00
|
|
|
|
expect(listPlatformTenants).toHaveBeenCalledWith({ page: 1, size: 200, status: 'ACTIVE' })
|
2026-08-12 12:19:02 +08:00
|
|
|
|
expect(wrapper.text()).toContain('目标客户')
|
2026-08-14 12:50:42 +08:00
|
|
|
|
expect(document.body.textContent).toContain('柏悦物流 · 启用')
|
|
|
|
|
|
expect(document.body.textContent).not.toContain('CUS-008')
|
2026-08-12 12:19:02 +08:00
|
|
|
|
expect(document.body.textContent).not.toContain(String(customer.id))
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
it('keeps the internal id only as the emitted contract value', async () => {
|
|
|
|
|
|
const wrapper = mountSelector()
|
|
|
|
|
|
await flushPromises()
|
|
|
|
|
|
|
|
|
|
|
|
expect(wrapper.emitted('update:modelValue')).toEqual([[String(customer.id)]])
|
|
|
|
|
|
expect(wrapper.text()).not.toContain(String(customer.id))
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2026-08-26 11:10:48 +08:00
|
|
|
|
it('selects the first active customer without preferring a fixed customer id', async () => {
|
|
|
|
|
|
vi.mocked(listPlatformTenants).mockResolvedValue({
|
|
|
|
|
|
records: [
|
|
|
|
|
|
{ ...customer, id: '9', tenantName: '停用客户', status: 'DISABLED' },
|
|
|
|
|
|
{ ...customer, id: '20002', tenantName: '首个客户' },
|
|
|
|
|
|
{ ...customer, id: '10001', tenantName: '后续客户' },
|
|
|
|
|
|
],
|
|
|
|
|
|
page: 1, size: 200, total: 3, pages: 1,
|
|
|
|
|
|
})
|
|
|
|
|
|
const wrapper = mountSelector()
|
|
|
|
|
|
await flushPromises()
|
|
|
|
|
|
|
|
|
|
|
|
expect(wrapper.emitted('update:modelValue')).toEqual([['20002']])
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
it('preserves an explicitly selected customer', async () => {
|
|
|
|
|
|
const wrapper = mountSelector({ modelValue: String(customer.id) })
|
|
|
|
|
|
await flushPromises()
|
|
|
|
|
|
|
|
|
|
|
|
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2026-08-14 12:50:42 +08:00
|
|
|
|
it('keeps non-active customers out of the selectable options', async () => {
|
|
|
|
|
|
vi.mocked(listPlatformTenants).mockResolvedValue({
|
|
|
|
|
|
records: [customer, { ...customer, id: '9', tenantName: '停用客户', status: 'DISABLED' }],
|
|
|
|
|
|
page: 1, size: 200, total: 2, pages: 1,
|
|
|
|
|
|
})
|
|
|
|
|
|
mountSelector({ modelValue: String(customer.id) })
|
|
|
|
|
|
await flushPromises()
|
|
|
|
|
|
|
|
|
|
|
|
expect(document.body.textContent).toContain('柏悦物流 · 启用')
|
|
|
|
|
|
expect(document.body.textContent).not.toContain('停用客户')
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2026-08-12 12:19:02 +08:00
|
|
|
|
it('safely degrades labels when customer name or code is missing', async () => {
|
|
|
|
|
|
vi.mocked(listPlatformTenants).mockResolvedValue({
|
|
|
|
|
|
records: [
|
2026-08-14 12:50:42 +08:00
|
|
|
|
{ ...customer, id: '1', tenantName: '', tenantCode: 'CUS-001', status: 'ACTIVE' },
|
|
|
|
|
|
{ ...customer, id: '2', tenantName: '远航供应链', tenantCode: '', status: 'ACTIVE' },
|
|
|
|
|
|
{ ...customer, id: '3', tenantName: '', tenantCode: '', status: 'ACTIVE' },
|
2026-08-12 12:19:02 +08:00
|
|
|
|
],
|
|
|
|
|
|
page: 1, size: 200, total: 3, pages: 1,
|
|
|
|
|
|
})
|
|
|
|
|
|
mountSelector({ modelValue: '1' })
|
|
|
|
|
|
await flushPromises()
|
|
|
|
|
|
|
2026-08-14 12:50:42 +08:00
|
|
|
|
expect(document.body.textContent).toContain('未命名客户 · 启用')
|
|
|
|
|
|
expect(document.body.textContent).toContain('远航供应链 · 启用')
|
|
|
|
|
|
expect(document.body.textContent).not.toContain('CUS-001')
|
2026-08-12 12:19:02 +08:00
|
|
|
|
expect(document.body.textContent).not.toMatch(/[((][123] ·/)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
it('uses a custom business label for both visible and accessible names', async () => {
|
|
|
|
|
|
const wrapper = mountSelector({ modelValue: String(customer.id), label: '客户企业' })
|
|
|
|
|
|
await flushPromises()
|
|
|
|
|
|
|
|
|
|
|
|
expect(wrapper.text()).toContain('客户企业')
|
|
|
|
|
|
expect(wrapper.get('[aria-label="客户企业"]').attributes('aria-label')).toBe('客户企业')
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
it('shows an actionable customer-list error and retries', async () => {
|
|
|
|
|
|
vi.mocked(listPlatformTenants)
|
|
|
|
|
|
.mockRejectedValueOnce('unavailable')
|
|
|
|
|
|
.mockResolvedValueOnce({ records: [customer], page: 1, size: 200, total: 1, pages: 1 })
|
|
|
|
|
|
const wrapper = mountSelector()
|
|
|
|
|
|
await flushPromises()
|
|
|
|
|
|
|
|
|
|
|
|
expect(wrapper.get('[role="alert"]').text()).toContain('客户列表加载失败,请重试')
|
|
|
|
|
|
await wrapper.get('[role="alert"] button').trigger('click')
|
|
|
|
|
|
await flushPromises()
|
|
|
|
|
|
expect(listPlatformTenants).toHaveBeenCalledTimes(2)
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|