Browse Source
Cover the imperative AlertBuilder path (alert()/confirm()/clearAllAlerts) that issue #8052 reported: mouse click on the confirm button resolves the promise, mouse click on cancel or Escape rejects with 'dialog cancelled', and the mounted container is removed from the DOM afterwards. Verified separately: oxlint/oxfmt/eslint clean, popup-ui typecheck clean, vitest 7/7 passing. Full-repo checkType blocked by unrelated uncommitted apps/web-ele/src/__tests__/repro-8214.test.ts (8214 track work). Co-authored-by: EvoX <evox@evomap.ai>pull/8322/head
committed by
GitHub
1 changed files with 147 additions and 0 deletions
@ -0,0 +1,147 @@ |
|||
import { computed, nextTick } from 'vue'; |
|||
|
|||
import { afterEach, describe, expect, it, vi } from 'vitest'; |
|||
|
|||
import { alert, clearAllAlerts, confirm } from '../index'; |
|||
|
|||
vi.mock('@vben-core/composables', () => { |
|||
// Alert 组件内部使用函数调用 $t(key),AlertBuilder 使用 $t.value(key),
|
|||
// 因此同时支持两种调用方式。
|
|||
const $t = Object.assign((key: string) => key, { |
|||
value: (key: string) => key, |
|||
}); |
|||
return { |
|||
useScrollLock: () => |
|||
computed({ |
|||
get: () => false, |
|||
set: () => {}, |
|||
}), |
|||
useSimpleLocale: () => ({ $t }), |
|||
}; |
|||
}); |
|||
|
|||
vi.mock('@vben-core/preferences', () => ({ |
|||
usePreferences: () => ({ |
|||
globalEscapeShortcutKey: { value: true }, |
|||
}), |
|||
})); |
|||
|
|||
/** |
|||
* 在当前 document 中查找文案匹配的按钮。 |
|||
*/ |
|||
function findButtonByText(text: string) { |
|||
return [...document.querySelectorAll('button')].find( |
|||
(element) => element.textContent?.trim() === text, |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* 查找 AlertBuilder 挂载到 body 的容器元素(其内容包含指定文案)。 |
|||
*/ |
|||
function findAlertContainer(content: string) { |
|||
return [...document.body.children].find((element) => |
|||
element.textContent?.includes(content), |
|||
); |
|||
} |
|||
|
|||
afterEach(() => { |
|||
clearAllAlerts(); |
|||
document.body.innerHTML = ''; |
|||
vi.restoreAllMocks(); |
|||
}); |
|||
|
|||
describe('imperative alert builder (AlertBuilder)', () => { |
|||
it('resolves the promise when the confirm button is clicked on an imperative alert()', async () => { |
|||
const promise = alert({ |
|||
content: 'Alert content', |
|||
confirmText: 'Confirm', |
|||
}); |
|||
await nextTick(); |
|||
await nextTick(); |
|||
|
|||
const button = findButtonByText('Confirm'); |
|||
expect(button).toBeInstanceOf(HTMLElement); |
|||
if (!(button instanceof HTMLElement)) return; |
|||
const container = findAlertContainer('Alert content'); |
|||
expect(container).toBeInstanceOf(HTMLElement); |
|||
if (!container) return; |
|||
|
|||
button.dispatchEvent(new MouseEvent('click', { bubbles: true })); |
|||
await expect(promise).resolves.toBeUndefined(); |
|||
await nextTick(); |
|||
|
|||
// 容器与按钮应从 DOM 中移除,页面恢复到调用前的状态。
|
|||
expect(findButtonByText('Confirm')).toBeUndefined(); |
|||
expect(document.body.contains(container)).toBe(false); |
|||
}); |
|||
|
|||
it('rejects with dialog cancelled when the cancel button is clicked on an imperative confirm()', async () => { |
|||
const promise = confirm({ |
|||
content: 'Confirm content', |
|||
confirmText: 'Confirm', |
|||
cancelText: 'Cancel', |
|||
}); |
|||
await nextTick(); |
|||
await nextTick(); |
|||
|
|||
const cancelButton = findButtonByText('Cancel'); |
|||
expect(cancelButton).toBeInstanceOf(HTMLElement); |
|||
if (!(cancelButton instanceof HTMLElement)) return; |
|||
const container = findAlertContainer('Confirm content'); |
|||
expect(container).toBeInstanceOf(HTMLElement); |
|||
if (!container) return; |
|||
|
|||
cancelButton.dispatchEvent(new MouseEvent('click', { bubbles: true })); |
|||
await expect(promise).rejects.toThrow('dialog cancelled'); |
|||
await nextTick(); |
|||
|
|||
// 容器与按钮应从 DOM 中移除。
|
|||
expect(findButtonByText('Cancel')).toBeUndefined(); |
|||
expect(document.body.contains(container)).toBe(false); |
|||
}); |
|||
|
|||
it('rejects with dialog cancelled when Escape is pressed on an imperative alert()', async () => { |
|||
const promise = alert({ |
|||
content: 'Alert content', |
|||
confirmText: 'Confirm', |
|||
}); |
|||
await nextTick(); |
|||
await nextTick(); |
|||
|
|||
const container = findAlertContainer('Alert content'); |
|||
expect(container).toBeInstanceOf(HTMLElement); |
|||
if (!container) return; |
|||
|
|||
document.dispatchEvent( |
|||
new KeyboardEvent('keydown', { bubbles: true, key: 'Escape' }), |
|||
); |
|||
await expect(promise).rejects.toThrow('dialog cancelled'); |
|||
await nextTick(); |
|||
|
|||
expect(findButtonByText('Confirm')).toBeUndefined(); |
|||
expect(document.body.contains(container)).toBe(false); |
|||
}); |
|||
|
|||
it('removes every mounted container when clearAllAlerts is called', async () => { |
|||
alert({ content: 'First alert', confirmText: 'First confirm' }); |
|||
alert({ content: 'Second alert', confirmText: 'Second confirm' }); |
|||
await nextTick(); |
|||
await nextTick(); |
|||
|
|||
expect(findButtonByText('First confirm')).toBeInstanceOf(HTMLElement); |
|||
expect(findButtonByText('Second confirm')).toBeInstanceOf(HTMLElement); |
|||
const firstContainer = findAlertContainer('First alert'); |
|||
const secondContainer = findAlertContainer('Second alert'); |
|||
expect(firstContainer).toBeInstanceOf(HTMLElement); |
|||
expect(secondContainer).toBeInstanceOf(HTMLElement); |
|||
if (!firstContainer || !secondContainer) return; |
|||
|
|||
clearAllAlerts(); |
|||
await nextTick(); |
|||
|
|||
expect(findButtonByText('First confirm')).toBeUndefined(); |
|||
expect(findButtonByText('Second confirm')).toBeUndefined(); |
|||
expect(document.body.contains(firstContainer)).toBe(false); |
|||
expect(document.body.contains(secondContainer)).toBe(false); |
|||
}); |
|||
}); |
|||
Loading…
Reference in new issue