import { flushPromises, mount } from '@vue/test-utils';
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import TrendPage from '../../index.vue';
|
|
const apiMocks = vi.hoisted(() => ({
|
getData: vi.fn(),
|
getOptions: vi.fn(),
|
}));
|
|
vi.mock('#/api/x/lims/shiyanshi/sxt', () => ({
|
getSxtTrendData: apiMocks.getData,
|
getSxtTrendOptions: apiMocks.getOptions,
|
}));
|
|
vi.mock('@jnpf/hooks', () => ({
|
useMessage: () => ({ createMessage: { error: vi.fn() } }),
|
}));
|
|
vi.mock('@vben/plugins/echarts', () => ({
|
EchartsUI: { name: 'EchartsUI', template: '<div />' },
|
useEcharts: () => ({ renderEcharts: vi.fn() }),
|
}));
|
|
const DateRangeStub = {
|
name: 'JnpfDateRange',
|
props: ['value'],
|
template: '<div />',
|
};
|
|
const OptionPopupStub = {
|
name: 'TrendOptionPopup',
|
props: ['disabled', 'multiple', 'options', 'value'],
|
emits: ['change', 'update:value'],
|
template: '<div />',
|
};
|
|
const TablePopupStub = {
|
name: 'TrendTablePopup',
|
props: ['disabled', 'options', 'value'],
|
emits: ['change', 'update:value'],
|
template: '<div />',
|
};
|
|
function mountPage() {
|
return mount(TrendPage, {
|
global: {
|
stubs: {
|
ASpin: { template: '<div><slot /></div>' },
|
'a-button': { template: '<button @click="$emit(\'click\')"><slot /></button>' },
|
'a-select': true,
|
'jnpf-date-range': DateRangeStub,
|
TrendOptionPopup: OptionPopupStub,
|
TrendTablePopup: TablePopupStub,
|
},
|
},
|
});
|
}
|
|
async function selectRequiredFilters(wrapper: ReturnType<typeof mountPage>) {
|
await flushPromises();
|
const optionPopups = wrapper.findAllComponents(OptionPopupStub);
|
optionPopups[0]!.vm.$emit('update:value', 'water');
|
optionPopups[0]!.vm.$emit('change', 'water');
|
await flushPromises();
|
|
optionPopups[1]!.vm.$emit('update:value', 'workshop-1');
|
optionPopups[1]!.vm.$emit('change', 'workshop-1');
|
await flushPromises();
|
|
const tablePopups = wrapper.findAllComponents(TablePopupStub);
|
tablePopups[0]!.vm.$emit('update:value', ['point-1']);
|
tablePopups[0]!.vm.$emit('change', ['point-1']);
|
await flushPromises();
|
|
const dateRange = wrapper.findComponent(DateRangeStub);
|
dateRange.vm.$emit('update:value', ['2026-07-01', '2026-07-31']);
|
tablePopups[1]!.vm.$emit('update:value', ['ph-item']);
|
await wrapper.vm.$nextTick();
|
return dateRange;
|
}
|
|
describe('water trend page', () => {
|
beforeEach(() => {
|
apiMocks.getOptions.mockResolvedValue({
|
data: {
|
chejian_list: [{ id: 'workshop-1', name: '中针车间' }],
|
jianyan_xiangmu_list: [
|
{
|
id: 'ph-item',
|
name: '酸碱度',
|
trend_enabled: true,
|
unit: 'pH',
|
},
|
{
|
id: 'configured-text-item',
|
name: '性状',
|
trend_enabled: false,
|
unit: '',
|
},
|
],
|
quyangdian_list: [
|
{
|
chejian_id: 'workshop-1',
|
id: 'point-1',
|
name: 'D2',
|
quyang_didian: '左门口',
|
quyangdian_bianhao: 'D2',
|
yangpin_leixing_id: 'water',
|
},
|
],
|
yangpin_leixing_list: [{ id: 'water', name: '纯化水' }],
|
},
|
});
|
apiMocks.getData.mockResolvedValue({
|
data: {
|
records: [
|
{
|
ceshi_jieguo: 7,
|
jianyan_xiang_id: 'inspection-1',
|
jianyan_riqi: '2026-07-01',
|
jianyan_xiangmu_id: 'ph-item',
|
quyangdian_id: 'point-1',
|
quyangdian_mingcheng: 'W-1',
|
renwu_jianyan_xiang_kuaizhao_id: 'snapshot-1',
|
},
|
],
|
standards: [
|
{
|
biaozhun_shangxian: 7.5,
|
biaozhun_xiaxian: 6.8,
|
jianyan_xiangmu_id: 'ph-item',
|
renwu_jianyan_xiang_kuaizhao_id: 'snapshot-1',
|
trend_enabled: true,
|
unit: 'pH',
|
},
|
],
|
},
|
});
|
});
|
|
it('keeps the original popup selectors and disables each lower level until its parent is selected', async () => {
|
const wrapper = mountPage();
|
await flushPromises();
|
|
const optionPopups = wrapper.findAllComponents(OptionPopupStub);
|
const tablePopups = wrapper.findAllComponents(TablePopupStub);
|
expect(optionPopups).toHaveLength(2);
|
expect(tablePopups).toHaveLength(2);
|
expect(optionPopups[1]!.props('disabled')).toBe(true);
|
expect(tablePopups[0]!.props('disabled')).toBe(true);
|
expect(tablePopups[1]!.props('disabled')).toBe(true);
|
});
|
|
it('requests the inspection item union for all selected sampling points', async () => {
|
const wrapper = mountPage();
|
await flushPromises();
|
const optionPopups = wrapper.findAllComponents(OptionPopupStub);
|
const tablePopups = wrapper.findAllComponents(TablePopupStub);
|
|
optionPopups[0]!.vm.$emit('update:value', 'water');
|
optionPopups[0]!.vm.$emit('change', 'water');
|
await flushPromises();
|
optionPopups[1]!.vm.$emit('update:value', 'workshop-1');
|
optionPopups[1]!.vm.$emit('change', 'workshop-1');
|
await flushPromises();
|
tablePopups[0]!.vm.$emit('update:value', ['point-1', 'point-2']);
|
tablePopups[0]!.vm.$emit('change', ['point-1', 'point-2']);
|
await flushPromises();
|
|
expect(apiMocks.getOptions).toHaveBeenLastCalledWith({
|
chejian_id: 'workshop-1',
|
quyangdian_ids: ['point-1', 'point-2'],
|
yangpin_leixing_id: 'water',
|
});
|
});
|
|
it('shows every configured inspection item without filtering by trend capability', async () => {
|
const wrapper = mountPage();
|
await flushPromises();
|
const optionPopups = wrapper.findAllComponents(OptionPopupStub);
|
const tablePopups = wrapper.findAllComponents(TablePopupStub);
|
|
optionPopups[0]!.vm.$emit('update:value', 'water');
|
optionPopups[0]!.vm.$emit('change', 'water');
|
await flushPromises();
|
optionPopups[1]!.vm.$emit('update:value', 'workshop-1');
|
optionPopups[1]!.vm.$emit('change', 'workshop-1');
|
await flushPromises();
|
tablePopups[0]!.vm.$emit('update:value', ['point-1']);
|
tablePopups[0]!.vm.$emit('change', ['point-1']);
|
await flushPromises();
|
|
expect(tablePopups[1]!.props('options')).toEqual(
|
expect.arrayContaining([expect.objectContaining({ value: 'ph-item' }), expect.objectContaining({ value: 'configured-text-item' })]),
|
);
|
});
|
|
it('ignores a pending item response after all sampling points are cleared', async () => {
|
const wrapper = mountPage();
|
await flushPromises();
|
const optionPopups = wrapper.findAllComponents(OptionPopupStub);
|
const tablePopups = wrapper.findAllComponents(TablePopupStub);
|
optionPopups[0]!.vm.$emit('update:value', 'water');
|
optionPopups[0]!.vm.$emit('change', 'water');
|
await flushPromises();
|
optionPopups[1]!.vm.$emit('update:value', 'workshop-1');
|
optionPopups[1]!.vm.$emit('change', 'workshop-1');
|
await flushPromises();
|
|
let resolveItems!: (value: unknown) => void;
|
apiMocks.getOptions.mockImplementationOnce(
|
() =>
|
new Promise((resolve) => {
|
resolveItems = resolve;
|
}),
|
);
|
tablePopups[0]!.vm.$emit('update:value', ['point-1']);
|
tablePopups[0]!.vm.$emit('change', ['point-1']);
|
await wrapper.vm.$nextTick();
|
tablePopups[0]!.vm.$emit('update:value', []);
|
tablePopups[0]!.vm.$emit('change', []);
|
|
resolveItems({
|
data: {
|
chejian_list: [{ id: 'workshop-1', name: '中针车间' }],
|
jianyan_xiangmu_list: [{ id: 'stale-item', name: '旧项目', trend_enabled: true, unit: '' }],
|
quyangdian_list: [],
|
yangpin_leixing_list: [{ id: 'water', name: '纯化水' }],
|
},
|
});
|
await flushPromises();
|
|
expect(wrapper.findAllComponents(TablePopupStub)[1]!.props('options')).toEqual([]);
|
});
|
|
it('clears a displayed chart when a query filter changes', async () => {
|
const wrapper = mountPage();
|
const dateRange = await selectRequiredFilters(wrapper);
|
|
await wrapper.find('.search-actions button').trigger('click');
|
await flushPromises();
|
expect(wrapper.find('.chart-block').exists()).toBe(true);
|
|
dateRange.vm.$emit('update:value', ['2026-08-01', '2026-08-31']);
|
await wrapper.vm.$nextTick();
|
|
expect(wrapper.find('.chart-block').exists()).toBe(false);
|
expect(wrapper.find('.empty-panel').text()).toContain('请选择筛选条件后搜索');
|
});
|
|
it('ignores a pending search response after a query filter changes', async () => {
|
let resolveData!: (value: unknown) => void;
|
apiMocks.getData.mockImplementationOnce(
|
() =>
|
new Promise((resolve) => {
|
resolveData = resolve;
|
}),
|
);
|
const wrapper = mountPage();
|
const dateRange = await selectRequiredFilters(wrapper);
|
|
await wrapper.find('.search-actions button').trigger('click');
|
dateRange.vm.$emit('update:value', ['2026-08-01', '2026-08-31']);
|
await wrapper.vm.$nextTick();
|
|
resolveData({
|
data: {
|
records: [
|
{
|
ceshi_jieguo: 7,
|
jianyan_xiang_id: 'inspection-1',
|
jianyan_riqi: '2026-07-01',
|
jianyan_xiangmu_id: 'ph-item',
|
quyangdian_id: 'point-1',
|
quyangdian_mingcheng: 'W-1',
|
renwu_jianyan_xiang_kuaizhao_id: 'snapshot-1',
|
},
|
],
|
standards: [
|
{
|
biaozhun_shangxian: 7.5,
|
biaozhun_xiaxian: 6.8,
|
jianyan_xiangmu_id: 'ph-item',
|
renwu_jianyan_xiang_kuaizhao_id: 'snapshot-1',
|
trend_enabled: true,
|
unit: 'pH',
|
},
|
],
|
},
|
});
|
await flushPromises();
|
|
expect(wrapper.find('.chart-block').exists()).toBe(false);
|
expect(wrapper.find('.empty-panel').text()).toContain('请选择筛选条件后搜索');
|
});
|
});
|