import { flushPromises, mount } from '@vue/test-utils' import ElementPlus, { ElMessage } from 'element-plus' import { beforeEach, describe, expect, test, vi } from 'vitest' import Application from './Application.vue' const applicationStore = vi.hoisted(() => ({ myApplications: [], loading: false, myPage: { currentPage: 1, pageSize: 20, total: 0, totalPages: 0 }, fetchMyApplications: vi.fn(), createApplication: vi.fn(), cancelApplication: vi.fn() })) const materialsStore = vi.hoisted(() => ({ materialOptions: [], fetchMaterialOptions: vi.fn() })) const stockStore = vi.hoisted(() => ({ fetchStock: vi.fn(), fetchStockByMaterialId: vi.fn() })) vi.mock('../stores/application', () => ({ useApplicationStore: () => applicationStore })) vi.mock('../stores/materials', () => ({ useMaterialsStore: () => materialsStore })) vi.mock('../stores/stock', () => ({ useStockStore: () => stockStore })) // 真实的 ElSelect 在 jsdom 下会因状态双向绑定反复触发自身更新而报 // "Maximum recursive updates exceeded"。这里用替身直接派发 change, // 模拟用户在状态下拉里选中某一项。 const SelectStub = { props: ['modelValue', 'placeholder', 'filterable', 'filterMethod', 'noDataText', 'disabled', 'clearable'], emits: ['update:modelValue', 'change'], methods: { pick(value) { this.$emit('update:modelValue', value) this.$emit('change', value) } }, template: '
' } const OptionStub = { props: ['label', 'value'], template: '' } function mountApplication() { return mount(Application, { global: { plugins: [ElementPlus], stubs: { teleport: true, ElSelect: SelectStub, ElOption: OptionStub } } }) } // 页面里有两处 ElSelect:申请表单里的物料选择,和「我的申请」里的状态筛选。 function statusSelect(wrapper) { return wrapper.findAllComponents(SelectStub) .find(select => select.props('placeholder') === '全部状态') } function setupState(wrapper) { return wrapper.vm.$.setupState } describe('提交申请后筛选条件与列表保持一致', () => { let successSpy beforeEach(() => { vi.clearAllMocks() applicationStore.createApplication.mockResolvedValue({ data: {} }) successSpy = vi.spyOn(ElMessage, 'success').mockImplementation(() => {}) }) test('状态下拉选中的值会传给列表查询', async () => { const wrapper = mountApplication() await flushPromises() statusSelect(wrapper).vm.pick('approved') await flushPromises() expect(setupState(wrapper).statusFilter).toBe('approved') expect(applicationStore.fetchMyApplications).toHaveBeenLastCalledWith('approved', 1) wrapper.unmount() }) // store 里提交后的那次刷新是刻意清空筛选的(好让刚提交的待审批单出现在列表里), // 页面这份状态(下拉框)必须跟着一起回到「全部」:否则会出现下拉写着「已通过」、 // 列表却是全量的表里不一,这次修复就是补的这一处。 test('提交成功后下拉框的筛选要一起重置为全部', async () => { const wrapper = mountApplication() await flushPromises() statusSelect(wrapper).vm.pick('approved') await flushPromises() expect(setupState(wrapper).statusFilter).toBe('approved') setupState(wrapper).applyForm.purpose = '测试用途' setupState(wrapper).applyForm.items = [ { material_id: 7, materialSearchText: '', quantity: 1 } ] await setupState(wrapper).handleSubmit() await flushPromises() expect(applicationStore.createApplication).toHaveBeenCalled() expect(setupState(wrapper).statusFilter).toBe('') wrapper.unmount() }) })