import { mount } from '@vue/test-utils' import ElementPlus from 'element-plus' import { nextTick } from 'vue' import { describe, expect, test, vi } from 'vitest' import MaterialImportResult from './MaterialImportResult.vue' const failedResult = { total_rows: 3, success_rows: 0, failed_rows: 2, errors: [ { row: 2, data: { name: '', spec: 'M8x30', unit: '个', major: '机械结构类', minor: '标准件' }, reason: '物料名称不能为空' }, { row: 4, data: { name: '螺栓', spec: '', unit: '吨', major: '机械结构类', minor: '标准件' }, reason: '单位「吨」不存在或已停用' } ] } // el-table 分两轮渲染:先注册列,下一轮才把单元格填上。只等一个 tick 的话 // 拿到的是空 ,断言文本会莫名其妙地失败(实测过一次),所以统一等两轮。 async function mountResult(result, options = {}) { const wrapper = mount(MaterialImportResult, { props: { result }, global: { plugins: [ElementPlus], stubs: { teleport: true }, ...options } }) await nextTick() await nextTick() return wrapper } describe('MaterialImportResult', () => { test('失败时展示行数摘要与每行错误', async () => { const wrapper = await mountResult(failedResult) expect(wrapper.text()).toContain('共 3 行') expect(wrapper.text()).toContain('2 行未通过') const rows = wrapper.findAll('tbody tr') expect(rows.length).toBe(2) expect(rows[0].text()).toContain('2') expect(rows[0].text()).toContain('物料名称不能为空') wrapper.unmount() }) test('导出错误明细时把行号与原因写进 CSV', async () => { const download = vi.fn() const wrapper = await mountResult(failedResult, { provide: { downloadCsv: download } }) await wrapper.find('[data-test="export-errors"]').trigger('click') expect(download).toHaveBeenCalledTimes(1) const [fileName, csv] = download.mock.calls[0] expect(fileName).toContain('导入错误明细') expect(csv).toContain('物料名称不能为空') expect(csv).toContain('行号') wrapper.unmount() }) test('全部成功时只展示成功摘要,不显示错误表格', async () => { const wrapper = await mountResult({ total_rows: 2, success_rows: 2, failed_rows: 0, errors: [] }) expect(wrapper.text()).toContain('成功导入 2 条') expect(wrapper.find('[data-test="error-table"]').exists()).toBe(false) wrapper.unmount() }) })