You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
288 lines
9.0 KiB
288 lines
9.0 KiB
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:
|
|
'<p style="text-indent:2em"><strong>说明</strong><img src="/a.png" onerror="alert(1)"><script>alert(1)</script></p>'
|
|
}
|
|
})
|
|
expect(rich.find('strong').text()).toBe('说明')
|
|
expect(rich.find('p').element.style.textIndent).toBe('2em')
|
|
expect(rich.find('script').exists()).toBe(false)
|
|
expect(rich.find('img').attributes('onerror')).toBeUndefined()
|
|
rich.destroy()
|
|
const plain = mount(Description, {
|
|
propsData: { value: '第一行\n第二行' }
|
|
})
|
|
expect(plain.text()).toContain('第一行\n第二行')
|
|
plain.destroy()
|
|
})
|
|
it('loads real statistics and the server reply snapshot', async() => {
|
|
statistics.mockResolvedValue({
|
|
responses: 2,
|
|
questions_count: 1,
|
|
average: 4,
|
|
questions: [
|
|
{
|
|
id: 1,
|
|
name: '满意度',
|
|
edit_input: 'radio',
|
|
stats: {
|
|
valid_count: 2,
|
|
average: 4,
|
|
other_count: 0,
|
|
options: [{ label: '满意', count: 2, percentage: 100 }]
|
|
}
|
|
}
|
|
]
|
|
})
|
|
show.mockResolvedValue({
|
|
id: 7,
|
|
snapshot: {
|
|
title: '提交时的标题',
|
|
desc: '<p><strong>历史问卷说明</strong></p>'
|
|
},
|
|
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('<strong>')
|
|
expect(wrapper.vm.reply.questions[0].display_value).toBe('0')
|
|
wrapper.destroy()
|
|
})
|
|
})
|