Files
flow-center-front/tests/components/department-roundtrip.component.test.ts
T
chenxing bed57846f4
build / build (push) Successful in 1m31s
feat(flow): 落地 FL2.0 原型——部门选人抽屉 / 授权管理页 / 退回重提入口(基线 origin/main)
在 c93313c 之上增量落地原型与前端规范,保留既有流程图入口/失败提示/指派预览/线级停发:

- 审批/抄送抽屉按原型重构(422→1026 / 239→742 行):科室树+成员多选、SYSTEM/CUSTOM 分支、
  CUSTOM 分类导航自动定位、跨节点导航重置、保存后重开回显
- 新增授权管理页 /admin/usage-grants(UsageGrants.vue,417 行):校域清单、按流程线筛选、
  授予/撤销后回读,失败不宣称成功
- 路由与 API:新增 usage-grant(schoolList/summary/grant/revoke)、department(groups/options/resolve/members)、
  instance/resubmit;TaskHandle 增加「退回待修改」入口(仅 status=50 显示)
- 错误处理沿用 flowError 统一出口,不透出后端原文
- 组件/契约测试:flow-error、flow2-contract、department-roundtrip、task-result

不含构建产物(dist-verify)与依赖目录
2026-10-30 10:15:47 +08:00

49 lines
3.2 KiB
TypeScript

import { describe, it, expect, vi, afterEach } from 'vitest';
import { mount, flushPromises, enableAutoUnmount } from '@vue/test-utils';
import { reactive, nextTick } from 'vue';
import ViewUIPlus from 'view-ui-plus';
import ApprovalDrawer from '@/views/flow/admin/def-editor/components/ApprovalDrawer.vue';
import NotifyDrawer from '@/views/flow/admin/def-editor/components/NotifyDrawer.vue';
import { EDITOR_CTX, createApproval, createNotify } from '@/views/flow/admin/def-editor/model';
const { api } = vi.hoisted(() => ({ api: { deptGroups: vi.fn(), deptResolve: vi.fn(), deptOptions: vi.fn() } }));
vi.mock('@/api/module/flow', () => ({ flowApi: api }));
enableAutoUnmount(afterEach);
const ok = (data: unknown) => ({ send: async () => data });
describe('CUSTOM 引用真实抽屉编辑往返', () => {
for (const mode of ['approval', 'notify'] as const) {
it(`${mode}:无 categoryId 的历史解析仍可反查分类,保存重开再保存不丢引用`, async () => {
document.body.innerHTML = '';
const ref = { departmentType: 'CUSTOM', departmentId: 9 };
api.deptGroups.mockImplementation(() => ok([
{ departmentType: 'SYSTEM', name: '系统组织' },
{ departmentType: 'CUSTOM', categoryId: 4, name: '教研组' },
]));
api.deptResolve.mockImplementation(() => ok([{ ...ref, name: '科学组', memberCount: 2, selectable: true }]));
api.deptOptions.mockImplementation(() => ok([{ ...ref, categoryId: 4, name: '科学组', memberCount: 2, selectable: true }]));
const node: any = mode === 'approval' ? createApproval('审批') : createNotify('抄送');
const key = mode === 'approval' ? 'assignee' : 'receivers';
node[key] = { type: 'DEPT', deptRefs: [ref] };
const ctx = { model: reactive({ list: [node] }), depts: [], userNames: {}, routers: [], availableVars: [], issueOf: () => [] };
const wrapper = mount(mode === 'approval' ? ApprovalDrawer : NotifyDrawer, {
props: { node, modelValue: true }, attachTo: document.body,
global: { plugins: [ViewUIPlus], provide: { [EDITOR_CTX as unknown as symbol]: ctx } },
});
await flushPromises(); await nextTick();
expect(document.body.textContent).toContain('科学组');
expect(api.deptOptions).toHaveBeenCalledWith({ type: 'CUSTOM' });
for (let round = 0; round < 2; round++) {
if (round) { await wrapper.setProps({ modelValue: false }); await wrapper.setProps({ modelValue: true }); await flushPromises(); }
const input = document.querySelector('input.ivu-input') as HTMLInputElement;
expect(input).toBeTruthy(); input.value = `修改名称${round}`; input.dispatchEvent(new Event('input', { bubbles: true }));
await nextTick();
const confirm = Array.from(document.querySelectorAll('button')).find(b => b.textContent?.trim() === '确定');
expect(confirm).toBeTruthy(); confirm!.click(); await nextTick();
expect(node[key]).toEqual({ type: 'DEPT', deptRefs: [ref] });
expect(node.name).toBe(`修改名称${round}`);
}
});
}
});