/** * 删除规则编辑弹窗(ModuleRuleEditModal): * - 勾条件 → predicate 存 {"kind":"dsl","expr":AST};写 SQL → predicate 存文本; * - 两种类型各自的必填校验(无条件 / 缺提示文案)不通过时不提交; * - 打开时按 predicate 三态回显类型与内容;标题按新增/编辑切换。 */ import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest' import { mount } from '@vue/test-utils' import { flushPromises } from '@vue/test-utils' import { createPinia, setActivePinia } from 'pinia' import { nextTick } from 'vue' import ModuleRuleEditModal from '@/views/module/module-management/ModuleRuleEditModal.vue' import { buildRuleQueryItems } from '@/views/module/module-management/ruleUtils' vi.mock('@/services/api', () => ({ loadDataApi: vi.fn() })) vi.mock('@/components/ui/message/message-manager.js', () => { const m = { success: vi.fn(), error: vi.fn(), warning: vi.fn(), info: vi.fn() } return { Message: m, default: m } }) beforeAll(() => { Object.defineProperty(HTMLElement.prototype, 'clientWidth', { configurable: true, get() { return 5000 }, }) }) const ITEMS = buildRuleQueryItems( [ { b_field: 'b_status', b_name: '状态', b_type: 'select', b_canuse: 1 }, { b_field: 'b_no', b_name: '单号', b_type: 'input', b_canuse: 1 }, ], {}, ) const ruleRow = () => ({ _rowKey: '-1', b_id: '1900000000000000001', b_scope_type: 'module', b_scope_id: 'order', b_hook: 'delete.pre', b_predicate: null, b_message: null, b_canuse: 1, b_xh: 10, }) async function mountModal(row = ruleRow(), isNew = false) { const pinia = createPinia() pinia.install({ provide() {}, config: { globalProperties: {} } }) setActivePinia(pinia) const wrapper = mount(ModuleRuleEditModal, { props: { open: true, row, isNew, items: ITEMS }, global: { plugins: [pinia] }, attachTo: document.body, }) await flushPromises() await nextTick() return wrapper } beforeEach(() => { document.body.innerHTML = '' }) describe('删除规则编辑弹窗', () => { it('勾条件:没有条件时不提交,选了条件后按 AST 组装 predicate', async () => { const row = ruleRow() const wrapper = await mountModal(row) await wrapper.vm.onOk() expect(wrapper.vm.conditionError).toBe('勾条件规则至少要有一个条件') expect(wrapper.emitted('ok')).toBeFalsy() wrapper.vm.conditionState = { nodes: [{ id: 'n1', at: 1, join: 'and', field: 'b_status', operator: 'eq', value: 'audit' }], groups: [], } await nextTick() expect(wrapper.vm.conditionSummary).toBe('状态 等于 audit') await wrapper.vm.onOk() const saved = wrapper.emitted('ok')?.[0]?.[0] expect(saved.b_hook).toBe('delete.pre') const predicate = JSON.parse(saved.b_predicate) expect(predicate.kind).toBe('dsl') expect(predicate.expr.children[0]).toMatchObject({ type: 'condition', field: 'b_status', operator: 'eq', value: 'audit', }) expect(wrapper.emitted('update:open')?.at(-1)).toEqual([false]) }) it('写 SQL:缺提示文案不提交,填好后原样存文本', async () => { const row = ruleRow() const wrapper = await mountModal(row) wrapper.vm.ruleType = 'sql' wrapper.vm.sqlText = 'select b_id from bill where b_id in (:ids) and b_settled = 1' await nextTick() await wrapper.vm.onOk() expect(wrapper.vm.sqlError).toBe('写 SQL 的规则必须填写提示文案') expect(wrapper.emitted('ok')).toBeFalsy() row.b_message = '单据已销账,不能删除' await wrapper.vm.onOk() expect(wrapper.emitted('ok')?.[0]?.[0].b_predicate).toBe( 'select b_id from bill where b_id in (:ids) and b_settled = 1', ) }) it('写 SQL:SQL 为空时不提交', async () => { const wrapper = await mountModal(ruleRow()) wrapper.vm.ruleType = 'sql' wrapper.vm.sqlText = ' ' await nextTick() await wrapper.vm.onOk() expect(wrapper.vm.sqlError).toBe('请填写规则 SQL') expect(wrapper.emitted('ok')).toBeFalsy() }) it('回显与标题:SQL 类型直接进 SQL 分支;新增/编辑标题不同', async () => { const row = { ...ruleRow(), b_predicate: 'select 1 as b_id' } const wrapper = await mountModal(row, true) expect(wrapper.vm.ruleType).toBe('sql') expect(wrapper.vm.sqlText).toBe('select 1 as b_id') expect(wrapper.vm.modalTitle).toBe('新增删除规则') const editWrapper = await mountModal({ ...ruleRow() }, false) expect(editWrapper.vm.modalTitle).toBe('编辑删除规则') }) })