新增: 全局对话框服务 AppDialog,Promise 风格 appAlert/appConfirm/appPrompt 替代原生弹窗

This commit is contained in:
lxy
2026-08-25 12:30:12 +08:00
parent 0907a104cf
commit 8eef4606c5
9 changed files with 253 additions and 25 deletions
+66
View File
@@ -0,0 +1,66 @@
/* dialog.test.ts — 全局对话框服务与宿主组件闭环验证(Teleport 后从 document 查询) */
import { describe, it, expect } from 'vitest'
import { mount, flushPromises } from '@vue/test-utils'
import AppDialog from '../src/components/common/AppDialog.vue'
import { appAlert, appConfirm, appPrompt, dialogState, resolveDialog } from '../src/core/dialog'
/** 触发 body 上(Teleport)按钮点击 */
function clickBtn(idx: number) {
const btns = document.body.querySelectorAll('.modal-actions button')
;(btns[idx] as HTMLElement).click()
}
describe('dialog 服务 + AppDialog 宿主', () => {
it('appPrompt 打开对话框 → 输入值提交', async () => {
const wrapper = mount(AppDialog, { attachTo: document.body })
const p = appPrompt('生成整套', { placeholder: '主题' })
await flushPromises()
expect(dialogState.open.value).toBe(true)
const input = document.body.querySelector('.modal-mask input') as HTMLInputElement
expect(input).not.toBeNull()
input.value = '远程办公'
input.dispatchEvent(new Event('input'))
await flushPromises()
clickBtn(1) // 确定
await expect(p).resolves.toBe('远程办公')
expect(dialogState.open.value).toBe(false)
wrapper.unmount()
})
it('appConfirm 取消 → false;确定 → true', async () => {
const wrapper = mount(AppDialog, { attachTo: document.body })
const p1 = appConfirm('删除?', '不可恢复', { danger: true })
await flushPromises()
clickBtn(0) // 取消
await expect(p1).resolves.toBe(false)
const p2 = appConfirm('删除?')
await flushPromises()
clickBtn(1) // 确定
await expect(p2).resolves.toBe(true)
wrapper.unmount()
})
it('appAlert 无输入框,单按钮关闭', async () => {
const wrapper = mount(AppDialog, { attachTo: document.body })
const p = appAlert('提示', '内容')
await flushPromises()
expect(document.body.querySelector('.modal-mask input')).toBeNull()
expect(document.body.querySelectorAll('.modal-actions button').length).toBe(1)
clickBtn(0)
await expect(p).resolves.toEqual({ ok: true, value: '' })
wrapper.unmount()
})
it('对话框 DOM 挂到 bodyTeleport)且带 modal-mask/modal 类', async () => {
const wrapper = mount(AppDialog, { attachTo: document.body })
appAlert('标题')
await flushPromises()
const mask = document.body.querySelector('.modal-mask')
expect(mask).not.toBeNull()
expect(mask!.querySelector('.modal')).not.toBeNull()
resolveDialog({ ok: true, value: '' })
await flushPromises()
wrapper.unmount()
})
})