/* @vitest-environment happy-dom */
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { defHttp } from '#/api/request';
|
import { router } from '#/router';
|
import { isDraftFlowConfig, onlineUtils, resolveOpenFlowEditConfig, resolveOpenFlowListConfig } from '#/utils/jnpf';
|
|
vi.mock('#/router', () => ({
|
router: {
|
push: vi.fn(),
|
},
|
}));
|
|
vi.mock('#/api/request', () => ({
|
defHttp: {
|
get: vi.fn(),
|
},
|
}));
|
|
describe('onlineUtils report view API', () => {
|
beforeEach(() => {
|
vi.mocked(defHttp.get).mockReset();
|
vi.mocked(router.push).mockClear();
|
});
|
|
it('calculates dates in supported units', () => {
|
expect(onlineUtils.calculateDate('2026-07-30', 2, 'month')).toBe('2026-09-30');
|
expect(onlineUtils.calculateDate('2026-07-30', 2, 'month', true)).toBe('2026-05-30');
|
expect(onlineUtils.calculateDate('2026-07-30', 1, 'quarter')).toBe('2026-10-30');
|
expect(onlineUtils.calculateDate('2026-01-31', 1, 'month')).toBe('2026-02-28');
|
});
|
|
it('accepts timestamps and rejects invalid calculation input', () => {
|
const timestamp = new Date(2026, 6, 30, 12).valueOf();
|
|
expect(onlineUtils.calculateDate(timestamp, 1, 'week')).toBe('2026-08-06');
|
expect(onlineUtils.calculateDate(String(timestamp), 1, 'week')).toBe('2026-08-06');
|
expect(onlineUtils.calculateDate('2026-07-30 12:30:45', 1, 'day')).toBe('2026-07-31');
|
expect(onlineUtils.calculateDate('invalid date', 1, 'day')).toBe('');
|
expect(onlineUtils.calculateDate('2026-07-30', 1, 'invalid' as never)).toBe('');
|
});
|
|
it('emits OPEN_REPORT_VIEW with config', () => {
|
const emitter = onlineUtils.getEmitter();
|
const listener = vi.fn();
|
emitter.on('OPEN_REPORT_VIEW', listener);
|
|
const config = {
|
title: '查看报告',
|
tabs: [{ key: 'attachments' as const }],
|
};
|
|
onlineUtils.openReportView(config);
|
|
expect(listener).toHaveBeenCalledWith(config);
|
emitter.off('OPEN_REPORT_VIEW', listener);
|
});
|
|
it('does not emit OPEN_REPORT_VIEW when tabs are empty', () => {
|
const emitter = onlineUtils.getEmitter();
|
const listener = vi.fn();
|
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
emitter.on('OPEN_REPORT_VIEW', listener);
|
|
onlineUtils.openReportView({ tabs: [] });
|
|
expect(listener).not.toHaveBeenCalled();
|
expect(errorSpy).toHaveBeenCalledWith('[onlineUtils.openReportView] tabs is required');
|
emitter.off('OPEN_REPORT_VIEW', listener);
|
errorSpy.mockRestore();
|
});
|
|
it('emits CLOSE_REPORT_VIEW', () => {
|
const emitter = onlineUtils.getEmitter();
|
const listener = vi.fn();
|
emitter.on('CLOSE_REPORT_VIEW', listener);
|
|
onlineUtils.closeReportView();
|
|
expect(listener).toHaveBeenCalledTimes(1);
|
emitter.off('CLOSE_REPORT_VIEW', listener);
|
});
|
|
it('emits workflow detail config with flowId and taskId', () => {
|
const emitter = onlineUtils.getEmitter();
|
const listener = vi.fn();
|
emitter.on('OPEN_FLOW_DETAIL', listener);
|
|
onlineUtils.openFlowDetail('flow_001', 'task_001');
|
|
expect(router.push).not.toHaveBeenCalled();
|
expect(listener).toHaveBeenCalledWith({
|
flowId: 'flow_001',
|
id: 'task_001',
|
isFlow: 0,
|
opType: 0,
|
taskId: 'task_001',
|
});
|
emitter.off('OPEN_FLOW_DETAIL', listener);
|
});
|
|
it('emits workflow detail config with camelCase object config and custom opType', () => {
|
const emitter = onlineUtils.getEmitter();
|
const listener = vi.fn();
|
emitter.on('OPEN_FLOW_DETAIL', listener);
|
|
onlineUtils.openFlowDetail({ flowId: 'flow_002', opType: 4, operatorId: 'operator_001', taskId: 'task_002' });
|
|
expect(router.push).not.toHaveBeenCalled();
|
expect(listener).toHaveBeenCalledWith(
|
expect.objectContaining({
|
flowId: 'flow_002',
|
id: 'task_002',
|
opType: 4,
|
operatorId: 'operator_001',
|
taskId: 'task_002',
|
}),
|
);
|
emitter.off('OPEN_FLOW_DETAIL', listener);
|
});
|
|
it('emits workflow edit config with flowId and taskId', () => {
|
const emitter = onlineUtils.getEmitter();
|
const listener = vi.fn();
|
emitter.on('OPEN_FLOW_EDIT', listener);
|
|
onlineUtils.openFlowEdit('flow_003', 'task_003');
|
|
expect(router.push).not.toHaveBeenCalled();
|
expect(listener).toHaveBeenCalledWith({
|
flowId: 'flow_003',
|
id: 'task_003',
|
isFlow: 0,
|
opType: '-1',
|
showHeaderCancelBtn: true,
|
taskId: 'task_003',
|
});
|
emitter.off('OPEN_FLOW_EDIT', listener);
|
});
|
|
it('emits workflow edit config with object config and flowTaskId', () => {
|
const emitter = onlineUtils.getEmitter();
|
const listener = vi.fn();
|
emitter.on('OPEN_FLOW_EDIT', listener);
|
|
onlineUtils.openFlowEdit({ flowId: 'flow_004', flowTaskId: 'task_004', operatorId: 'operator_004' });
|
|
expect(listener).toHaveBeenCalledWith(
|
expect.objectContaining({
|
flowId: 'flow_004',
|
flowTaskId: 'task_004',
|
id: 'task_004',
|
opType: '-1',
|
operatorId: 'operator_004',
|
showHeaderCancelBtn: true,
|
taskId: 'task_004',
|
}),
|
);
|
emitter.off('OPEN_FLOW_EDIT', listener);
|
});
|
|
it('uses business id for draft workflow edit config', () => {
|
const emitter = onlineUtils.getEmitter();
|
const listener = vi.fn();
|
emitter.on('OPEN_FLOW_EDIT', listener);
|
|
onlineUtils.openFlowEdit({ flowId: 'flow_005', flowState: 0, flowTaskId: 'missing_task_005', id: 'biz_005' });
|
|
expect(listener).toHaveBeenCalledWith(
|
expect.objectContaining({
|
flowId: 'flow_005',
|
flowState: 0,
|
flowTaskId: 'missing_task_005',
|
id: 'biz_005',
|
opType: '-1',
|
taskId: 'biz_005',
|
}),
|
);
|
emitter.off('OPEN_FLOW_EDIT', listener);
|
});
|
|
it('detects draft workflow config', () => {
|
expect(isDraftFlowConfig({ f_flow_state: 0 })).toBe(true);
|
expect(isDraftFlowConfig({ flowState: '1' })).toBe(false);
|
});
|
|
it('resolves workflow version id to template id before edit', async () => {
|
vi.mocked(defHttp.get).mockResolvedValue({ data: { flowId: 'version_001', id: 'template_001' } });
|
|
const config = await resolveOpenFlowEditConfig({ flowId: 'version_001', id: 'biz_001', opType: '-1' });
|
|
expect(defHttp.get).toHaveBeenCalledWith({ url: '/api/workflow/template/Info/version_001' }, { errorMessageMode: 'none' });
|
expect(config).toEqual({ flowId: 'template_001', id: 'biz_001', opType: '-1' });
|
});
|
|
it('emits workflow form config with flowId and params', () => {
|
const emitter = onlineUtils.getEmitter();
|
const listener = vi.fn();
|
emitter.on('OPEN_FLOW_FORM', listener);
|
|
onlineUtils.openFlowForm('flow_003', { batchNo: 'B001', materialName: '耗材A' });
|
|
expect(router.push).not.toHaveBeenCalled();
|
expect(listener).toHaveBeenCalledWith({
|
flowId: 'flow_003',
|
formData: {
|
batchNo: 'B001',
|
materialName: '耗材A',
|
},
|
id: '',
|
isFlow: 0,
|
opType: '-1',
|
params: {
|
batchNo: 'B001',
|
materialName: '耗材A',
|
},
|
});
|
emitter.off('OPEN_FLOW_FORM', listener);
|
});
|
|
it('emits workflow form config with object config', () => {
|
const emitter = onlineUtils.getEmitter();
|
const listener = vi.fn();
|
emitter.on('OPEN_FLOW_FORM', listener);
|
|
onlineUtils.openFlowForm({
|
flowId: 'flow_004',
|
formData: { materialName: '默认耗材' },
|
params: { batchNo: 'B002' },
|
title: '耗材入库验收',
|
});
|
|
expect(listener).toHaveBeenCalledWith(
|
expect.objectContaining({
|
flowId: 'flow_004',
|
formData: {
|
batchNo: 'B002',
|
materialName: '默认耗材',
|
},
|
id: '',
|
opType: '-1',
|
params: { batchNo: 'B002' },
|
title: '耗材入库验收',
|
}),
|
);
|
emitter.off('OPEN_FLOW_FORM', listener);
|
});
|
|
it('emits workflow list config with flowId', () => {
|
const emitter = onlineUtils.getEmitter();
|
const listener = vi.fn();
|
emitter.on('OPEN_FLOW_LIST_MODAL', listener);
|
|
const config = {
|
flowId: 'flow_006',
|
params: { applicant: 'admin' },
|
title: '留样销毁台账',
|
};
|
|
onlineUtils.openFlowList(config);
|
|
expect(listener).toHaveBeenCalledWith(config);
|
emitter.off('OPEN_FLOW_LIST_MODAL', listener);
|
});
|
|
it('emits workflow list config with flowId and params arguments', () => {
|
const emitter = onlineUtils.getEmitter();
|
const listener = vi.fn();
|
emitter.on('OPEN_FLOW_LIST_MODAL', listener);
|
|
onlineUtils.openFlowList('flow_007', { applicant: 'admin' });
|
|
expect(listener).toHaveBeenCalledWith({
|
flowId: 'flow_007',
|
params: { applicant: 'admin' },
|
});
|
emitter.off('OPEN_FLOW_LIST_MODAL', listener);
|
});
|
|
it('resolves workflow version id to template id before opening list', async () => {
|
vi.mocked(defHttp.get).mockResolvedValue({ data: { flowId: 'version_002', id: 'template_002' } });
|
|
const config = await resolveOpenFlowListConfig({ flowId: 'version_002', params: { applicant: 'admin' } });
|
|
expect(defHttp.get).toHaveBeenCalledWith({ url: '/api/workflow/template/Info/version_002' }, { errorMessageMode: 'none' });
|
expect(config).toEqual({ flowId: 'template_002', params: { applicant: 'admin' } });
|
});
|
|
it('emits workflow list config with menuId', () => {
|
const emitter = onlineUtils.getEmitter();
|
const listener = vi.fn();
|
emitter.on('OPEN_FLOW_LIST_MODAL', listener);
|
|
onlineUtils.openFlowList({ menuId: 'menu_001' });
|
|
expect(listener).toHaveBeenCalledWith({ menuId: 'menu_001' });
|
emitter.off('OPEN_FLOW_LIST_MODAL', listener);
|
});
|
|
it('does not emit workflow list when target is missing', () => {
|
const emitter = onlineUtils.getEmitter();
|
const listener = vi.fn();
|
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
emitter.on('OPEN_FLOW_LIST_MODAL', listener);
|
|
onlineUtils.openFlowList({});
|
|
expect(listener).not.toHaveBeenCalled();
|
expect(errorSpy).toHaveBeenCalledWith('[onlineUtils.openFlowList] flowId, menuId or path is required');
|
emitter.off('OPEN_FLOW_LIST_MODAL', listener);
|
errorSpy.mockRestore();
|
});
|
});
|