import { mount, shallowMount, createLocalVue } from '@vue/test-utils' import ElementUI from 'element-ui' import FieldSettings from '@/views/survey/components/SurveyFieldSettings.vue' import Editor from '@/views/survey/components/editPane.vue' import Question from '@/views/survey/components/SurveyQuestion.vue' import PreviewField from '@/views/survey/components/SurveyPreviewField.vue' import Description from '@/views/survey/components/SurveyDescription.vue' import Results from '@/views/survey/components/SurveyResultsDialog.vue' import { save } from '@/api/survey/index' import { statistics, show } from '@/api/survey/evaluationForm' jest.mock('@/api/survey/index', () => ({ save: jest.fn(() => Promise.resolve({ id: 1 })) })) jest.mock('@/api/survey/evaluationForm', () => ({ statistics: jest.fn(), index: jest.fn(), show: jest.fn(), textAnswers: jest.fn() })) const localVue = createLocalVue() localVue.use(ElementUI) const flush = () => new Promise((resolve) => setTimeout(resolve, 0)) describe('Survey editing and results', () => { afterEach(() => { jest.clearAllMocks() }) it('saves mixed dimensions with zero lower bound and stable option keys', async() => { const wrapper = shallowMount(Editor, { localVue, propsData: { question: { name: '资源对接', field: 'resource', edit_input: 'multi_dimension', dimensions: [ { name: '是否跟进', field: 'follow', select_item: [{ key: 'yes', value: '是' }], need_fill: true }, { name: '意向数量', field: 'count', edit_input: 'number', config: { integer: true, min: 0 }, need_fill: true } ] } } }) await wrapper.vm.save() const payload = save.mock.calls[0][0] expect(payload.dimensions[0].select_item[0].key).toBe('yes') expect(payload.dimensions[1].config.min).toBe(0) expect(payload.dimensions[1].edit_input).toBe('number') expect(payload.dimensions.every((d) => !d.need_fill && d.rule === '')).toBe( true ) expect(wrapper.emitted().saved).toBeTruthy() wrapper.destroy() }) it('keeps a cleared numeric maximum unlimited instead of defaulting to zero', () => { const field = { edit_input: 'number', config: { integer: true, min: 0, max: undefined } } const wrapper = mount( { render(h) { return h('el-form', [h(FieldSettings, { props: { field }})]) } }, { localVue } ) expect(field.config.max).toBeUndefined() expect(wrapper.findAll('input[type="number"]').at(1).element.value).toBe( '' ) wrapper.destroy() }) it('renders zero as an answer and chapter headings without inputs', () => { const wrapper = mount(Question, { localVue, propsData: { answered: true, question: { name: '数量', edit_input: 'number', display_value: '0' } } }) expect(wrapper.find('.answer').text()).toBe('0') wrapper.destroy() const section = mount(Question, { localVue, propsData: { question: { name: '课程评价', edit_input: 'section', help: '请选择评分' } } }) expect(section.findAll('input').length).toBe(0) expect(section.text()).toContain('请选择评分') section.destroy() }) it('shows score labels once and reveals selected supplementary input', async() => { const wrapper = mount(Question, { localVue, propsData: { question: { name: '评分', edit_input: 'radio', config: { is_score: true, other_key: 'custom' }, select_item: [{ key: 'custom', value: '10分', score: 10 }] } } }) expect(wrapper.text().match(/10分/g)).toHaveLength(1) wrapper.setData({ previewValue: 'custom' }) await wrapper.vm.$nextTick() expect( wrapper.find('textarea[placeholder="请填写补充说明"]').exists() ).toBe(true) wrapper.destroy() }) it('shows all reply options with selected radio and checkbox values read-only', () => { for (const type of ['radio', 'checkbox']) { const wrapper = mount(Question, { localVue, propsData: { answered: true, question: { name: '选择', edit_input: type, selected_keys: ['0'], display_value: '零分', select_item: [ { key: 0, value: '零分' }, { key: 'other', value: '其他' } ] } } }) expect(wrapper.findAll('input')).toHaveLength(2) expect(wrapper.findAll('input').at(0).element.checked).toBe(true) expect(wrapper.findAll('input').at(1).element.checked).toBe(false) expect( wrapper .findAll('input') .wrappers.every((input) => input.element.disabled) ).toBe(true) expect(wrapper.text()).toContain('学员选择:零分') expect(wrapper.text()).toContain('其他') wrapper.destroy() } const combo = mount(Question, { localVue, propsData: { answered: true, question: { name: '组合', edit_input: 'multi_dimension', dimensions: [ { field: 'intent', name: '意向', selected_keys: ['no'], display_value: '否', select_item: [ { key: 'yes', value: '是' }, { key: 'no', value: '否' } ] } ] } } }) expect(combo.findAll('input')).toHaveLength(2) expect(combo.findAll('input').at(1).element.checked).toBe(true) combo.destroy() }) it('uses wrapping scores and vertical ordinary choices for preview fields', () => { const score = mount(PreviewField, { localVue, propsData: { field: { edit_input: 'radio', config: { is_score: true }, select_item: [{ key: '5', value: '5分' }] } } }) expect(score.find('.scores').exists()).toBe(true) score.destroy() const ordinary = mount(PreviewField, { localVue, propsData: { field: { edit_input: 'radio', config: {}, select_item: [{ key: 'yes', value: '是' }] } } }) expect(ordinary.find('.scores').exists()).toBe(false) ordinary.destroy() const number = mount(PreviewField, { localVue, propsData: { field: { edit_input: 'number', config: { integer: true, min: 0 }} } }) expect(number.find('input').attributes('placeholder')).toBe('请输入数量') expect(number.text()).not.toContain('最小') number.destroy() }) it('renders rich descriptions safely and preserves plain text', () => { const rich = mount(Description, { propsData: { value: '
说明
历史问卷说明
' }, user: { name: '学员' }, questions: [ { id: 1, name: '历史题目', edit_input: 'number', display_value: '0' } ] }) const wrapper = mount(Results, { localVue, propsData: { visible: false, surveyData: { id: 10, title: '现在的标题' } } }) wrapper.setProps({ visible: true }) await flush() expect(statistics).toHaveBeenCalledWith({ course_content_evaluation_id: 10 }) expect(wrapper.text()).toContain('有效作答 2 人') await wrapper.vm.openReply({ id: 7 }) await flush() expect(wrapper.vm.reply.snapshot.title).toBe('提交时的标题') expect(document.body.querySelector('.reply .description strong').textContent).toBe('历史问卷说明') expect(wrapper.text()).not.toContain('') expect(wrapper.vm.reply.questions[0].display_value).toBe('0') wrapper.destroy() }) })