From 493a29c8621a11e3a0ce5f157fea2b69fa21b41f Mon Sep 17 00:00:00 2001 From: liaoxuezhi <2betop.cn@gmail.com> Date: Wed, 20 Dec 2023 14:42:57 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20dialog=20=E5=86=85?= =?UTF-8?q?=E9=83=A8=E5=81=9A=E5=B8=B8=E8=A7=84=E5=8A=A8=E4=BD=9C=E6=B2=A1?= =?UTF-8?q?=E5=8F=8D=E5=BA=94=E7=9A=84=E9=97=AE=E9=A2=98=20Close:=20#9149?= =?UTF-8?q?=20(#9167)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../amis/__tests__/renderers/Dialog.test.tsx | 193 ++++++++++++++++++ packages/amis/src/renderers/Dialog.tsx | 9 +- packages/amis/src/renderers/Drawer.tsx | 9 +- 3 files changed, 205 insertions(+), 6 deletions(-) create mode 100644 packages/amis/__tests__/renderers/Dialog.test.tsx diff --git a/packages/amis/__tests__/renderers/Dialog.test.tsx b/packages/amis/__tests__/renderers/Dialog.test.tsx new file mode 100644 index 000000000..a06dbb8a5 --- /dev/null +++ b/packages/amis/__tests__/renderers/Dialog.test.tsx @@ -0,0 +1,193 @@ +import { + cleanup, + fireEvent, + render, + waitFor, + screen +} from '@testing-library/react'; +import '../../src'; +import {clearStoresCache, render as amisRender} from '../../src'; +import {makeEnv as makeEnvRaw, replaceReactAriaIds, wait} from '../helper'; +import rows from '../mockData/rows'; +import type {RenderOptions} from '../../src'; + +afterEach(() => { + cleanup(); + clearStoresCache(); + jest.useRealTimers(); +}); + +/** 避免updateLocation里的console.error */ +const makeEnv = (env?: Partial) => + makeEnvRaw({updateLocation: () => {}, ...env}); + +/** + * https://github.com/baidu/amis/issues/1405 + * + * 验证弹窗的 CRUD 中再次弹出一个 crud,里面的 crud 确认关闭,不会关闭外面的 crud + */ +test('1. Renderer:dialog inner crud close outter crud component', async () => { + const {container, getByText} = render( + amisRender( + { + type: 'page', + body: { + type: 'button', + label: '第一层弹框', + actionType: 'dialog', + dialog: { + title: '第一层弹框标题', + body: [ + { + type: 'button', + label: '第二次弹框', + actionType: 'dialog', + dialog: { + title: '第二层弹框标题', + body: [ + { + type: 'tpl', + tpl: '对你点击了', + inline: false + }, + { + type: 'crud', + api: '', + columns: [ + { + name: 'id', + label: 'ID', + type: 'text' + }, + { + name: 'engine', + label: '渲染引擎', + type: 'text' + } + ] + }, + { + type: 'button', + label: '按钮', + actionType: 'dialog', + dialog: { + title: '系统提示', + body: '对你点击了' + } + } + ], + actions: [ + { + type: 'button', + label: '第二层确认', + actionType: 'submit' + } + ], + type: 'dialog' + }, + size: 'md', + level: 'primary' + }, + { + type: 'crud', + api: '', + columns: [ + { + name: 'id', + label: 'ID', + type: 'text' + }, + { + name: 'engine', + label: '渲染引擎', + type: 'text' + } + ] + } + ], + type: 'dialog' + }, + size: 'md', + level: 'primary' + } + }, + {}, + makeEnv({}) + ) + ); + + // events + fireEvent.click(getByText('第一层弹框')); + await wait(200); + + expect(getByText('第二次弹框')).toBeInTheDocument(); + fireEvent.click(getByText('第二次弹框')); + + await wait(200); + expect(getByText('第二层弹框标题')).toBeInTheDocument(); + + expect(getByText('第二层确认')).toBeInTheDocument(); + fireEvent.click(getByText('第二层确认')); + await wait(400); + + expect(getByText('第一层弹框标题')).toBeInTheDocument(); + // 还有第二次弹窗的按钮,说明第一层弹窗没有关闭 + expect(getByText('第二次弹框')).toBeInTheDocument(); +}); + +/** + * https://github.com/baidu/amis/issues/9149 + * + * 验证弹窗内部的 动作是通用动作时是否能正确响应。 + * + * 比如弹窗里面有个按钮是页面跳转,看是否执行了页面跳转 + */ +test('2. Renderer:dialog inner component with common action', async () => { + const jumpTo = jest.fn(); + const {container, getByText} = render( + amisRender( + { + type: 'page', + title: '表单页面', + body: [ + { + label: 'OpenADialog', + type: 'button', + actionType: 'dialog', + level: 'primary', + dialog: { + body: { + type: 'form', + api: 'post:/api/smart_lvct_boards/excel', + body: [ + { + label: '下载Excel模板', + type: 'action', + level: 'success', + actionType: 'url', + url: '/api/filedown/zhuban' + } + ] + } + } + } + ] + }, + {}, + makeEnv({ + jumpTo + }) + ) + ); + + // events + fireEvent.click(getByText('OpenADialog')); + await wait(200); + + expect(getByText('下载Excel模板')).toBeInTheDocument(); + fireEvent.click(getByText('下载Excel模板')); + await wait(400); + + expect(jumpTo).toBeCalledTimes(1); + expect(jumpTo.mock.calls[0][0]).toBe('/api/filedown/zhuban'); +}); diff --git a/packages/amis/src/renderers/Dialog.tsx b/packages/amis/src/renderers/Dialog.tsx index c94827033..e02dc7358 100644 --- a/packages/amis/src/renderers/Dialog.tsx +++ b/packages/amis/src/renderers/Dialog.tsx @@ -932,8 +932,10 @@ export class DialogRenderer extends Dialog { const {onAction, store, onConfirm, env, dispatchEvent, onClose} = this.props; if (action.from === this.$$id) { - // 可能是孩子又派送回来到自己了,这时候就不要处理了。 - return; + // 如果是从 children 里面委托过来的,那就直接向上冒泡。 + return onAction + ? onAction(e, action, data, throwErrors, delegate || this.context) + : false; } const scoped = this.context as IScopedContext; @@ -1021,7 +1023,8 @@ export class DialogRenderer extends Dialog { typeof action.close === 'string' && this.closeTarget(action.close); } - } else if (this.tryChildrenToHandle(action, data)) { + } else if (!action.from && this.tryChildrenToHandle(action, data)) { + // 如果有 from 了,说明是从子节点冒泡上来的,那就不再走让子节点处理的逻辑。 // do nothing } else if (action.actionType === 'ajax') { store.setCurrentAction(action); diff --git a/packages/amis/src/renderers/Drawer.tsx b/packages/amis/src/renderers/Drawer.tsx index 4075d12ec..0976b0811 100644 --- a/packages/amis/src/renderers/Drawer.tsx +++ b/packages/amis/src/renderers/Drawer.tsx @@ -882,8 +882,10 @@ export class DrawerRenderer extends Drawer { const {onClose, onAction, store, env, dispatchEvent} = this.props; if (action.from === this.$$id) { - // 可能是孩子又派送回来到自己了,这时候就不要处理了。 - return; + // 如果是从 children 里面委托过来的,那就直接向上冒泡。 + return onAction + ? onAction(e, action, data, throwErrors, delegate || this.context) + : false; } const scoped = this.context as IScopedContext; @@ -933,7 +935,8 @@ export class DrawerRenderer extends Drawer { ? this.handleSelfClose() : this.closeTarget(action.close); } - } else if (this.tryChildrenToHandle(action, data)) { + } else if (!action.from && this.tryChildrenToHandle(action, data)) { + // 如果有 from 了,说明是从子节点冒泡上来的,那就不再走让子节点处理的逻辑。 // do nothing } else if (action.actionType === 'ajax') { store.setCurrentAction(action);