From c84644b3bd7aff276327005845af32f9aac0dbf6 Mon Sep 17 00:00:00 2001 From: liaoxuezhi <2betop.cn@gmail.com> Date: Mon, 10 Jul 2023 10:32:38 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dcrud=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E4=B8=AD=E7=9A=84=E5=80=BC=E5=9B=9E=E6=98=BE?= =?UTF-8?q?=E9=97=AE=E9=A2=98,=E5=8F=AA=E5=9B=9E=E6=98=BE=20query=20?= =?UTF-8?q?=E9=83=A8=E5=88=86=20Close:=20#7274=20(#7418)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__tests__/renderers/CRUDfilter.test.tsx | 315 ++++++++++++++++++ packages/amis/src/renderers/CRUD.tsx | 3 +- packages/amis/src/renderers/Table/index.tsx | 9 +- 3 files changed, 324 insertions(+), 3 deletions(-) create mode 100644 packages/amis/__tests__/renderers/CRUDfilter.test.tsx diff --git a/packages/amis/__tests__/renderers/CRUDfilter.test.tsx b/packages/amis/__tests__/renderers/CRUDfilter.test.tsx new file mode 100644 index 000000000..2de686295 --- /dev/null +++ b/packages/amis/__tests__/renderers/CRUDfilter.test.tsx @@ -0,0 +1,315 @@ +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}); + +// 主要用来验证是否可以回显正确,如果外部存在同名变量是否不影响 filter +test('CRUD filter1', async () => { + const mockFetcher = jest.fn().mockImplementation((api: any) => { + return Promise.resolve({ + data: { + status: 0, + data: { + items: [{id: 1, a: 'a1', b: 'b1'}] + } + } + }); + }); + const {container} = render( + amisRender( + { + type: 'page', + data: {b: '2'}, + body: { + type: 'crud', + api: '/api/mock2/sample', + filter: { + body: [ + { + type: 'input-text', + name: 'a' + }, + { + type: 'input-text', + name: 'b' + } + ] + }, + columns: [ + { + name: 'id', + label: 'ID' + }, + { + name: 'a', + label: 'A' + }, + { + name: 'b', + label: 'B' + } + ] + } + }, + { + location: { + pathname: '/mock2/sample', + search: '?a=1', + query: '' + } as any + }, + makeEnv({fetcher: mockFetcher}) + ) + ); + await wait(200); + const a = container.querySelector('input[name="a"]')!; + const b = container.querySelector('input[name="b"]')!; + expect(a).toBeTruthy(); + expect(a.nodeValue).not.toBe('1'); + + // 因为数据不在 query 里面,所以不显示是正常的 + expect(b).toBeTruthy(); + expect(b.nodeValue).not.toBe(''); +}); + +// 验证 autoGenerateFilter 模式是否表现一致 +test('CRUD filter2', async () => { + const mockFetcher = jest.fn().mockImplementation((api: any) => { + return Promise.resolve({ + data: { + status: 0, + data: { + items: [{id: 1, a: 'a1', b: 'b1'}] + } + } + }); + }); + const {container} = render( + amisRender( + { + type: 'page', + data: {b: '2'}, + body: { + type: 'crud', + api: '/api/mock2/sample', + autoGenerateFilter: true, + columns: [ + { + name: 'id', + label: 'ID' + }, + { + name: 'a', + searchable: true, + label: 'A' + }, + { + name: 'b', + searchable: true, + label: 'B' + } + ] + } + }, + { + location: { + pathname: '/mock2/sample', + search: '?a=1', + query: '' + } as any + }, + makeEnv({fetcher: mockFetcher}) + ) + ); + await wait(200); + const a = container.querySelector('input[name="a"]')!; + const b = container.querySelector('input[name="b"]')!; + expect(a).toBeTruthy(); + expect(a.nodeValue).not.toBe('1'); + + // 因为数据不在 query 里面,所以不显示是正常的 + expect(b).toBeTruthy(); + expect(b.nodeValue).not.toBe(''); +}); + +// picker 的话,不应该回显任何数据 +test('Picker filter1', async () => { + const mockFetcher = jest.fn().mockImplementation((api: any) => { + return Promise.resolve({ + data: { + status: 0, + data: { + items: [{id: 1, a: 'a1', b: 'b1'}] + } + } + }); + }); + const {container} = render( + amisRender( + { + type: 'page', + data: {b: '2'}, + body: { + type: 'form', + body: [ + { + type: 'picker', + name: 'xxx', + source: '/api/mock2/sample', + pickerSchema: { + type: 'crud', + filter: { + body: [ + { + type: 'input-text', + name: 'a' + }, + { + type: 'input-text', + name: 'b' + } + ] + }, + columns: [ + { + name: 'id', + label: 'ID' + }, + { + name: 'a', + label: 'A' + }, + { + name: 'b', + label: 'B' + } + ] + } + } + ] + } + }, + { + location: { + pathname: '/mock2/sample', + search: '?a=1', + query: '' + } as any + }, + makeEnv({fetcher: mockFetcher, getModalContainer: () => container} as any) + ) + ); + await wait(200); + const pickerBtn = container.querySelector('span.cxd-Picker-btn')!; + expect(pickerBtn).toBeTruthy(); + + fireEvent.click(pickerBtn); + + await wait(500); + const a = container.querySelector('input[name="a"]')!; + const b = container.querySelector('input[name="b"]')!; + + // picker 里面不应该自动回显任何数据 + expect(a).toBeTruthy(); + expect(a.nodeValue).not.toBe(''); + + // picker 里面不应该自动回显任何数据 + expect(b).toBeTruthy(); + expect(b.nodeValue).not.toBe(''); +}); + +// picker 的话,不应该回显任何数据 +// autoGenerateFilter 模式也一样 +test('Picker filter2', async () => { + const mockFetcher = jest.fn().mockImplementation((api: any) => { + return Promise.resolve({ + data: { + status: 0, + data: { + items: [{id: 1, a: 'a1', b: 'b1'}] + } + } + }); + }); + const {container} = render( + amisRender( + { + type: 'page', + data: {b: '2'}, + body: { + type: 'form', + body: [ + { + type: 'picker', + name: 'xxx', + source: '/api/mock2/sample', + pickerSchema: { + type: 'crud', + autoGenerateFilter: true, + columns: [ + { + name: 'id', + label: 'ID' + }, + { + name: 'a', + label: 'A', + searchable: true + }, + { + name: 'b', + label: 'B', + searchable: true + } + ] + } + } + ] + } + }, + { + location: { + pathname: '/mock2/sample', + search: '?a=1', + query: '' + } as any + }, + makeEnv({fetcher: mockFetcher, getModalContainer: () => container} as any) + ) + ); + await wait(200); + const pickerBtn = container.querySelector('span.cxd-Picker-btn')!; + expect(pickerBtn).toBeTruthy(); + + fireEvent.click(pickerBtn); + + await wait(500); + const a = container.querySelector('input[name="a"]')!; + const b = container.querySelector('input[name="b"]')!; + + // picker 里面不应该自动回显任何数据 + expect(a).toBeTruthy(); + expect(a.nodeValue).not.toBe(''); + + // picker 里面不应该自动回显任何数据 + expect(b).toBeTruthy(); + expect(b.nodeValue).not.toBe(''); +}); diff --git a/packages/amis/src/renderers/CRUD.tsx b/packages/amis/src/renderers/CRUD.tsx index 5468ee196..85c1f3ce7 100644 --- a/packages/amis/src/renderers/CRUD.tsx +++ b/packages/amis/src/renderers/CRUD.tsx @@ -2344,7 +2344,8 @@ export default class CRUD extends React.Component { onReset: this.handleFilterReset, onSubmit: this.handleFilterSubmit, onInit: this.handleFilterInit, - formStore: undefined + formStore: undefined, + canAccessSuperData: false } ) : null} diff --git a/packages/amis/src/renderers/Table/index.tsx b/packages/amis/src/renderers/Table/index.tsx index 240d0d31c..7965bdc6d 100644 --- a/packages/amis/src/renderers/Table/index.tsx +++ b/packages/amis/src/renderers/Table/index.tsx @@ -1728,7 +1728,9 @@ export default class Table extends React.Component { onSearchableFromInit, classnames: cx, autoGenerateFilter, - translate: __ + translate: __, + query, + data } = this.props; const {columnsNum, showBtnToolbar} = typeof autoGenerateFilter === 'boolean' @@ -1796,6 +1798,7 @@ export default class Table extends React.Component { mode: 'horizontal', submitText: __('search'), body: body, + canAccessSuperData: false, actions: [ { type: 'dropdown-button', @@ -1814,6 +1817,7 @@ export default class Table extends React.Component { name: `__search_${column.searchable?.name ?? column.name}`, option: column.searchable?.label ?? column.label, value: column.enableSearch, + label: false, badge: { offset: [-10, 5], visibleOn: `${ @@ -1866,7 +1870,8 @@ export default class Table extends React.Component { onReset: onSearchableFromReset, onSubmit: onSearchableFromSubmit, onInit: onSearchableFromInit, - formStore: undefined + formStore: undefined, + data: query ? createObject(data, query) : data } ); }