diff --git a/src/dialog/__tests__/dialog.test.tsx b/src/dialog/__tests__/dialog.test.tsx new file mode 100644 index 000000000..e13f087c7 --- /dev/null +++ b/src/dialog/__tests__/dialog.test.tsx @@ -0,0 +1,322 @@ +import React, { act } from 'react'; +import { render, screen, fireEvent, vi, it, describe, expect, afterEach, beforeEach, cleanup } from '@test/utils'; +import Button from 'tdesign-mobile-react/button/Button'; +import { DialogPlugin, Dialog } from '../index'; + +const prefix = 't'; +const name = `.${prefix}-dialog`; + +describe('Dialog', () => { + beforeEach(() => { + vi.useFakeTimers(); + }); + + afterEach(() => { + cleanup(); + const overlays = document.querySelectorAll('.t-overlay'); + const popups = document.querySelectorAll('.t-popup'); + const dialogs = document.querySelectorAll('.t-dialog'); + + overlays.forEach((overlay) => overlay.remove()); + popups.forEach((popup) => popup.remove()); + dialogs.forEach((dialog) => dialog.remove()); + vi.useRealTimers(); + }); + + describe('props', () => { + it(': visible', async () => { + const { rerender } = render(); + expect(document.querySelector(name)).toBeInTheDocument(); + + rerender(); + await act(async () => { + vi.advanceTimersByTime(300); + }); + expect(document.querySelector('.t-popup')).toHaveStyle({ display: 'none' }); + }); + + it(': title', () => { + render(); + expect(document.querySelector(`${name}__header`).textContent).toBe('标题'); + }); + + it(': content', () => { + render(); + expect(document.querySelector(`${name}__content`).textContent).toBe('中间内容'); + }); + + it(': middle', () => { + render(自定义内容} />); + expect(document.querySelector('.custom-middle')).toBeInTheDocument(); + }); + + it(': top', () => { + render(自定义顶部内容} />); + expect(document.querySelector('.custom-top')).toBeInTheDocument(); + }); + + it(': destroyOnClose', () => { + render(); + expect(document.querySelector(name)).not.toBeNull(); + }); + + it(': overlayProps', async () => { + const backgroundColor = 'rgba(0, 0, 0, 0.5)'; + render(); + await act(async () => { + vi.advanceTimersByTime(1000); + }); + const overlay = document.querySelector('.t-overlay'); + expect(overlay).toHaveStyle(`background-color: ${backgroundColor}`); + }); + + it(': preventScrollThrough', () => { + render(); + const classNames = document.body.className; + expect(classNames).toBe('t-overlay--lock'); + }); + + it(': showOverlay', () => { + render(); + expect(document.querySelector('.t-overlay')).toBeFalsy(); + }); + + it(': buttonLayout', () => { + const confirmBtn = { + content: '确认', + variant: 'text' as const, + size: 'large' as const, + }; + const cancelBtn = () => ]} + onClose={onClose} + />, + ); + fireEvent.click(document.querySelector('.test-btn')); + expect(onClose).toHaveBeenCalled(); + + rerender(); + const footer = document.querySelector(`${name}__footer`); + expect(footer).toBeTruthy(); + + rerender(); + expect(document.querySelector(`${name}__footer`)).toBeTruthy(); + }); + + it(': closeBtn', () => { + render(); + expect(document.querySelector(`${name}__close-btn`)).toBeTruthy(); + }); + + it(': zIndex', () => { + render(); + expect(document.querySelector('.t-popup')).toBeTruthy(); + }); + + it(': width', () => { + const { rerender } = render(); + expect(document.querySelector(name)).toHaveStyle('width: 300px'); + + rerender(); + expect(document.querySelector(name)).toHaveStyle('width: 400px'); + }); + + it(': closeOnOverlayClick', async () => { + const onClose = vi.fn(); + render(); + const overlay = document.querySelector('.t-overlay'); + fireEvent.click(overlay); + await act(async () => { + vi.advanceTimersByTime(1000); + }); + expect(onClose).toHaveBeenCalledTimes(1); + }); + }); + + describe('plugin', () => { + it(': show', async () => { + let instance = null; + const onClose = vi.fn(); + const onConfirm = vi.fn(); + const onClosed = vi.fn(); + await act(async () => { + instance = DialogPlugin({ + title: '标题', + visible: false, + closeBtn: true, + content: '中间内容', + confirmBtn: { + content: '确定', + className: 'confirm-btn', + }, + cancelBtn: { + content: '取消', + className: 'cancel-btn', + }, + onClose, + onConfirm, + onClosed, + }); + }); + instance.show(); + const diaog = document.querySelector(name); + expect(diaog).toBeTruthy(); + + const closeBtn = document.querySelector('.t-icon'); + const confirmBtn = document.querySelector('.confirm-btn'); + const cancelBtn = document.querySelector('.cancel-btn'); + await act(async () => { + fireEvent.click(closeBtn); + fireEvent.click(confirmBtn); + fireEvent.click(cancelBtn); + }); + expect(onClose).toHaveBeenCalled(); + expect(onConfirm).toHaveBeenCalled(); + await act(async () => { + await vi.advanceTimersByTime(1000); + }); + expect(onClosed).toHaveBeenCalled(); + }); + + it(': hide', async () => { + let instance = null; + const onClosed = vi.fn(); + await act(async () => { + instance = DialogPlugin({ + title: '标题', + onClosed, + }); + }); + instance.hide(); + + setTimeout(() => { + expect(document.querySelector(name)).toBeFalsy(); + expect(onClosed).toHaveBeenCalled(); + }, 1000); + }); + + it(': update', async () => { + let instance = null; + await act(async () => { + instance = DialogPlugin({ + title: '标题', + onConfirm: vi.fn(), + onCancel: vi.fn(), + }); + }); + instance.update({ title: '新标题' }); + setInterval(() => { + expect(document.querySelector(`${name}__header`).textContent).toBe('新标题'); + }, 1000); + }); + + it(': destroy', async () => { + let instance = null; + await act(async () => { + instance = DialogPlugin({ + title: '标题', + }); + }); + instance.destroy(); + await act(async () => { + vi.advanceTimersByTime(1000); + }); + expect(document.querySelector(name)).toBeFalsy(); + }); + + it(': alert', async () => { + await act(async () => { + Dialog.alert({ + title: '标题', + content: '内容', + }); + }); + + await act(async () => { + vi.advanceTimersByTime(1000); + }); + expect(document.querySelector(`${name}__header`)).toBeTruthy(); + }); + + it(': confirm', async () => { + await act(async () => { + Dialog.confirm({ + title: '标题', + content: '内容', + onConfirm: vi.fn(), + }); + }); + expect(document.querySelector(`${name}__header`)).toBeTruthy(); + }); + }); + + describe('event', () => { + it(': onCancel', () => { + const onCancel = vi.fn(); + const onClose = vi.fn(); + const { rerender } = render(); + fireEvent.click(screen.getByText('退出')); + expect(onCancel).toHaveBeenCalled(); + expect(onClose).toHaveBeenCalled(); + + rerender(); + fireEvent.click(screen.getByText('退出')); + }); + + it(': onClose', async () => { + const onClose = vi.fn(); + render(); + const closeBtn = document.querySelector('.t-icon'); + fireEvent.click(closeBtn); + setTimeout(() => { + expect(onClose).toHaveBeenCalled(); + expect(document.querySelector(name)).toBeFalsy(); + }, 1000); + }); + + it(': onClosed', async () => { + const onClosed = vi.fn(); + const { rerender } = render(); + rerender(); + await act(async () => { + vi.advanceTimersByTime(1000); + }); + expect(onClosed).toHaveBeenCalled(); + }); + + it(': onConfirm', () => { + const onConfirm = vi.fn(); + const { rerender } = render(); + fireEvent.click(screen.getByText('下一步')); + expect(onConfirm).toHaveBeenCalled(); + + rerender(); + fireEvent.click(screen.getByText('下一步')); + }); + + it(': onOverlayClick', async () => { + const onOverlayClick = vi.fn(); + render(); + const overlay = document.querySelector('.t-overlay'); + fireEvent.click(overlay); + await act(async () => { + vi.advanceTimersByTime(1000); + }); + expect(onOverlayClick).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/dialog/_example/confirm.tsx b/src/dialog/_example/confirm.tsx index 01de7c1d0..2284117a2 100644 --- a/src/dialog/_example/confirm.tsx +++ b/src/dialog/_example/confirm.tsx @@ -42,7 +42,32 @@ const ConfirmUsage = React.memo(() => { > 确认类-无标题 - + { + setAlertProps({ ...alertProps, visible: false }); + }} + onConfirm={() => { + setAlertProps({ ...alertProps, visible: false }); + }} + /> +
+ { diff --git a/src/dialog/_example/feedback.tsx b/src/dialog/_example/feedback.tsx index abeacd42a..c05f2b540 100644 --- a/src/dialog/_example/feedback.tsx +++ b/src/dialog/_example/feedback.tsx @@ -21,7 +21,7 @@ const Feedback = React.memo(() => { }); }} > - 反馈类-基础 + 反馈类-带标题
+ +
+
+ +
+ +
+
+ + { + setAlertProps({ ...alertProps, visible: false }); + }} + onConfirm={() => { + setAlertProps({ ...alertProps, visible: false }); + }} + /> +
+ - + - + {/* - + */} ); } diff --git a/src/dialog/_example/multi-state.tsx b/src/dialog/_example/multi-state.tsx index e5714e177..13a84b429 100644 --- a/src/dialog/_example/multi-state.tsx +++ b/src/dialog/_example/multi-state.tsx @@ -36,6 +36,8 @@ const MultiStateUsage = React.memo(() => { 文字按钮
+
水平基础按钮
+
+
垂直基础按钮
+
- +
带关闭按钮的对话框
); return { - hide: ref.current?.hide, - show: ref.current?.show, - update: ref.current?.update, - destroy, + hide: () => ref.current?.hide(), + show: () => ref.current?.show(), + update: (opts: DialogShowProps) => ref.current?.update(opts), + destroy: () => ref.current?.destroy(), }; } diff --git a/test/snap/__snapshots__/csr.test.jsx.snap b/test/snap/__snapshots__/csr.test.jsx.snap index b718f4356..25abd93c4 100644 --- a/test/snap/__snapshots__/csr.test.jsx.snap +++ b/test/snap/__snapshots__/csr.test.jsx.snap @@ -44983,6 +44983,35 @@ exports[`csr snapshot test > csr test src/dialog/_example/confirm.tsx 1`] = ` /> +
+ + `; @@ -45000,7 +45029,7 @@ exports[`csr snapshot test > csr test src/dialog/_example/feedback.tsx 1`] = ` class="t-button__content" > - 反馈类-基础 + 反馈类-带标题
csr test src/dialog/_example/feedback.tsx 1`] = `
+ +
csr test src/dialog/_example/image-dialog.tsx 1`] = class="t-button__content" > - 图片居中 + 图片置顶-无标题 + + +
+ +
+ +
+ +