/* @vitest-environment happy-dom */
|
|
import type { VueWrapper } from '@vue/test-utils';
|
import type { Component } from 'vue';
|
|
import { mount } from '@vue/test-utils';
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
import { defineComponent, getCurrentInstance, h, inject, nextTick, provide } from 'vue';
|
|
const modalMocks = vi.hoisted(() => ({
|
closeModal: vi.fn(),
|
createConfirm: vi.fn(),
|
openModal: vi.fn(),
|
print: vi.fn(),
|
register: vi.fn(),
|
reload: vi.fn(),
|
}));
|
|
vi.mock('#/router', () => ({
|
router: {
|
push: vi.fn(),
|
},
|
}));
|
|
vi.mock('@jnpf/hooks', () => ({
|
useGlobSetting: () => ({ apiURL: '' }),
|
useMessage: () => ({
|
createConfirm: modalMocks.createConfirm,
|
}),
|
}));
|
|
vi.mock('@jnpf/ui/modal', async () => {
|
const { defineComponent, h, onMounted } = await import('vue');
|
|
return {
|
BasicModal: defineComponent({
|
name: 'BasicModal',
|
emits: ['register'],
|
props: {
|
closeFunc: Function,
|
},
|
setup(_, { emit, slots }) {
|
onMounted(() => emit('register'));
|
|
return () =>
|
h('section', { 'data-test': 'basic-modal' }, [
|
h('header', { 'data-test': 'modal-title' }, slots.title?.()),
|
h('main', { 'data-test': 'modal-content' }, slots.default?.()),
|
]);
|
},
|
}),
|
useModal: () => [modalMocks.register, { closeModal: modalMocks.closeModal, openModal: modalMocks.openModal }],
|
};
|
});
|
|
vi.mock('ant-design-vue', async () => {
|
const { defineComponent, h } = await import('vue');
|
|
return {
|
Button: defineComponent({
|
name: 'AButton',
|
props: {
|
danger: Boolean,
|
disabled: Boolean,
|
loading: Boolean,
|
type: String,
|
},
|
emits: ['click'],
|
setup(props, { emit, slots }) {
|
return () =>
|
h(
|
'button',
|
{
|
disabled: props.disabled || props.loading,
|
type: 'button',
|
onClick: () => emit('click'),
|
},
|
slots.default?.(),
|
);
|
},
|
}),
|
Space: defineComponent({
|
name: 'ASpace',
|
setup(_, { slots }) {
|
return () => h('div', { 'data-test': 'space' }, slots.default?.());
|
},
|
}),
|
Spin: defineComponent({
|
name: 'ASpin',
|
setup(_, { slots }) {
|
return () => h('div', slots.default?.());
|
},
|
}),
|
};
|
});
|
|
vi.mock('#/components/CustomPrint/CustomPrintPreviewPane.vue', () => ({
|
default: defineComponent({
|
name: 'CustomPrintPreviewPane',
|
emits: ['error', 'loaded', 'loading'],
|
props: {
|
config: {
|
required: true,
|
type: Object,
|
},
|
},
|
setup(_, { expose }) {
|
expose({ print: modalMocks.print, reload: modalMocks.reload });
|
|
return () => h('div', { 'data-test': 'custom-print-preview' });
|
},
|
}),
|
}));
|
|
vi.mock('../ReportAttachmentsPane.vue', () => ({
|
default: defineComponent({
|
name: 'ReportAttachmentsPane',
|
setup() {
|
return () => h('div', { 'data-test': 'attachments-pane' });
|
},
|
}),
|
}));
|
|
vi.mock('../ReportFormDetailPane.vue', () => ({
|
default: defineComponent({
|
name: 'ReportFormDetailPane',
|
props: {
|
tab: {
|
required: true,
|
type: Object,
|
},
|
},
|
setup(props) {
|
return () => h('div', { 'data-test': 'form-detail-pane' }, props.tab.id);
|
},
|
}),
|
}));
|
|
import { onlineUtils } from '#/utils/jnpf';
|
|
import GlobalReportViewModal from '../index.vue';
|
|
const customPrintTab = {
|
key: 'customPrint',
|
print: {
|
data: { id: 'record-id' },
|
template: 'template-id',
|
},
|
} as const;
|
|
function mountModal() {
|
return mount(GlobalReportViewModal, {
|
global: {
|
components: {
|
'a-tab-pane': defineComponent({
|
name: 'ATabPane',
|
props: {
|
tab: String,
|
},
|
setup(props) {
|
const instance = getCurrentInstance();
|
const setActiveKey = inject<(key: string) => void>('setActiveKey');
|
|
return () =>
|
h(
|
'div',
|
{
|
'data-test': 'tab-pane',
|
onClick: () => setActiveKey?.(String(instance?.vnode.key)),
|
},
|
props.tab,
|
);
|
},
|
}),
|
'a-tabs': defineComponent({
|
name: 'ATabs',
|
emits: ['update:activeKey'],
|
props: {
|
activeKey: String,
|
},
|
setup(_, { emit, slots }) {
|
provide('setActiveKey', (key: string) => emit('update:activeKey', key));
|
|
return () => h('div', { 'data-test': 'tabs' }, slots.default?.());
|
},
|
}),
|
},
|
},
|
});
|
}
|
|
async function openReportView(config = {}) {
|
onlineUtils.openReportView({
|
tabs: [customPrintTab],
|
title: '查看报告',
|
...config,
|
});
|
|
await nextTick();
|
await nextTick();
|
}
|
|
async function emitPrintLoaded(wrapper: VueWrapper) {
|
wrapper.findComponent({ name: 'CustomPrintPreviewPane' }).vm.$emit('loaded');
|
await nextTick();
|
}
|
|
function getButton(wrapper: VueWrapper, text: string) {
|
const button = wrapper.findAll('button').find(item => item.text() === text);
|
|
expect(button, `button "${text}" exists`).toBeTruthy();
|
return button!;
|
}
|
|
function queryButton(wrapper: VueWrapper, text: string) {
|
return wrapper.findAll('button').find(item => item.text() === text);
|
}
|
|
function getFormDetailText(wrapper: VueWrapper) {
|
return wrapper.find('[data-test="form-detail-pane"]').text();
|
}
|
|
describe('GlobalReportViewModal interactions', () => {
|
let wrapper: VueWrapper<Component> | null = null;
|
|
beforeEach(() => {
|
modalMocks.closeModal.mockClear();
|
modalMocks.createConfirm.mockClear();
|
modalMocks.openModal.mockClear();
|
modalMocks.print.mockClear();
|
modalMocks.register.mockClear();
|
modalMocks.reload.mockClear();
|
wrapper = mountModal();
|
});
|
|
afterEach(() => {
|
wrapper?.unmount();
|
wrapper = null;
|
vi.clearAllMocks();
|
});
|
|
it('无 actions 时显示默认打印按钮和关闭按钮', async () => {
|
await openReportView();
|
await emitPrintLoaded(wrapper!);
|
|
expect(getButton(wrapper!, '导出PDF').attributes('disabled')).toBeUndefined();
|
expect(getButton(wrapper!, '打印').attributes('disabled')).toBeUndefined();
|
expect(getButton(wrapper!, '关闭').exists()).toBe(true);
|
});
|
|
it('有 actions 时显示业务动作且不显示默认打印按钮', async () => {
|
await openReportView({
|
actions: [
|
{
|
key: 'approve',
|
label: '审核通过',
|
onClick: vi.fn(),
|
type: 'primary',
|
},
|
],
|
});
|
|
expect(getButton(wrapper!, '审核通过').exists()).toBe(true);
|
expect(queryButton(wrapper!, '导出PDF')).toBeUndefined();
|
expect(queryButton(wrapper!, '打印')).toBeUndefined();
|
expect(getButton(wrapper!, '关闭').exists()).toBe(true);
|
});
|
|
it('actions 为空数组时隐藏默认打印按钮', async () => {
|
await openReportView({
|
actions: [],
|
});
|
|
expect(queryButton(wrapper!, '导出PDF')).toBeUndefined();
|
expect(queryButton(wrapper!, '打印')).toBeUndefined();
|
expect(getButton(wrapper!, '关闭').exists()).toBe(true);
|
});
|
|
it('action 没有 confirmText 时点击后直接执行 action 且不弹确认', async () => {
|
const onClick = vi.fn();
|
|
await openReportView({
|
actions: [
|
{
|
key: 'approve',
|
label: '审核通过',
|
onClick,
|
},
|
],
|
});
|
|
await getButton(wrapper!, '审核通过').trigger('click');
|
|
expect(modalMocks.createConfirm).not.toHaveBeenCalled();
|
expect(onClick).toHaveBeenCalledTimes(1);
|
});
|
|
it('action 有 confirmText 时点击后弹出确认且不直接执行 action', async () => {
|
const onClick = vi.fn();
|
|
await openReportView({
|
actions: [
|
{
|
confirmText: '确认审核通过吗?',
|
key: 'approve',
|
label: '审核通过',
|
onClick,
|
},
|
],
|
});
|
|
await getButton(wrapper!, '审核通过').trigger('click');
|
|
expect(modalMocks.createConfirm).toHaveBeenCalledTimes(1);
|
expect(modalMocks.createConfirm).toHaveBeenCalledWith(
|
expect.objectContaining({
|
content: '确认审核通过吗?',
|
}),
|
);
|
expect(onClick).not.toHaveBeenCalled();
|
|
const confirmOptions = modalMocks.createConfirm.mock.calls[0]?.[0] as { onOk: () => void } | undefined;
|
expect(confirmOptions).toBeTruthy();
|
confirmOptions!.onOk();
|
await nextTick();
|
|
expect(onClick).toHaveBeenCalledTimes(1);
|
});
|
|
it('点击打印和导出PDF时调用打印预览 expose 的 print', async () => {
|
await openReportView();
|
await emitPrintLoaded(wrapper!);
|
|
await getButton(wrapper!, '打印').trigger('click');
|
expect(modalMocks.print).toHaveBeenCalledTimes(1);
|
|
await getButton(wrapper!, '导出PDF').trigger('click');
|
expect(modalMocks.print).toHaveBeenCalledTimes(2);
|
});
|
|
it('onlineUtils.closeReportView 连续触发时只关闭一次并只调用一次 onClose', async () => {
|
const onClose = vi.fn();
|
|
await openReportView({ onClose });
|
|
onlineUtils.closeReportView();
|
onlineUtils.closeReportView();
|
|
expect(modalMocks.closeModal).toHaveBeenCalledTimes(1);
|
expect(onClose).toHaveBeenCalledTimes(1);
|
});
|
|
it('点击关闭按钮后再次触发 closeReportView 仍只关闭一次', async () => {
|
const onClose = vi.fn();
|
|
await openReportView({ onClose });
|
|
await getButton(wrapper!, '关闭').trigger('click');
|
onlineUtils.closeReportView();
|
|
expect(modalMocks.closeModal).toHaveBeenCalledTimes(1);
|
expect(onClose).toHaveBeenCalledTimes(1);
|
});
|
|
it('unmount 后清理 report view 事件监听', async () => {
|
await openReportView();
|
|
expect(modalMocks.openModal).toHaveBeenCalledTimes(1);
|
|
wrapper!.unmount();
|
wrapper = null;
|
|
onlineUtils.openReportView({
|
tabs: [customPrintTab],
|
title: '卸载后打开',
|
});
|
onlineUtils.closeReportView();
|
|
await nextTick();
|
await nextTick();
|
|
expect(modalMocks.openModal).toHaveBeenCalledTimes(1);
|
expect(modalMocks.closeModal).not.toHaveBeenCalled();
|
});
|
|
it('loaded 前打印按钮 disabled,loaded 后启用', async () => {
|
await openReportView();
|
|
expect(getButton(wrapper!, '打印').attributes('disabled')).toBeDefined();
|
|
await emitPrintLoaded(wrapper!);
|
|
expect(getButton(wrapper!, '打印').attributes('disabled')).toBeUndefined();
|
});
|
|
it('支持在多个 formDetail tab 之间切换', async () => {
|
await openReportView({
|
activeKey: 'formDetail',
|
tabs: [
|
{
|
id: 'form-id-1',
|
key: 'formDetail',
|
modelId: 'model-id-1',
|
title: '委托信息',
|
},
|
{
|
id: 'form-id-2',
|
key: 'formDetail',
|
modelId: 'model-id-2',
|
title: '检验记录',
|
},
|
],
|
});
|
|
expect(wrapper!.findAll('[data-test="tab-pane"]').map(item => item.text())).toEqual(['委托信息', '检验记录']);
|
expect(getFormDetailText(wrapper!)).toContain('form-id-1');
|
|
await wrapper!.findAll('[data-test="tab-pane"]')[1]!.trigger('click');
|
|
expect(getFormDetailText(wrapper!)).toContain('form-id-2');
|
});
|
});
|