81 lines
3.7 KiB
TypeScript
81 lines
3.7 KiB
TypeScript
import { readFileSync } from 'node:fs'
|
|
import { fileURLToPath } from 'node:url'
|
|
import { mount } from '@vue/test-utils'
|
|
import { describe, expect, it } from 'vitest'
|
|
import MessageComposerDialog from './components/MessageComposerDialog.vue'
|
|
import TemplateEditorDialog from './components/TemplateEditorDialog.vue'
|
|
|
|
const source = (path: string) => readFileSync(fileURLToPath(new URL(path, import.meta.url)), 'utf8')
|
|
|
|
const dialogStubs = {
|
|
AppDialog: { props: ['width'], template: '<div class="dialog" :data-width="width"><slot /><slot name="footer" :close="() => {}" /></div>' },
|
|
ApiErrorMeta: true,
|
|
PlatformTenantSelector: true,
|
|
'el-alert': true,
|
|
'el-form': { template: '<form><slot /></form>' },
|
|
'el-form-item': { template: '<label><slot /></label>' },
|
|
'el-segmented': true,
|
|
'el-select': { template: '<select><slot /></select>' },
|
|
'el-option': true,
|
|
'el-input': true,
|
|
'el-switch': true,
|
|
'el-date-picker': true,
|
|
'el-button': { props: ['disabled'], template: '<button :disabled="disabled"><slot /></button>' },
|
|
}
|
|
|
|
describe('notification center contract UI', () => {
|
|
it.each([
|
|
'./pages/MessageManagementView.vue',
|
|
'./pages/MessageTemplatesView.vue',
|
|
])('keeps actions as the first table column in %s', (path) => {
|
|
const content = source(path)
|
|
expect(content).toMatch(/const columns:[^=]+\s*=\s*\[\{key:'actions',label:'操作'/)
|
|
})
|
|
|
|
it('does not expose unsupported clear-read or disabled-template restore actions', () => {
|
|
const templates = source('./pages/MessageTemplatesView.vue')
|
|
expect(templates).toContain("status!=='DISABLED'")
|
|
expect(templates).toContain("status==='DRAFT'?'激活':'禁用'")
|
|
})
|
|
|
|
it('exposes read-only task delivery evidence behind the task list contract', () => {
|
|
const management = source('./pages/MessageManagementView.vue')
|
|
expect(management).toContain('getTask(row.id)')
|
|
expect(management).toContain('消息任务详情')
|
|
expect(management).toContain('任务失败原因')
|
|
expect(management).toContain('收件人投递明细')
|
|
expect(management).toContain('failureReason')
|
|
expect(management).toContain('notificationCategoryLabel((row as NotificationTask).category)')
|
|
expect(management).toContain('notificationCategoryLabel(detail.category)')
|
|
expect(management).toContain('notificationAppLabel(row.appCode)')
|
|
expect(management).toContain('notificationRecipientStatusLabel(row.status)')
|
|
})
|
|
|
|
it('uses the prototype composer width and exposes the real send command', () => {
|
|
const wrapper = mount(MessageComposerDialog, {
|
|
props: { modelValue: true, templates: [] },
|
|
global: { stubs: dialogStubs },
|
|
})
|
|
expect(wrapper.get('.dialog').attributes('data-width')).toContain('680px')
|
|
expect(wrapper.findAll('button').some((button) => button.text() === '立即发送' && !button.attributes('disabled'))).toBe(true)
|
|
expect(wrapper.text()).not.toContain('存为草稿')
|
|
})
|
|
|
|
it('keeps the scheduled-send switch actionable and clears its date when disabled', () => {
|
|
const composer = source('./components/MessageComposerDialog.vue')
|
|
expect(composer).toContain('if (value && !form.scheduledAt)')
|
|
expect(composer).toContain('if (!value) form.scheduledAt = \'\'')
|
|
expect(composer).toContain('Date.now() + 5 * 60 * 1000')
|
|
})
|
|
|
|
it('uses the prototype editor width and exposes the real save command', () => {
|
|
const wrapper = mount(TemplateEditorDialog, {
|
|
props: { modelValue: true },
|
|
global: { stubs: dialogStubs },
|
|
})
|
|
expect(wrapper.get('.dialog').attributes('data-width')).toContain('760px')
|
|
const save = wrapper.findAll('button').find((button) => button.text() === '保存模板')
|
|
expect(save?.attributes('disabled')).toBeUndefined()
|
|
})
|
|
})
|