From 3b7c1345cc8b9a19d497735944d425195f63719e Mon Sep 17 00:00:00 2001 From: Zeke Zhang <958414905@qq.com> Date: Wed, 13 Dec 2023 14:14:33 +0800 Subject: [PATCH] test(e2e): add tests for client (#3144) * test: add tests for lazy loading of association fields * refactor: migrate * test: add tests for page * test: add tests for page menu * test: add tests for tabs * test: add tests for detail block * test: add tests for list block * test: add tests for grid card block * test: add tests for filter collapse block * test: add tests for markdown block * test: add tests for table block * test: add tests for table block * test: add tests for lazy loading of association fields * test: add tests for data scope * test: add tests for filter block * test: add tests for block template * test: add tests for drag and sorting * test: add tests for sorting rules * test: make testing more stable * Revert "test: make testing more stable" This reverts commit 78b7badeb65bfc603fb746efbdb8e242a763ae6a. * perf: remove enableToConfig * test: make testing more stable * test: make testing more stable * test: delete newly created records to make tests more stable * fix: fix error when deleting records * test: make testing more stable * test: make testing more stable * test: fix tests * refactor: optimize file structure * test: fix tests * test: fix tests * refactor: optimize description * refactor: optimize description * refactor: use __e2e__ as the root directory for test files * fix: fix build * test: make testing more stable --- .eslintrc | 3 +- packages/core/build/src/buildDeclaration.ts | 4 +- packages/core/build/src/constant.ts | 1 + .../client/src/__tests__/e2e/action.test.ts | 338 - .../client/src/__tests__/e2e/block.test.ts | 561 -- .../src/__tests__/e2e/bugs/T-2165.test.ts | 292 - .../src/__tests__/e2e/bugs/T-2174.test.ts | 583 -- .../src/__tests__/e2e/bugs/T-2176.test.ts | 227 - .../src/__tests__/e2e/bugs/T-2183.test.ts | 178 - .../src/__tests__/e2e/bugs/T-2186.test.ts | 173 - .../src/__tests__/e2e/bugs/T-2200.test.ts | 370 - .../src/__tests__/e2e/checkTableRow.test.ts | 232 - .../__tests__/e2e/createCollections.test.ts | 264 - .../src/__tests__/e2e/createDataBlock.test.ts | 54 - .../client/src/__tests__/e2e/field.test.ts | 332 - .../__tests__/e2e/loadAssociationData.test.ts | 66 - .../client/src/__tests__/e2e/menu.test.ts | 212 - .../client/src/__tests__/e2e/mock.test.ts | 196 - .../client/src/__tests__/e2e/page.test.ts | 178 - .../src/__tests__/e2e/pageSchema.test.ts | 462 -- .../associationFields.test.ts | 103 - .../e2e/schemaInitializer/pageGrid.test.ts | 49 - .../e2e/schemaInitializer/pageTabs.test.ts | 15 - .../__tests__/e2e/schemaInitializer/utils.ts | 21 - .../schemaSettings/actions/addChild.test.ts | 38 - .../e2e/schemaSettings/actions/addNew.test.ts | 86 - .../schemaSettings/actions/addRecord.test.ts | 19 - .../schemaSettings/actions/bulkDelete.test.ts | 17 - .../e2e/schemaSettings/actions/delete.test.ts | 35 - .../schemaSettings/actions/duplicate.test.ts | 21 - .../e2e/schemaSettings/actions/edit.test.ts | 21 - .../schemaSettings/actions/expectOptions.ts | 8 - .../e2e/schemaSettings/actions/filter.test.ts | 30 - .../e2e/schemaSettings/actions/popup.test.ts | 38 - .../schemaSettings/actions/refresh.test.ts | 17 - .../schemaSettings/actions/saveRecord.test.ts | 25 - .../e2e/schemaSettings/actions/submit.test.ts | 17 - .../actions/updateRecord.test.ts | 38 - .../e2e/schemaSettings/actions/view.test.ts | 21 - .../e2e/schemaSettings/formBlock.test.ts | 286 - .../schemaSettings/formDataTemplates.test.ts | 94 - .../e2e/schemaSettings/linkageRules.test.ts | 225 - .../schemaSettings/setDefaultValue.test.ts | 204 - .../variablesLazyLoad/templatesOfPage.ts | 531 -- .../core/client/src/__tests__/e2e/utils.ts | 33 - .../__e2e__/schemaInitializer.test.ts} | 18 +- .../__e2e__/schemaSettings.test.ts | 63 + .../collapse-filter/__e2e__/templatesOfBug.ts | 0 .../__e2e__/schemaInitializer.test.ts} | 27 +- .../__e2e__/schemaSettings.test.ts | 71 + .../__e2e__/templatesOfBug.ts | 0 .../__e2e__/schemaInitializer.test.ts | 87 + .../__e2e__/schemaSettings.test.ts | 25 + .../__e2e__/templatesOfBug.ts | 0 .../dialog/__e2e__/schemaInitializer.test.ts} | 93 +- .../dialog/__e2e__/schemaSettings.test.ts | 48 + .../modules/dialog/__e2e__/templatesOfBug.ts | 0 .../form-creation/__e2e__/dragAndDrop.test.ts | 30 + .../__e2e__/lazyLoadAssociationFields.test.ts | 225 + .../__e2e__/lazyLoadVariables.test.ts} | 7 +- .../__e2e__/schemaInitializer.test.ts} | 33 +- .../__e2e__/schemaSettings.test.ts | 1181 ++++ .../form-creation/__e2e__/templatesOfBug.ts | 2921 ++++++++ .../__e2e__/schemaInitializer.test.ts | 20 + .../form-edit/__e2e__/schemaSettings.test.ts | 175 + .../form-edit/__e2e__/templatesOfBug.ts | 0 .../__e2e__/schemaInitializer.test.ts} | 30 +- .../__e2e__/schemaSettings.test.ts | 108 + .../form-filter/__e2e__/templatesOfBug.ts | 0 .../__e2e__/schemaInitializer.test.ts} | 141 +- .../grid-card/__e2e__/schemaSettings.test.ts | 51 + .../grid-card/__e2e__/templatesOfBug.ts | 0 .../list/__e2e__/schemaInitializer.test.ts} | 130 +- .../list/__e2e__/schemaSettings.test.ts | 25 + .../modules/list/__e2e__/templatesOfBug.ts | 0 .../__e2e__/schemaInitializer.test.ts | 11 + .../markdown/__e2e__/schemaSettings.test.ts | 31 + .../markdown/__e2e__/templatesOfBug.ts | 0 .../modules/menu/__e2e__/dragAndDrop.test.ts | 22 + .../menu/__e2e__/schemaInitializer.test.ts} | 2 +- .../menu/__e2e__/schemaSettings.test.ts | 225 + .../modules/menu/__e2e__/templatesOfBug.ts | 0 .../modules/page/__e2e__/dragAndDrop.test.ts | 21 + .../page/__e2e__/schemaInitailizer.test.ts | 13 + .../page/__e2e__/schemaSettings.test.ts | 103 + .../modules/page/__e2e__/templatesOfBug.ts | 0 .../__e2e__/pluginManager.test.ts} | 44 +- .../plugin-manager/__e2e__/templatesOfBug.ts | 0 .../__e2e__/schemaInitializer.test.ts | 101 + .../__e2e__/schemaSettings.test.ts | 19 + .../__e2e__/templatesOfBug.ts | 0 .../table-data-selector/__e2e__/utils.ts | 24 + .../table-tree/__e2e__/schemaSettings.test.ts | 45 + .../table-tree/__e2e__/templatesOfBug.ts | 0 .../table/__e2e__/actions/duplicate.test.ts | 14 + .../table/__e2e__/actions/filter.test.ts | 31 + .../table/__e2e__/checkboxForTableRow.test.ts | 22 + .../modules/table/__e2e__/dragAndDrop.test.ts | 32 + .../table/__e2e__/schemaInitializer.test.ts} | 148 +- .../table/__e2e__/schemaSettings.test.ts | 713 ++ .../table/__e2e__/templatesOfBug.ts} | 334 +- .../antd/association-field/InternalViewer.tsx | 2 +- .../antd/grid-card/GridCard.Item.tsx | 2 + packages/core/test/src/client/e2eUtils.ts | 253 +- packages/core/test/src/client/index.ts | 1 - .../test/src/client/templatesOfBug/T-2614.ts | 836 --- .../test/src/client/templatesOfBug/T-2615.ts | 904 --- .../test/src/client/templatesOfBug/index.ts | 2 - .../test/src/client/templatesOfCollection.ts | 55 +- .../core/test/src/client/templatesOfPage.ts | 6107 ++++++++++++++++- .../{__tests__/e2e => __e2e__}/auth.test.ts | 0 .../form-item}/commonTesting.ts | 0 .../details-single-data}/advanced.test.ts | 35 +- .../details-single-data}/basic.test.ts | 70 +- .../details-single-data}/choices.test.ts | 78 +- .../details-single-data}/datetime.test.ts | 44 +- .../details-single-data}/media.test.ts | 82 +- .../details-single-data}/relation.test.ts | 74 +- .../details-single-data}/systemInfo.test.ts | 70 +- .../form-item/form-creation}/advanced.test.ts | 64 +- .../form-item/form-creation}/basic.test.ts | 66 +- .../form-item/form-creation}/choices.test.ts | 72 +- .../form-item/form-creation}/datetime.test.ts | 64 +- .../form-item/form-creation}/media.test.ts | 72 +- .../form-item/form-creation}/relation.test.ts | 185 +- .../form-creation}/systemInfo.test.ts | 64 +- .../form-item/form-edit}/advanced.test.ts | 66 +- .../form-item/form-edit}/basic.test.ts | 70 +- .../form-item/form-edit}/choices.test.ts | 78 +- .../form-item/form-edit}/datetime.test.ts | 74 +- .../form-item/form-edit}/media.test.ts | 78 +- .../form-item/form-edit}/relation.test.ts | 122 +- .../form-item/form-edit}/systemInfo.test.ts | 70 +- .../table-column-item/advanced.test.ts | 34 + .../table-column-item/basic.test.ts | 171 + .../table-column-item/choices.test.ts | 50 + .../table-column-item/datetime.test.ts | 34 + .../table-column-item/media.test.ts | 26 + .../table-column-item/relation.test.ts | 105 + .../table-column-item/systemInfo.test.ts | 50 + .../table-column-item/utils.ts | 37 + .../src/server/index.ts | 2 +- .../src/client/__tests__/e2e/demo.test.ts | 3 - playwright.config.ts | 3 +- scripts/auth.setup.ts | 5 + vitest.config.ts | 1 + 146 files changed, 14879 insertions(+), 9584 deletions(-) delete mode 100644 packages/core/client/src/__tests__/e2e/action.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/block.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/bugs/T-2165.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/bugs/T-2174.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/bugs/T-2176.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/bugs/T-2183.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/bugs/T-2186.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/bugs/T-2200.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/checkTableRow.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/createCollections.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/createDataBlock.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/field.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/loadAssociationData.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/menu.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/mock.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/page.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/pageSchema.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaInitializer/associationFields.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaInitializer/pageGrid.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaInitializer/pageTabs.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaInitializer/utils.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/actions/addChild.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/actions/addNew.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/actions/addRecord.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/actions/bulkDelete.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/actions/delete.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/actions/duplicate.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/actions/edit.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/actions/expectOptions.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/actions/filter.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/actions/popup.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/actions/refresh.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/actions/saveRecord.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/actions/submit.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/actions/updateRecord.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/actions/view.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/formBlock.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/formDataTemplates.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/linkageRules.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/setDefaultValue.test.ts delete mode 100644 packages/core/client/src/__tests__/e2e/schemaSettings/variablesLazyLoad/templatesOfPage.ts delete mode 100644 packages/core/client/src/__tests__/e2e/utils.ts rename packages/core/client/src/{__tests__/e2e/schemaInitializer/filterCollapseBlock.test.ts => modules/collapse-filter/__e2e__/schemaInitializer.test.ts} (69%) create mode 100644 packages/core/client/src/modules/collapse-filter/__e2e__/schemaSettings.test.ts create mode 100644 packages/core/client/src/modules/collapse-filter/__e2e__/templatesOfBug.ts rename packages/core/client/src/{__tests__/e2e/schemaInitializer/detailsBlock.test.ts => modules/details-multi-data/__e2e__/schemaInitializer.test.ts} (76%) create mode 100644 packages/core/client/src/modules/details-multi-data/__e2e__/schemaSettings.test.ts create mode 100644 packages/core/client/src/modules/details-multi-data/__e2e__/templatesOfBug.ts create mode 100644 packages/core/client/src/modules/details-single-data/__e2e__/schemaInitializer.test.ts create mode 100644 packages/core/client/src/modules/details-single-data/__e2e__/schemaSettings.test.ts create mode 100644 packages/core/client/src/modules/details-single-data/__e2e__/templatesOfBug.ts rename packages/core/client/src/{__tests__/e2e/schemaInitializer/actions.test.ts => modules/dialog/__e2e__/schemaInitializer.test.ts} (58%) create mode 100644 packages/core/client/src/modules/dialog/__e2e__/schemaSettings.test.ts create mode 100644 packages/core/client/src/modules/dialog/__e2e__/templatesOfBug.ts create mode 100644 packages/core/client/src/modules/form-creation/__e2e__/dragAndDrop.test.ts create mode 100644 packages/core/client/src/modules/form-creation/__e2e__/lazyLoadAssociationFields.test.ts rename packages/core/client/src/{__tests__/e2e/schemaSettings/variablesLazyLoad/defaultValue.test.ts => modules/form-creation/__e2e__/lazyLoadVariables.test.ts} (65%) rename packages/core/client/src/{__tests__/e2e/schemaInitializer/formBlock.test.ts => modules/form-creation/__e2e__/schemaInitializer.test.ts} (70%) create mode 100644 packages/core/client/src/modules/form-creation/__e2e__/schemaSettings.test.ts create mode 100644 packages/core/client/src/modules/form-creation/__e2e__/templatesOfBug.ts create mode 100644 packages/core/client/src/modules/form-edit/__e2e__/schemaInitializer.test.ts create mode 100644 packages/core/client/src/modules/form-edit/__e2e__/schemaSettings.test.ts create mode 100644 packages/core/client/src/modules/form-edit/__e2e__/templatesOfBug.ts rename packages/core/client/src/{__tests__/e2e/schemaInitializer/filterFormBlock.test.ts => modules/form-filter/__e2e__/schemaInitializer.test.ts} (74%) create mode 100644 packages/core/client/src/modules/form-filter/__e2e__/schemaSettings.test.ts create mode 100644 packages/core/client/src/modules/form-filter/__e2e__/templatesOfBug.ts rename packages/core/client/src/{__tests__/e2e/schemaInitializer/gridCardBlock.test.ts => modules/grid-card/__e2e__/schemaInitializer.test.ts} (81%) create mode 100644 packages/core/client/src/modules/grid-card/__e2e__/schemaSettings.test.ts create mode 100644 packages/core/client/src/modules/grid-card/__e2e__/templatesOfBug.ts rename packages/core/client/src/{__tests__/e2e/schemaInitializer/listBlock.test.ts => modules/list/__e2e__/schemaInitializer.test.ts} (83%) create mode 100644 packages/core/client/src/modules/list/__e2e__/schemaSettings.test.ts create mode 100644 packages/core/client/src/modules/list/__e2e__/templatesOfBug.ts create mode 100644 packages/core/client/src/modules/markdown/__e2e__/schemaInitializer.test.ts create mode 100644 packages/core/client/src/modules/markdown/__e2e__/schemaSettings.test.ts create mode 100644 packages/core/client/src/modules/markdown/__e2e__/templatesOfBug.ts create mode 100644 packages/core/client/src/modules/menu/__e2e__/dragAndDrop.test.ts rename packages/core/client/src/{__tests__/e2e/schemaInitializer/menu.test.ts => modules/menu/__e2e__/schemaInitializer.test.ts} (98%) create mode 100644 packages/core/client/src/modules/menu/__e2e__/schemaSettings.test.ts create mode 100644 packages/core/client/src/modules/menu/__e2e__/templatesOfBug.ts create mode 100644 packages/core/client/src/modules/page/__e2e__/dragAndDrop.test.ts create mode 100644 packages/core/client/src/modules/page/__e2e__/schemaInitailizer.test.ts create mode 100644 packages/core/client/src/modules/page/__e2e__/schemaSettings.test.ts create mode 100644 packages/core/client/src/modules/page/__e2e__/templatesOfBug.ts rename packages/core/client/src/{__tests__/e2e/pm.test.ts => modules/plugin-manager/__e2e__/pluginManager.test.ts} (78%) create mode 100644 packages/core/client/src/modules/plugin-manager/__e2e__/templatesOfBug.ts create mode 100644 packages/core/client/src/modules/table-data-selector/__e2e__/schemaInitializer.test.ts create mode 100644 packages/core/client/src/modules/table-data-selector/__e2e__/schemaSettings.test.ts create mode 100644 packages/core/client/src/modules/table-data-selector/__e2e__/templatesOfBug.ts create mode 100644 packages/core/client/src/modules/table-data-selector/__e2e__/utils.ts create mode 100644 packages/core/client/src/modules/table-tree/__e2e__/schemaSettings.test.ts create mode 100644 packages/core/client/src/modules/table-tree/__e2e__/templatesOfBug.ts create mode 100644 packages/core/client/src/modules/table/__e2e__/actions/duplicate.test.ts create mode 100644 packages/core/client/src/modules/table/__e2e__/actions/filter.test.ts create mode 100644 packages/core/client/src/modules/table/__e2e__/checkboxForTableRow.test.ts create mode 100644 packages/core/client/src/modules/table/__e2e__/dragAndDrop.test.ts rename packages/core/client/src/{__tests__/e2e/schemaInitializer/tableBlock.test.ts => modules/table/__e2e__/schemaInitializer.test.ts} (86%) create mode 100644 packages/core/client/src/modules/table/__e2e__/schemaSettings.test.ts rename packages/core/client/src/{__tests__/e2e/bugs/T-2187.test.ts => modules/table/__e2e__/templatesOfBug.ts} (64%) delete mode 100644 packages/core/test/src/client/templatesOfBug/T-2614.ts delete mode 100644 packages/core/test/src/client/templatesOfBug/T-2615.ts delete mode 100644 packages/core/test/src/client/templatesOfBug/index.ts rename packages/plugins/@nocobase/plugin-auth/src/client/{__tests__/e2e => __e2e__}/auth.test.ts (100%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item}/commonTesting.ts (100%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/details => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data}/advanced.test.ts (96%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/details => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data}/basic.test.ts (98%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/details => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data}/choices.test.ts (97%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/details => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data}/datetime.test.ts (97%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/details => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data}/media.test.ts (98%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/details => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data}/relation.test.ts (97%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/details => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data}/systemInfo.test.ts (98%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation}/advanced.test.ts (98%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation}/basic.test.ts (99%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation}/choices.test.ts (99%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation}/datetime.test.ts (99%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation}/media.test.ts (99%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation}/relation.test.ts (85%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation}/systemInfo.test.ts (98%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit}/advanced.test.ts (98%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit}/basic.test.ts (99%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit}/choices.test.ts (99%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit}/datetime.test.ts (98%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit}/media.test.ts (99%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit}/relation.test.ts (91%) rename packages/{core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm => plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit}/systemInfo.test.ts (98%) create mode 100644 packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/advanced.test.ts create mode 100644 packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/basic.test.ts create mode 100644 packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/choices.test.ts create mode 100644 packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/datetime.test.ts create mode 100644 packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/media.test.ts create mode 100644 packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/relation.test.ts create mode 100644 packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/systemInfo.test.ts create mode 100644 packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/utils.ts delete mode 100644 packages/plugins/@nocobase/plugin-theme-editor/src/client/__tests__/e2e/demo.test.ts diff --git a/.eslintrc b/.eslintrc index 4e5100309..0db89b0ba 100755 --- a/.eslintrc +++ b/.eslintrc @@ -60,7 +60,8 @@ "overrides": [ { "files": [ - "**/e2e/**/*.{ts,js,tsx,jsx}" + "**/e2e/**/*.{ts,js,tsx,jsx}", + "**/__e2e__/**/*.{ts,js,tsx,jsx}" ], "rules": { "@typescript-eslint/no-floating-promises": "error" diff --git a/packages/core/build/src/buildDeclaration.ts b/packages/core/build/src/buildDeclaration.ts index c3269f75e..fb3ab5634 100644 --- a/packages/core/build/src/buildDeclaration.ts +++ b/packages/core/build/src/buildDeclaration.ts @@ -1,7 +1,6 @@ import gulp from 'gulp'; -import path from 'path'; -import fs from 'fs'; import gulpTs from 'gulp-typescript'; +import path from 'path'; import { ROOT_PATH } from './constant'; export const buildDeclaration = (cwd: string, targetDir: string) => { @@ -17,6 +16,7 @@ export const buildDeclaration = (cwd: string, targetDir: string) => { `!${path.join(srcPath, '**/demos{,/**}')}`, `!${path.join(srcPath, '**/__test__{,/**}')}`, `!${path.join(srcPath, '**/__tests__{,/**}')}`, + `!${path.join(srcPath, '**/__e2e__{,/**}')}`, `!${path.join(srcPath, '**/*.mdx')}`, `!${path.join(srcPath, '**/*.md')}`, `!${path.join(srcPath, '**/*.+(test|e2e|spec).+(js|jsx|ts|tsx)')}`, diff --git a/packages/core/build/src/constant.ts b/packages/core/build/src/constant.ts index 70203bdf4..9b113f84d 100644 --- a/packages/core/build/src/constant.ts +++ b/packages/core/build/src/constant.ts @@ -4,6 +4,7 @@ import path from 'path'; export const globExcludeFiles = [ '!src/**/__tests__', '!src/**/__test__', + '!src/**/__e2e__', '!src/**/demos', '!src/**/fixtures', '!src/**/*.mdx', diff --git a/packages/core/client/src/__tests__/e2e/action.test.ts b/packages/core/client/src/__tests__/e2e/action.test.ts deleted file mode 100644 index 30eb0caf9..000000000 --- a/packages/core/client/src/__tests__/e2e/action.test.ts +++ /dev/null @@ -1,338 +0,0 @@ -import { expect, test } from '@nocobase/test/client'; -const tablePageSchema = { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Page', - properties: { - '3r0yxum84w2': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'BlockInitializers', - properties: { - vduni5v1u2v: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - qwrauugqc1k: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - '92vs3ej14vo': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'TableBlockProvider', - 'x-acl-action': 'users:list', - 'x-decorator-props': { - collection: 'users', - resource: 'users', - action: 'list', - params: { - pageSize: 20, - }, - rowKey: 'id', - showIndex: true, - dragSort: false, - disableTemplate: false, - }, - 'x-designer': 'TableBlockDesigner', - 'x-component': 'CardItem', - 'x-filter-targets': [], - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'TableActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 'var(--nb-spacing)', - }, - }, - 'x-uid': 'gzu2uanef12', - 'x-async': false, - 'x-index': 1, - }, - vlkh4fiq98e: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'array', - 'x-initializer': 'TableColumnInitializers', - 'x-component': 'TableV2', - 'x-component-props': { - rowKey: 'id', - rowSelection: { - type: 'checkbox', - }, - useProps: '{{ useTableBlockProps }}', - }, - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Actions") }}', - 'x-action-column': 'actions', - 'x-decorator': 'TableV2.Column.ActionBar', - 'x-component': 'TableV2.Column', - 'x-designer': 'TableV2.ActionColumnDesigner', - 'x-initializer': 'TableActionColumnInitializers', - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'DndContext', - 'x-component': 'Space', - 'x-component-props': { - split: '|', - }, - 'x-uid': 'q44b0dv50za', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'i8tnis8ymcm', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'u60i2x1lo97', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': '6jb6jfh1770', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '9oykdej2ufq', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '8iolmzoelll', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '0dhkzj75zh7', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'n8gs3wg1sxp', - 'x-async': true, - 'x-index': 1, -}; - -test.describe('add action & remove action', () => { - test('add action & remove action in block', async ({ page, mockPage }) => { - await mockPage({ pageSchema: tablePageSchema }).goto(); - await page.getByLabel('block-item-CardItem-users-table').click(); - await page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-users').click(); - //添加按钮 - await page.getByRole('menuitem', { name: 'Filter' }).click(); - await page.getByRole('menuitem', { name: 'Add new' }).click(); - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-users').hover(); - await page.getByText('Enable actions').hover(); - await expect(page.getByLabel('action-Filter.Action-Filter-filter-users-table')).toBeVisible(); - await expect(page.getByLabel('action-Action-Add new-create-users-table')).toBeVisible(); - await expect(page.getByLabel('action-Action-Delete-destroy-users-table')).toBeVisible(); - await expect(page.getByRole('menuitem', { name: 'Filter' }).getByRole('switch')).toBeChecked(); - await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).toBeChecked(); - await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).toBeChecked(); - //移除按钮 - await page.getByRole('menuitem', { name: 'Filter' }).click(); - await page.getByRole('menuitem', { name: 'Add new' }).click(); - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await expect(page.getByLabel('action-Action-Add new-create-users-table')).not.toBeVisible(); - await expect( - page.getByLabel('block-item-CardItem-users-table').getByRole('button', { name: 'Delete' }), - ).not.toBeVisible(); - await expect( - page.getByLabel('block-item-CardItem-users-table').getByLabel('Filter', { exact: true }), - ).not.toBeVisible(); - await expect(page.getByRole('menuitem', { name: 'Filter' }).getByRole('switch')).not.toBeChecked(); - await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).not.toBeChecked(); - await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).not.toBeChecked(); - }); -}); - -test.describe('action drag in block', () => { - test('drag th action orders', async ({ page, mockPage }) => { - await mockPage({ pageSchema: tablePageSchema }).goto(); - await page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-users').hover(); - //添加按钮 - await page.getByRole('menuitem', { name: 'Add new' }).click(); - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await page.getByRole('menuitem', { name: 'Refresh' }).click(); - // 向右挪动鼠标指针,用以关闭下拉列表 - await page.mouse.move(300, 0); - - const addNewBtn = await page.getByLabel('action-Action-Add new-create-users-table'); - await addNewBtn.hover(); - const addNewDrag = await page.getByLabel('action-Action-Add new-create-users-table').getByLabel('designer-drag'); - await addNewDrag.hover(); - - const delBtn = await page.getByLabel('action-Action-Delete-destroy-users-table'); - await addNewDrag.dragTo(delBtn); - const refreshBtn = await page.getByLabel('action-Action-Refresh-refresh-users-table'); - await addNewBtn.hover(); - await addNewBtn.getByLabel('designer-drag').dragTo(refreshBtn); - - const addNew = await addNewBtn.boundingBox(); - const del = await delBtn.boundingBox(); - const refresh = await refreshBtn.boundingBox(); - const max = Math.max(addNew.x, refresh.x, del.x); - //拖拽调整排序符合预期 - await expect(addNew.x).toBe(max); - }); -}); - -test.describe('action display config', () => { - test('editing action name,icon and color', async ({ page, mockPage }) => { - await mockPage({ pageSchema: tablePageSchema }).goto(); - await page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-users').hover(); - //添加按钮 - await page.getByRole('menuitem', { name: 'Add new' }).click(); - await page.getByLabel('action-Action-Add new-create-users-table').hover(); - await page.getByLabel('action-Action-Add new-create-users-table').getByLabel('designer-schema-settings').hover(); - //更新按钮图标、名称、样式 - await page.getByRole('menuitem', { name: 'Edit button' }).click(); - await page.getByRole('textbox').fill('Add new1'); - await page.getByRole('button', { name: 'close', exact: true }).click(); - await page.getByRole('button', { name: 'Select icon', exact: true }).click(); - await page.getByLabel('user-add').click(); - await page.getByLabel('Danger red').check(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - await expect( - page.getByLabel('block-item-CardItem-users-table').locator('.nb-action-bar').getByLabel('user-add'), - ).toBeVisible(); - await expect( - page.getByLabel('block-item-CardItem-users-table').locator('.nb-action-bar').locator('.ant-btn-dangerous'), - ).toBeVisible(); - }); - test('action open mode ', async ({ page, mockPage }) => { - await mockPage({ pageSchema: tablePageSchema }).goto(); - await page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-users').hover(); - //添加按钮 - await page.getByRole('menuitem', { name: 'Add new' }).click(); - await page.getByLabel('action-Action-Add new-create-users-table').click(); - await expect(page.locator('.ant-drawer')).toBeVisible(); - - //更新按钮打开方式 - await page.locator('.ant-drawer-mask').click(); - await page.getByLabel('action-Action-Add new-create-users-table').hover(); - await page.getByRole('button', { name: 'designer-schema-settings-Action-Action.Designer-users' }).hover(); - await page.getByRole('menuitem', { name: 'Open mode' }).click(); - await page.getByRole('option', { name: 'Dialog' }).click(); - await page.getByLabel('action-Action-Add new-create-users-table').click(); - const drawerComponent = page.getByTestId('modal-Action.Container-users-Add record'); - await expect(drawerComponent).toBeInViewport(); - }); - test('setting action model size', async ({ page, mockPage }) => { - await mockPage({ pageSchema: tablePageSchema }).goto(); - await page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-users').hover(); - //添加按钮 - await page.getByRole('menuitem', { name: 'Add new' }).click(); - await page.getByLabel('action-Action-Add new-create-users-table').click(); - await expect(page.locator('.ant-drawer')).toBeVisible(); - await page.locator('.ant-drawer-mask').click(); - //修改尺寸 - await page.getByLabel('action-Action-Add new-create-users-table').hover(); - await page.getByRole('button', { name: 'designer-schema-settings-Action-Action.Designer-users' }).hover(); - await page.getByRole('menuitem', { name: 'Popup size' }).click(); - - //默认尺寸为Middle - await expect(page.getByTitle('Popup size').locator('.ant-select-selection-item')).toHaveText('Middle'); - //设置为large - await page.getByRole('option', { name: 'Large' }).click(); - - await page.getByLabel('action-Action-Add new-create-users-table').click(); - const drawerItem = page.locator('.ant-drawer > .ant-drawer-content-wrapper'); - const drawerWidth = await drawerItem.evaluate((element) => { - const computedStyle = window.getComputedStyle(element); - const parent = element.parentElement; - const parentWidth = window.getComputedStyle(parent).getPropertyValue('width'); - const percentageWidth = (parseFloat(computedStyle.width) / parseFloat(parentWidth)) * 100; - return percentageWidth; - }); - //宽度为70% - expect(drawerWidth).toBe(70); - }); -}); - -test.describe('action linkage rule', () => { - test('action linkage to hide', async ({ page, mockPage }) => { - await mockPage({ pageSchema: tablePageSchema }).goto(); - await page - .getByLabel('block-item-CardItem-users-table') - .getByRole('button', { name: 'Actions', exact: true }) - .hover(); - await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-users').hover(); - await page.getByRole('menuitem', { name: 'View' }).click(); - await page.getByLabel('block-item-CardItem-users-table').getByLabel('View').hover(); - await page.getByLabel('View').getByLabel('designer-schema-settings').hover(); - await page.getByRole('menuitem', { name: 'Linkage rules' }).click(); - await page.getByRole('button', { name: 'plus Add linkage rule', exact: true }).click(); - await page.getByText('Add condition', { exact: true }).click(); - await page.getByTestId('select-filter-field').click(); - await page.getByTitle('ID', { exact: true }).getByText('ID').click(); - await page.getByRole('spinbutton').fill('1'); - await page.getByText('Add property').click(); - await page.getByTestId('select-linkage-properties').click(); - await page.getByText('Hidden').click(); - await page.locator('.ant-modal').getByRole('button', { name: 'OK', exact: true }).click(); - //配置中,按钮显示半透明 - const actionItem = page.getByLabel('block-item-CardItem-users-table').getByLabel('View'); - const inputErrorBorderColor = await actionItem.evaluate((element) => { - const computedStyle = window.getComputedStyle(element); - return computedStyle.opacity; - }); - expect(inputErrorBorderColor).toBe('0.1'); - //使用中,按钮隐藏 - await page.getByRole('button', { name: 'highlight' }).click(); - await expect(page.getByLabel('block-item-CardItem-users-table').getByLabel('View')).not.toBeVisible(); - }); - test('action linkage to disabled', async ({ page, mockPage }) => { - await mockPage({ pageSchema: tablePageSchema }).goto(); - await page - .getByLabel('block-item-CardItem-users-table') - .getByRole('button', { name: 'Actions', exact: true }) - .hover(); - await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-users').hover(); - await page.getByRole('menuitem', { name: 'View' }).click(); - await page.getByLabel('block-item-CardItem-users-table').getByLabel('View').hover(); - await page.getByLabel('View').getByLabel('designer-schema-settings').hover(); - await page.getByRole('menuitem', { name: 'Linkage rules' }).click(); - await page.getByRole('button', { name: 'plus Add linkage rule', exact: true }).click(); - await page.getByText('Add condition', { exact: true }).click(); - await page.getByTestId('select-filter-field').click(); - await page.getByTitle('ID', { exact: true }).getByText('ID').click(); - await page.getByRole('spinbutton').fill('1'); - await page.getByText('Add property').click(); - await page.getByTestId('select-linkage-properties').click(); - await page.getByText('Disabled').click(); - await page.locator('.ant-modal').getByRole('button', { name: 'OK', exact: true }).click(); - - const linkBtn = page.getByLabel('block-item-CardItem-users-table').getByLabel('View'); - const linkBtnCursor = await linkBtn.evaluate((element) => { - const computedStyle = window.getComputedStyle(element); - return computedStyle.cursor; - }); - - //按钮禁用 - expect(linkBtnCursor).toBe('not-allowed'); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/block.test.ts b/packages/core/client/src/__tests__/e2e/block.test.ts deleted file mode 100644 index dbb0f8079..000000000 --- a/packages/core/client/src/__tests__/e2e/block.test.ts +++ /dev/null @@ -1,561 +0,0 @@ -import { expect, test } from '@nocobase/test/client'; - -const tablePageSchema = { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Page', - properties: { - mwxaaxb9y9v: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'BlockInitializers', - properties: { - ibb0kjq3kyl: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - p39cigcjpij: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - '237ec1x538e': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'TableBlockProvider', - 'x-acl-action': 'users:list', - 'x-decorator-props': { - collection: 'users', - resource: 'users', - action: 'list', - params: { - pageSize: 20, - }, - rowKey: 'id', - showIndex: true, - dragSort: false, - disableTemplate: false, - }, - 'x-designer': 'TableBlockDesigner', - 'x-component': 'CardItem', - 'x-filter-targets': [], - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'TableActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 'var(--nb-spacing)', - }, - }, - properties: { - lmeom75gry5: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-action': 'create', - 'x-acl-action': 'create', - title: "{{t('Add new')}}", - 'x-designer': 'Action.Designer', - 'x-component': 'Action', - 'x-decorator': 'ACLActionProvider', - 'x-component-props': { - openMode: 'drawer', - type: 'primary', - component: 'CreateRecordAction', - icon: 'PlusOutlined', - }, - 'x-align': 'right', - 'x-acl-action-props': { - skipScopeCheck: true, - }, - properties: { - drawer: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Add record") }}', - 'x-component': 'Action.Container', - 'x-component-props': { - className: 'nb-action-popup', - }, - properties: { - tabs: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Tabs', - 'x-component-props': {}, - 'x-initializer': 'TabPaneInitializersForCreateFormBlock', - properties: { - tab1: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{t("Add new")}}', - 'x-component': 'Tabs.TabPane', - 'x-designer': 'Tabs.Designer', - 'x-component-props': {}, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'CreateFormBlockInitializers', - 'x-uid': 'w224zhqyair', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'lll44vre1t6', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'c025dgp5tyk', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'og2z02rfxhx', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'vn9wxzx83y3', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '7s3fcxfjc0y', - 'x-async': false, - 'x-index': 1, - }, - zqdtqsjqgc1: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'array', - 'x-initializer': 'TableColumnInitializers', - 'x-component': 'TableV2', - 'x-component-props': { - rowKey: 'id', - rowSelection: { - type: 'checkbox', - }, - useProps: '{{ useTableBlockProps }}', - }, - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Actions") }}', - 'x-action-column': 'actions', - 'x-decorator': 'TableV2.Column.ActionBar', - 'x-component': 'TableV2.Column', - 'x-designer': 'TableV2.ActionColumnDesigner', - 'x-initializer': 'TableActionColumnInitializers', - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'DndContext', - 'x-component': 'Space', - 'x-component-props': { - split: '|', - }, - properties: { - kdcs236lihl: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Edit") }}', - 'x-action': 'update', - 'x-designer': 'Action.Designer', - 'x-component': 'Action.Link', - 'x-component-props': { - openMode: 'drawer', - icon: 'EditOutlined', - }, - 'x-decorator': 'ACLActionProvider', - 'x-designer-props': { - linkageAction: true, - }, - properties: { - drawer: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Edit record") }}', - 'x-component': 'Action.Container', - 'x-component-props': { - className: 'nb-action-popup', - }, - properties: { - tabs: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Tabs', - 'x-component-props': {}, - 'x-initializer': 'TabPaneInitializers', - properties: { - tab1: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{t("Edit")}}', - 'x-component': 'Tabs.TabPane', - 'x-designer': 'Tabs.Designer', - 'x-component-props': {}, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'RecordBlockInitializers', - 'x-uid': 's49vs6v3qs0', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '33qff1grgqn', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '3z1hbrs3bre', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '09vwzm2det2', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'bgdfnken9ua', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'tn98i5lgydw', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'ubmt489cxzn', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 't6eg1ye4wf4', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'h4yvac2sy2g', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '3xei2593vgu', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'm67du7wrojo', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '7aige8a5w3q', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'qpbgsjdsgaq', - 'x-async': true, - 'x-index': 1, -}; - -test.describe('add block & delete block', () => { - test('add block,then delete block', async ({ page, mockPage }) => { - await mockPage().goto(); - await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); - await page.getByRole('menuitem', { name: 'table Table' }).click(); - await page.getByRole('menuitem', { name: 'Users' }).click(); - await expect(page.getByLabel('block-item-CardItem-users-table')).toBeVisible(); - await expect(page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-users')).toBeVisible(); - await expect(page.getByLabel('schema-initializer-TableV2-TableColumnInitializers-users')).toBeVisible(); - //删除区块 - await page.getByLabel('block-item-CardItem-users-table').hover(); - await page - .getByLabel('block-item-CardItem-users-table') - .getByRole('button', { name: 'designer-schema-settings' }) - .click(); - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - await expect(page.getByLabel('block-item-CardItem-users-table')).not.toBeVisible(); - await expect(page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-users')).not.toBeVisible(); - await expect(page.getByLabel('schema-initializer-TableV2-TableColumnInitializers-users')).not.toBeVisible(); - }); -}); - -test.describe('block title', () => { - test('edit block title', async ({ page, mockPage }) => { - await mockPage({ - pageSchema: tablePageSchema, - }).goto(); - await page.getByLabel('block-item-CardItem-users-table').hover(); - await page - .getByLabel('block-item-CardItem-users-table') - .getByRole('button', { name: 'designer-schema-settings' }) - .hover(); - await page.getByRole('menuitem', { name: 'Edit block title' }).click(); - await page.getByLabel('block-item-Input-users-Block title').click(); - await page.getByLabel('block-item-Input-users-Block title').getByRole('textbox').fill('block title'); - await page.locator('.ant-modal').getByRole('button', { name: 'OK', exact: true }).click(); - await expect(page.getByLabel('block-item-CardItem-users-table').locator('.ant-card-head')).toBeVisible(); - await expect(page.getByLabel('block-item-CardItem-users-table').locator('.ant-card-head')).toHaveText( - 'block title', - ); - - //回显 - await page - .getByLabel('block-item-CardItem-users-table') - .getByRole('button', { name: 'designer-schema-settings' }) - .hover(); - await page.getByRole('menuitem', { name: 'Edit block title' }).click(); - const inputValue = await page.getByRole('textbox').inputValue(); - expect(inputValue).toBe('block title'); - }); -}); - -test.describe('block template', () => { - test('save block template & using block template', async ({ page, mockPage }) => { - await mockPage({ - name: 'block template source', - pageSchema: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Page', - properties: { - bg76x03o9f2: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'BlockInitializers', - properties: { - gdj0ceke8ac: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - ftx8xnesvev: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - tu0dxua38tw: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-acl-action-props': { - skipScopeCheck: true, - }, - 'x-acl-action': 'users:create', - 'x-decorator': 'FormBlockProvider', - 'x-decorator-props': { - resource: 'users', - collection: 'users', - }, - 'x-designer': 'FormV2.Designer', - 'x-component': 'CardItem', - 'x-component-props': {}, - properties: { - avv3vpk0nlv: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'FormV2', - 'x-component-props': { - useProps: '{{ useFormBlockProps }}', - }, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'FormItemInitializers', - properties: { - gnw25oyqe56: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - rdbe3gg1qv5: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - nickname: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'string', - 'x-designer': 'FormItem.Designer', - 'x-component': 'CollectionField', - 'x-decorator': 'FormItem', - 'x-collection-field': 'users.nickname', - 'x-component-props': {}, - 'x-uid': 'okrljzl6j7s', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '1zjdduck27k', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'l0cyy3gzz86', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '4wrgwkyyf81', - 'x-async': false, - 'x-index': 1, - }, - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'FormActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - layout: 'one-column', - style: { - marginTop: 24, - }, - }, - 'x-uid': '2apymtcq35d', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': '1tnmbrvb9ad', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'vo1pyqmoe28', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'z59pkpc8uhq', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'vsfafj9qcx9', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'sdj6iw5b0gs', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'uz4dyz41vt1', - 'x-async': true, - 'x-index': 1, - }, - }).goto(); - await page.getByLabel('block-item-CardItem-users-form').hover(); - await page - .getByLabel('block-item-CardItem-users-form') - .getByLabel('designer-schema-settings-CardItem-FormV2.Designer-users') - .hover(); - await page.getByRole('menuitem', { name: 'Save as block template' }).click(); - await page.getByLabel('Save as template').getByRole('textbox').fill('Users_Form'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - await page.getByLabel('block-item-CardItem-users-form').hover(); - - //保存模板后当前区块为引用区块 - const titleTag = await page.getByLabel('block-item-CardItem-users-form').locator('.title-tag').nth(1).innerText(); - expect(titleTag).toContain('Reference template'); - - // using block template - await mockPage({ - name: 'block template', - pageSchema: tablePageSchema, - }).goto(); - await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); - //使用复制模板 - await page.getByRole('menuitem', { name: 'form Form' }).first().hover(); - await page.getByRole('menuitem', { name: 'Users' }).hover(); - await page.getByRole('menuitem', { name: 'Duplicate template' }).hover(); - await page.getByRole('menuitem', { name: 'Users_Form (Fields only)' }).click(); - await expect(page.getByLabel('block-item-CardItem-users-form')).toBeVisible(); - - //在新建操作中使用引用模板 - await page.getByLabel('action-Action-Add new-create-users-table').click(); - await page.getByLabel('schema-initializer-Grid-CreateFormBlockInitializers-users').click(); - await page.getByRole('menuitem', { name: 'form Form' }).hover(); - await page.getByRole('menuitem', { name: 'Reference template' }).hover(); - await page.getByRole('menuitem', { name: 'Users_Form (Fields only)' }).click(); - await page.getByLabel('schema-initializer-Grid-CreateFormBlockInitializers-users').hover(); - await expect(page.locator('.ant-drawer').getByLabel('block-item-CardItem-users-form')).toBeVisible(); - await page.locator('.ant-drawer-mask').click(); - - //在编辑操作中使用引用模板 - await page.getByLabel('action-Action.Link-Edit-update-users-table-0').click(); - await page.getByLabel('schema-initializer-Grid-RecordBlockInitializers-users').click(); - await page.getByRole('menuitem', { name: 'form Form' }).hover(); - await page.getByRole('menuitem', { name: 'Reference template' }).hover(); - await page.getByRole('menuitem', { name: 'Users_Form (Fields only)' }).click(); - await page.getByLabel('schema-initializer-Grid-RecordBlockInitializers-users').hover(); - - //修改引用模板 - await page.locator('.ant-drawer').getByLabel('schema-initializer-Grid-FormItemInitializers-users').click(); - await page.getByRole('menuitem', { name: 'Phone' }).click(); - await page.locator('.ant-drawer-mask').click(); - //复制模板不同步,引用模板同步 - await expect( - page.getByLabel('block-item-CardItem-users-form').getByLabel('block-item-CollectionField-users-form-users.phone'), - ).not.toBeVisible(); - await page.getByLabel('block-item-CardItem-users-table').getByLabel('action-Action-Add').click(); - await expect(page.getByLabel('block-item-CollectionField-users-form-users.phone')).toBeVisible(); - await page.locator('.ant-drawer-mask').click(); - - //删除模板 - await page.getByTestId('plugin-settings-button').click(); - await page.getByLabel('ui-schema-storage').click(); - await page.getByRole('menuitem', { name: 'layout Block templates' }).click(); - await page.getByLabel('action-Action.Link-Delete-destroy-uiSchemaTemplates-table-Users_Form').click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/bugs/T-2165.test.ts b/packages/core/client/src/__tests__/e2e/bugs/T-2165.test.ts deleted file mode 100644 index 02adcaf3d..000000000 --- a/packages/core/client/src/__tests__/e2e/bugs/T-2165.test.ts +++ /dev/null @@ -1,292 +0,0 @@ -import { expect, test } from '@nocobase/test/client'; - -const config = { - pageSchema: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Page', - properties: { - '4nd32b2msmb': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'BlockInitializers', - properties: { - psn8ekavlq6: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - '78sh75l4aye': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - x1bef0fr3mp: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-acl-action-props': { - skipScopeCheck: true, - }, - 'x-acl-action': 'users:create', - 'x-decorator': 'FormBlockProvider', - 'x-decorator-props': { - resource: 'users', - collection: 'users', - }, - 'x-designer': 'FormV2.Designer', - 'x-component': 'CardItem', - 'x-component-props': {}, - properties: { - dmzuakwhn67: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'FormV2', - 'x-component-props': { - useProps: '{{ useFormBlockProps }}', - }, - properties: { - grid: { - 'x-uid': 'hjzgxol8pmk', - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'FormItemInitializers', - 'x-linkage-rules': [ - { - condition: { - $and: [], - }, - actions: [ - { - targetFields: ['nickname'], - operator: 'value', - value: { - mode: 'express', - value: '{{$nForm.nickname}}', - result: '{{$nForm.nickname}}', - }, - }, - { - targetFields: ['username'], - operator: 'value', - value: { - mode: 'express', - value: '{{$nForm.phone}}', - result: '{{$nForm.phone}}', - }, - }, - ], - }, - ], - properties: { - ghhc0yhkzo3: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - cogs086ympz: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - nickname: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'string', - 'x-designer': 'FormItem.Designer', - 'x-component': 'CollectionField', - 'x-decorator': 'FormItem', - 'x-collection-field': 'users.nickname', - 'x-component-props': {}, - 'x-uid': 'uham04eoezy', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '2skfzuw7qxe', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'ejr3cir9ka5', - 'x-async': false, - 'x-index': 1, - }, - ffhaknxhqpx: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - i3ryir3ak3d: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - username: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'string', - 'x-designer': 'FormItem.Designer', - 'x-component': 'CollectionField', - 'x-decorator': 'FormItem', - 'x-collection-field': 'users.username', - 'x-component-props': {}, - 'x-uid': 'kw6xnym0d2b', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'l7w26sen1yq', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'agrwgc6u5nh', - 'x-async': false, - 'x-index': 2, - }, - duw19c22p3a: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - '64y498coobd': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - email: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'string', - 'x-designer': 'FormItem.Designer', - 'x-component': 'CollectionField', - 'x-decorator': 'FormItem', - 'x-collection-field': 'users.email', - 'x-component-props': {}, - 'x-uid': 'yw4htrn4yus', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'co2ntoxojzd', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '1ma4kg0h049', - 'x-async': false, - 'x-index': 3, - }, - gkcvoutlsnn: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - '0wpsholkerv': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - phone: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'string', - 'x-designer': 'FormItem.Designer', - 'x-component': 'CollectionField', - 'x-decorator': 'FormItem', - 'x-collection-field': 'users.phone', - 'x-component-props': {}, - 'x-uid': 'vuakogudr4a', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'pjbv5opckij', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '7r2oycam1jj', - 'x-async': false, - 'x-index': 4, - }, - }, - 'x-async': false, - 'x-index': 1, - }, - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'FormActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - layout: 'one-column', - style: { - marginTop: 24, - }, - }, - 'x-uid': 'q2ln2amp70q', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'ftb89wttlgb', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '7xk8np3hom7', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'etlsqr2svs6', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'vnqpjz7rukb', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'xq6asyjoszu', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'audztrgao6i', - 'x-async': true, - 'x-index': 1, - }, -}; - -// fix https://nocobase.height.app/T-2165 -test('BUG: variable labels should be displayed normally', async ({ page, mockPage }) => { - await mockPage(config).goto(); - - await page.getByLabel('block-item-CardItem-users-form').hover(); - await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-users').hover(); - await page.getByRole('menuitem', { name: 'Linkage rules' }).click(); - - await expect(page.getByText('Current form / Nickname')).toBeVisible(); - await expect(page.getByText('Current form / Phone')).toBeVisible(); -}); diff --git a/packages/core/client/src/__tests__/e2e/bugs/T-2174.test.ts b/packages/core/client/src/__tests__/e2e/bugs/T-2174.test.ts deleted file mode 100644 index c446bcab3..000000000 --- a/packages/core/client/src/__tests__/e2e/bugs/T-2174.test.ts +++ /dev/null @@ -1,583 +0,0 @@ -import { expect, test } from '@nocobase/test/client'; - -const config = { - pageSchema: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Page', - 'x-index': 1, - properties: { - x9ersztdq7x: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'BlockInitializers', - 'x-index': 1, - properties: { - ppgwx2drpng: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - 'x-index': 1, - properties: { - c25gfj884oe: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - 'x-index': 1, - properties: { - urmc26btvb5: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'TableBlockProvider', - 'x-acl-action': 'test2174:list', - 'x-decorator-props': { - collection: 'test2174', - resource: 'test2174', - action: 'list', - params: { - pageSize: 20, - }, - rowKey: 'id', - showIndex: true, - dragSort: false, - disableTemplate: false, - }, - 'x-designer': 'TableBlockDesigner', - 'x-component': 'CardItem', - 'x-filter-targets': [], - 'x-index': 1, - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'TableActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 'var(--nb-spacing)', - }, - }, - 'x-index': 1, - 'x-uid': '7wfu81uqxox', - 'x-async': false, - }, - yxgybgmfhkp: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'array', - 'x-initializer': 'TableColumnInitializers', - 'x-component': 'TableV2', - 'x-component-props': { - rowKey: 'id', - rowSelection: { - type: 'checkbox', - }, - useProps: '{{ useTableBlockProps }}', - }, - 'x-index': 2, - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Actions") }}', - 'x-action-column': 'actions', - 'x-decorator': 'TableV2.Column.ActionBar', - 'x-component': 'TableV2.Column', - 'x-designer': 'TableV2.ActionColumnDesigner', - 'x-initializer': 'TableActionColumnInitializers', - 'x-index': 1, - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'DndContext', - 'x-component': 'Space', - 'x-component-props': { - split: '|', - }, - 'x-index': 1, - properties: { - r51kgwrhpgd: { - 'x-uid': 'udzm8hggmmb', - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: 'View details', - 'x-action': 'view', - 'x-designer': 'Action.Designer', - 'x-component': 'Action.Link', - 'x-component-props': { - openMode: 'drawer', - danger: false, - }, - 'x-decorator': 'ACLActionProvider', - 'x-designer-props': { - linkageAction: true, - }, - 'x-index': 1, - properties: { - drawer: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("View record") }}', - 'x-component': 'Action.Container', - 'x-component-props': { - className: 'nb-action-popup', - }, - 'x-index': 1, - properties: { - tabs: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Tabs', - 'x-component-props': {}, - 'x-initializer': 'TabPaneInitializers', - 'x-index': 1, - properties: { - tab1: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{t("Details")}}', - 'x-component': 'Tabs.TabPane', - 'x-designer': 'Tabs.Designer', - 'x-component-props': {}, - 'x-index': 1, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'RecordBlockInitializers', - 'x-index': 1, - properties: { - g8w7wq09bgo: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - 'x-index': 1, - properties: { - '42t1ais26x8': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - 'x-index': 1, - properties: { - zmq6hmh2i3a: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-acl-action-props': { - skipScopeCheck: true, - }, - 'x-acl-action': 'test2174.f_q32e4ieq49n:create', - 'x-decorator': 'FormBlockProvider', - 'x-decorator-props': { - useSourceId: '{{ useSourceIdFromParentRecord }}', - useParams: '{{ useParamsFromRecord }}', - action: null, - resource: 'test2174.f_q32e4ieq49n', - collection: 'test2174', - association: 'test2174.f_q32e4ieq49n', - }, - 'x-designer': 'FormV2.Designer', - 'x-component': 'CardItem', - 'x-component-props': {}, - 'x-index': 1, - properties: { - qii0gw1cb8e: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'FormV2', - 'x-component-props': { - useProps: '{{ useFormBlockProps }}', - }, - 'x-index': 1, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'FormItemInitializers', - 'x-index': 1, - properties: { - s3hhb0ohnv1: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - 'x-index': 1, - properties: { - t2qtgv250s0: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - 'x-index': 1, - properties: { - singleSelect: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'string', - 'x-designer': 'FormItem.Designer', - 'x-component': 'CollectionField', - 'x-decorator': 'FormItem', - 'x-collection-field': - 'test2174.singleSelect', - 'x-component-props': { - style: { - width: '100%', - }, - }, - 'x-index': 1, - 'x-uid': '75ls3qlq3kw', - 'x-async': false, - }, - }, - 'x-uid': 'ndb8zhrxgq0', - 'x-async': false, - }, - }, - 'x-uid': '14q94mijyx4', - 'x-async': false, - }, - }, - 'x-uid': '6vfyrsrkw29', - 'x-async': false, - }, - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'CreateFormActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - layout: 'one-column', - style: { - marginTop: 24, - }, - }, - 'x-index': 2, - properties: { - afuxokt3osc: { - _isJSONSchemaObject: true, - version: '2.0', - title: '{{ t("Submit") }}', - 'x-action': 'submit', - 'x-component': 'Action', - 'x-designer': 'Action.Designer', - 'x-component-props': { - type: 'primary', - htmlType: 'submit', - useProps: '{{ useCreateActionProps }}', - }, - 'x-action-settings': { - triggerWorkflows: [], - }, - type: 'void', - 'x-index': 1, - 'x-uid': '6idd8u0fs5v', - 'x-async': false, - }, - }, - 'x-uid': '8xm66k2wcbq', - 'x-async': false, - }, - }, - 'x-uid': 'ia7qdocnj0k', - 'x-async': false, - }, - }, - 'x-uid': 'ai78ycshc04', - 'x-async': false, - }, - }, - 'x-uid': 'gipnqnxa7c7', - 'x-async': false, - }, - }, - 'x-uid': '4fztm3s6pqr', - 'x-async': false, - }, - }, - 'x-uid': 'yiwh3chdjzg', - 'x-async': false, - }, - }, - 'x-uid': 'mar9ww8zdd6', - 'x-async': false, - }, - }, - 'x-uid': '29brl1obftp', - 'x-async': false, - }, - }, - 'x-uid': 'r4qbds05tcz', - 'x-async': false, - }, - }, - 'x-async': false, - }, - }, - 'x-uid': 'hp7glbaipmc', - 'x-async': false, - }, - }, - 'x-uid': 'k9u1fta4jdq', - 'x-async': false, - }, - x6soi4xw3yn: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'TableV2.Column.Decorator', - 'x-designer': 'TableV2.Column.Designer', - 'x-component': 'TableV2.Column', - 'x-index': 2, - properties: { - singleSelect: { - _isJSONSchemaObject: true, - version: '2.0', - 'x-collection-field': 'test2174.singleSelect', - 'x-component': 'CollectionField', - 'x-component-props': { - style: { - width: '100%', - }, - ellipsis: true, - }, - 'x-read-pretty': true, - 'x-decorator': null, - 'x-decorator-props': { - labelStyle: { - display: 'none', - }, - }, - default: 'np55dbbny0e', - 'x-index': 1, - 'x-uid': 'ots1wvv436n', - 'x-async': false, - }, - }, - 'x-uid': 'yx4mdriq3jp', - 'x-async': false, - }, - aoj0myt8kgn: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'TableV2.Column.Decorator', - 'x-designer': 'TableV2.Column.Designer', - 'x-component': 'TableV2.Column', - 'x-index': 3, - properties: { - f_q32e4ieq49n: { - _isJSONSchemaObject: true, - version: '2.0', - 'x-collection-field': 'test2174.f_q32e4ieq49n', - 'x-component': 'CollectionField', - 'x-component-props': { - ellipsis: true, - size: 'small', - fieldNames: { - label: 'singleSelect', - value: 'id', - }, - }, - 'x-read-pretty': true, - 'x-decorator': null, - 'x-decorator-props': { - labelStyle: { - display: 'none', - }, - }, - 'x-index': 1, - properties: { - ony7hpl5247: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("View record") }}', - 'x-component': 'AssociationField.Viewer', - 'x-component-props': { - className: 'nb-action-popup', - }, - 'x-index': 1, - properties: { - tabs: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Tabs', - 'x-component-props': {}, - 'x-initializer': 'TabPaneInitializers', - 'x-index': 1, - properties: { - tab1: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{t("Details")}}', - 'x-component': 'Tabs.TabPane', - 'x-designer': 'Tabs.Designer', - 'x-component-props': {}, - 'x-index': 1, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'RecordBlockInitializers', - 'x-index': 1, - 'x-uid': 'roog7uz0d2o', - 'x-async': false, - }, - }, - 'x-uid': 'x05lq9x1n0n', - 'x-async': false, - }, - }, - 'x-uid': 'hrymp5hthg3', - 'x-async': false, - }, - }, - 'x-uid': 'ujkf9096qwq', - 'x-async': false, - }, - }, - 'x-uid': '02kpdjz33yd', - 'x-async': false, - }, - }, - 'x-uid': 'e366r5cz2cv', - 'x-async': false, - }, - }, - 'x-uid': 'wkdjjugn3l8', - 'x-async': false, - }, - }, - 'x-uid': 'n3f07077krt', - 'x-async': false, - }, - }, - 'x-uid': 'i920mrykzkp', - 'x-async': false, - }, - }, - 'x-uid': '8a5n45kb55h', - 'x-async': false, - }, - }, - 'x-uid': 'wcobb00rn5y', - 'x-async': false, - }, - }, - 'x-uid': 'pfr9jap0zsf', - 'x-async': true, - }, - collections: [ - { - name: 'test2174', - title: 'Test', - fields: [ - { - name: 'f_lkqy3eh4ag7', - interface: 'integer', - isForeignKey: true, - uiSchema: { - type: 'number', - title: 'f_lkqy3eh4ag7', - 'x-component': 'InputNumber', - 'x-read-pretty': true, - }, - }, - { - name: 'f_rathx54cqpy', - interface: 'integer', - isForeignKey: true, - uiSchema: { - type: 'number', - title: 'f_rathx54cqpy', - 'x-component': 'InputNumber', - 'x-read-pretty': true, - }, - }, - { - name: 'singleSelect', - interface: 'select', - uiSchema: { - enum: [ - { - value: 'np55dbbny0e', - label: 'option1', - }, - { - value: 'zxteco8rjfc', - label: 'option2', - }, - { - value: 'p7pi40zd91q', - label: 'option3', - }, - ], - type: 'string', - 'x-component': 'Select', - title: 'Single select', - }, - }, - { - name: 'f_q32e4ieq49n', - interface: 'o2m', - foreignKey: 'f_rathx54cqpy', - uiSchema: { - 'x-component': 'AssociationField', - 'x-component-props': { - multiple: true, - fieldNames: { - label: 'id', - value: 'id', - }, - }, - title: 'One to many', - }, - target: 'test2174', - targetKey: 'id', - sourceKey: 'id', - }, - ], - }, - ], -}; - -// fix https://nocobase.height.app/T-2174 -test('BUG: should show default value option', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(config).waitForInit(); - await mockRecord('test2174'); - await nocoPage.goto(); - - await page.getByLabel('action-Action.Link-View details-view-test2174-table-0').click(); - await page.getByLabel('block-item-CollectionField-test2174-form-test2174.singleSelect-Single select').hover(); - await page - .getByLabel('designer-schema-settings-CollectionField-FormItem.Designer-test2174-test2174.singleSelect') - .hover(); - - await expect(page.getByRole('menuitem', { name: 'Set default value' })).toBeVisible(); -}); diff --git a/packages/core/client/src/__tests__/e2e/bugs/T-2176.test.ts b/packages/core/client/src/__tests__/e2e/bugs/T-2176.test.ts deleted file mode 100644 index acf758461..000000000 --- a/packages/core/client/src/__tests__/e2e/bugs/T-2176.test.ts +++ /dev/null @@ -1,227 +0,0 @@ -import { expect, test } from '@nocobase/test/client'; - -const config = { - pageSchema: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Page', - properties: { - gyi7sgwfctr: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'BlockInitializers', - properties: { - nm5sil2dc2y: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - '3ux5rf2637w': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - '27osls2fuo8': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'TableBlockProvider', - 'x-acl-action': 'roles:list', - 'x-decorator-props': { - collection: 'roles', - resource: 'roles', - action: 'list', - params: { - pageSize: 20, - }, - rowKey: 'name', - showIndex: true, - dragSort: false, - disableTemplate: false, - }, - 'x-designer': 'TableBlockDesigner', - 'x-component': 'CardItem', - 'x-filter-targets': [], - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'TableActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 'var(--nb-spacing)', - }, - }, - 'x-uid': 'kk95b2toxch', - 'x-async': false, - 'x-index': 1, - }, - igzxzc2vt2t: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'array', - 'x-initializer': 'TableColumnInitializers', - 'x-component': 'TableV2', - 'x-component-props': { - rowKey: 'id', - rowSelection: { - type: 'checkbox', - }, - useProps: '{{ useTableBlockProps }}', - }, - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Actions") }}', - 'x-action-column': 'actions', - 'x-decorator': 'TableV2.Column.ActionBar', - 'x-component': 'TableV2.Column', - 'x-designer': 'TableV2.ActionColumnDesigner', - 'x-initializer': 'TableActionColumnInitializers', - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'DndContext', - 'x-component': 'Space', - 'x-component-props': { - split: '|', - }, - properties: { - ocawgcp0v8w: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("View") }}', - 'x-action': 'view', - 'x-designer': 'Action.Designer', - 'x-component': 'Action.Link', - 'x-component-props': { - openMode: 'drawer', - }, - 'x-decorator': 'ACLActionProvider', - 'x-designer-props': { - linkageAction: true, - }, - properties: { - drawer: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("View record") }}', - 'x-component': 'Action.Container', - 'x-component-props': { - className: 'nb-action-popup', - }, - properties: { - tabs: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Tabs', - 'x-component-props': {}, - 'x-initializer': 'TabPaneInitializers', - properties: { - tab1: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{t("Details")}}', - 'x-component': 'Tabs.TabPane', - 'x-designer': 'Tabs.Designer', - 'x-component-props': {}, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'RecordBlockInitializers', - 'x-uid': 'v1z2373u5p1', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'p52m5ti5boo', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '2l5qzwu1wg3', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'gkictroi33j', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'a07j11haxbn', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'dqe0do6km5f', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'ei7nn2r7iut', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'i9pw6eivnpg', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': '13fp2kvtrlv', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '5babsjvcjrr', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'uw2uttteuhi', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'kwblwpbedaf', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'bzvxogn0d5r', - 'x-async': true, - 'x-index': 1, - }, -}; - -// fix https://nocobase.height.app/T-2176 -test('BUG: Relationship block issue, menu should not display loading', async ({ page, mockPage }) => { - await mockPage(config).goto(); - await page.getByLabel('action-Action.Link-View-view-roles-table-root').click(); - await page.getByLabel('schema-initializer-Grid-RecordBlockInitializers-roles').hover(); - - // 因为下面的断言是判断是否隐藏,又因为一开始就是隐藏的,所以为了准确,需要等待一下 - await page.waitForTimeout(300); - - // 这个输入框不应该显示 - await expect(page.getByPlaceholder('Search and select collection')).toBeHidden(); -}); diff --git a/packages/core/client/src/__tests__/e2e/bugs/T-2183.test.ts b/packages/core/client/src/__tests__/e2e/bugs/T-2183.test.ts deleted file mode 100644 index 88940d258..000000000 --- a/packages/core/client/src/__tests__/e2e/bugs/T-2183.test.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { expect, test } from '@nocobase/test/client'; - -const config = { - pageSchema: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Page', - properties: { - '3c1ivjciciu': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'BlockInitializers', - properties: { - '1n5r9s23amo': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - bsmuf6ly8b2: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - ppv3te8l7mo: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'TableBlockProvider', - 'x-acl-action': 'users:list', - 'x-decorator-props': { - collection: 'users', - resource: 'users', - action: 'list', - params: { - pageSize: 20, - }, - rowKey: 'id', - showIndex: true, - dragSort: false, - disableTemplate: false, - }, - 'x-designer': 'TableBlockDesigner', - 'x-component': 'CardItem', - 'x-filter-targets': [], - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'TableActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 'var(--nb-spacing)', - }, - }, - properties: { - o8wqytvd6as: { - 'x-uid': '9vghmn6u5eo', - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Filter") }}', - 'x-action': 'filter', - 'x-designer': 'Filter.Action.Designer', - 'x-component': 'Filter.Action', - 'x-component-props': { - icon: 'FilterOutlined', - useProps: '{{ useFilterActionProps }}', - }, - 'x-align': 'left', - default: { - $and: [], - }, - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'qq7hs80xlut', - 'x-async': false, - 'x-index': 1, - }, - r02zx6qq4ql: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'array', - 'x-initializer': 'TableColumnInitializers', - 'x-component': 'TableV2', - 'x-component-props': { - rowKey: 'id', - rowSelection: { - type: 'checkbox', - }, - useProps: '{{ useTableBlockProps }}', - }, - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Actions") }}', - 'x-action-column': 'actions', - 'x-decorator': 'TableV2.Column.ActionBar', - 'x-component': 'TableV2.Column', - 'x-designer': 'TableV2.ActionColumnDesigner', - 'x-initializer': 'TableActionColumnInitializers', - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'DndContext', - 'x-component': 'Space', - 'x-component-props': { - split: '|', - }, - 'x-uid': '4fcw4u63f3p', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'pxqbve61e9i', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'kta6g2v3m9s', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'yu418id0x3t', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'xrvoeyz6uop', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'u64df000i8u', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'hofapxvp8p7', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'w7nv1c98j2g', - 'x-async': true, - 'x-index': 1, - }, -}; - -// fix https://nocobase.height.app/T-2183 -test('BUG: should save conditions', async ({ page, mockPage }) => { - await mockPage(config).goto(); - await page.getByLabel('action-Filter.Action-Filter-filter-users-table').click(); - await page.getByText('Add condition', { exact: true }).click(); - await page.getByTestId('select-filter-field').getByLabel('Search').click(); - await page.getByRole('menuitemcheckbox', { name: 'ID' }).click(); - await page.getByRole('button', { name: 'Save conditions' }).click(); - - await page.reload(); - await page.getByLabel('action-Filter.Action-Filter-filter-users-table').click(); - - // After refreshing the browser, the set field and operator should still be visible - await expect(page.getByTestId('select-filter-field').getByText('ID')).toBeVisible(); - await expect(page.getByTestId('select-filter-operator').getByText('is')).toBeVisible(); -}); diff --git a/packages/core/client/src/__tests__/e2e/bugs/T-2186.test.ts b/packages/core/client/src/__tests__/e2e/bugs/T-2186.test.ts deleted file mode 100644 index 3ca8acdef..000000000 --- a/packages/core/client/src/__tests__/e2e/bugs/T-2186.test.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { expect, test } from '@nocobase/test/client'; - -const config = { - pageSchema: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Page', - properties: { - cglzmr757wp: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'BlockInitializers', - properties: { - '0r1mwh6fgdj': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - kjjiumynoor: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - qzbbcmvyy7n: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'TableBlockProvider', - 'x-acl-action': 'users:list', - 'x-decorator-props': { - collection: 'users', - resource: 'users', - action: 'list', - params: { - pageSize: 20, - }, - rowKey: 'id', - showIndex: true, - dragSort: false, - disableTemplate: false, - }, - 'x-designer': 'TableBlockDesigner', - 'x-component': 'CardItem', - 'x-filter-targets': [], - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'TableActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 'var(--nb-spacing)', - }, - }, - properties: { - '8yt1cl9miol': { - 'x-uid': 'pcebb2lm84j', - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Filter") }}', - 'x-action': 'filter', - 'x-designer': 'Filter.Action.Designer', - 'x-component': 'Filter.Action', - 'x-component-props': { - icon: 'FilterOutlined', - useProps: '{{ useFilterActionProps }}', - }, - 'x-align': 'left', - default: { - $and: [{}], - }, - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'sz9p441he7c', - 'x-async': false, - 'x-index': 1, - }, - fqmmittx9pb: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'array', - 'x-initializer': 'TableColumnInitializers', - 'x-component': 'TableV2', - 'x-component-props': { - rowKey: 'id', - rowSelection: { - type: 'checkbox', - }, - useProps: '{{ useTableBlockProps }}', - }, - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Actions") }}', - 'x-action-column': 'actions', - 'x-decorator': 'TableV2.Column.ActionBar', - 'x-component': 'TableV2.Column', - 'x-designer': 'TableV2.ActionColumnDesigner', - 'x-initializer': 'TableActionColumnInitializers', - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'DndContext', - 'x-component': 'Space', - 'x-component-props': { - split: '|', - }, - 'x-uid': 'r4m451vcj6l', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'fogxvhca4sg', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '6ywen03do22', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': '47n8qnj6q20', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'xnc0acxgrxz', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '5dy05u5q2b2', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'rue5m4yfin6', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '3xce5ru15d6', - 'x-async': true, - 'x-index': 1, - }, -}; - -// fix https://nocobase.height.app/T-2186 -test('BUG(Filter): the input box displayed should correspond to the field type', async ({ page, mockPage }) => { - await mockPage(config).goto(); - - await page.getByLabel('action-Filter.Action-Filter-filter-users-table').click(); - await page.getByTestId('select-filter-field').getByLabel('Search').click(); - await page.getByRole('menuitemcheckbox', { name: 'ID' }).click(); - - // 应该显示数字输入框 - await expect(page.getByRole('spinbutton')).toBeVisible(); -}); diff --git a/packages/core/client/src/__tests__/e2e/bugs/T-2200.test.ts b/packages/core/client/src/__tests__/e2e/bugs/T-2200.test.ts deleted file mode 100644 index d293e2912..000000000 --- a/packages/core/client/src/__tests__/e2e/bugs/T-2200.test.ts +++ /dev/null @@ -1,370 +0,0 @@ -import { expect, test } from '@nocobase/test/client'; - -const config = { - pageSchema: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Page', - properties: { - n7k4be0tpgt: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'BlockInitializers', - properties: { - ai6ojrzwkiv: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - amsy67ggjr3: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - ajob701dt18: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'TableBlockProvider', - 'x-acl-action': 'users:list', - 'x-decorator-props': { - collection: 'users', - resource: 'users', - action: 'list', - params: { - pageSize: 20, - }, - rowKey: 'id', - showIndex: true, - dragSort: false, - disableTemplate: false, - }, - 'x-designer': 'TableBlockDesigner', - 'x-component': 'CardItem', - 'x-filter-targets': [], - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'TableActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 'var(--nb-spacing)', - }, - }, - 'x-uid': 'farfrcvsydq', - 'x-async': false, - 'x-index': 1, - }, - t1o3f4r1j4q: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'array', - 'x-initializer': 'TableColumnInitializers', - 'x-component': 'TableV2', - 'x-component-props': { - rowKey: 'id', - rowSelection: { - type: 'checkbox', - }, - useProps: '{{ useTableBlockProps }}', - }, - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Actions") }}', - 'x-action-column': 'actions', - 'x-decorator': 'TableV2.Column.ActionBar', - 'x-component': 'TableV2.Column', - 'x-designer': 'TableV2.ActionColumnDesigner', - 'x-initializer': 'TableActionColumnInitializers', - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'DndContext', - 'x-component': 'Space', - 'x-component-props': { - split: '|', - }, - properties: { - ezur2k7gz8k: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Edit") }}', - 'x-action': 'update', - 'x-designer': 'Action.Designer', - 'x-component': 'Action.Link', - 'x-component-props': { - openMode: 'drawer', - icon: 'EditOutlined', - }, - 'x-decorator': 'ACLActionProvider', - 'x-designer-props': { - linkageAction: true, - }, - properties: { - drawer: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Edit record") }}', - 'x-component': 'Action.Container', - 'x-component-props': { - className: 'nb-action-popup', - }, - properties: { - tabs: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Tabs', - 'x-component-props': {}, - 'x-initializer': 'TabPaneInitializers', - properties: { - tab1: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{t("Edit")}}', - 'x-component': 'Tabs.TabPane', - 'x-designer': 'Tabs.Designer', - 'x-component-props': {}, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'RecordBlockInitializers', - properties: { - dv88ljcl0qw: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - '548w29v01eb': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - q83tzsynghl: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-acl-action-props': { - skipScopeCheck: false, - }, - 'x-acl-action': 'users:update', - 'x-decorator': 'FormBlockProvider', - 'x-decorator-props': { - useSourceId: '{{ useSourceIdFromParentRecord }}', - useParams: '{{ useParamsFromRecord }}', - action: 'get', - resource: 'users', - collection: 'users', - }, - 'x-designer': 'FormV2.Designer', - 'x-component': 'CardItem', - 'x-component-props': {}, - properties: { - '8kzqujhwsyl': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'FormV2', - 'x-component-props': { - useProps: '{{ useFormBlockProps }}', - }, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'FormItemInitializers', - properties: { - '3i87cpmv87x': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - am7wls8qu12: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - roles: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'string', - 'x-designer': 'FormItem.Designer', - 'x-component': 'CollectionField', - 'x-decorator': 'FormItem', - 'x-collection-field': 'users.roles', - 'x-component-props': {}, - 'x-uid': 'e196r19yspx', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'ato3s57xtbt', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'dx3bqu24t50', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'rjbjrnn88sq', - 'x-async': false, - 'x-index': 1, - }, - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'UpdateFormActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - layout: 'one-column', - style: { - marginTop: 24, - }, - }, - 'x-uid': 'zh8o2drtd9h', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'ytafkst3w0s', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'ioqb8wteiwr', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'iavf0r5sl2n', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '994dlhgh1iz', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'k390f3n1rz7', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'xm264vyzmkf', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'asl2rgfrz7p', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'xfre469n0yi', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'gdjgqvxv6b1', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'fnctj4uc8xy', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '2dc4d3mlw3k', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '51i2scjmis1', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': '75owqo6visj', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'r4bvdbzinup', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'h066j2xouwn', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'qrkik5iy790', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '3vzzy7tipgq', - 'x-async': true, - 'x-index': 1, - }, -}; - -// fix https://nocobase.height.app/T-2200 -test('BUG: should be possible to change the value of the association field normally', async ({ page, mockPage }) => { - await mockPage(config).goto(); - - await page.getByLabel('action-Action.Link-Edit-update-users-table-0').click(); - await expect(page.getByLabel('Admin')).toBeVisible(); - await expect(page.getByLabel('Member')).toBeVisible(); - await expect(page.getByLabel('Root')).toBeVisible(); - - await page.getByTestId('select-object-multiple').click(); - await page.getByRole('option', { name: 'Member' }).click(); - // 再次点击,关闭下拉框。 - await page.getByTestId('select-object-multiple').click(); - - await expect(page.getByLabel('Admin')).toBeVisible(); - await expect(page.getByLabel('Member')).toBeHidden(); - await expect(page.getByLabel('Root')).toBeVisible(); - - await page.getByLabel('schema-initializer-Grid-FormItemInitializers-users').hover(); - await page.getByRole('menuitem', { name: 'Nickname' }).click(); - - await page.mouse.move(200, 0); - - await page.waitForTimeout(200); - await expect(page.getByLabel('Admin')).toBeVisible(); - await expect(page.getByLabel('Member')).toBeHidden(); - await expect(page.getByLabel('Root')).toBeVisible(); -}); diff --git a/packages/core/client/src/__tests__/e2e/checkTableRow.test.ts b/packages/core/client/src/__tests__/e2e/checkTableRow.test.ts deleted file mode 100644 index 640163841..000000000 --- a/packages/core/client/src/__tests__/e2e/checkTableRow.test.ts +++ /dev/null @@ -1,232 +0,0 @@ -import { expect, test } from '@nocobase/test/client'; - -const config = { - pageSchema: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Page', - properties: { - nrwnyusnbrd: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'BlockInitializers', - properties: { - w85tu6tnlfp: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - q9vljapijwj: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - zia3dyel3jr: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'TableBlockProvider', - 'x-acl-action': 't_fhdhd0nk7b9:list', - 'x-decorator-props': { - collection: 't_fhdhd0nk7b9', - resource: 't_fhdhd0nk7b9', - action: 'list', - params: { - pageSize: 20, - }, - rowKey: 'id', - showIndex: true, - dragSort: false, - disableTemplate: false, - }, - 'x-designer': 'TableBlockDesigner', - 'x-component': 'CardItem', - 'x-filter-targets': [], - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'TableActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 'var(--nb-spacing)', - }, - }, - properties: { - '5210td4a1ms': { - _isJSONSchemaObject: true, - version: '2.0', - title: '{{ t("Delete") }}', - 'x-action': 'destroy', - 'x-component': 'Action', - 'x-designer': 'Action.Designer', - 'x-decorator': 'ACLActionProvider', - 'x-acl-action-props': { - skipScopeCheck: true, - }, - 'x-component-props': { - icon: 'DeleteOutlined', - confirm: { - title: "{{t('Delete record')}}", - content: "{{t('Are you sure you want to delete it?')}}", - }, - useProps: '{{ useBulkDestroyActionProps }}', - }, - 'x-acl-action': 't_fhdhd0nk7b9:destroy', - 'x-align': 'right', - type: 'void', - 'x-uid': 'aud7zy2m18z', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'j10gefyy50y', - 'x-async': false, - 'x-index': 1, - }, - k88f9zdl4k1: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'array', - 'x-initializer': 'TableColumnInitializers', - 'x-component': 'TableV2', - 'x-component-props': { - rowKey: 'id', - rowSelection: { - type: 'checkbox', - }, - useProps: '{{ useTableBlockProps }}', - }, - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Actions") }}', - 'x-action-column': 'actions', - 'x-decorator': 'TableV2.Column.ActionBar', - 'x-component': 'TableV2.Column', - 'x-designer': 'TableV2.ActionColumnDesigner', - 'x-initializer': 'TableActionColumnInitializers', - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'DndContext', - 'x-component': 'Space', - 'x-component-props': { - split: '|', - }, - 'x-uid': 'lky44f6h6kh', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'fvkqaxe6bo1', - 'x-async': false, - 'x-index': 1, - }, - wwn0ajwixxl: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'TableV2.Column.Decorator', - 'x-designer': 'TableV2.Column.Designer', - 'x-component': 'TableV2.Column', - properties: { - f_vbrlno0zej9: { - _isJSONSchemaObject: true, - version: '2.0', - 'x-collection-field': 't_fhdhd0nk7b9.f_vbrlno0zej9', - 'x-component': 'CollectionField', - 'x-component-props': { - ellipsis: true, - }, - 'x-read-pretty': true, - 'x-decorator': null, - 'x-decorator-props': { - labelStyle: { - display: 'none', - }, - }, - 'x-uid': 'emphc9g52u7', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'q7h24jnc070', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'a9qdzmt4vai', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': '98ta7h4ba1f', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'mo6eowotbqd', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '2nmkby45kce', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'zyukds9t2ln', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'd0j1mfitnmr', - 'x-async': true, - 'x-index': 1, - }, - collections: [ - { - name: 't_fhdhd0nk7b9', - title: 'test', - fields: [ - { - name: 'f_vbrlno0zej9', - interface: 'input', - }, - ], - }, - ], -}; - -test('check table row', async ({ page, mockPage, mockRecords }) => { - const nocoPage = await mockPage(config).waitForInit(); - const records = await mockRecords('t_fhdhd0nk7b9', 3); - await nocoPage.goto(); - - await expect(page.getByText(records[0].f_vbrlno0zej9)).toBeVisible(); - - await page.getByLabel('table-index-1').hover(); - await page.getByRole('checkbox', { name: 'checkbox' }).click(); - await page.getByLabel('action-Action-Delete-destroy-t_fhdhd0nk7b9-table').click(); - - // 显示确认弹窗 - await expect(page.getByText('Are you sure you want to delete it?')).toBeVisible(); - - // 点击确认 - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // 确认内容已被删除 - await expect(page.getByText(records[0].f_vbrlno0zej9)).not.toBeVisible(); -}); diff --git a/packages/core/client/src/__tests__/e2e/createCollections.test.ts b/packages/core/client/src/__tests__/e2e/createCollections.test.ts deleted file mode 100644 index 2357feb53..000000000 --- a/packages/core/client/src/__tests__/e2e/createCollections.test.ts +++ /dev/null @@ -1,264 +0,0 @@ -import { expect, test } from '@nocobase/test/client'; - -const pageConfig = { - collections: [ - { - name: 't_wbjenhqk5dz', - title: 'collection1', - inherit: false, - hidden: false, - description: null, - fields: [ - { - name: 'id', - type: 'bigInt', - interface: 'id', - description: null, - collectionName: 't_wbjenhqk5dz', - parentKey: null, - reverseKey: null, - autoIncrement: true, - primaryKey: true, - allowNull: false, - uiSchema: { - type: 'number', - title: '{{t("ID")}}', - 'x-component': 'InputNumber', - 'x-read-pretty': true, - }, - }, - { - name: 'createdAt', - type: 'date', - interface: 'createdAt', - description: null, - collectionName: 't_wbjenhqk5dz', - parentKey: null, - reverseKey: null, - field: 'createdAt', - uiSchema: { - type: 'datetime', - title: '{{t("Created at")}}', - 'x-component': 'DatePicker', - 'x-component-props': {}, - 'x-read-pretty': true, - }, - }, - { - name: 'createdBy', - type: 'belongsTo', - interface: 'createdBy', - description: null, - collectionName: 't_wbjenhqk5dz', - parentKey: null, - reverseKey: null, - target: 'users', - foreignKey: 'createdById', - uiSchema: { - type: 'object', - title: '{{t("Created by")}}', - 'x-component': 'AssociationField', - 'x-component-props': { - fieldNames: { - value: 'id', - label: 'nickname', - }, - }, - 'x-read-pretty': true, - }, - targetKey: 'id', - }, - { - name: 'updatedAt', - type: 'date', - interface: 'updatedAt', - description: null, - collectionName: 't_wbjenhqk5dz', - parentKey: null, - reverseKey: null, - field: 'updatedAt', - uiSchema: { - type: 'string', - title: '{{t("Last updated at")}}', - 'x-component': 'DatePicker', - 'x-component-props': {}, - 'x-read-pretty': true, - }, - }, - { - name: 'updatedBy', - type: 'belongsTo', - interface: 'updatedBy', - description: null, - collectionName: 't_wbjenhqk5dz', - parentKey: null, - reverseKey: null, - target: 'users', - foreignKey: 'updatedById', - uiSchema: { - type: 'object', - title: '{{t("Last updated by")}}', - 'x-component': 'AssociationField', - 'x-component-props': { - fieldNames: { - value: 'id', - label: 'nickname', - }, - }, - 'x-read-pretty': true, - }, - targetKey: 'id', - }, - ], - category: [], - logging: true, - autoGenId: true, - createdBy: true, - updatedBy: true, - createdAt: true, - updatedAt: true, - sortable: true, - template: 'general', - view: false, - }, - { - name: 't_u0c1mmzldgo', - title: 'collection2', - inherit: false, - hidden: false, - description: null, - fields: [ - { - name: 'id', - type: 'bigInt', - interface: 'id', - description: null, - collectionName: 't_u0c1mmzldgo', - parentKey: null, - reverseKey: null, - autoIncrement: true, - primaryKey: true, - allowNull: false, - uiSchema: { - type: 'number', - title: '{{t("ID")}}', - 'x-component': 'InputNumber', - 'x-read-pretty': true, - }, - }, - { - name: 'createdAt', - type: 'date', - interface: 'createdAt', - description: null, - collectionName: 't_u0c1mmzldgo', - parentKey: null, - reverseKey: null, - field: 'createdAt', - uiSchema: { - type: 'datetime', - title: '{{t("Created at")}}', - 'x-component': 'DatePicker', - 'x-component-props': {}, - 'x-read-pretty': true, - }, - }, - { - name: 'createdBy', - type: 'belongsTo', - interface: 'createdBy', - description: null, - collectionName: 't_u0c1mmzldgo', - parentKey: null, - reverseKey: null, - target: 'users', - foreignKey: 'createdById', - uiSchema: { - type: 'object', - title: '{{t("Created by")}}', - 'x-component': 'AssociationField', - 'x-component-props': { - fieldNames: { - value: 'id', - label: 'nickname', - }, - }, - 'x-read-pretty': true, - }, - targetKey: 'id', - }, - { - name: 'updatedAt', - type: 'date', - interface: 'updatedAt', - description: null, - collectionName: 't_u0c1mmzldgo', - parentKey: null, - reverseKey: null, - field: 'updatedAt', - uiSchema: { - type: 'string', - title: '{{t("Last updated at")}}', - 'x-component': 'DatePicker', - 'x-component-props': {}, - 'x-read-pretty': true, - }, - }, - { - name: 'updatedBy', - type: 'belongsTo', - interface: 'updatedBy', - description: null, - collectionName: 't_u0c1mmzldgo', - parentKey: null, - reverseKey: null, - target: 'users', - foreignKey: 'updatedById', - uiSchema: { - type: 'object', - title: '{{t("Last updated by")}}', - 'x-component': 'AssociationField', - 'x-component-props': { - fieldNames: { - value: 'id', - label: 'nickname', - }, - }, - 'x-read-pretty': true, - }, - targetKey: 'id', - }, - ], - category: [], - logging: true, - autoGenId: true, - createdBy: true, - updatedBy: true, - createdAt: true, - updatedAt: true, - sortable: true, - template: 'general', - view: false, - }, - ], -}; - -test.describe('createCollections', () => { - test('quickly create collections', async ({ page, mockPage }) => { - await mockPage(pageConfig).goto(); - - await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); - await page.getByRole('menuitem', { name: 'table Table' }).hover(); - - await expect(page.getByRole('menuitem', { name: 'collection1' })).toBeVisible(); - await expect(page.getByRole('menuitem', { name: 'collection2' })).toBeVisible(); - }); - - test('no page, just create collections', async ({ page, createCollections }) => { - await createCollections(pageConfig.collections); - await page.goto('/admin/settings/collection-manager/collections'); - - await expect(page.getByText('collection1')).toBeVisible(); - await expect(page.getByText('collection2')).toBeVisible(); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/createDataBlock.test.ts b/packages/core/client/src/__tests__/e2e/createDataBlock.test.ts deleted file mode 100644 index 2b515f3ce..000000000 --- a/packages/core/client/src/__tests__/e2e/createDataBlock.test.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { expect, test } from '@nocobase/test/client'; - -test.describe('create data block', () => { - test('table', async ({ page, mockPage }) => { - await mockPage().goto(); - - await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); - await page.getByRole('menuitem', { name: 'table Table' }).hover(); - await page.getByRole('menuitem', { name: 'Users' }).click(); - - await expect(page.getByText('Configure columns')).toBeVisible(); - }); - - test('form', async ({ page, mockPage }) => { - await mockPage().goto(); - - await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); - await page.getByRole('menuitem', { name: 'Form' }).first().hover(); - await page.getByRole('menuitem', { name: 'Users' }).click(); - await page.mouse.move(300, 0); - - await expect(page.getByText('Configure fields')).toBeVisible(); - }); - - test('details', async ({ page, mockPage }) => { - await mockPage().goto(); - - await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); - await page.getByRole('menuitem', { name: 'Details' }).hover(); - await page.getByRole('menuitem', { name: 'Users' }).click(); - - await expect(page.getByText('Configure fields')).toBeVisible(); - }); - - test('list', async ({ page, mockPage }) => { - await mockPage().goto(); - - await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); - await page.getByRole('menuitem', { name: 'ordered-list List' }).hover(); - await page.getByRole('menuitem', { name: 'Users' }).click(); - - await expect(page.getByText('Configure fields').first()).toBeVisible(); - }); - - test('grid card', async ({ page, mockPage }) => { - await mockPage().goto(); - - await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); - await page.getByRole('menuitem', { name: 'Grid Card' }).hover(); - await page.getByRole('menuitem', { name: 'Users' }).click(); - - await expect(page.getByText('Configure fields').first()).toBeVisible(); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/field.test.ts b/packages/core/client/src/__tests__/e2e/field.test.ts deleted file mode 100644 index bf4c89b9c..000000000 --- a/packages/core/client/src/__tests__/e2e/field.test.ts +++ /dev/null @@ -1,332 +0,0 @@ -import { expect, test } from '@nocobase/test/client'; -import { approximateColor } from './utils'; -const formPageSchema = { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Page', - properties: { - lyie34rtcu4: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'BlockInitializers', - properties: { - skmxkfr67em: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - '860xnb3egb8': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - aa9rqm7bkud: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-acl-action-props': { - skipScopeCheck: true, - }, - 'x-acl-action': 'users:create', - 'x-decorator': 'FormBlockProvider', - 'x-decorator-props': { - resource: 'users', - collection: 'users', - }, - 'x-designer': 'FormV2.Designer', - 'x-component': 'CardItem', - 'x-component-props': {}, - properties: { - t4mi2jywqj7: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'FormV2', - 'x-component-props': { - useProps: '{{ useFormBlockProps }}', - }, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'FormItemInitializers', - 'x-uid': '66dozhzo5ld', - 'x-async': false, - 'x-index': 1, - }, - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'FormActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - layout: 'one-column', - style: { - marginTop: 24, - }, - }, - 'x-uid': 'q8am9zt6m2x', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': '4ojxya0re8h', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '183n4o77awp', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'zwxgkj66isi', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '8tryd9kz9bd', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'piwq6rrjrsq', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '5cszm46yqxb', - 'x-async': true, - 'x-index': 1, -}; - -test.describe('add field & remove field in block', () => { - test('add field,then remove field in block', async ({ page, mockPage }) => { - await mockPage({ pageSchema: formPageSchema }).goto(); - await page.getByLabel('schema-initializer-Grid-FormItemInitializers-users').hover(); - await page.getByRole('menuitem', { name: 'Nickname' }).click(); - await page.getByRole('menuitem', { name: 'Username' }).click(); - await page.getByRole('menuitem', { name: 'Email' }).click(); - //添加字段 - await expect(page.getByLabel('block-item-CollectionField-users-form-users.nickname')).toBeVisible(); - await expect(page.getByLabel('block-item-CollectionField-users-form-users.username')).toBeVisible(); - await expect(page.getByLabel('block-item-CollectionField-users-form-users.email')).toBeVisible(); - //激活的状态 - await expect(page.getByRole('menuitem', { name: 'Nickname' }).getByRole('switch')).toBeChecked(); - await expect(page.getByRole('menuitem', { name: 'Username' }).getByRole('switch')).toBeChecked(); - await expect(page.getByRole('menuitem', { name: 'Email' }).getByRole('switch')).toBeChecked(); - //移除字段 - await page.getByRole('menuitem', { name: 'Nickname' }).click(); - await page.getByRole('menuitem', { name: 'Username' }).click(); - await page.getByRole('menuitem', { name: 'Email' }).click(); - await expect(page.getByLabel('block-item-CollectionField-users-form-users.nickname')).not.toBeVisible(); - await expect(page.getByLabel('block-item-CollectionField-users-form-users.username')).not.toBeVisible(); - await expect(page.getByLabel('block-item-CollectionField-users-form-users.email')).not.toBeVisible(); - await expect(page.getByRole('menuitem', { name: 'Nickname' }).getByRole('switch')).not.toBeChecked(); - await expect(page.getByRole('menuitem', { name: 'Username' }).getByRole('switch')).not.toBeChecked(); - await expect(page.getByRole('menuitem', { name: 'Email' }).getByRole('switch')).not.toBeChecked(); - }); -}); - -test.describe('drag field in block', () => { - test('drag field for layout', async ({ page, mockPage }) => { - await mockPage({ pageSchema: formPageSchema }).goto(); - await page.getByLabel('schema-initializer-Grid-FormItemInitializers-users').click(); - await page.getByRole('menuitem', { name: 'Nickname' }).click(); - await page.getByRole('menuitem', { name: 'Username' }).click(); - await page.getByRole('menuitem', { name: 'Email' }).click(); - - const sourceElement = page.getByLabel('block-item-CollectionField-users-form-users.nickname'); - await sourceElement.hover(); - const source = sourceElement.getByLabel('designer-drag'); - await source.hover(); - const targetElement = page.getByLabel('block-item-CollectionField-users-form-users.username'); - await source.dragTo(targetElement); - - const targetElement2 = page.getByLabel('block-item-CollectionField-users-form-users.email'); - await source.hover(); - await source.dragTo(targetElement2); - - await sourceElement.hover(); - const nickname = await source.boundingBox(); - const username = await targetElement.boundingBox(); - const email = await targetElement2.boundingBox(); - const max = Math.max(username.y, nickname.y, email.y); - //拖拽调整排序符合预期 - expect(nickname.y).toBe(max); - }); -}); - -test.describe('field setting config ', () => { - test('edit field label in block', async ({ page, mockPage }) => { - await mockPage({ pageSchema: formPageSchema }).goto(); - await page.getByLabel('schema-initializer-Grid-FormItemInitializers-users').hover(); - await page.getByRole('menuitem', { name: 'Username' }).click(); - await page.getByLabel('block-item-CollectionField-users-form-users.username').hover(); - await page.getByLabel('designer-schema-settings-CollectionField-FormItem.Designer-users-users.username').hover(); - await page.getByRole('menuitem', { name: 'Edit field title' }).click(); - await page.getByLabel('block-item-Input-users-Field title').getByRole('textbox').fill('Username1'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - await expect( - page.getByLabel('block-item-CollectionField-users-form-users.username').getByText('Username1'), - ).toBeVisible(); - //回显 - await page.getByLabel('block-item-CollectionField-users-form-users.username').click(); - await page - .getByLabel('block-item-CollectionField-users-form-users.username') - .getByLabel('designer-schema-settings') - .hover(); - await page.getByRole('menuitem', { name: 'Edit field title' }).click(); - await expect(page.getByLabel('block-item-Input-users-Field title').getByRole('textbox')).toHaveValue('Username1'); - }); - test('display & not display field label in block ', async ({ page, mockPage }) => { - await mockPage({ pageSchema: formPageSchema }).goto(); - await page.getByLabel('schema-initializer-Grid-FormItemInitializers-users').hover(); - await page.getByRole('menuitem', { name: 'Username' }).click(); - await page.getByLabel('block-item-CollectionField-users-form-users.username').click(); - await page - .getByLabel('block-item-CollectionField-users-form-users.username') - .getByLabel('designer-schema-settings') - .hover(); - await page.getByRole('menuitem', { name: 'Display title' }).hover(); - //默认显示 - await expect(page.getByRole('menuitem', { name: 'Display title' }).getByRole('switch')).toBeChecked(); - //设置不显示标题 - await page.getByRole('menuitem', { name: 'Display title' }).click(); - const labelItem = page - .getByLabel('block-item-CollectionField-users-form-users.username') - .locator('.ant-formily-item-label'); - const labelDisplay = await labelItem.evaluate((element) => { - const computedStyle = window.getComputedStyle(element); - return computedStyle.display; - }); - expect(labelDisplay).toBe('none'); - //设置显示标题 - await page.getByLabel('block-item-CollectionField-users-form-users.username').click(); - await page - .getByLabel('block-item-CollectionField-users-form-users.username') - .getByLabel('designer-schema-settings') - .hover(); - await page.getByRole('menuitem', { name: 'Display title' }).click(); - const labelDisplay1 = await labelItem.evaluate((element) => { - const computedStyle = window.getComputedStyle(element); - return computedStyle.display; - }); - expect(labelDisplay1).toBe('flex'); - }); - test('edit field description ', async ({ page, mockPage }) => { - await mockPage({ pageSchema: formPageSchema }).goto(); - const description = 'field description'; - const descriptionColor = 'rgba(0, 0, 0, 0.65)'; - await page.getByLabel('schema-initializer-Grid-FormItemInitializers-users').click(); - await page.getByRole('menuitem', { name: 'Username' }).click(); - await page.getByLabel('block-item-CollectionField-users-form-users.username').click(); - await page - .getByLabel('block-item-CollectionField-users-form-users.username') - .getByLabel('designer-schema-settings') - .hover(); - await page.getByRole('menuitem', { name: 'Edit description' }).click(); - await page.getByLabel('block-item-Input.TextArea-users').locator('textarea').fill(description); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - const descriptionItem = page - .getByLabel('block-item-CollectionField-users-form-users.username') - .locator('.ant-formily-item-extra'); - const descriptionItemColor = await descriptionItem.evaluate((element) => { - const computedStyle = window.getComputedStyle(element); - return computedStyle.color; - }); - //字段描述样式符合预期 - expect(await descriptionItem.innerText()).toBe(description); - const isApproximate = approximateColor(descriptionItemColor, descriptionColor); - expect(isApproximate).toBe(true); - }); - test('field required ', async ({ page, mockPage }) => { - await mockPage({ pageSchema: formPageSchema }).goto(); - await page.getByLabel('schema-initializer-Grid-FormItemInitializers-users').click(); - await page.getByRole('menuitem', { name: 'Nickname' }).click(); - await page.getByLabel('block-item-CollectionField-users-form-users.nickname').click(); - await page - .getByLabel('block-item-CollectionField-users-form-users.nickname') - .getByLabel('designer-schema-settings') - .hover(); - await page.getByRole('menuitem', { name: 'Required' }).click(); - await page.getByLabel('schema-initializer-ActionBar-FormActionInitializers-users').click(); - await page.getByRole('menuitem', { name: 'Submit' }).click(); - await page.getByLabel('action-Action-Submit-submit-users-form').click(); - //必填校验符合预期 - await expect( - page.getByLabel('block-item-CollectionField-users-form-users.nickname').locator('.ant-formily-item-error-help'), - ).toBeVisible(); - const inputItem = page.getByLabel('block-item-CollectionField-users-form-users.nickname').locator('input'); - const inputErrorBorderColor = await inputItem.evaluate((element) => { - const computedStyle = window.getComputedStyle(element); - return computedStyle.borderColor; - }); - //样式符合预期 - expect(inputErrorBorderColor).toBe('rgb(255, 77, 79)'); - // TODO: 该断言无效,因为在任何情况下该断言都能通过 - // 断言表单未被提交 - expect(page.getByLabel('block-item-CardItem-users-form').locator('form')).not.toHaveProperty('submitted', true); - }); - test('field validation rule ', async ({ page, mockPage }) => { - await mockPage({ pageSchema: formPageSchema }).goto(); - const errorMessage = 'this is error message'; - await page.getByLabel('schema-initializer-Grid-FormItemInitializers-users').click(); - await page.getByRole('menuitem', { name: 'Nickname' }).click(); - - await page.getByLabel('block-item-CollectionField-users-form-users.nickname').click(); - await page - .getByLabel('block-item-CollectionField-users-form-users.nickname') - .getByLabel('designer-schema-settings') - .hover(); - await page.getByRole('menuitem', { name: 'Set validation rules' }).click(); - await page.getByRole('button', { name: 'plus Add validation rule' }).click(); - await page.getByLabel('block-item-InputNumber-users-Max length').getByRole('spinbutton').fill('3'); - await page.getByRole('button', { name: 'Error message' }).locator('textarea').fill(errorMessage); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - await page.getByLabel('block-item-CollectionField-users-form-users.nickname').getByRole('textbox').fill('1111'); - const errorInfo = page - .getByLabel('block-item-CollectionField-users-form-users.nickname') - .locator('.ant-formily-item-error-help'); - await expect(errorInfo).toBeVisible(); - //报错信息符合预期 - expect(await errorInfo.innerText()).toBe(errorMessage); - await page.getByLabel('schema-initializer-ActionBar-FormActionInitializers-users').click(); - await page.getByRole('menuitem', { name: 'Submit' }).click(); - await page.getByLabel('action-Action-Submit-submit-users-form').click(); - // TODO: 该断言无效,因为在任何情况下该断言都能通过 - // 断言表单未被提交 - expect(page.getByLabel('block-item-CardItem-users-form').locator('form')).not.toHaveProperty('submitted', true); - }); - test('field pattern ', async ({ page, mockPage }) => { - await mockPage({ pageSchema: formPageSchema }).goto(); - await page.getByLabel('schema-initializer-Grid-FormItemInitializers-users').click(); - await page.getByRole('menuitem', { name: 'Nickname' }).click(); - - await page.getByLabel('block-item-CollectionField-users-form-users.nickname').click(); - const inputElement = page.getByLabel('block-item-CollectionField-users-form-users.nickname').locator('input'); - await page - .getByLabel('block-item-CollectionField-users-form-users.nickname') - .getByLabel('designer-schema-settings') - .hover(); - await page.getByRole('menuitem', { name: 'Pattern' }).click(); - - //禁用 - await page.getByRole('option', { name: 'Readonly' }).click(); - await expect(inputElement).toBeDisabled(); - await page.getByRole('menuitem', { name: 'Pattern' }).click(); - //只读 - await page.getByText('Easy-reading').click(); - await expect( - page.getByLabel('block-item-CollectionField-users-form-users.nickname').locator('.ant-description-input'), - ).toBeInViewport(); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/loadAssociationData.test.ts b/packages/core/client/src/__tests__/e2e/loadAssociationData.test.ts deleted file mode 100644 index e8d04352d..000000000 --- a/packages/core/client/src/__tests__/e2e/loadAssociationData.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { T2614, T2615, expect, test } from '@nocobase/test/client'; - -test.describe('load association data', () => { - // https://nocobase.height.app/T-2615 - test('should load association data', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(T2615).waitForInit(); - await mockRecord('T2615'); - await nocoPage.goto(); - - // 1. 新增表单中应该显示关系字段的数据 - await page.getByRole('button', { name: 'Add new' }).click(); - await page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o-m2o').getByLabel('Search').click(); - await page.getByRole('option', { name: '1' }).click(); - await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o.m2oOfTarget1')).toHaveText( - `m2oOfTarget1:1`, - ); - - // 关闭弹窗 - await page.getByLabel('drawer-Action.Container-T2615-Add record-mask').click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // 2. 编辑表单中应该显示关系字段的数据 - await page.getByLabel('action-Action.Link-Edit record-update-T2615-table-0').click(); - await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o-m2o')).toHaveText(`m2o:1`); - await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o.m2oOfTarget1')).toHaveText( - `m2oOfTarget1:1`, - ); - - await page.getByLabel('drawer-Action.Container-T2615-Edit record-mask').click(); - - // 3. 详情中应该显示关系字段的数据 - await page.getByLabel('action-Action.Link-View record-view-T2615-table-0').click(); - await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o-m2o')).toHaveText(`m2o:1`); - await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o.m2oOfTarget1')).toHaveText( - `m2oOfTarget1:1`, - ); - }); - - // https://nocobase.height.app/T-2614 - test('should load association data in subform', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(T2614).waitForInit(); - await mockRecord('T2614'); - await nocoPage.goto(); - - // 查看详情 - await page.getByLabel('action-Action.Link-View record-view-T2614-table-0').click(); - await expect( - page.getByLabel('block-item-CollectionField-T2614Target1-form-T2614Target1.m2oOfTarget1-m2oOfTarget1'), - ).toHaveText(`m2oOfTarget1:1`); - await expect( - page.getByLabel('block-item-CollectionField-T2614Target1-form-T2614Target1.m2oOfTarget1.id'), - ).toHaveText(`ID:1`); - - // 关闭弹窗 - await page.getByLabel('drawer-Action.Container-T2614-View record-mask').click(); - - // 编辑详情 - await page.getByLabel('action-Action.Link-Edit record-update-T2614-table-0').click(); - await expect( - page.getByLabel('block-item-CollectionField-T2614Target1-form-T2614Target1.m2oOfTarget1-m2oOfTarget1'), - ).toHaveText(`m2oOfTarget1:1`); - await expect( - page.getByLabel('block-item-CollectionField-T2614Target1-form-T2614Target1.m2oOfTarget1.id'), - ).toHaveText(`ID:1`); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/menu.test.ts b/packages/core/client/src/__tests__/e2e/menu.test.ts deleted file mode 100644 index 92444ac8b..000000000 --- a/packages/core/client/src/__tests__/e2e/menu.test.ts +++ /dev/null @@ -1,212 +0,0 @@ -import { enableToConfig, expect, test } from '@nocobase/test/client'; -import { approximateColor } from './utils'; - -test.describe('menu page', () => { - test('create new page, then delete', async ({ page, mockPage }) => { - await mockPage().goto(); - const pageTitle = 'new page'; - await page.getByTestId('schema-initializer-Menu-header').hover(); - await page.getByRole('menuitem', { name: 'Page' }).click(); - await page.getByRole('textbox').click(); - await page.getByRole('textbox').fill(pageTitle); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - const menuItem = page.getByRole('menu').locator('li').filter({ hasText: pageTitle }); - const defaultBackgroundColor = await menuItem.evaluate((element) => { - const computedStyle = window.getComputedStyle(element); - return computedStyle.backgroundColor; - }); - await menuItem.click(); - // 获取激活后的背景高亮颜色 - const activeBackgroundColor = await menuItem.evaluate((element) => { - const computedStyle = window.getComputedStyle(element); - return computedStyle.backgroundColor; - }); - // 菜单高亮/进入空页面只有一个add block 按钮 - expect(activeBackgroundColor).not.toBe(defaultBackgroundColor); - await expect(page.getByLabel('schema-initializer-Grid-BlockInitializers')).toBeVisible(); - await expect(page.getByTitle(pageTitle)).toBeVisible(); - const divElement = page.locator('.nb-page-content'); - const buttons = await divElement.locator('button').count(); - const divText = await divElement.textContent(); - - expect(buttons).toEqual(1); - expect(divText).toBe('Add block'); - - // 删除页面,避免影响其他测试 - await page.getByLabel(pageTitle).click(); - await page.getByLabel(pageTitle).getByLabel('designer-schema-settings').hover(); - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - await mockPage().goto(); - await expect(page.getByTitle(pageTitle)).not.toBeVisible(); - }); - test('edit menu title', async ({ page, mockPage }) => { - const pageTitle = 'page title'; - const newPageTitle = 'page title1'; - await mockPage({ - name: pageTitle, - }).goto(); - await page.getByLabel(pageTitle).hover(); - await page.getByLabel(pageTitle).getByLabel('designer-schema-settings').hover(); - await page.getByRole('menuitem', { name: 'Edit' }).click(); - await page.mouse.move(300, 0); - await page.getByRole('textbox').click(); - await page.getByRole('textbox').fill(newPageTitle); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - await page.getByRole('menu').getByText(newPageTitle).click(); - await mockPage().goto(); - await page.getByText(newPageTitle).click(); - await expect(page.getByTitle(newPageTitle)).toBeVisible(); - }); - test('move menu ', async ({ page, mockPage }) => { - const pageTitle1 = 'page1'; - const pageTitle2 = 'page2'; - await mockPage({ - name: pageTitle1, - }).goto(); - await mockPage({ name: pageTitle2 }).goto(); - await enableToConfig(page); - await page.getByRole('menu').getByText(pageTitle1).click(); - await page.getByRole('menu').getByText(pageTitle1).hover(); - await page.getByLabel(pageTitle1).getByLabel('designer-schema-settings').hover(); - await page.getByRole('menuitem', { name: 'Move to' }).click(); - await page.getByRole('dialog').click(); - await page.getByLabel('Search').click(); - await page.locator('.ant-select-dropdown').getByText(pageTitle2).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - const page1 = await page.getByRole('menu').getByText(pageTitle1).boundingBox(); - const page2 = await page.getByRole('menu').getByText(pageTitle2).boundingBox(); - //拖拽菜单排序符合预期 - expect(page2.x).toBeLessThan(page1.x); - }); - - test('insert page before', async ({ page, mockPage }) => { - const pageTitle3 = 'page3'; - const pageTitle4 = 'page4'; - await mockPage({ - name: pageTitle3, - }).goto(); - - await page.getByLabel(pageTitle3).click(); - await page.getByLabel(pageTitle3).hover(); - await page.getByLabel(pageTitle3).getByLabel('designer-schema-settings').hover(); - - await page.getByRole('menuitem', { name: 'Insert before' }).hover(); - - await page.getByRole('menuitem', { name: 'Page', exact: true }).click(); - await page.getByRole('textbox').fill(pageTitle4); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - const page3 = await page.getByLabel(pageTitle3).boundingBox(); - const page4 = await page.getByLabel(pageTitle4).boundingBox(); - //插入的菜单位置符合预期,且进入空页面 - expect(page4.x).toBeLessThan(page3.x); - await page.getByRole('menu').getByText(pageTitle4).click(); - await expect(page.getByLabel('schema-initializer-Grid-BlockInitializers')).toBeVisible(); - //删除页面 - await page.getByLabel(pageTitle4).click(); - await page.getByLabel(pageTitle4).getByLabel('designer-schema-settings').hover(); - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - }); - - test('insert page after', async ({ page, mockPage }) => { - const pageTitle5 = 'page5'; - const pageTitle6 = 'page6'; - await mockPage({ - name: pageTitle5, - }).goto(); - - await page.getByLabel(pageTitle5).click(); - await page.getByLabel(pageTitle5).hover(); - await page.getByLabel(pageTitle5).getByLabel('designer-schema-settings').hover(); - - await page.getByRole('menuitem', { name: 'Insert after' }).hover(); - - await page.getByRole('menuitem', { name: 'Page', exact: true }).click(); - await page.getByRole('textbox').fill(pageTitle6); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - const page6 = await page.getByLabel(pageTitle6).boundingBox(); - const page5 = await page.getByLabel(pageTitle5).boundingBox(); - //插入的菜单位置符合预期 - expect(page5.x).toBeLessThan(page6.x); - await page.getByLabel(pageTitle6).click(); - await expect(page.getByLabel('schema-initializer-Grid-BlockInitializers')).toBeVisible(); - //删除页面 - await page.getByLabel(pageTitle6).getByLabel('designer-schema-settings-Menu.Item').hover(); - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - }); -}); - -test.describe('menu group', () => { - test('create new menu group, then delete', async ({ page, mockPage }) => { - await mockPage().goto(); - await page.getByTestId('schema-initializer-Menu-header').hover(); - await page.getByRole('menuitem', { name: 'Group' }).click(); - await page.getByRole('textbox').click(); - await page.getByRole('textbox').fill('menu Group'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - await page.getByText('menu Group').click(); - - await expect(page.getByTestId('schema-initializer-Menu-side')).toBeVisible(); - const sideBar = await page.locator('ul').filter({ hasText: /^Add menu item$/ }); - await expect(sideBar).toBeVisible(); - - //添加子页面 - await page - .locator('ul') - .filter({ hasText: /^Add menu item$/ }) - .click(); - await page.getByTestId('schema-initializer-Menu-side').click(); - await page.getByRole('menuitem', { name: 'Page', exact: true }).click(); - await page.getByRole('textbox').click(); - await page.getByRole('textbox').fill('group page'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - await page.getByText('group page').click(); - //进入子页面 - await expect(page.getByTitle('group page')).toBeVisible(); - //对应分组/子菜单项均高亮 - const menuItem = await page.getByRole('menu').locator('li').filter({ hasText: 'menu Group' }); - const menuItemBackgroundColor = await menuItem.evaluate((element) => { - const computedStyle = window.getComputedStyle(element); - return computedStyle.backgroundColor; - }); - const isApproximate = approximateColor(menuItemBackgroundColor, 'rgba(255, 255, 255, 0.1)'); - expect(isApproximate).toBe(true); - const pageItem = page.getByRole('menu').locator('li').filter({ hasText: 'group page' }); - - const pageItemBackgroundColor = await pageItem.evaluate((element) => { - const computedStyle = window.getComputedStyle(element); - return computedStyle.backgroundColor; - }); - expect(pageItemBackgroundColor).toBe('rgb(230, 244, 255)'); - - // 删除页面,避免影响其他测试 - await page.getByLabel('menu Group').click(); - await page.getByLabel('menu Group').hover(); - await page.getByLabel('menu Group').getByLabel('designer-schema-settings').first().hover(); - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - await mockPage().goto(); - await expect(page.getByTitle('menu Group')).not.toBeVisible(); - }); -}); - -test.describe('menu link', () => { - test('create new menu link, then delete', async ({ page, mockPage, deletePage }) => { - await mockPage().goto(); - await page.getByTestId('schema-initializer-Menu-header').hover(); - await page.getByRole('menuitem', { name: 'Link' }).click(); - await page.getByLabel('block-item-Input-Menu item title').getByRole('textbox').fill('link menu'); - await page.getByLabel('block-item-Input-Link').getByRole('textbox').fill('https://www.baidu.com/'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - await page.getByLabel('link menu').click(); - const page2 = await page.waitForEvent('popup'); - - expect(page2.url()).toBe('https://www.baidu.com/'); - // 删除页面,避免影响其他测试 - await deletePage('link menu'); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/mock.test.ts b/packages/core/client/src/__tests__/e2e/mock.test.ts deleted file mode 100644 index 7229be39d..000000000 --- a/packages/core/client/src/__tests__/e2e/mock.test.ts +++ /dev/null @@ -1,196 +0,0 @@ -import { expect, test } from '@nocobase/test/client'; - -const phonePageConfig = { - collections: [ - { - name: 't_x3mxc1ymorw', - title: 'mock-testing', - fields: [ - { - name: 'email', - title: 'Email', - interface: 'email', - }, - ], - }, - ], - pageSchema: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Page', - 'x-index': 1, - properties: { - zyfy6q68u10: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'BlockInitializers', - 'x-index': 1, - properties: { - nkbrwj149hw: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - t9wwr80ymdc: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - b0iohq28s9u: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'TableBlockProvider', - 'x-acl-action': 't_x3mxc1ymorw:list', - 'x-decorator-props': { - collection: 't_x3mxc1ymorw', - resource: 't_x3mxc1ymorw', - action: 'list', - params: { - pageSize: 20, - }, - rowKey: 'id', - showIndex: true, - dragSort: false, - disableTemplate: false, - }, - 'x-designer': 'TableBlockDesigner', - 'x-component': 'CardItem', - 'x-filter-targets': [], - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'TableActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 'var(--nb-spacing)', - }, - }, - 'x-uid': '0wksx4dtgum', - 'x-async': false, - 'x-index': 1, - }, - zvooo4ygn4x: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'array', - 'x-initializer': 'TableColumnInitializers', - 'x-component': 'TableV2', - 'x-component-props': { - rowKey: 'id', - rowSelection: { - type: 'checkbox', - }, - useProps: '{{ useTableBlockProps }}', - }, - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Actions") }}', - 'x-action-column': 'actions', - 'x-decorator': 'TableV2.Column.ActionBar', - 'x-component': 'TableV2.Column', - 'x-designer': 'TableV2.ActionColumnDesigner', - 'x-initializer': 'TableActionColumnInitializers', - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'DndContext', - 'x-component': 'Space', - 'x-component-props': { - split: '|', - }, - 'x-uid': '3gombpceyjl', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'vcjbrby0i27', - 'x-async': false, - 'x-index': 1, - }, - olrr4chfvfh: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'TableV2.Column.Decorator', - 'x-designer': 'TableV2.Column.Designer', - 'x-component': 'TableV2.Column', - properties: { - email: { - _isJSONSchemaObject: true, - version: '2.0', - 'x-collection-field': 't_x3mxc1ymorw.email', - 'x-component': 'CollectionField', - 'x-component-props': { - ellipsis: true, - }, - 'x-read-pretty': true, - 'x-decorator': null, - 'x-decorator-props': { - labelStyle: { - display: 'none', - }, - }, - 'x-uid': 'sqogd3z6o95', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'vcve0j78imw', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'benml5cswa0', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'v0bydleh1ni', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'rmplhh05qpr', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'szfwommojdg', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'k8t4d8im9lx', - 'x-async': false, - }, - }, - 'x-uid': 't6726o68agh', - 'x-async': true, - }, -}; - -test.describe('mock record', () => { - test('email field', async ({ page, mockPage, mockRecords }) => { - const nocoPage = await mockPage(phonePageConfig).waitForInit(); - const records = await mockRecords<{ email: string }>('t_x3mxc1ymorw', 3); - await nocoPage.goto(); - - await expect(page.getByRole('cell', { name: records[0].email })).toBeVisible(); - await expect(page.getByRole('cell', { name: records[1].email })).toBeVisible(); - await expect(page.getByRole('cell', { name: records[2].email })).toBeVisible(); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/page.test.ts b/packages/core/client/src/__tests__/e2e/page.test.ts deleted file mode 100644 index dc0278465..000000000 --- a/packages/core/client/src/__tests__/e2e/page.test.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { expect, test } from '@nocobase/test/client'; - -test.describe('page header', () => { - test('disabled & enabled page header', async ({ page, mockPage }) => { - const pageTitle = 'page header'; - await mockPage({ name: pageTitle }).goto(); - //默认开启 - await expect(page.getByTitle(pageTitle)).toBeVisible(); - await page.getByTitle(pageTitle).click(); - await page.getByLabel('designer-schema-settings-Page').hover(); - await expect(page.getByRole('menuitem', { name: 'Enable page header' }).getByRole('switch')).toBeChecked(); - //关闭 - await page.getByRole('menuitem', { name: 'Enable page header' }).getByRole('switch').click(); - await expect(page.locator('.ant-page-header')).not.toBeVisible(); - await expect(page.getByRole('menuitem', { name: 'Enable page header' }).getByRole('switch')).not.toBeChecked(); - //开启 - await page.getByRole('main').locator('span').nth(1).click(); - await page.getByLabel('designer-schema-settings-Page').hover(); - await page.getByRole('menuitem', { name: 'Enable page header' }).getByRole('switch').click(); - await expect(page.locator('.ant-page-header').getByTitle(pageTitle)).toBeVisible(); - }); -}); - -test.describe('page title', () => { - test('disable & not disable page title', async ({ page, mockPage }) => { - const pageTitle = 'page title'; - await mockPage({ name: pageTitle }).goto(); - //默认显示 - await expect(page.getByTitle(pageTitle)).toBeVisible(); - await page.getByTitle(pageTitle).click(); - await page.getByLabel('designer-schema-settings-Page').hover(); - await expect(page.getByRole('menuitem', { name: 'Display page title' }).getByRole('switch')).toBeChecked(); - //不显示 - await page.getByRole('menuitem', { name: 'Display page title' }).getByRole('switch').click(); - await expect(page.locator('.ant-page-header')).toBeVisible(); - await expect(page.locator('.ant-page-header').getByTitle(pageTitle)).not.toBeVisible(); - await expect(page.getByRole('menuitem', { name: 'Display page title' }).getByRole('switch')).not.toBeChecked(); - //开启 - await page.locator('.ant-page-header').click(); - await page.getByLabel('designer-schema-settings-Page').hover(); - await page.getByRole('menuitem', { name: 'Display page title' }).getByRole('switch').click(); - await expect(page.locator('.ant-page-header').getByTitle(pageTitle)).toBeVisible(); - }); - test('edit page title', async ({ page, mockPage }) => { - await mockPage({ name: 'page title1' }).goto(); - - await expect(page.getByTitle('page title1')).toBeVisible(); - await page.getByTitle('page title1').click(); - await page.getByLabel('designer-schema-settings-Page').hover(); - await page.getByRole('menuitem', { name: 'Edit page title' }).click(); - await page.getByRole('textbox').click(); - await page.getByRole('textbox').fill('page title2'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - await page.getByText('page title2').click(); - await expect(page.getByText('page title2')).toBeVisible(); - //菜单栏不调整 - await expect(page.getByLabel('page title1')).toBeVisible(); - }); -}); - -test.describe('page tabs', () => { - test('enable & disabled page tab', async ({ page, mockPage }) => { - await mockPage({ name: 'page tab' }).goto(); - await page.getByTitle('page tab').click(); - await page.getByLabel('designer-schema-settings-Page').hover(); - //默认不启用 - await expect(page.getByRole('menuitem', { name: 'Enable page tabs' }).getByRole('switch')).not.toBeChecked(); - //启用标签 - await page.getByRole('menuitem', { name: 'Enable page tabs' }).click(); - await expect(page.getByRole('tab').locator('div').filter({ hasText: 'Unnamed' })).toBeVisible(); - await expect(page.getByLabel('schema-initializer-Page-tabs')).toBeVisible(); - await page.getByRole('tab').locator('div').filter({ hasText: 'Unnamed' }).click(); - await expect(page.getByLabel('schema-initializer-Grid-BlockInitializers')).toBeVisible(); - - //添加新的tab - await page.getByLabel('schema-initializer-Page-tabs').click(); - await page.getByRole('textbox').click(); - await page.getByRole('textbox').fill('page tab 1'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - await page.getByText('page tab 1').click(); - await page.getByLabel('schema-initializer-Page-tabs').click(); - await page.getByRole('textbox').click(); - await page.getByRole('textbox').fill('page tab 2'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - await page.getByText('page tab 2').click(); - - //激活的tab样式符合预期 - await expect(page.getByText('page tab 1')).toBeVisible(); - await expect(page.getByText('page tab 2')).toBeVisible(); - await expect(page.getByLabel('schema-initializer-Grid-BlockInitializers')).toBeVisible(); - await expect(page.getByRole('tab', { name: 'page tab 2' })).toHaveAttribute('aria-selected', 'true'); - - //修改tab名称 - await page.getByText('Unnamed').hover(); - await page.getByRole('tab', { name: 'Unnamed' }).getByLabel('designer-schema-settings-Page').hover(); - await page.getByRole('menuitem', { name: 'Edit' }).click(); - await page.getByRole('textbox').fill('page tab'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - const tabMenuItem1 = await page.getByRole('tab').getByText('page tab', { exact: true }); - await expect(tabMenuItem1).toBeVisible(); - await expect(page.getByLabel('schema-initializer-Grid-BlockInitializers')).toBeVisible(); - - //删除 tab - await page.getByRole('tab').getByText('page tab', { exact: true }).hover(); - await page - .getByRole('tab', { name: 'page tab designer-drag-handler' }) - .getByLabel('designer-schema-settings') - .hover(); - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - await expect(page.getByRole('tab').getByText('page tab', { exact: true })).not.toBeVisible(); - await page.getByRole('tab').getByText('page tab 1').click(); - - //禁用标签 - await page.getByTitle('page tab', { exact: true }).hover(); - await page.getByRole('button', { name: 'designer-schema-settings-Page' }).hover(); - await page.getByRole('menuitem', { name: 'Enable page tabs' }).click(); - await expect(page.getByText('page tab 2')).not.toBeVisible(); - }); - - test('drag page tab sorting', async ({ page, mockPage }) => { - await mockPage({ - pageSchema: { - 'x-uid': 'h8q2mcgo3cq', - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Page', - 'x-component-props': { - enablePageTabs: true, - }, - properties: { - bi8ep3svjee: { - 'x-uid': '9kr7xm9x4ln', - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'BlockInitializers', - title: 'tab 1', - 'x-async': false, - 'x-index': 1, - }, - rw91udnzpr3: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: 'tab 2', - 'x-component': 'Grid', - 'x-initializer': 'BlockInitializers', - 'x-uid': 'o5vp90rqsjx', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-async': true, - 'x-index': 1, - }, - }).goto(); - - const sourceElement = page.locator('span:has-text("tab 2")'); - await sourceElement.hover(); - const source = page.getByRole('button', { name: 'drag' }); - await source.hover(); - const targetElement = page.locator('span:has-text("tab 1")'); - const sourceBoundingBox = await sourceElement.boundingBox(); - const targetBoundingBox = await targetElement.boundingBox(); - //拖拽标签调整排序 拖拽前 1-2 - expect(targetBoundingBox.x).toBeLessThan(sourceBoundingBox.x); - await source.dragTo(targetElement); - await sourceElement.dragTo(targetElement); - const tab2 = await page.locator('span:has-text("tab 2")').boundingBox(); - const tab1 = await page.locator('span:has-text("tab 1")').boundingBox(); - //拖拽后 2-1 - expect(tab2.x).toBeLessThan(tab1.x); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/pageSchema.test.ts b/packages/core/client/src/__tests__/e2e/pageSchema.test.ts deleted file mode 100644 index 2e9ef7ebe..000000000 --- a/packages/core/client/src/__tests__/e2e/pageSchema.test.ts +++ /dev/null @@ -1,462 +0,0 @@ -import { expect, test } from '@nocobase/test/client'; - -const pageConfig = { - pageSchema: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Page', - properties: { - pdxwiogf3pc: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'BlockInitializers', - properties: { - txjj2q9859s: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - w4ziz4txnrn: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - xpfe7mh0n0p: { - 'x-uid': '7pdacls95qk', - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'TableBlockProvider', - 'x-acl-action': 'users:list', - 'x-decorator-props': { - collection: 'users', - resource: 'users', - action: 'list', - params: { - pageSize: 20, - }, - rowKey: 'id', - showIndex: true, - dragSort: false, - disableTemplate: false, - }, - 'x-designer': 'TableBlockDesigner', - 'x-component': 'CardItem', - 'x-filter-targets': [], - 'x-component-props': { - title: 'Table block', - }, - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'TableActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 'var(--nb-spacing)', - }, - }, - 'x-uid': 'wb5mvwm537t', - 'x-async': false, - 'x-index': 1, - }, - xj9bu0sv4yz: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'array', - 'x-initializer': 'TableColumnInitializers', - 'x-component': 'TableV2', - 'x-component-props': { - rowKey: 'id', - rowSelection: { - type: 'checkbox', - }, - useProps: '{{ useTableBlockProps }}', - }, - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Actions") }}', - 'x-action-column': 'actions', - 'x-decorator': 'TableV2.Column.ActionBar', - 'x-component': 'TableV2.Column', - 'x-designer': 'TableV2.ActionColumnDesigner', - 'x-initializer': 'TableActionColumnInitializers', - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'DndContext', - 'x-component': 'Space', - 'x-component-props': { - split: '|', - }, - 'x-uid': '33rzky3kemq', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '7nnw5grzet8', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'm54bsjcv09a', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '4yi4kr1wgkz', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'g6bhfeaba55', - 'x-async': false, - 'x-index': 1, - }, - j9xgdusioku: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - '4pdar7yt1d1': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - prtqni04a5t: { - 'x-uid': 'coyws8els85', - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-acl-action-props': { - skipScopeCheck: true, - }, - 'x-acl-action': 'users:create', - 'x-decorator': 'FormBlockProvider', - 'x-decorator-props': { - resource: 'users', - collection: 'users', - }, - 'x-designer': 'FormV2.Designer', - 'x-component': 'CardItem', - 'x-component-props': { - title: 'Form block', - }, - properties: { - uo3q3bs1l4c: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'FormV2', - 'x-component-props': { - useProps: '{{ useFormBlockProps }}', - }, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'FormItemInitializers', - 'x-uid': '54w1s4gkrp4', - 'x-async': false, - 'x-index': 1, - }, - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'FormActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - layout: 'one-column', - style: { - marginTop: 24, - }, - }, - 'x-uid': 'wx1ymybhw4d', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': '47x9aotslaf', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '4tdyzz3hh3s', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '5pr5x41th9y', - 'x-async': false, - 'x-index': 2, - }, - hlm6jtcx5px: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - '0if9syydrxn': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - fhi0k7tswj1: { - 'x-uid': 'dntzs4ojq9y', - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-acl-action': 'users:view', - 'x-decorator': 'DetailsBlockProvider', - 'x-decorator-props': { - resource: 'users', - collection: 'users', - readPretty: true, - action: 'list', - params: { - pageSize: 1, - }, - rowKey: 'id', - }, - 'x-designer': 'DetailsDesigner', - 'x-component': 'CardItem', - 'x-component-props': { - title: 'Details block', - }, - properties: { - ru4sjmi898d: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Details', - 'x-read-pretty': true, - 'x-component-props': { - useProps: '{{ useDetailsBlockProps }}', - }, - properties: { - '74jvk36v996': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'DetailsActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 24, - }, - }, - 'x-uid': 'zpt2ewuvd3i', - 'x-async': false, - 'x-index': 1, - }, - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'ReadPrettyFormItemInitializers', - 'x-uid': 'ivgyowpi1rj', - 'x-async': false, - 'x-index': 2, - }, - pagination: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Pagination', - 'x-component-props': { - useProps: '{{ useDetailsPaginationProps }}', - }, - 'x-uid': 'yl3bc57sqmx', - 'x-async': false, - 'x-index': 3, - }, - }, - 'x-uid': 't3sshcjbw53', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'so9f6fq7nmf', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'jdrrxpdel86', - 'x-async': false, - 'x-index': 3, - }, - ipq256mnxif: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - h65018f1z8b: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - ym27n2ko5vr: { - 'x-uid': 'j45qq035eas', - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-acl-action': 'users:view', - 'x-decorator': 'List.Decorator', - 'x-decorator-props': { - resource: 'users', - collection: 'users', - readPretty: true, - action: 'list', - params: { - pageSize: 10, - }, - runWhenParamsChanged: true, - rowKey: 'id', - }, - 'x-component': 'CardItem', - 'x-designer': 'List.Designer', - 'x-component-props': { - title: 'List block', - }, - properties: { - actionBar: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'ListActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 'var(--nb-spacing)', - }, - }, - 'x-uid': 'c66vjxpf8bf', - 'x-async': false, - 'x-index': 1, - }, - list: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'array', - 'x-component': 'List', - 'x-component-props': { - props: '{{ useListBlockProps }}', - }, - properties: { - item: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'object', - 'x-component': 'List.Item', - 'x-read-pretty': true, - 'x-component-props': { - useProps: '{{ useListItemProps }}', - }, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'ReadPrettyFormItemInitializers', - 'x-initializer-props': { - useProps: '{{ useListItemInitializerProps }}', - }, - 'x-uid': 'uqml2dwp9rv', - 'x-async': false, - 'x-index': 1, - }, - actionBar: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-align': 'left', - 'x-initializer': 'ListItemActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - useProps: '{{ useListActionBarProps }}', - layout: 'one-column', - }, - 'x-uid': 'de6lsblu8nf', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'uzulduo8g1z', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 's53c3p9hmf1', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'zg9l4uw1rmy', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'qw9hle324xg', - 'x-async': false, - 'x-index': 4, - }, - }, - 'x-uid': 'lvyncy91yyv', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'ny9ds6mjkkj', - 'x-async': true, - 'x-index': 1, - }, -}; - -test.describe('pageSchema', () => { - test('quickly create page schema', async ({ page, mockPage }) => { - await mockPage(pageConfig).goto(); - - await expect(page.getByText('Table block')).toBeVisible(); - await expect(page.getByText('Form block')).toBeVisible(); - await expect(page.getByText('Details block')).toBeVisible(); - await expect(page.getByText('List block')).toBeVisible(); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaInitializer/associationFields.test.ts b/packages/core/client/src/__tests__/e2e/schemaInitializer/associationFields.test.ts deleted file mode 100644 index 1691e5d06..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaInitializer/associationFields.test.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { - expect, - oneDetailBlockWithM2oFieldToGeneral, - oneFormBlockWithRolesFieldBasedUsers, - test, -} from '@nocobase/test/client'; - -test.describe('association fields with dialog', () => { - test('data selector', async ({ page, mockPage }) => { - await mockPage(oneFormBlockWithRolesFieldBasedUsers).goto(); - - // open dialog - await page.getByTestId('select-data-picker').click(); - - // add blocks - await page.getByLabel('schema-initializer-Grid-TableSelectorInitializers-roles').hover(); - await page.getByRole('menuitem', { name: 'form Table' }).click(); - - // 筛选区块这里应该是可以直接点击的,不应该有二级菜单 - await page.getByText('Form').click(); - await page.getByRole('menuitem', { name: 'Collapse' }).click(); - - await page.getByRole('menuitem', { name: 'Add text' }).click(); - - await expect(page.getByLabel('block-item-CardItem-roles-table-selector')).toBeVisible(); - await expect(page.getByLabel('block-item-CardItem-roles-filter-form')).toBeVisible(); - - // 向下滚动一点距离,使得下方的区块可见 - await page.getByLabel('block-item-CardItem-roles-table-selector').hover(); - await page.mouse.wheel(0, 500); - - await expect(page.getByLabel('block-item-CardItem-roles-filter-collapse')).toBeVisible(); - await expect(page.getByLabel('block-item-Markdown.Void-roles-form')).toBeVisible(); - }); - - test('click association link to view', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(oneDetailBlockWithM2oFieldToGeneral).waitForInit(); - const record = await mockRecord('targetToGeneral'); - await nocoPage.goto(); - - // open dialog - await page - .getByLabel('block-item-CollectionField-targetToGeneral-details-targetToGeneral.toGeneral-toGeneral') - .getByText(record.id, { exact: true }) - .click(); - - // add a tab - await page.getByLabel('schema-initializer-Tabs-TabPaneInitializers-general').click(); - await page.getByRole('textbox').click(); - await page.getByRole('textbox').fill('test8'); - await page.getByLabel('action-Action-Submit-general-details').click(); - - await expect(page.getByText('test8')).toBeVisible(); - - // add blocks - await page.getByLabel('schema-initializer-Grid-RecordBlockInitializers-general').hover(); - await page.getByRole('menuitem', { name: 'Details' }).click(); - await page.getByText('Form').click(); - await page.getByRole('menuitem', { name: 'Markdown' }).click(); - - await expect(page.getByText('GeneralConfigure actionsConfigure fields')).toBeVisible(); - await expect(page.getByText('GeneralConfigure fieldsConfigure actions')).toBeVisible(); - await expect(page.getByLabel('block-item-Markdown.Void-general-markdown')).toBeVisible(); - - // 删除已创建的 blocks,腾出页面空间 - // delete details block - await page.getByText('GeneralConfigure actionsConfigure fields').hover(); - await page.getByLabel('designer-schema-settings-CardItem-FormV2.ReadPrettyDesigner-general').hover(); - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - // delete form block - await page.getByLabel('block-item-CardItem-general-form').hover(); - await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - // delete markdown block - await page.getByLabel('block-item-Markdown.Void-general-markdown').hover(); - await page.getByLabel('designer-schema-settings-Markdown.Void-Markdown.Void.Designer-general').hover(); - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // add relationship blocks - await page.getByLabel('schema-initializer-Grid-RecordBlockInitializers-general').hover(); - await page.getByRole('menuitem', { name: 'Many to one' }).hover(); - await page.getByRole('menuitem', { name: 'Details' }).click(); - - await page.mouse.move(300, 0); - - await page.getByLabel('schema-initializer-Grid-RecordBlockInitializers-general').hover(); - await page.getByRole('menuitem', { name: 'One to many' }).hover(); - - // 下拉列表中,可选择以下区块进行创建 - await expect(page.getByText('Table')).toBeVisible(); - await expect(page.getByRole('menuitem', { name: 'Details' }).nth(1)).toBeVisible(); - await expect(page.getByRole('menuitem', { name: 'List' })).toBeVisible(); - await expect(page.getByRole('menuitem', { name: 'Grid Card' })).toBeVisible(); - await expect(page.getByText('Form').nth(1)).toBeVisible(); - await expect(page.getByRole('menuitem', { name: 'Calendar' })).toBeVisible(); - - await page.getByText('Table').click(); - await expect(page.getByLabel('block-item-CardItem-users-table')).toBeVisible(); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaInitializer/pageGrid.test.ts b/packages/core/client/src/__tests__/e2e/schemaInitializer/pageGrid.test.ts deleted file mode 100644 index 2404a425a..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaInitializer/pageGrid.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { expect, test } from '@nocobase/test/client'; -import { createBlock } from './utils'; - -test.describe('Page.Grid', () => { - test('create block', async ({ page, mockPage }) => { - await mockPage().goto(); - const button = page.getByLabel('schema-initializer-Grid-BlockInitializers'); - - // add table block - await button.hover(); - await createBlock(page, 'Table'); - await expect(page.getByLabel('block-item-CardItem-users-table')).toBeVisible(); - - // add form block - await button.hover(); - await createBlock(page, 'Form'); - await expect(page.getByLabel('block-item-CardItem-users-form')).toBeVisible(); - - // add detail block - await button.hover(); - await createBlock(page, 'Details'); - await expect(page.getByLabel('block-item-CardItem-users-details')).toBeVisible(); - - // add list block - await button.hover(); - await createBlock(page, 'List'); - await expect(page.getByLabel('block-item-CardItem-users-list')).toBeVisible(); - - // add grid card block - await button.hover(); - await createBlock(page, 'Grid Card'); - await expect(page.getByLabel('block-item-BlockItem-users-grid-card')).toBeVisible(); - - // add filter form block - await button.hover(); - await createBlock(page, 'Filter form'); - await expect(page.getByLabel('block-item-CardItem-users-filter-form')).toBeVisible(); - - // add collapse block - await button.hover(); - await createBlock(page, 'Collapse'); - await expect(page.getByLabel('block-item-CardItem-users-filter-collapse')).toBeVisible(); - - // add markdown block - await button.hover(); - await createBlock(page, 'Markdown'); - await expect(page.getByLabel('block-item-Markdown.Void-markdown')).toBeVisible(); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaInitializer/pageTabs.test.ts b/packages/core/client/src/__tests__/e2e/schemaInitializer/pageTabs.test.ts deleted file mode 100644 index 5e214c3de..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaInitializer/pageTabs.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { expect, tabPageEmpty, test } from '@nocobase/test/client'; - -test.describe('Page.Tabs', () => { - test('enable to create tab', async ({ page, mockPage }) => { - await mockPage(tabPageEmpty).goto(); - - // add tab page - await page.getByLabel('schema-initializer-Page-tabs').click(); - await page.getByRole('textbox').click(); - await page.getByRole('textbox').fill('tab1'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - await expect(page.getByText('tab1', { exact: true })).toBeVisible(); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaInitializer/utils.ts b/packages/core/client/src/__tests__/e2e/schemaInitializer/utils.ts deleted file mode 100644 index a00bc4a58..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaInitializer/utils.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Page } from '@playwright/test'; - -export const createBlock = async (page: Page, name: string) => { - await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); - - if (name === 'Form') { - await page.getByText('Form', { exact: true }).first().hover(); - } else if (name === 'Filter form') { - await page.getByText('Form', { exact: true }).nth(1).hover(); - } else { - await page.getByText(name, { exact: true }).hover(); - } - - if (name === 'Markdown') { - await page.getByRole('menuitem', { name: 'Markdown' }).click(); - } else { - await page.getByRole('menuitem', { name: 'Users' }).click(); - } - - await page.mouse.move(300, 0); -}; diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/addChild.test.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/actions/addChild.test.ts deleted file mode 100644 index 8d1f42150..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/addChild.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Page, oneEmptyTableWithTreeCollection, test } from '@nocobase/test/client'; -import { expectOptions } from './expectOptions'; - -test.describe('add child', () => { - const showMenu = async (page: Page) => { - await page.getByLabel('action-Action.Link-Add child-create-treeCollection-table-0').hover(); - await page.getByLabel('designer-schema-settings-Action.Link-Action.Designer-tree').hover(); - }; - - test('supported options', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(oneEmptyTableWithTreeCollection).waitForInit(); - await nocoPage.goto(); - - // 添加一行数据 - // TODO: 使用 mockRecord 为 tree 表添加一行数据无效 - await page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-treeCollection').hover(); - await page.getByRole('menuitem', { name: 'Add new' }).click(); - await page.getByRole('button', { name: 'Add new' }).click(); - await page.getByLabel('schema-initializer-Grid-CreateFormBlockInitializers-treeCollection').hover(); - await page.getByRole('menuitem', { name: 'form Form' }).click(); - await page.mouse.move(300, 0); - await page.getByLabel('schema-initializer-ActionBar-CreateFormActionInitializers-treeCollection').hover(); - await page.getByRole('menuitem', { name: 'Submit' }).click(); - await page.mouse.move(300, 0); - await page.getByRole('button', { name: 'Submit' }).click(); - - // 添加 add child 按钮 - await page.getByRole('button', { name: 'Actions' }).hover(); - await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-tree').hover(); - await page.getByRole('menuitem', { name: 'Add child' }).click(); - - await expectOptions({ - page, - showMenu: () => showMenu(page), - enableOptions: ['Edit button', 'Linkage rules', 'Open mode', 'Popup size', 'Delete'], - }); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/addNew.test.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/actions/addNew.test.ts deleted file mode 100644 index 3133f88cc..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/addNew.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { Page, expect, oneEmptyTableBlockWithActions, test } from '@nocobase/test/client'; -import { expectOptions } from './expectOptions'; - -test.describe('add new', () => { - const showMenu = async (page: Page) => { - await page.getByRole('button', { name: 'Add new' }).hover(); - await page.getByRole('button', { name: 'designer-schema-settings-Action-Action.Designer-general' }).hover(); - }; - - test('supported options', async ({ page, mockPage, mockRecord }) => { - await mockPage(oneEmptyTableBlockWithActions).goto(); - - await expectOptions({ - page, - showMenu: () => showMenu(page), - enableOptions: ['Edit button', 'Open mode', 'Popup size', 'Delete'], - }); - }); - - test('edit button', async ({ page, mockPage, mockRecord }) => { - await mockPage(oneEmptyTableBlockWithActions).goto(); - - await showMenu(page); - await page.getByRole('menuitem', { name: 'Edit button' }).click(); - await page.getByLabel('block-item-Input-general-Button title').getByRole('textbox').click(); - await page.getByLabel('block-item-Input-general-Button title').getByRole('textbox').fill('1234'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - await expect(page.getByRole('button', { name: '1234' })).toBeVisible(); - }); - - test('open mode', async ({ page, mockPage, mockRecord }) => { - await mockPage(oneEmptyTableBlockWithActions).goto(); - await showMenu(page); - - // 默认是 drawer - await expect(page.getByRole('menuitem', { name: 'Open mode' }).getByText('Drawer')).toBeVisible(); - - // 切换为 dialog - await page.getByRole('menuitem', { name: 'Open mode' }).click(); - await page.getByRole('option', { name: 'Dialog' }).click(); - - await page.getByRole('button', { name: 'Add new' }).click(); - await expect(page.getByTestId('modal-Action.Container-general-Add record')).toBeVisible(); - }); - - test('popup size', async ({ page, mockPage, mockRecord }) => { - await mockPage(oneEmptyTableBlockWithActions).goto(); - - await showMenu(page); - // 默认值 middle - await expect(page.getByRole('menuitem', { name: 'Popup size' }).getByText('Middle')).toBeVisible(); - - // 切换为 small - await page.getByRole('menuitem', { name: 'Popup size' }).click(); - await page.getByRole('option', { name: 'Small' }).click(); - - await page.getByRole('button', { name: 'Add new' }).click(); - const drawerWidth = - (await page.getByTestId('drawer-Action.Container-general-Add record').boundingBox())?.width || 0; - expect(drawerWidth).toBeLessThanOrEqual(400); - - await page.getByLabel('drawer-Action.Container-general-Add record-mask').click(); - - // 切换为 large - await showMenu(page); - await page.getByRole('menuitem', { name: 'Popup size' }).click(); - await page.getByRole('option', { name: 'Large' }).click(); - - await page.getByRole('button', { name: 'Add new' }).click(); - const drawerWidth2 = - (await page.getByTestId('drawer-Action.Container-general-Add record').boundingBox())?.width || 0; - expect(drawerWidth2).toBeGreaterThanOrEqual(800); - }); - - test('delete', async ({ page, mockPage, mockRecord }) => { - await mockPage(oneEmptyTableBlockWithActions).goto(); - - await showMenu(page); - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await page.mouse.move(300, 0); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - await expect(page.getByRole('button', { name: 'Add new' })).toBeHidden(); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/addRecord.test.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/actions/addRecord.test.ts deleted file mode 100644 index 8cb459b94..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/addRecord.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Page, oneEmptyTableBlockWithActions, test } from '@nocobase/test/client'; -import { expectOptions } from './expectOptions'; - -test.describe('add record', () => { - const showMenu = async (page: Page) => { - await page.getByRole('button', { name: 'Add record' }).hover(); - await page.getByRole('button', { name: 'designer-schema-settings-Action-Action.Designer-general' }).hover(); - }; - - test('supported options', async ({ page, mockPage, mockRecord }) => { - await mockPage(oneEmptyTableBlockWithActions).goto(); - - await expectOptions({ - page, - showMenu: () => showMenu(page), - enableOptions: ['Edit button', 'Open mode', 'Popup size', 'Delete'], - }); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/bulkDelete.test.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/actions/bulkDelete.test.ts deleted file mode 100644 index e95b0db2c..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/bulkDelete.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { oneEmptyTableBlockWithActions, test } from '@nocobase/test/client'; -import { expectOptions } from './expectOptions'; - -test.describe('bulk delete', () => { - test('supported options', async ({ page, mockPage }) => { - await mockPage(oneEmptyTableBlockWithActions).goto(); - - await expectOptions({ - page, - showMenu: async () => { - await page.getByRole('button', { name: 'Delete' }).hover(); - await page.getByRole('button', { name: 'designer-schema-settings-Action-Action.Designer-general' }).hover(); - }, - enableOptions: ['Edit button', 'Delete'], - }); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/delete.test.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/actions/delete.test.ts deleted file mode 100644 index 2c6d9f2cf..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/delete.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Page, expect, oneEmptyTableBlockWithActions, test } from '@nocobase/test/client'; -import { expectOptions } from './expectOptions'; - -test.describe('delete', () => { - const showMenu = async (page: Page) => { - await page.getByLabel('action-Action.Link-Delete-destroy-general-table-0').hover(); - await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }).hover(); - }; - - test('supported options', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(oneEmptyTableBlockWithActions).waitForInit(); - await mockRecord('general'); - await nocoPage.goto(); - - await expectOptions({ - page, - showMenu: () => showMenu(page), - enableOptions: ['Edit button', 'Linkage rules', 'Delete'], - }); - }); - - test('edit button', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(oneEmptyTableBlockWithActions).waitForInit(); - await mockRecord('general'); - await nocoPage.goto(); - - await showMenu(page); - await page.getByRole('menuitem', { name: 'Edit button' }).click(); - await page.getByLabel('block-item-Input-general-Button title').getByRole('textbox').click(); - await page.getByLabel('block-item-Input-general-Button title').getByRole('textbox').fill('Delete record'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - await expect(page.getByLabel('action-Action.Link-Delete record-destroy-general-table-0')).toBeVisible(); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/duplicate.test.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/actions/duplicate.test.ts deleted file mode 100644 index db384fd53..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/duplicate.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Page, oneEmptyTableBlockWithActions, test } from '@nocobase/test/client'; -import { expectOptions } from './expectOptions'; - -test.describe('duplicate', () => { - const showMenu = async (page: Page) => { - await page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0').hover(); - await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }).hover(); - }; - - test('supported options', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(oneEmptyTableBlockWithActions).waitForInit(); - await mockRecord('general'); - await nocoPage.goto(); - - await expectOptions({ - page, - showMenu: () => showMenu(page), - enableOptions: ['Edit button', 'Linkage rules', 'Duplicate mode', 'Open mode', 'Popup size', 'Delete'], - }); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/edit.test.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/actions/edit.test.ts deleted file mode 100644 index 3e5286309..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/edit.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Page, oneEmptyTableBlockWithActions, test } from '@nocobase/test/client'; -import { expectOptions } from './expectOptions'; - -test.describe('edit', () => { - const showMenu = async (page: Page) => { - await page.getByLabel('action-Action.Link-Edit-update-general-table-0').hover(); - await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }).hover(); - }; - - test('supported options', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(oneEmptyTableBlockWithActions).waitForInit(); - await mockRecord('general'); - await nocoPage.goto(); - - await expectOptions({ - page, - showMenu: () => showMenu(page), - enableOptions: ['Edit button', 'Linkage rules', 'Open mode', 'Popup size', 'Delete'], - }); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/expectOptions.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/actions/expectOptions.ts deleted file mode 100644 index 928d3a23b..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/expectOptions.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { expect } from '@nocobase/test/client'; - -export async function expectOptions({ showMenu, enableOptions, page }) { - await showMenu(); - for (const option of enableOptions) { - await expect(page.getByRole('menuitem', { name: option })).toBeVisible(); - } -} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/filter.test.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/actions/filter.test.ts deleted file mode 100644 index 0f5979628..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/filter.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Page, oneEmptyTableBlockWithActions, test } from '@nocobase/test/client'; -import { expectOptions } from './expectOptions'; - -test.describe('filter', () => { - const showMenu = async (page: Page) => { - await page.getByRole('button', { name: 'Filter' }).hover(); - await page.getByLabel('designer-schema-settings-Filter.Action-Filter.Action.Designer-general').hover(); - }; - - test('supported options', async ({ page, mockPage, mockRecord }) => { - await mockPage(oneEmptyTableBlockWithActions).goto(); - - await expectOptions({ - page, - showMenu: () => showMenu(page), - enableOptions: [ - 'Edit button', - 'Delete', - 'Many to one', - 'One to many', - 'Single select', - 'ID', - 'Created at', - 'Last updated at', - 'Created by', - 'Last updated by', - ], - }); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/popup.test.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/actions/popup.test.ts deleted file mode 100644 index 3ecbe50a2..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/popup.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Page, oneEmptyTableBlockWithActions, test } from '@nocobase/test/client'; -import { expectOptions } from './expectOptions'; - -const addSomeCustomActions = async (page: Page) => { - // 先删除掉之前的 actions - await page.getByRole('button', { name: 'Actions' }).hover(); - await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-general').hover(); - await page.getByRole('menuitem', { name: 'View' }).click(); - await page.getByRole('menuitem', { name: 'Edit' }).click(); - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await page.getByRole('menuitem', { name: 'Duplicate' }).click(); - - // 再增加两个自定义的 actions - await page.getByRole('menuitem', { name: 'Customize' }).hover(); - await page.getByRole('menuitem', { name: 'Popup' }).click(); - await page.getByRole('menuitem', { name: 'Update record' }).click(); -}; - -test.describe('popup', () => { - const showMenu = async (page: Page) => { - await page.getByLabel('action-Action.Link-Popup-customize:popup-general-table-0').hover(); - await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }).hover(); - }; - - test('supported options', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(oneEmptyTableBlockWithActions).waitForInit(); - await mockRecord('general'); - await nocoPage.goto(); - await addSomeCustomActions(page); - - await showMenu(page); - await expectOptions({ - page, - showMenu: () => showMenu(page), - enableOptions: ['Edit button', 'Linkage rules', 'Open mode', 'Popup size', 'Delete'], - }); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/refresh.test.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/actions/refresh.test.ts deleted file mode 100644 index 9f40a3b16..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/refresh.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { oneEmptyTableBlockWithActions, test } from '@nocobase/test/client'; -import { expectOptions } from './expectOptions'; - -test.describe('refresh', () => { - test('supported options', async ({ page, mockPage }) => { - await mockPage(oneEmptyTableBlockWithActions).goto(); - - await expectOptions({ - page, - showMenu: async () => { - await page.getByRole('button', { name: 'Refresh' }).hover(); - await page.getByRole('button', { name: 'designer-schema-settings-Action-Action.Designer-general' }).hover(); - }, - enableOptions: ['Edit button', 'Delete'], - }); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/saveRecord.test.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/actions/saveRecord.test.ts deleted file mode 100644 index 09021e673..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/saveRecord.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { oneEmptyFormWithActions, test } from '@nocobase/test/client'; -import { expectOptions } from './expectOptions'; - -test.describe('save record', () => { - test('supported options', async ({ page, mockPage }) => { - await mockPage(oneEmptyFormWithActions).goto(); - - await expectOptions({ - page, - showMenu: async () => { - await page.getByRole('button', { name: 'Save record' }).hover(); - await page.getByRole('button', { name: 'designer-schema-settings-Action-Action.Designer-users' }).hover(); - }, - enableOptions: [ - 'Edit button', - 'Linkage rules', - 'Assign field values', - 'Skip required validation', - 'After successful submission', - 'Bind workflows', - 'Delete', - ], - }); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/submit.test.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/actions/submit.test.ts deleted file mode 100644 index d468af569..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/submit.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { oneEmptyFormWithActions, test } from '@nocobase/test/client'; -import { expectOptions } from './expectOptions'; - -test.describe('submit', () => { - test('supported options', async ({ page, mockPage }) => { - await mockPage(oneEmptyFormWithActions).goto(); - - await expectOptions({ - page, - showMenu: async () => { - await page.getByRole('button', { name: 'Submit' }).hover(); - await page.getByRole('button', { name: 'designer-schema-settings-Action-Action.Designer-users' }).hover(); - }, - enableOptions: ['Edit button', 'Linkage rules', 'Bind workflows', 'Delete'], - }); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/updateRecord.test.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/actions/updateRecord.test.ts deleted file mode 100644 index a40aecb38..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/updateRecord.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Page, oneEmptyTableBlockWithActions, test } from '@nocobase/test/client'; -import { expectOptions } from './expectOptions'; - -const addSomeCustomActions = async (page: Page) => { - // 先删除掉之前的 actions - await page.getByRole('button', { name: 'Actions' }).hover(); - await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-general').hover(); - await page.getByRole('menuitem', { name: 'View' }).click(); - await page.getByRole('menuitem', { name: 'Edit' }).click(); - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await page.getByRole('menuitem', { name: 'Duplicate' }).click(); - - // 再增加两个自定义的 actions - await page.getByRole('menuitem', { name: 'Customize' }).hover(); - await page.getByRole('menuitem', { name: 'Popup' }).click(); - await page.getByRole('menuitem', { name: 'Update record' }).click(); -}; - -test.describe('update record', () => { - const showMenu = async (page: Page) => { - await page.getByLabel('action-Action.Link-Update record-customize:update-general-table-0').hover(); - await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }).hover(); - }; - - test('supported options', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(oneEmptyTableBlockWithActions).waitForInit(); - await mockRecord('general'); - await nocoPage.goto(); - await addSomeCustomActions(page); - - await showMenu(page); - await expectOptions({ - page, - showMenu: () => showMenu(page), - enableOptions: ['Edit button', 'Linkage rules', 'Assign field values', 'After successful submission', 'Delete'], - }); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/view.test.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/actions/view.test.ts deleted file mode 100644 index 1125015ed..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/actions/view.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Page, oneEmptyTableBlockWithActions, test } from '@nocobase/test/client'; -import { expectOptions } from './expectOptions'; - -test.describe('view', () => { - const showMenu = async (page: Page) => { - await page.getByLabel('action-Action.Link-View-view-general-table-0').hover(); - await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }).hover(); - }; - - test('supported options', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(oneEmptyTableBlockWithActions).waitForInit(); - await mockRecord('general'); - await nocoPage.goto(); - - await expectOptions({ - page, - showMenu: () => showMenu(page), - enableOptions: ['Edit button', 'Linkage rules', 'Open mode', 'Popup size', 'Delete'], - }); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formBlock.test.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/formBlock.test.ts deleted file mode 100644 index 9918f14ac..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formBlock.test.ts +++ /dev/null @@ -1,286 +0,0 @@ -import { Page, expect, oneTableBlockWithActionsAndFormBlocks, test } from '@nocobase/test/client'; - -const clickOption = async (page: Page, optionName: string) => { - await page.getByLabel('block-item-CardItem-general-form').hover(); - await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); - await page.getByRole('menuitem', { name: optionName }).click(); -}; - -test.describe('SchemaSettings: creating form block', () => { - test('Edit block title', async ({ page, mockPage }) => { - await mockPage(oneTableBlockWithActionsAndFormBlocks).goto(); - await page.getByRole('button', { name: 'Add new' }).click(); - - // 打开编辑弹窗 - await clickOption(page, 'Edit block title'); - await page.getByRole('textbox').click(); - await page.getByRole('textbox').fill('Block title 123'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - const runExpect = async () => { - // 设置成功后,显示在区块顶部 - await expect( - page.getByLabel('block-item-CardItem-general-form').getByText('Block title 123', { exact: true }), - ).toBeVisible(); - - // 再次打开编辑弹窗时,显示的是上次设置的值 - await clickOption(page, 'Edit block title'); - await expect(page.getByRole('textbox')).toHaveValue('Block title 123'); - }; - - await runExpect(); - - // 刷新页面后,显示的应该依然是上次设置的值 - await page.reload(); - await page.getByRole('button', { name: 'Add new' }).click(); - await runExpect(); - }); - test('Linkage rules', async ({ page, mockPage }) => { - await mockPage(oneTableBlockWithActionsAndFormBlocks).goto(); - await page.getByRole('button', { name: 'Add new' }).click(); - - // 打开编辑弹窗 - await clickOption(page, 'Linkage rules'); - await page.getByRole('button', { name: 'Add linkage rule' }).click(); - await page.getByText('Add property').click(); - await page.getByTestId('select-linkage-property-field').click(); - await page.getByText('singleLineText', { exact: true }).click(); - await page.getByTestId('select-linkage-action-field').click(); - await page.getByRole('option', { name: 'Visible' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - const runExpect = async () => { - await expect(page.getByTestId('select-linkage-property-field').getByText('singleLineText')).toBeVisible(); - await expect(page.getByTestId('select-linkage-action-field').getByText('Visible')).toBeVisible(); - }; - - // 再次打开,设置的值应该存在 - await clickOption(page, 'Linkage rules'); - await runExpect(); - - // 刷新页面后,设置的值应该依然存在 - await page.reload(); - await page.getByRole('button', { name: 'Add new' }).click(); - await clickOption(page, 'Linkage rules'); - await runExpect(); - }); - test('Form data templates', async ({ page, mockPage }) => { - await mockPage(oneTableBlockWithActionsAndFormBlocks).goto(); - await page.getByRole('button', { name: 'Add new' }).click(); - - // 打开编辑弹窗 - await clickOption(page, 'Form data templates'); - await page.getByRole('button', { name: 'Add template' }).click(); - - await page.getByLabel('block-item-Select-general-Title field').getByTestId('select-single').click(); - await page.getByRole('option', { name: 'singleLineText' }).click(); - await page.getByRole('button', { name: 'singleLineText (Duplicate)' }).click(); - - await expect( - page.getByRole('button', { name: 'singleLineText (Duplicate)' }).locator('.ant-tree-checkbox'), - ).toHaveClass(/ant-tree-checkbox-checked/); - - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // 区块顶部应该显示 Data template 选项 - await expect(page.getByText('Data template:', { exact: true })).toBeVisible(); - - // 再次打开,设置的值应该存在 - await clickOption(page, 'Form data templates'); - await expect(page.getByLabel('block-item-Select-general-Title field').getByTestId('select-single')).toHaveText( - 'singleLineText', - ); - await expect( - page.getByRole('button', { name: 'singleLineText (Duplicate)' }).locator('.ant-tree-checkbox'), - ).toHaveClass(/ant-tree-checkbox-checked/); - - // 刷新页面后,设置的值应该还在 - await page.reload(); - await page.getByRole('button', { name: 'Add new' }).click(); - await expect(page.getByText('Data template:', { exact: true })).toBeVisible(); - - await clickOption(page, 'Form data templates'); - await expect(page.getByLabel('block-item-Select-general-Title field').getByTestId('select-single')).toHaveText( - 'singleLineText', - ); - await expect( - page.getByRole('button', { name: 'singleLineText (Duplicate)' }).locator('.ant-tree-checkbox'), - ).toHaveClass(/ant-tree-checkbox-checked/); - }); - test('Convert reference to duplicate & Save as block template', async ({ page, mockPage }) => { - await mockPage(oneTableBlockWithActionsAndFormBlocks).goto(); - await page.getByRole('button', { name: 'Add new' }).click(); - - // 打开编辑弹窗 - await clickOption(page, 'Save as block template'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // 设置成功后,不再显示 Save as block template 选项,而是显示 Convert reference to duplicate 选项 - await page.getByLabel('block-item-CardItem-general-form').hover(); - await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); - await expect(page.getByRole('menuitem', { name: 'Save as block template' })).not.toBeVisible(); - await expect(page.getByRole('menuitem', { name: 'Convert reference to duplicate' })).toBeVisible(); - - // 刷新页面 - await page.reload(); - await page.getByRole('button', { name: 'Add new' }).click(); - await page.getByLabel('block-item-CardItem-general-form').hover(); - await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); - await expect(page.getByRole('menuitem', { name: 'Save as block template' })).not.toBeVisible(); - await expect(page.getByRole('menuitem', { name: 'Convert reference to duplicate' })).toBeVisible(); - - // Convert reference to duplicate - await clickOption(page, 'Convert reference to duplicate'); - await expect(page.getByRole('menuitem', { name: 'Save as block template' })).toBeVisible(); - await expect(page.getByRole('menuitem', { name: 'Convert reference to duplicate' })).not.toBeVisible(); - - // 刷新页面 - await page.reload(); - await page.getByRole('button', { name: 'Add new' }).click(); - await page.getByLabel('block-item-CardItem-general-form').hover(); - await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); - await expect(page.getByRole('menuitem', { name: 'Save as block template' })).toBeVisible(); - await expect(page.getByRole('menuitem', { name: 'Convert reference to duplicate' })).not.toBeVisible(); - }); - test('Delete', async ({ page, mockPage }) => { - await mockPage(oneTableBlockWithActionsAndFormBlocks).goto(); - - await page.getByRole('button', { name: 'Add new' }).click(); - await page.getByLabel('block-item-CardItem-general-form').hover(); - await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); - - // 打开编辑弹窗 - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // 设置成功后,显示在区块顶部 - await expect(page.getByLabel('block-item-CardItem-general-form')).not.toBeVisible(); - - // 刷新页面后,区块依然是被删除状态 - await page.reload(); - await page.getByRole('button', { name: 'Add new' }).click(); - await expect(page.getByLabel('block-item-CardItem-general-form')).not.toBeVisible(); - }); -}); - -test.describe('SchemaSettings: editing list block', () => { - test('Edit block title', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(oneTableBlockWithActionsAndFormBlocks).waitForInit(); - await mockRecord('general'); - await nocoPage.goto(); - await page.getByText('Edit', { exact: true }).click(); - - // 打开编辑弹窗 - await clickOption(page, 'Edit block title'); - await page.getByRole('textbox').click(); - await page.getByRole('textbox').fill('Block title 123'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - const runExpect = async () => { - // 设置成功后,显示在区块顶部 - await expect( - page.getByLabel('block-item-CardItem-general-form').getByText('Block title 123', { exact: true }), - ).toBeVisible(); - - // 再次打开编辑弹窗时,显示的是上次设置的值 - await clickOption(page, 'Edit block title'); - await expect(page.getByRole('textbox')).toHaveValue('Block title 123'); - }; - - await runExpect(); - - // 刷新页面后,显示的应该依然是上次设置的值 - await page.reload(); - await page.getByText('Edit', { exact: true }).click(); - await runExpect(); - }); - test('Linkage rules', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(oneTableBlockWithActionsAndFormBlocks).waitForInit(); - await mockRecord('general'); - await nocoPage.goto(); - await page.getByText('Edit', { exact: true }).click(); - - // 打开编辑弹窗 - await clickOption(page, 'Linkage rules'); - await page.getByRole('button', { name: 'Add linkage rule' }).click(); - await page.getByText('Add property').click(); - await page.getByTestId('select-linkage-property-field').click(); - await page.getByText('singleLineText', { exact: true }).click(); - await page.getByTestId('select-linkage-action-field').click(); - await page.getByRole('option', { name: 'Visible' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - const runExpect = async () => { - await expect(page.getByTestId('select-linkage-property-field').getByText('singleLineText')).toBeVisible(); - await expect(page.getByTestId('select-linkage-action-field').getByText('Visible')).toBeVisible(); - }; - - // 再次打开,设置的值应该存在 - await clickOption(page, 'Linkage rules'); - await runExpect(); - - // 刷新页面后,设置的值应该依然存在 - await page.reload(); - await page.getByText('Edit', { exact: true }).click(); - await clickOption(page, 'Linkage rules'); - await runExpect(); - }); - test('Convert reference to duplicate & Save as block template', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(oneTableBlockWithActionsAndFormBlocks).waitForInit(); - await mockRecord('general'); - await nocoPage.goto(); - await page.getByText('Edit', { exact: true }).click(); - - // 打开编辑弹窗 - await clickOption(page, 'Save as block template'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // 设置成功后,不再显示 Save as block template 选项,而是显示 Convert reference to duplicate 选项 - await page.getByLabel('block-item-CardItem-general-form').hover(); - await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); - await expect(page.getByRole('menuitem', { name: 'Save as block template' })).not.toBeVisible(); - await expect(page.getByRole('menuitem', { name: 'Convert reference to duplicate' })).toBeVisible(); - - // 刷新页面 - await page.reload(); - await page.getByText('Edit', { exact: true }).click(); - await page.getByLabel('block-item-CardItem-general-form').hover(); - await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); - await expect(page.getByRole('menuitem', { name: 'Save as block template' })).not.toBeVisible(); - await expect(page.getByRole('menuitem', { name: 'Convert reference to duplicate' })).toBeVisible(); - - // Convert reference to duplicate - await clickOption(page, 'Convert reference to duplicate'); - await expect(page.getByRole('menuitem', { name: 'Save as block template' })).toBeVisible(); - await expect(page.getByRole('menuitem', { name: 'Convert reference to duplicate' })).not.toBeVisible(); - - // 刷新页面 - await page.reload(); - await page.getByText('Edit', { exact: true }).click(); - await page.getByLabel('block-item-CardItem-general-form').hover(); - await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); - await expect(page.getByRole('menuitem', { name: 'Save as block template' })).toBeVisible(); - await expect(page.getByRole('menuitem', { name: 'Convert reference to duplicate' })).not.toBeVisible(); - }); - test('Delete', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(oneTableBlockWithActionsAndFormBlocks).waitForInit(); - await mockRecord('general'); - await nocoPage.goto(); - - await page.getByText('Edit', { exact: true }).click(); - await page.getByLabel('block-item-CardItem-general-form').hover(); - await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); - - // 打开编辑弹窗 - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // 设置成功后,显示在区块顶部 - await expect(page.getByLabel('block-item-CardItem-general-form')).not.toBeVisible(); - - // 刷新页面后,区块依然是被删除状态 - await page.reload(); - await page.getByText('Edit', { exact: true }).click(); - await expect(page.getByLabel('block-item-CardItem-general-form')).not.toBeVisible(); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formDataTemplates.test.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/formDataTemplates.test.ts deleted file mode 100644 index fb4d47284..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formDataTemplates.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { expect, oneTableBlockWithAddNewAndViewAndEditAndBasicFields, test } from '@nocobase/test/client'; - -test.describe('formDataTemplates', () => { - test('basic usage', async ({ page, mockPage, mockRecords }) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); - const records = await mockRecords('general', 3); - await nocoPage.goto(); - - const record = records.find((item) => item.id === 2); - - const openDialog = async () => { - await page.getByLabel('block-item-CardItem-general-form').hover(); - await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); - await page.getByRole('menuitem', { name: 'Form data templates' }).click(); - }; - - await page.getByRole('button', { name: 'Add new' }).click(); - await openDialog(); - await page.getByRole('button', { name: 'plus Add template' }).click(); - - // 非继承表是不需要显示 Collection 选项的 - await expect(page.getByText('Collection:')).toBeHidden(); - - // 添加一个数据范围,条件是:ID = 2 - await page.getByText('Add condition', { exact: true }).click(); - await page.getByTestId('select-filter-field').getByLabel('Search').click(); - await page.getByRole('menuitemcheckbox', { name: 'ID' }).click(); - await page.getByLabel('Form data templates').getByRole('spinbutton').click(); - await page.getByLabel('Form data templates').getByRole('spinbutton').fill('2'); - - // 选择 ID 作为 title field - await page.getByTestId('select-single').click(); - await page.getByRole('option', { name: 'ID' }).click(); - - // 仅选中一个字段 - await page.getByRole('button', { name: 'singleLineText (Duplicate)' }).click(); - - // 保存 - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // 保存成功后应该显示 Data template 选项 - await expect(page.getByText('Data template:')).toBeVisible(); - - // 选择一个模板 - await page.getByTestId('select-form-data-template').click(); - await page.getByRole('option', { name: 'Template name 1' }).click(); - await page.getByTestId('select-object-undefined').click(); - - // 因为添加了数据范围,所以只显示一个选项 - await expect(page.getByRole('option')).toHaveCount(1); - - // 选中数据 - await page.getByRole('option', { name: '2' }).click(); - - await expect( - page - .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') - .getByRole('textbox'), - ).toHaveValue(record.singleLineText); - - // 其它未选中的字段的数据应该是空的 - await expect( - page.getByLabel('block-item-CollectionField-general-form-general.integer-integer').getByRole('spinbutton'), - ).toBeEmpty(); - - // 同步表单字段 - await openDialog(); - await page.getByLabel('action-Action.Link-Sync from form fields-general').click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // 重新选择一下数据,字段值才会被填充 - // TODO: 保存后,数据应该直接被填充上 - await page.getByLabel('icon-close-select').click(); - await page.getByTestId('select-object-undefined').getByLabel('Search').click(); - await page.getByRole('option', { name: '2' }).click(); - - await expect( - page.getByLabel('block-item-CollectionField-general-form-general.email-email').getByRole('textbox'), - ).toHaveValue(record.email); - await expect( - page.getByLabel('block-item-CollectionField-general-form-general.integer-integer').getByRole('spinbutton'), - ).toHaveValue(String(record.integer)); - await expect( - page.getByLabel('block-item-CollectionField-general-form-general.number-number').getByRole('spinbutton'), - ).toHaveValue(String(record.number)); - - // 隐藏模板选项 - await openDialog(); - await page.getByLabel('Display data template selector').click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - await expect(page.getByText('Data template:')).toBeHidden(); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/linkageRules.test.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/linkageRules.test.ts deleted file mode 100644 index bdac3c271..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/linkageRules.test.ts +++ /dev/null @@ -1,225 +0,0 @@ -import { expect, oneTableBlockWithAddNewAndViewAndEditAndBasicFields, test } from '@nocobase/test/client'; - -test.describe('LinkageRules', () => { - test('form: basic usage', async ({ page, mockPage }) => { - const openLinkageRules = async () => { - await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); - await page.getByRole('menuitem', { name: 'Linkage rules' }).click(); - }; - - await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).goto(); - - await page.getByRole('button', { name: 'Add new' }).click(); - - // 设置第一组规则 -------------------------------------------------------------------------- - // 打开联动规则弹窗 - await page.getByLabel('block-item-CardItem-general-form').hover(); - await openLinkageRules(); - - // 增加一组规则 - // 条件:singleLineText 字段的值包含 123 时 - await page.getByRole('button', { name: 'plus Add linkage rule' }).click(); - await page.getByText('Add condition', { exact: true }).click(); - await page.getByTestId('select-filter-field').click(); - await page.getByRole('menuitemcheckbox', { name: 'singleLineText' }).click(); - await page.getByLabel('Linkage rules').locator('input[type="text"]').click(); - await page.getByLabel('Linkage rules').locator('input[type="text"]').fill('123'); - - // action:禁用 longText 字段 - await page.getByText('Add property').click(); - await page.getByTestId('select-linkage-property-field').click(); - await page.getByRole('tree').getByText('longText').click(); - await page.getByTestId('select-linkage-action-field').click(); - await page.getByRole('option', { name: 'Disabled' }).click(); - - // 保存规则 - await page.getByRole('button', { name: 'OK' }).click(); - - // 验证第一组规则 -------------------------------------------------------------------------- - // 初始状态下,longText 字段是可编辑的 - await expect( - page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), - ).toBeEditable(); - - // 输入 123,longText 字段被禁用 - await page - .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') - .getByRole('textbox') - .click(); - await page - .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') - .getByRole('textbox') - .fill('123'); - await expect( - page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), - ).toBeDisabled(); - - // 清空输入,longText 字段应该恢复成可编辑状态 - await page - .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') - .getByRole('textbox') - .clear(); - await expect( - page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), - ).toBeEditable(); - - // 修改第一组规则,使其条件中包含一个变量 -------------------------------------------------------------------------- - // 当 singleLineText 字段的值包含 longText 字段的值时,禁用 longText 字段 - await openLinkageRules(); - await page.getByLabel('variable-button').click(); - await page.getByRole('menuitemcheckbox', { name: 'Current form' }).click(); - await page.getByRole('menuitemcheckbox', { name: 'longText' }).click(); - await page.getByRole('button', { name: 'OK' }).click(); - - // singleLineText 字段和 longText 字段都为空的情况下,longText 字段应该是可编辑的 - await expect( - page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), - ).toBeEditable(); - - // 先为 longText 字段填入 123,然后为 singleLineText 字段填入 1,longText 字段应该是可编辑的 - await page - .getByLabel('block-item-CollectionField-general-form-general.longText-longText') - .getByRole('textbox') - .fill('123'); - await page - .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') - .getByRole('textbox') - .fill('1'); - await expect( - page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), - ).toBeEditable(); - - // 改变变量的值:即将 longText 字段的值改为 1,longText 字段应该是禁用的 - await page - .getByLabel('block-item-CollectionField-general-form-general.longText-longText') - .getByRole('textbox') - .click(); - await page.keyboard.press('Backspace'); - await page.keyboard.press('Backspace'); - await expect( - page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), - ).toBeDisabled(); - - // 添加第二组规则 ------------------------------------------------------------------------------------------- - await openLinkageRules(); - - // 增加一条规则:当 number 字段的值等于 123 时 - await page.getByRole('button', { name: 'plus Add linkage rule' }).click(); - await page.locator('.ant-collapse-header').nth(1).getByRole('img', { name: 'right' }).click(); - - await page.getByLabel('Linkage rules').getByRole('tabpanel').getByText('Add condition', { exact: true }).click(); - await page.getByRole('button', { name: 'Search Select field' }).click(); - await page.getByRole('menuitemcheckbox', { name: 'number' }).click(); - await page.getByLabel('Linkage rules').getByRole('spinbutton').click(); - await page.getByLabel('Linkage rules').getByRole('spinbutton').fill('123'); - - // action:使 longText 字段可编辑 - await page.getByLabel('Linkage rules').getByRole('tabpanel').getByText('Add property').click(); - await page.getByRole('button', { name: 'Search Select field' }).click(); - await page.getByRole('tree').getByText('longText').click(); - await page.getByRole('button', { name: 'Search action' }).click(); - await page.getByRole('option', { name: 'Editable' }).click(); - - // action: 为 longText 字段赋上常量值 - await page.getByLabel('Linkage rules').getByRole('tabpanel').getByText('Add property').click(); - await page.getByRole('button', { name: 'Search Select field' }).click(); - await page.getByRole('tree').getByText('longText').click(); - await page.getByRole('button', { name: 'Search action' }).click(); - await page.getByRole('option', { name: 'Value', exact: true }).click(); - await page.getByLabel('dynamic-component-linkage-rules').getByRole('textbox').fill('456'); - - // action: 为 integer 字段附上一个表达式,使其值等于 number 字段的值 - await page.getByLabel('Linkage rules').getByRole('tabpanel').getByText('Add property').click(); - - await page.getByRole('button', { name: 'Search Select field' }).click(); - await page.getByRole('tree').getByText('integer').click(); - await page.getByRole('button', { name: 'Search action' }).click(); - await page.getByRole('option', { name: 'Value', exact: true }).click(); - await page.getByTestId('select-linkage-value-type').nth(1).click(); - await page.getByText('Expression').click(); - - await page.getByText('xSelect a variable').click(); - await page.getByRole('menuitemcheckbox', { name: 'Current form right' }).click(); - await page.getByRole('menuitemcheckbox', { name: 'number' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // 验证第二组规则 ------------------------------------------------------------------------------------------- - // 此时 longText 字段是禁用状态,当满足第二组规则时,longText 字段应该是可编辑的 - await page - .getByLabel('block-item-CollectionField-general-form-general.number-number') - .getByRole('spinbutton') - .fill('123'); - await expect( - page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), - ).toBeEditable(); - - // 并且 longText 字段的值应该是 456 - await expect( - page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), - ).toHaveValue('456'); - - // integer 字段的值应该等于 number 字段的值 - await expect( - page.getByLabel('block-item-CollectionField-general-form-general.integer-integer').getByRole('spinbutton'), - ).toHaveValue('123'); - }); - - test('action: basic usage', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); - const record = await mockRecord('general'); - await nocoPage.goto(); - - const openLinkageRules = async () => { - await page.getByLabel('action-Action.Link-View record-view-general-table-0').hover(); - await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }).hover(); - await page.getByRole('menuitem', { name: 'Linkage rules' }).click(); - }; - - // 设置第一组规则 -------------------------------------------------------------------------- - await openLinkageRules(); - await page.getByRole('button', { name: 'plus Add linkage rule' }).click(); - - // 添加一个条件:ID 等于 1 - await page.getByText('Add condition', { exact: true }).click(); - await page.getByTestId('select-filter-field').click(); - await page.getByRole('menuitemcheckbox', { name: 'ID' }).click(); - await page.getByRole('spinbutton').click(); - await page.getByRole('spinbutton').fill('1'); - - // action: 禁用按钮 - await page.getByText('Add property').click(); - await page.getByLabel('block-item-ArrayCollapse-general').click(); - await page.getByTestId('select-linkage-properties').getByLabel('Search').click(); - await page.getByRole('option', { name: 'Disabled' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - await expect(page.getByLabel('action-Action.Link-View record-view-general-table-0')).toHaveAttribute( - 'disabled', - '', - ); - - // 设置第二组规则 -------------------------------------------------------------------------- - await openLinkageRules(); - await page.getByRole('button', { name: 'plus Add linkage rule' }).click(); - await page.locator('.ant-collapse-header').nth(1).getByRole('img', { name: 'right' }).click(); - - // 添加一个条件:ID 等于 1 - await page.getByRole('tabpanel').getByText('Add condition', { exact: true }).click(); - await page.getByRole('button', { name: 'Search Select field' }).getByLabel('Search').click(); - await page.getByRole('menuitemcheckbox', { name: 'ID' }).click(); - await page.getByRole('spinbutton').click(); - await page.getByRole('spinbutton').fill('1'); - - // action: 使按钮可用 - await page.getByRole('tabpanel').getByText('Add property').click(); - await page.getByRole('combobox', { name: 'Search' }).click(); - await page.getByRole('option', { name: 'Enabled' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // 后面的 action 会覆盖前面的 - await expect(page.getByLabel('action-Action.Link-View record-view-general-table-0')).not.toHaveAttribute( - 'disabled', - '', - ); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/setDefaultValue.test.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/setDefaultValue.test.ts deleted file mode 100644 index 4918e4b3c..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/setDefaultValue.test.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { - expect, - oneTableBlockWithAddNewAndViewAndEditAndBasicFields, - oneTableBlockWithAddNewAndViewAndEditAndRelationFields, - test, -} from '@nocobase/test/client'; - -test.describe('set default value', () => { - test('basic fields', async ({ page, mockPage }) => { - await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).goto(); - - const openDialog = async (fieldName: string) => { - await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) - .hover(); - await page.getByRole('menuitem', { name: 'Set default value', exact: true }).click(); - }; - - await page.getByRole('button', { name: 'Add new' }).click(); - await openDialog('singleLineText'); - await page.getByLabel('Set default value').getByRole('textbox').click(); - await page.getByLabel('Set default value').getByRole('textbox').fill('test default value'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // 关闭弹窗在打开,应该显示默认值 - await page.getByLabel('drawer-Action.Container-general-Add record-mask').click(); - await page.getByRole('button', { name: 'Add new' }).click(); - await expect( - page - .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') - .getByRole('textbox'), - ).toHaveValue('test default value'); - - // 为 longText 设置一个变量默认值: {{ currentForm.singleLineText }} - await openDialog('longText'); - await page.getByLabel('variable-button').click(); - await page.getByRole('menuitemcheckbox', { name: 'Current form' }).click(); - await page.getByRole('menuitemcheckbox', { name: 'singleLineText' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - await page.getByLabel('drawer-Action.Container-general-Add record-mask').click(); - await page.getByRole('button', { name: 'Add new' }).click(); - // 值应该和 singleLineText 一致 - await expect( - page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), - ).toHaveValue('test default value'); - - // 更改变量的值,longText 的值也应该跟着变化 - await page - .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') - .getByRole('textbox') - .fill('new value'); - await expect( - page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), - ).toHaveValue('new value'); - }); - - test('subform: basic fields', async ({ page, mockPage }) => { - await mockPage(oneTableBlockWithAddNewAndViewAndEditAndRelationFields).goto(); - - await page.getByRole('button', { name: 'Add new' }).click(); - - // 先切换为子表单 - await page.getByLabel('block-item-CollectionField-general-form-general.manyToOne-manyToOne').hover(); - await page - .getByLabel('designer-schema-settings-CollectionField-FormItem.Designer-general-general.manyToOne') - .hover(); - await page.getByRole('menuitem', { name: 'Field component' }).click(); - await page.getByRole('option', { name: 'Sub-form', exact: true }).click(); - - // 关闭下拉菜单 - await page.getByLabel('block-item-CollectionField-general-form-general.manyToOne-manyToOne').hover(); - await page - .getByLabel('designer-schema-settings-CollectionField-FormItem.Designer-general-general.manyToOne') - .hover(); - await page.mouse.move(100, 0); - - await page.getByLabel('schema-initializer-Grid-FormItemInitializers-users').hover(); - await page.getByRole('menuitem', { name: 'Nickname' }).click(); - await page.getByRole('menuitem', { name: 'Username' }).click(); - - // 子表单状态下,没有默认值选项 - await page.getByLabel('block-item-CollectionField-general-form-general.manyToOne-manyToOne').hover(); - await expect(page.getByRole('menuitem', { name: 'Set default value' })).not.toBeVisible(); - - // 测试子表单字段默认值 ------------------------------------------------------------------------------------------ - await page.getByLabel(`block-item-CollectionField-users-form-users.nickname-Nickname`).hover(); - await page.getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-users-users.Nickname`).hover(); - await page.getByRole('menuitem', { name: 'Set default value', exact: true }).click(); - await page.getByLabel('Set default value').getByRole('textbox').click(); - await page.getByLabel('Set default value').getByRole('textbox').fill('test default value'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // 关闭弹窗在打开,应该显示默认值 - await page.getByLabel('drawer-Action.Container-general-Add record-mask').click(); - await page.getByRole('button', { name: 'Add new' }).click(); - await expect( - page.getByLabel('block-item-CollectionField-users-form-users.nickname-Nickname').getByRole('textbox'), - ).toHaveValue('test default value'); - - // 为 username 设置一个变量默认值: {{ currentObject.nickname }} - await page.getByLabel(`block-item-CollectionField-users-form-users.username-Username`).hover(); - await page.getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-users-users.Username`).hover(); - await page.getByRole('menuitem', { name: 'Set default value', exact: true }).click(); - await page.getByLabel('variable-button').click(); - await page.getByRole('menuitemcheckbox', { name: 'Current object' }).click(); - await page.getByRole('menuitemcheckbox', { name: 'Nickname' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - await page.getByLabel('drawer-Action.Container-general-Add record-mask').click(); - await page.getByRole('button', { name: 'Add new' }).click(); - // 值应该和 Nickname 一致 - await expect( - page.getByLabel('block-item-CollectionField-users-form-users.username-Username').getByRole('textbox'), - ).toHaveValue('test default value'); - - // 更改变量的值,longText 的值也应该跟着变化 - await page - .getByLabel('block-item-CollectionField-users-form-users.nickname-Nickname') - .getByRole('textbox') - .fill('new value'); - await expect( - page.getByLabel('block-item-CollectionField-users-form-users.username-Username').getByRole('textbox'), - ).toHaveValue('new value'); - }); - - test('subtable: basic fields', async ({ page, mockPage }) => { - await mockPage(oneTableBlockWithAddNewAndViewAndEditAndRelationFields).goto(); - - await page.getByRole('button', { name: 'Add new' }).click(); - - // 先切换为子表格 - await page.getByLabel('block-item-CollectionField-general-form-general.oneToMany-oneToMany').hover(); - await page - .getByLabel('designer-schema-settings-CollectionField-FormItem.Designer-general-general.oneToMany') - .hover(); - await page.getByRole('menuitem', { name: 'Field component' }).click(); - await page.getByRole('option', { name: 'Sub-table' }).click(); - - // 关闭下拉菜单 - await page.getByLabel('block-item-CollectionField-general-form-general.oneToMany-oneToMany').hover(); - await page - .getByLabel('designer-schema-settings-CollectionField-FormItem.Designer-general-general.oneToMany') - .hover(); - await page.mouse.move(100, 0); - - await page.getByLabel('schema-initializer-AssociationField.SubTable-TableColumnInitializers-users').hover(); - await page.getByRole('menuitem', { name: 'Nickname' }).click(); - await page.getByRole('menuitem', { name: 'Username' }).click(); - - // 子表格状态下,没有默认值选项 - await page.getByLabel('block-item-CollectionField-general-form-general.oneToMany-oneToMany').hover(); - await expect(page.getByRole('menuitem', { name: 'Set default value' })).not.toBeVisible(); - - // 测试子表格字段默认值 ------------------------------------------------------------------------------------------ - await page.getByRole('button', { name: 'Nickname', exact: true }).hover(); - await page - .getByRole('button', { name: 'designer-schema-settings-TableV2.Column-TableV2.Column.Designer-users' }) - .hover(); - await page.getByRole('menuitem', { name: 'Set default value', exact: true }).click(); - await page.getByLabel('Set default value').getByRole('textbox').click(); - await page.getByLabel('Set default value').getByRole('textbox').fill('test default value'); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // 当新增一行时,应该显示默认值 - await page.getByRole('button', { name: 'plus' }).click(); - await expect( - page - .getByRole('cell', { name: 'block-item-CollectionField-users-form-users.nickname-Nickname' }) - .getByRole('textbox'), - ).toHaveValue('test default value'); - - // 为 username 设置一个变量默认值: {{ currentObject.nickname }} - await page.getByRole('button', { name: 'Username', exact: true }).hover(); - await page - .getByRole('button', { name: 'designer-schema-settings-TableV2.Column-TableV2.Column.Designer-users' }) - .hover(); - await page.getByRole('menuitem', { name: 'Set default value', exact: true }).click(); - await page.mouse.move(300, 0); - await page.getByLabel('variable-button').click(); - await page.getByRole('menuitemcheckbox', { name: 'Current object' }).click(); - await page.getByRole('menuitemcheckbox', { name: 'Nickname' }).click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // 值应该和 Nickname 一致 - await expect( - page - .getByRole('cell', { name: 'block-item-CollectionField-users-form-users.username-Username' }) - .getByRole('textbox'), - ).toHaveValue('test default value'); - - // 更改变量的值,longText 的值也应该跟着变化 - await page - .getByRole('cell', { name: 'block-item-CollectionField-users-form-users.username-Username' }) - .getByRole('textbox') - .fill('new value'); - await expect( - page - .getByRole('cell', { name: 'block-item-CollectionField-users-form-users.username-Username' }) - .getByRole('textbox'), - ).toHaveValue('new value'); - }); -}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/variablesLazyLoad/templatesOfPage.ts b/packages/core/client/src/__tests__/e2e/schemaSettings/variablesLazyLoad/templatesOfPage.ts deleted file mode 100644 index b99c85a12..000000000 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/variablesLazyLoad/templatesOfPage.ts +++ /dev/null @@ -1,531 +0,0 @@ -import { PageConfig, generalWithMultiLevelRelationshipFields } from '@nocobase/test/client'; - -export const testingLazyLoadingOfAssociationFieldsForTheCurrentRecord: PageConfig = { - collections: generalWithMultiLevelRelationshipFields, - pageSchema: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Page', - properties: { - twh6vbpbeh7: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'BlockInitializers', - properties: { - i7hhy9qt3vm: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - zo5ry8mb8i8: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - md9lzbo43sa: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'TableBlockProvider', - 'x-acl-action': 'general:list', - 'x-decorator-props': { - collection: 'general', - resource: 'general', - action: 'list', - params: { - pageSize: 20, - }, - rowKey: 'id', - showIndex: true, - dragSort: false, - disableTemplate: false, - }, - 'x-designer': 'TableBlockDesigner', - 'x-component': 'CardItem', - 'x-filter-targets': [], - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'TableActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 'var(--nb-spacing)', - }, - }, - properties: { - ztk6e5lq2lu: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-action': 'create', - 'x-acl-action': 'create', - title: "{{t('Add new')}}", - 'x-designer': 'Action.Designer', - 'x-component': 'Action', - 'x-decorator': 'ACLActionProvider', - 'x-component-props': { - openMode: 'drawer', - type: 'primary', - component: 'CreateRecordAction', - icon: 'PlusOutlined', - }, - 'x-align': 'right', - 'x-acl-action-props': { - skipScopeCheck: true, - }, - properties: { - drawer: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Add record") }}', - 'x-component': 'Action.Container', - 'x-component-props': { - className: 'nb-action-popup', - }, - properties: { - tabs: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Tabs', - 'x-component-props': {}, - 'x-initializer': 'TabPaneInitializersForCreateFormBlock', - properties: { - tab1: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{t("Add new")}}', - 'x-component': 'Tabs.TabPane', - 'x-designer': 'Tabs.Designer', - 'x-component-props': {}, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'CreateFormBlockInitializers', - properties: { - ec8k6t8hyfd: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - i0kq9r8uagp: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - kiwjcmb22ni: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-acl-action-props': { - skipScopeCheck: true, - }, - 'x-acl-action': 'general:create', - 'x-decorator': 'FormBlockProvider', - 'x-decorator-props': { - resource: 'general', - collection: 'general', - }, - 'x-designer': 'FormV2.Designer', - 'x-component': 'CardItem', - 'x-component-props': {}, - properties: { - q93o4rn1hum: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'FormV2', - 'x-component-props': { - useProps: '{{ useFormBlockProps }}', - }, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'FormItemInitializers', - properties: { - '11k61q066eh': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - ilk6g3zfb99: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - m2oField0: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'string', - 'x-designer': 'FormItem.Designer', - 'x-component': 'CollectionField', - 'x-decorator': 'FormItem', - 'x-collection-field': 'general.m2oField0', - 'x-component-props': {}, - 'x-uid': 'zrdwygwt68n', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'jbzdmkicrbq', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '19tec55bhv8', - 'x-async': false, - 'x-index': 1, - }, - t964dpznx8s: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - wcc2gxtezpj: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - singleLineText: { - 'x-uid': 'h6nhc1du9zi', - _isJSONSchemaObject: true, - version: '2.0', - type: 'string', - 'x-designer': 'FormItem.Designer', - 'x-component': 'CollectionField', - 'x-decorator': 'FormItem', - 'x-collection-field': - 'general.singleLineText', - 'x-component-props': {}, - default: - '{{$nForm.m2oField0.m2oField1.id}}', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 't1fh9mrbi65', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '5pzmjkt6nk9', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'i969ieh0rfu', - 'x-async': false, - 'x-index': 1, - }, - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'CreateFormActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - layout: 'one-column', - style: { - marginTop: 24, - }, - }, - 'x-uid': 'lrwiyzyg7ow', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'gz3ygly62js', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'q8gn2pt12ng', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'p0gdtennahr', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'f8741pdnbcy', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'f27ge9qf7u6', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'xa5ujnlaqd6', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'd6dy86bjt0b', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'aycw09vymqy', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'tzdqfr6lmjy', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '7zzwexd3e4i', - 'x-async': false, - 'x-index': 1, - }, - qoq998l2i65: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'array', - 'x-initializer': 'TableColumnInitializers', - 'x-component': 'TableV2', - 'x-component-props': { - rowKey: 'id', - rowSelection: { - type: 'checkbox', - }, - useProps: '{{ useTableBlockProps }}', - }, - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Actions") }}', - 'x-action-column': 'actions', - 'x-decorator': 'TableV2.Column.ActionBar', - 'x-component': 'TableV2.Column', - 'x-designer': 'TableV2.ActionColumnDesigner', - 'x-initializer': 'TableActionColumnInitializers', - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'DndContext', - 'x-component': 'Space', - 'x-component-props': { - split: '|', - }, - properties: { - '8kaku37mdre': { - 'x-uid': 'j1n2bte2wn4', - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: 'View record', - 'x-action': 'view', - 'x-designer': 'Action.Designer', - 'x-component': 'Action.Link', - 'x-component-props': { - openMode: 'drawer', - danger: false, - }, - 'x-decorator': 'ACLActionProvider', - 'x-designer-props': { - linkageAction: true, - }, - properties: { - drawer: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("View record") }}', - 'x-component': 'Action.Container', - 'x-component-props': { - className: 'nb-action-popup', - }, - properties: { - tabs: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Tabs', - 'x-component-props': {}, - 'x-initializer': 'TabPaneInitializers', - properties: { - tab1: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{t("Details")}}', - 'x-component': 'Tabs.TabPane', - 'x-designer': 'Tabs.Designer', - 'x-component-props': {}, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'RecordBlockInitializers', - 'x-uid': '6k8q5pvnbjg', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'txzczhz6s4g', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'chdb0wf0riz', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '7jpie07p1s7', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-async': false, - 'x-index': 1, - }, - '0xml7nfy4gs': { - 'x-uid': 'inv9i7a8i9t', - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: 'Edit record', - 'x-action': 'update', - 'x-designer': 'Action.Designer', - 'x-component': 'Action.Link', - 'x-component-props': { - openMode: 'drawer', - danger: false, - }, - 'x-decorator': 'ACLActionProvider', - 'x-designer-props': { - linkageAction: true, - }, - properties: { - drawer: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Edit record") }}', - 'x-component': 'Action.Container', - 'x-component-props': { - className: 'nb-action-popup', - }, - properties: { - tabs: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Tabs', - 'x-component-props': {}, - 'x-initializer': 'TabPaneInitializers', - properties: { - tab1: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{t("Edit")}}', - 'x-component': 'Tabs.TabPane', - 'x-designer': 'Tabs.Designer', - 'x-component-props': {}, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'RecordBlockInitializers', - 'x-uid': 'yqsyvw7utn4', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'pb3iqfcd6a5', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '3byo77j4fh6', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '1gscyc9hw6f', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'v4zy14lc4g4', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 's2ej5h10jxd', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'xoknlt7jnhh', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'ovphvqtknwh', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'y4mqu08ojko', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'mszhp81fvd9', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'ylndxgnumz2', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'sj1cs0vneuv', - 'x-async': true, - 'x-index': 1, - }, -}; diff --git a/packages/core/client/src/__tests__/e2e/utils.ts b/packages/core/client/src/__tests__/e2e/utils.ts deleted file mode 100644 index 9c05efbf3..000000000 --- a/packages/core/client/src/__tests__/e2e/utils.ts +++ /dev/null @@ -1,33 +0,0 @@ -//颜色值的近似比较,而不是精确比较 -function approximateColor(actualColor, expectedColor) { - const regex = /rgba?\((\d+), (\d+), (\d+)(?:, ([0-9.]+))?\)/; - const actualMatch = actualColor.match(regex); - const expectedMatch = expectedColor.match(regex); - - if (actualMatch && expectedMatch) { - const tolerance = 2; // 允许的颜色分量误差 - for (let i = 1; i <= 4; i++) { - const actualValue = parseInt(actualMatch[i], 10); - const expectedValue = parseInt(expectedMatch[i], 10); - if (Math.abs(actualValue - expectedValue) > tolerance) { - return false; - } - } - return true; - } - - return false; -} - -async function waitForModalToBeHidden(page) { - await page.waitForFunction(() => { - const modal = document.querySelector('.ant-modal'); - if (modal) { - const computedStyle = window.getComputedStyle(modal); - return computedStyle.display === 'none' || computedStyle.visibility === 'hidden'; - } - return true; // 如果找不到modal,也算作不可见 - }); -} - -export { approximateColor, waitForModalToBeHidden }; diff --git a/packages/core/client/src/__tests__/e2e/schemaInitializer/filterCollapseBlock.test.ts b/packages/core/client/src/modules/collapse-filter/__e2e__/schemaInitializer.test.ts similarity index 69% rename from packages/core/client/src/__tests__/e2e/schemaInitializer/filterCollapseBlock.test.ts rename to packages/core/client/src/modules/collapse-filter/__e2e__/schemaInitializer.test.ts index dc008d262..7ccbeb0d0 100644 --- a/packages/core/client/src/__tests__/e2e/schemaInitializer/filterCollapseBlock.test.ts +++ b/packages/core/client/src/modules/collapse-filter/__e2e__/schemaInitializer.test.ts @@ -1,7 +1,19 @@ -import { expect, oneEmptyFilterCollapseBlock, test } from '@nocobase/test/client'; +import { createBlockInPage, expect, oneEmptyFilterCollapseBlock, test } from '@nocobase/test/client'; -test.describe('Filter Collapse', () => { - test('add fields', async ({ page, mockPage }) => { +test.describe('where collapse block can be added', () => { + test('page', async ({ page, mockPage }) => { + await mockPage().goto(); + + await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); + await createBlockInPage(page, 'Collapse'); + await expect(page.getByLabel('block-item-CardItem-users-filter-collapse')).toBeVisible(); + }); + + test('data selector popup', async ({ page, mockPage }) => {}); +}); + +test.describe('configure fields', () => { + test('association fields & choices fields', async ({ page, mockPage }) => { await mockPage(oneEmptyFilterCollapseBlock).goto(); // add fields diff --git a/packages/core/client/src/modules/collapse-filter/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/collapse-filter/__e2e__/schemaSettings.test.ts new file mode 100644 index 000000000..29a71ccdc --- /dev/null +++ b/packages/core/client/src/modules/collapse-filter/__e2e__/schemaSettings.test.ts @@ -0,0 +1,63 @@ +import { + expect, + expectSettingsMenu, + oneCollapseAndOneTableWithSameCollection, + oneEmptyFilterCollapseBlock, + test, +} from '@nocobase/test/client'; + +test.describe('collapse schema settings', () => { + test('supported options', async ({ page, mockPage }) => { + await mockPage(oneEmptyFilterCollapseBlock).goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByLabel('block-item-CardItem-general-filter-collapse').hover(); + await page.getByLabel('designer-schema-settings-CardItem-AssociationFilter.BlockDesigner-general').hover(); + }, + supportedOptions: ['Edit block title', 'Save as template', 'Connect data blocks', 'Delete'], + }); + }); + + test.describe('connect data blocks', () => { + test('connecting two blocks of the same collection', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(oneCollapseAndOneTableWithSameCollection).waitForInit(); + const records = await mockRecords('general', [ + { singleSelect: 'option1' }, + { singleSelect: 'option2' }, + { singleSelect: 'option3' }, + ]); + await nocoPage.goto(); + + // 将上面的 Collapse 连接到下面的 Table + await page.getByLabel('block-item-CardItem-general-filter-collapse').hover(); + await page.getByLabel('designer-schema-settings-CardItem-AssociationFilter.BlockDesigner-general').hover(); + await page.getByRole('menuitem', { name: 'Connect data blocks' }).hover(); + await page.getByRole('menuitem', { name: 'General' }).click(); + + // 点击一个选项,进行筛选 + await page.getByRole('button', { name: 'right singleSelect search' }).click(); + await page.getByLabel('block-item-CardItem-general-filter-collapse').getByText('Option1').click(); + + // 注意:在本地运行时,由于运行结束后不会清空之前创建的数据,所以在第一次运行之后,下面会报错。如果遇到这种情况,可以先不管 + await expect( + page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: 'Option2' }), + ).toBeHidden(); + await expect( + page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: 'Option3' }), + ).toBeHidden(); + await expect( + page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: 'Option1' }), + ).toBeVisible(); + + // 再次点击,重置筛选 + await page.getByLabel('block-item-CardItem-general-filter-collapse').getByText('Option1').click(); + await expect(page.getByLabel('block-item-CardItem-general-table').getByRole('row')).toHaveCount( + records.length + 1, + ); + }); + }); +}); + +test.describe('fields schema settings', () => {}); diff --git a/packages/core/client/src/modules/collapse-filter/__e2e__/templatesOfBug.ts b/packages/core/client/src/modules/collapse-filter/__e2e__/templatesOfBug.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/core/client/src/__tests__/e2e/schemaInitializer/detailsBlock.test.ts b/packages/core/client/src/modules/details-multi-data/__e2e__/schemaInitializer.test.ts similarity index 76% rename from packages/core/client/src/__tests__/e2e/schemaInitializer/detailsBlock.test.ts rename to packages/core/client/src/modules/details-multi-data/__e2e__/schemaInitializer.test.ts index 7d45266eb..30d53901f 100644 --- a/packages/core/client/src/__tests__/e2e/schemaInitializer/detailsBlock.test.ts +++ b/packages/core/client/src/modules/details-multi-data/__e2e__/schemaInitializer.test.ts @@ -1,15 +1,24 @@ -import { expect, oneEmptyDetailsBlock, test } from '@nocobase/test/client'; +import { createBlockInPage, expect, oneEmptyDetailsBlock, test } from '@nocobase/test/client'; -test.describe('Details block', () => { - test('add fields', async ({ page, mockPage }) => { +test.describe('where multi data details block can be added', () => { + test('page', async ({ page, mockPage }) => { + await mockPage().goto(); + await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); + await createBlockInPage(page, 'Details'); + await expect(page.getByLabel('block-item-CardItem-users-details')).toBeVisible(); + }); +}); + +test.describe('configure fields', () => { + test('display collection fields & display association fields & add text', async ({ page, mockPage }) => { await mockPage(oneEmptyDetailsBlock).goto(); const formItemInitializer = page.getByLabel('schema-initializer-Grid-ReadPrettyFormItemInitializers-general'); // add fields await formItemInitializer.hover(); - await page.getByRole('menuitem', { name: 'ID' }).click(); - await expect(page.getByRole('menuitem', { name: 'ID' }).getByRole('switch')).toBeChecked(); + await page.getByRole('menuitem', { name: 'ID', exact: true }).click(); + await expect(page.getByRole('menuitem', { name: 'ID', exact: true }).getByRole('switch')).toBeChecked(); // add association fields await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); @@ -26,8 +35,8 @@ test.describe('Details block', () => { // delete fields await formItemInitializer.hover(); - await page.getByRole('menuitem', { name: 'ID' }).click(); - await expect(page.getByRole('menuitem', { name: 'ID' }).getByRole('switch')).not.toBeChecked(); + await page.getByRole('menuitem', { name: 'ID', exact: true }).click(); + await expect(page.getByRole('menuitem', { name: 'ID', exact: true }).getByRole('switch')).not.toBeChecked(); await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); await page.getByRole('menuitem', { name: 'Nickname' }).click(); @@ -46,8 +55,10 @@ test.describe('Details block', () => { await page.getByRole('menuitem', { name: 'Add text' }).click(); await expect(page.getByLabel('block-item-Markdown.Void-general-details')).toBeVisible(); }); +}); - test('add action buttons', async ({ page, mockPage }) => { +test.describe('configure actions', () => { + test('edit & delete & duplicate', async ({ page, mockPage }) => { await mockPage(oneEmptyDetailsBlock).goto(); await page.getByLabel('schema-initializer-ActionBar-DetailsActionInitializers-general').hover(); diff --git a/packages/core/client/src/modules/details-multi-data/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/details-multi-data/__e2e__/schemaSettings.test.ts new file mode 100644 index 000000000..01524d8c3 --- /dev/null +++ b/packages/core/client/src/modules/details-multi-data/__e2e__/schemaSettings.test.ts @@ -0,0 +1,71 @@ +import { + expectSettingsMenu, + oneDetailBlockWithM2oFieldToGeneral, + oneEmptyDetailsBlock, + test, +} from '@nocobase/test/client'; + +test.describe('multi data details block schema settings', () => { + test('supported options', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneDetailBlockWithM2oFieldToGeneral).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByLabel('block-item-CardItem-targetToGeneral-details').hover(); + await page.getByLabel('designer-schema-settings-CardItem-DetailsDesigner-targetToGeneral').hover(); + }, + supportedOptions: [ + 'Edit block title', + 'Set the data scope', + 'Set default sorting rules', + 'Save as block template', + 'Delete', + ], + }); + }); +}); + +test.describe('actions schema settings', () => { + test('edit & delete & duplicate', async ({ page, mockPage }) => { + await mockPage(oneEmptyDetailsBlock).goto(); + + // 创建 Edit & Delete & Duplicate 三个按钮 + await page.getByLabel('schema-initializer-ActionBar-DetailsActionInitializers-general').hover(); + await page.getByRole('menuitem', { name: 'Edit' }).click(); + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.getByRole('menuitem', { name: 'Duplicate' }).click(); + + // Edit button settings --------------------------------------------------------------- + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByRole('button', { name: 'Edit' }).hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action' }).hover(); + }, + supportedOptions: ['Edit button', 'Linkage rules', 'Open mode', 'Popup size', 'Delete'], + }); + + // Delete settings ------------------------------------------------------------------- + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByRole('button', { name: 'Delete' }).hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action' }).hover(); + }, + supportedOptions: ['Edit button', 'Linkage rules', 'Delete'], + }); + + // Duplicate settings ---------------------------------------------------------------- + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByRole('button', { name: 'Duplicate' }).hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action' }).hover(); + }, + supportedOptions: ['Edit button', 'Duplicate mode', 'Open mode', 'Popup size', 'Delete'], + }); + }); +}); diff --git a/packages/core/client/src/modules/details-multi-data/__e2e__/templatesOfBug.ts b/packages/core/client/src/modules/details-multi-data/__e2e__/templatesOfBug.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/core/client/src/modules/details-single-data/__e2e__/schemaInitializer.test.ts b/packages/core/client/src/modules/details-single-data/__e2e__/schemaInitializer.test.ts new file mode 100644 index 000000000..da60ba03c --- /dev/null +++ b/packages/core/client/src/modules/details-single-data/__e2e__/schemaInitializer.test.ts @@ -0,0 +1,87 @@ +import { Page, expect, expectSettingsMenu, oneEmptyTableBlockWithActions, test } from '@nocobase/test/client'; + +test.describe('where single data details block can be added', () => { + test('popup', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneEmptyTableBlockWithActions).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + + await page.getByLabel('action-Action.Link-View-view-general-table-0').click(); + await page.getByLabel('schema-initializer-Grid-RecordBlockInitializers-general').hover(); + await page.getByRole('menuitem', { name: 'Details' }).click(); + await page.mouse.move(300, 0); + + await expect(page.getByLabel('block-item-CardItem-general-form')).toBeVisible(); + }); +}); + +test.describe('configure actions', () => { + test('edit & delete & duplicate & print & customize', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneEmptyTableBlockWithActions).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + + await page.getByLabel('action-Action.Link-View-view-general-table-0').click(); + await page.getByLabel('schema-initializer-Grid-RecordBlockInitializers-general').hover(); + await page.getByRole('menuitem', { name: 'Details' }).click(); + await page.mouse.move(300, 0); + + // create edit ------------------------------------------------------------------------------------ + await createAction(page, 'Edit'); + await expect(page.getByLabel('action-Action-Edit-update-general-form-0')).toBeVisible(); + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByLabel('action-Action-Edit-update-general-form-0').hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action-Action.Designer-general' }).hover(); + }, + supportedOptions: ['Edit button', 'Linkage rules', 'Open mode', 'Popup size', 'Delete'], + }); + await deleteAction(page, 'action-Action-Edit-update-general-form-0'); + + // create delete ------------------------------------------------------------------------------------ + await createAction(page, 'Delete'); + await expect(page.getByLabel('action-Action-Delete-destroy-general-form-0')).toBeVisible(); + + // create duplicate ------------------------------------------------------------------------------------ + await createAction(page, 'Duplicate'); + await expect(page.getByLabel('action-Action-Duplicate-duplicate-general-form-0')).toBeVisible(); + + // create print + await createAction(page, 'Print'); + await expect(page.getByLabel('action-Action-Print-print-general-form-0')).toBeVisible(); + + // create customize actions ---------------------------------------------------------------------------- + // Popup + await createCustomAction(page, 'Popup'); + await expect(page.getByLabel('action-Action-Popup-customize:popup-general-form-0')).toBeVisible(); + + // Update record + await createCustomAction(page, 'Update record'); + await expect(page.getByLabel('action-Action-Update record-customize:update-general-form-0')).toBeVisible(); + }); +}); + +test.describe('configure fields', () => {}); + +async function createAction(page: Page, name: string) { + await page.getByLabel('schema-initializer-ActionBar-ReadPrettyFormActionInitializers-general').hover(); + await page.getByRole('menuitem', { name: name }).click(); + await expect(page.getByRole('menuitem', { name: name }).getByRole('switch')).toBeChecked(); + await page.mouse.move(300, 0); +} + +async function createCustomAction(page: Page, name: string) { + await page.getByLabel('schema-initializer-ActionBar-ReadPrettyFormActionInitializers-general').hover(); + await page.getByRole('menuitem', { name: 'Customize' }).hover(); + await page.getByRole('menuitem', { name: name }).click(); + await page.mouse.move(0, 400); +} + +async function deleteAction(page: Page, label: string) { + await page.getByLabel(label).hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action-' }).hover(); + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.mouse.move(0, 300); + await page.getByRole('button', { name: 'OK', exact: true }).click(); +} diff --git a/packages/core/client/src/modules/details-single-data/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/details-single-data/__e2e__/schemaSettings.test.ts new file mode 100644 index 000000000..58fd4c771 --- /dev/null +++ b/packages/core/client/src/modules/details-single-data/__e2e__/schemaSettings.test.ts @@ -0,0 +1,25 @@ +import { expectSettingsMenu, oneTableBlockWithAddNewAndViewAndEditAndBasicFields, test } from '@nocobase/test/client'; + +test.describe('single details block schema settings', () => { + test('supported options', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + + // 打开抽屉 + await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByLabel('block-item-CardItem-general-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-FormV2.ReadPrettyDesigner-general').hover(); + }, + supportedOptions: ['Edit block title', 'Save as block template', 'Delete'], + }); + }); +}); + +test.describe('actions schema settings', () => {}); + +test.describe('fields schema settings', () => {}); diff --git a/packages/core/client/src/modules/details-single-data/__e2e__/templatesOfBug.ts b/packages/core/client/src/modules/details-single-data/__e2e__/templatesOfBug.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/core/client/src/__tests__/e2e/schemaInitializer/actions.test.ts b/packages/core/client/src/modules/dialog/__e2e__/schemaInitializer.test.ts similarity index 58% rename from packages/core/client/src/__tests__/e2e/schemaInitializer/actions.test.ts rename to packages/core/client/src/modules/dialog/__e2e__/schemaInitializer.test.ts index 28ede7820..25d4ad4dc 100644 --- a/packages/core/client/src/__tests__/e2e/schemaInitializer/actions.test.ts +++ b/packages/core/client/src/modules/dialog/__e2e__/schemaInitializer.test.ts @@ -1,11 +1,13 @@ import { expect, + oneDetailBlockWithM2oFieldToGeneral, oneEmptyTableBlockWithActions, oneEmptyTableBlockWithCustomizeActions, + oneFormBlockWithRolesFieldBasedUsers, test, } from '@nocobase/test/client'; -test.describe('Actions with dialog', () => { +test.describe('where to open a popup and what can be added to it', () => { test('add new', async ({ page, mockPage }) => { await mockPage(oneEmptyTableBlockWithActions).goto(); @@ -53,7 +55,7 @@ test.describe('Actions with dialog', () => { await expect(page.getByLabel('block-item-Markdown.Void-general-markdown')).toBeVisible(); }); - test('view & edit & popup', async ({ page, mockPage, mockRecord }) => { + test('view', async ({ page, mockPage, mockRecord }) => { const nocoPage = await mockPage(oneEmptyTableBlockWithActions).waitForInit(); await mockRecord('general'); await nocoPage.goto(); @@ -138,4 +140,91 @@ test.describe('Actions with dialog', () => { await expect(page.getByLabel('block-item-CardItem-general-form')).toBeVisible(); await expect(page.getByLabel('block-item-Markdown.Void-general-markdown')).toBeVisible(); }); + + test('association link', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneDetailBlockWithM2oFieldToGeneral).waitForInit(); + const record = await mockRecord('targetToGeneral'); + await nocoPage.goto(); + + // open dialog + await page + .getByLabel('block-item-CollectionField-targetToGeneral-details-targetToGeneral.toGeneral-toGeneral') + .getByText(record.id, { exact: true }) + .click(); + + // add a tab + await page.getByLabel('schema-initializer-Tabs-TabPaneInitializers-general').click(); + await page.getByRole('textbox').click(); + await page.getByRole('textbox').fill('test8'); + await page.getByLabel('action-Action-Submit-general-details').click(); + + await expect(page.getByText('test8')).toBeVisible(); + + // add blocks + await page.getByLabel('schema-initializer-Grid-RecordBlockInitializers-general').hover(); + await page.getByRole('menuitem', { name: 'Details' }).click(); + await page.getByText('Form').click(); + await page.getByRole('menuitem', { name: 'Markdown' }).click(); + + await expect(page.getByText('GeneralConfigure actionsConfigure fields')).toBeVisible(); + await expect(page.getByText('GeneralConfigure fieldsConfigure actions')).toBeVisible(); + await expect(page.getByLabel('block-item-Markdown.Void-general-markdown')).toBeVisible(); + + // 删除已创建的 blocks,腾出页面空间 + // delete details block + await page.getByText('GeneralConfigure actionsConfigure fields').hover(); + await page.getByLabel('designer-schema-settings-CardItem-FormV2.ReadPrettyDesigner-general').hover(); + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + // delete form block + await page.getByLabel('block-item-CardItem-general-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + // delete markdown block + await page.getByLabel('block-item-Markdown.Void-general-markdown').hover(); + await page.getByLabel('designer-schema-settings-Markdown.Void-Markdown.Void.Designer-general').hover(); + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // add relationship blocks + await page.getByLabel('schema-initializer-Grid-RecordBlockInitializers-general').hover(); + await page.getByRole('menuitem', { name: 'Many to one' }).hover(); + await page.getByRole('menuitem', { name: 'Details' }).click(); + + await page.mouse.move(300, 0); + + await page.getByLabel('schema-initializer-Grid-RecordBlockInitializers-general').hover(); + await page.getByRole('menuitem', { name: 'One to many' }).hover(); + + // 下拉列表中,可选择以下区块进行创建 + await expect(page.getByText('Table')).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Details' }).nth(1)).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'List' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Grid Card' })).toBeVisible(); + await expect(page.getByText('Form').nth(1)).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Calendar' })).toBeVisible(); + + await page.getByText('Table').click(); + await expect(page.getByLabel('block-item-CardItem-users-table')).toBeVisible(); + }); + + test('data picker', async ({ page, mockPage }) => { + await mockPage(oneFormBlockWithRolesFieldBasedUsers).goto(); + + // open dialog + await page.getByTestId('select-data-picker').click(); + + // add blocks + await page.getByLabel('schema-initializer-Grid-TableSelectorInitializers-roles').hover(); + await page.getByRole('menuitem', { name: 'form Table' }).click(); + await page.getByText('Form').click(); + await page.getByRole('menuitem', { name: 'Collapse' }).click(); + await page.getByRole('menuitem', { name: 'Add text' }).click(); + + await expect(page.getByLabel('block-item-CardItem-roles-table-selector')).toBeVisible(); + await expect(page.getByLabel('block-item-CardItem-roles-filter-form')).toBeVisible(); + await expect(page.getByLabel('block-item-CardItem-roles-filter-collapse')).toBeVisible(); + await expect(page.getByLabel('block-item-Markdown.Void-roles-form')).toBeVisible(); + }); }); diff --git a/packages/core/client/src/modules/dialog/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/dialog/__e2e__/schemaSettings.test.ts new file mode 100644 index 000000000..031aa16f7 --- /dev/null +++ b/packages/core/client/src/modules/dialog/__e2e__/schemaSettings.test.ts @@ -0,0 +1,48 @@ +import { NocoPage, Page, expect, oneEmptyTableBlockWithActions, test } from '@nocobase/test/client'; + +test.describe('tabs schema settings', () => { + let commonPage: NocoPage; + let commonPageUrl: string; + + test.beforeAll(async ({ mockManualDestroyPage }) => { + commonPage = await mockManualDestroyPage(oneEmptyTableBlockWithActions).waitForInit(); + commonPageUrl = await commonPage.getUrl(); + }); + + test.afterAll(async () => { + await commonPage.destroy(); + }); + + async function showSettings(page: Page) { + await page.getByTestId('drawer-Action.Container-general-Add record').getByText('Add new').hover(); + await page.getByLabel('designer-schema-settings-Tabs.TabPane-Tabs.Designer-general').hover(); + } + + test('edit', async ({ page }) => { + await page.goto(commonPageUrl); + await page.getByRole('button', { name: 'Add new' }).click(); + + await showSettings(page); + await page.getByRole('menuitem', { name: 'Edit', exact: true }).click(); + await page.mouse.move(300, 0); + await page.getByLabel('block-item-Input-general-Tab name').getByRole('textbox').click(); + await page.getByLabel('block-item-Input-general-Tab name').getByRole('textbox').fill('Add new with new name'); + await page.getByRole('button', { name: 'Select icon' }).click(); + await page.getByLabel('account-book').locator('svg').click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + await expect(page.getByText('Add new with new name')).toBeVisible(); + await expect(page.getByLabel('account-book').locator('svg')).toBeVisible(); + }); + + test('delete', async ({ page }) => { + await page.goto(commonPageUrl); + await page.getByRole('button', { name: 'Add new' }).click(); + + await showSettings(page); + await page.getByRole('menuitem', { name: 'Delete', exact: true }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + await expect(page.getByTestId('drawer-Action.Container-general-Add record').getByText('Add new')).toBeHidden(); + }); +}); diff --git a/packages/core/client/src/modules/dialog/__e2e__/templatesOfBug.ts b/packages/core/client/src/modules/dialog/__e2e__/templatesOfBug.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/core/client/src/modules/form-creation/__e2e__/dragAndDrop.test.ts b/packages/core/client/src/modules/form-creation/__e2e__/dragAndDrop.test.ts new file mode 100644 index 000000000..e844d5e41 --- /dev/null +++ b/packages/core/client/src/modules/form-creation/__e2e__/dragAndDrop.test.ts @@ -0,0 +1,30 @@ +import { expect, oneFormBlockBasedOnUsers, test } from '@nocobase/test/client'; + +test('fields', async ({ page, mockPage }) => { + await mockPage(oneFormBlockBasedOnUsers).goto(); + await page.getByLabel('schema-initializer-Grid-FormItemInitializers-users').click(); + await page.getByRole('menuitem', { name: 'Nickname' }).click(); + await page.getByRole('menuitem', { name: 'Username' }).click(); + await page.getByRole('menuitem', { name: 'Email' }).click(); + + const sourceElement = page.getByLabel('block-item-CollectionField-users-form-users.nickname'); + await sourceElement.hover(); + const source = sourceElement.getByLabel('designer-drag'); + await source.hover(); + const targetElement = page.getByLabel('block-item-CollectionField-users-form-users.username'); + await source.dragTo(targetElement); + + const targetElement2 = page.getByLabel('block-item-CollectionField-users-form-users.email'); + await source.hover(); + await source.dragTo(targetElement2); + + await sourceElement.hover(); + const nickname = await source.boundingBox(); + const username = await targetElement.boundingBox(); + const email = await targetElement2.boundingBox(); + const max = Math.max(username.y, nickname.y, email.y); + //拖拽调整排序符合预期 + expect(nickname.y).toBe(max); +}); + +test('actions', async () => {}); diff --git a/packages/core/client/src/modules/form-creation/__e2e__/lazyLoadAssociationFields.test.ts b/packages/core/client/src/modules/form-creation/__e2e__/lazyLoadAssociationFields.test.ts new file mode 100644 index 000000000..0053d3a52 --- /dev/null +++ b/packages/core/client/src/modules/form-creation/__e2e__/lazyLoadAssociationFields.test.ts @@ -0,0 +1,225 @@ +import { + expect, + oneFormWithMultiLevelAssociationFields, + oneSubformWithMultiLevelAssociationFields, + oneTableSubformWithMultiLevelAssociationFields, + oneTableSubtableWithMultiLevelAssociationFields, + test, +} from '@nocobase/test/client'; +import { T2200, T2614, T2615 } from './templatesOfBug'; + +test.describe('display association fields', () => { + test('form: should display correctly', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneFormWithMultiLevelAssociationFields).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + + // 为关系字段选中一个值 + await page + .getByLabel('block-item-CollectionField-general-form-general.m2oField0-m2oField0') + .getByLabel('Search') + .click(); + await page.getByRole('option', { name: '1', exact: true }).click(); + + // 相应的字段应显示出来对应的值 + await expect(page.getByLabel('block-item-CollectionField-general-form-general.m2oField0.id')).toHaveText('ID:1'); + await expect(page.getByLabel('block-item-CollectionField-general-form-general.m2oField0.m2oField1')).toHaveText( + 'm2oField1:1', + ); + }); + + test('subform: should display correctly', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneSubformWithMultiLevelAssociationFields).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + + // 为子表单中的关系字段选中一个值 + await page + .getByLabel('block-item-CollectionField-m2oField1-form-m2oField1.m2oField1-m2oField1') + .getByLabel('Search') + .click(); + await page.getByRole('option', { name: '1', exact: true }).click(); + + // 相应的字段应显示出来对应的值 + await expect(page.getByLabel('block-item-CollectionField-m2oField1-form-m2oField1.m2oField1.id')).toHaveText( + 'ID:1', + ); + await expect(page.getByLabel('block-item-CollectionField-m2oField1-form-m2oField1.m2oField1.m2oField2')).toHaveText( + 'm2oField2:1', + ); + }); + + test('subform: load association fields', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneTableSubformWithMultiLevelAssociationFields).waitForInit(); + const record = await mockRecord('general'); + await nocoPage.goto(); + + // 查看详情 + await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); + await expect(page.getByLabel('block-item-CollectionField-general-form-general.id-ID')).toHaveText( + `ID:${record.id}`, + ); + await expect(page.getByLabel('block-item-CollectionField-m2oField1-form-m2oField1.id-ID')).toHaveText( + `ID:${record.m2oField0.id}`, + ); + await expect(page.getByLabel('block-item-CollectionField-m2oField2-form-m2oField2.id-ID')).toHaveText( + `ID:${record.m2oField0.m2oField1.id}`, + ); + await expect(page.getByLabel('block-item-CollectionField-m2oField3-form-m2oField3.id-ID')).toHaveText( + `ID:${record.m2oField0.m2oField1.m2oField2.id}`, + ); + await expect(page.getByLabel('block-item-CollectionField-m2oField3-form-m2oField3.m2oField3-m2oField3')).toHaveText( + `m2oField3:${record.m2oField0.m2oField1.m2oField2.m2oField3.id}`, + ); + await page.getByLabel('drawer-Action.Container-general-View record-mask').click(); + + // 编辑详情 + await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); + await expect(page.getByLabel('block-item-CollectionField-general-form-general.id-ID')).toHaveText( + `ID:${record.id}`, + ); + await expect(page.getByLabel('block-item-CollectionField-m2oField1-form-m2oField1.id-ID')).toHaveText( + `ID:${record.m2oField0.id}`, + ); + await expect(page.getByLabel('block-item-CollectionField-m2oField2-form-m2oField2.id-ID')).toHaveText( + `ID:${record.m2oField0.m2oField1.id}`, + ); + await expect(page.getByLabel('block-item-CollectionField-m2oField3-form-m2oField3.id-ID')).toHaveText( + `ID:${record.m2oField0.m2oField1.m2oField2.id}`, + ); + await expect(page.getByLabel('block-item-CollectionField-m2oField3-form-m2oField3.m2oField3-m2oField3')).toHaveText( + `m2oField3:${record.m2oField0.m2oField1.m2oField2.m2oField3.id}`, + ); + }); + + test('subtable: load association fields', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneTableSubtableWithMultiLevelAssociationFields).waitForInit(); + const record = await mockRecord('general'); + await nocoPage.goto(); + + // 查看详情 + await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); + await expect(page.getByLabel('block-item-CollectionField-general-form-general.id-ID')).toHaveText( + `ID:${record.id}`, + ); + + for (let index = 0; index < record.m2mField0.length; index++) { + await expect( + page + .getByLabel('block-item-CollectionField-general-form-general.m2mField0-m2mField0') + .getByLabel('block-item-CollectionField-m2mField1-form-m2mField1.m2mField1-m2mField1') + .nth(index), + ).toHaveText(new RegExp(record.m2mField0[index].m2mField1.map((item) => item.id).join(','))); + } + + await page.getByLabel('drawer-Action.Container-general-View record-mask').click(); + + // 编辑详情 + await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); + await expect(page.getByLabel('block-item-CollectionField-general-form-general.id-ID')).toHaveText( + `ID:${record.id}`, + ); + for (let index = 0; index < record.m2mField0.length; index++) { + await expect( + page + .getByLabel('block-item-CollectionField-general-form-general.m2mField0-m2mField0') + .getByLabel('block-item-CollectionField-m2mField1-form-m2mField1.m2mField1-m2mField1') + .nth(index), + ).toHaveText(new RegExp(record.m2mField0[index].m2mField1.map((item) => item.id).join(''))); + } + }); + + // https://nocobase.height.app/T-2615 + test('BUG: should load association data', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(T2615).waitForInit(); + await mockRecord('T2615'); + await nocoPage.goto(); + + // 1. 新增表单中应该显示关系字段的数据 + await page.getByRole('button', { name: 'Add new' }).click(); + await page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o-m2o').getByLabel('Search').click(); + await page.getByRole('option', { name: '1' }).click(); + await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o.m2oOfTarget1')).toHaveText( + `m2oOfTarget1:1`, + ); + + // 关闭弹窗 + await page.getByLabel('drawer-Action.Container-T2615-Add record-mask').click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 2. 编辑表单中应该显示关系字段的数据 + await page.getByLabel('action-Action.Link-Edit record-update-T2615-table-0').click(); + await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o-m2o')).toHaveText(`m2o:1`); + await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o.m2oOfTarget1')).toHaveText( + `m2oOfTarget1:1`, + ); + + await page.getByLabel('drawer-Action.Container-T2615-Edit record-mask').click(); + + // 3. 详情中应该显示关系字段的数据 + await page.getByLabel('action-Action.Link-View record-view-T2615-table-0').click(); + await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o-m2o')).toHaveText(`m2o:1`); + await expect(page.getByLabel('block-item-CollectionField-T2615-form-T2615.m2o.m2oOfTarget1')).toHaveText( + `m2oOfTarget1:1`, + ); + }); + + // https://nocobase.height.app/T-2614 + test('BUG: should load association data in subform', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(T2614).waitForInit(); + await mockRecord('T2614'); + await nocoPage.goto(); + + // 查看详情 + await page.getByLabel('action-Action.Link-View record-view-T2614-table-0').click(); + await expect( + page.getByLabel('block-item-CollectionField-T2614Target1-form-T2614Target1.m2oOfTarget1-m2oOfTarget1'), + ).toHaveText(`m2oOfTarget1:1`); + await expect( + page.getByLabel('block-item-CollectionField-T2614Target1-form-T2614Target1.m2oOfTarget1.id'), + ).toHaveText(`ID:1`); + + // 关闭弹窗 + await page.getByLabel('drawer-Action.Container-T2614-View record-mask').click(); + + // 编辑详情 + await page.getByLabel('action-Action.Link-Edit record-update-T2614-table-0').click(); + await expect( + page.getByLabel('block-item-CollectionField-T2614Target1-form-T2614Target1.m2oOfTarget1-m2oOfTarget1'), + ).toHaveText(`m2oOfTarget1:1`); + await expect( + page.getByLabel('block-item-CollectionField-T2614Target1-form-T2614Target1.m2oOfTarget1.id'), + ).toHaveText(`ID:1`); + }); +}); + +test.describe('association fields', () => { + // fix https://nocobase.height.app/T-2200 + test('BUG: should be possible to change the value of the association field normally', async ({ page, mockPage }) => { + await mockPage(T2200).goto(); + + await page.getByLabel('action-Action.Link-Edit-update-users-table-0').click(); + await expect(page.getByLabel('Admin')).toBeVisible(); + await expect(page.getByLabel('Member')).toBeVisible(); + await expect(page.getByLabel('Root')).toBeVisible(); + + await page.getByTestId('select-object-multiple').click(); + await page.getByRole('option', { name: 'Member' }).click(); + // 再次点击,关闭下拉框。 + await page.getByTestId('select-object-multiple').click(); + + await expect(page.getByLabel('Admin')).toBeVisible(); + await expect(page.getByLabel('Member')).toBeHidden(); + await expect(page.getByLabel('Root')).toBeVisible(); + + await page.getByLabel('schema-initializer-Grid-FormItemInitializers-users').hover(); + await page.getByRole('menuitem', { name: 'Nickname' }).click(); + + await page.mouse.move(200, 0); + + await page.waitForTimeout(200); + await expect(page.getByLabel('Admin')).toBeVisible(); + await expect(page.getByLabel('Member')).toBeHidden(); + await expect(page.getByLabel('Root')).toBeVisible(); + }); +}); diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/variablesLazyLoad/defaultValue.test.ts b/packages/core/client/src/modules/form-creation/__e2e__/lazyLoadVariables.test.ts similarity index 65% rename from packages/core/client/src/__tests__/e2e/schemaSettings/variablesLazyLoad/defaultValue.test.ts rename to packages/core/client/src/modules/form-creation/__e2e__/lazyLoadVariables.test.ts index 2c693b1c8..ad7bc3b31 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/variablesLazyLoad/defaultValue.test.ts +++ b/packages/core/client/src/modules/form-creation/__e2e__/lazyLoadVariables.test.ts @@ -1,9 +1,8 @@ -import { expect, test } from '@nocobase/test/client'; -import { testingLazyLoadingOfAssociationFieldsForTheCurrentRecord } from './templatesOfPage'; +import { expect, formBlockDefaultValueTemplate, test } from '@nocobase/test/client'; -test.describe('default value: lazy load value of variables', () => { +test.describe('variables with default value', () => { test('current form', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(testingLazyLoadingOfAssociationFieldsForTheCurrentRecord).waitForInit(); + const nocoPage = await mockPage(formBlockDefaultValueTemplate).waitForInit(); await mockRecord('general'); await nocoPage.goto(); diff --git a/packages/core/client/src/__tests__/e2e/schemaInitializer/formBlock.test.ts b/packages/core/client/src/modules/form-creation/__e2e__/schemaInitializer.test.ts similarity index 70% rename from packages/core/client/src/__tests__/e2e/schemaInitializer/formBlock.test.ts rename to packages/core/client/src/modules/form-creation/__e2e__/schemaInitializer.test.ts index fceccbf37..86ceff53a 100644 --- a/packages/core/client/src/__tests__/e2e/schemaInitializer/formBlock.test.ts +++ b/packages/core/client/src/modules/form-creation/__e2e__/schemaInitializer.test.ts @@ -1,12 +1,23 @@ -import { expect, oneEmptyForm, test } from '@nocobase/test/client'; +import { createBlockInPage, expect, oneEmptyForm, test } from '@nocobase/test/client'; -test.describe('Form', () => { - test('add fields', async ({ page, mockPage }) => { +test.describe('where creation form block can be added', () => { + test('page', async ({ page, mockPage }) => { + await mockPage().goto(); + + await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); + await createBlockInPage(page, 'Form'); + await expect(page.getByLabel('block-item-CardItem-users-form')).toBeVisible(); + }); +}); + +test.describe('configure fields', () => { + test('display collection fields & display association fields & add text', async ({ page, mockPage }) => { await mockPage(oneEmptyForm).goto(); + // collection fields await page.getByLabel('schema-initializer-Grid-FormItemInitializers-general').hover(); - await page.getByRole('menuitem', { name: 'ID' }).click(); - await expect(page.getByRole('menuitem', { name: 'ID' }).getByRole('switch')).toBeChecked(); + await page.getByRole('menuitem', { name: 'ID', exact: true }).click(); + await expect(page.getByRole('menuitem', { name: 'ID', exact: true }).getByRole('switch')).toBeChecked(); // add association fields await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); @@ -21,8 +32,8 @@ test.describe('Form', () => { // delete fields await page.getByLabel('schema-initializer-Grid-FormItemInitializers-general').hover(); - await page.getByRole('menuitem', { name: 'ID' }).click(); - await expect(page.getByRole('menuitem', { name: 'ID' }).getByRole('switch')).not.toBeChecked(); + await page.getByRole('menuitem', { name: 'ID', exact: true }).click(); + await expect(page.getByRole('menuitem', { name: 'ID', exact: true }).getByRole('switch')).not.toBeChecked(); await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); await page.getByRole('menuitem', { name: 'Nickname' }).click(); @@ -42,9 +53,11 @@ test.describe('Form', () => { await expect(page.getByLabel('block-item-Markdown.Void-general-form')).toBeVisible(); }); - test.pgOnly('add inherit fields', async ({ page, mockPage }) => {}); + test.pgOnly('display inherit fields', async ({ page, mockPage }) => {}); +}); - test('add action buttons', async ({ page, mockPage }) => { +test.describe('configure actions', () => { + test('submit', async ({ page, mockPage }) => { await mockPage(oneEmptyForm).goto(); await page.getByLabel('schema-initializer-ActionBar-FormActionInitializers-general').hover(); @@ -65,7 +78,7 @@ test.describe('Form', () => { await expect(page.getByRole('button', { name: 'Submit' })).not.toBeVisible(); }); - test('add custom action buttons', async ({ page, mockPage }) => { + test('customize: save record', async ({ page, mockPage }) => { await mockPage(oneEmptyForm).goto(); await page.getByLabel('schema-initializer-ActionBar-FormActionInitializers-general').hover(); diff --git a/packages/core/client/src/modules/form-creation/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/form-creation/__e2e__/schemaSettings.test.ts new file mode 100644 index 000000000..ba2365b06 --- /dev/null +++ b/packages/core/client/src/modules/form-creation/__e2e__/schemaSettings.test.ts @@ -0,0 +1,1181 @@ +import { + Page, + expect, + expectSettingsMenu, + oneEmptyForm, + oneEmptyFormWithActions, + oneTableBlockWithActionsAndFormBlocks, + oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, + oneTableBlockWithAddNewAndViewAndEditAndBasicFields, + test, +} from '@nocobase/test/client'; +import { T2165, T2174 } from './templatesOfBug'; + +const clickOption = async (page: Page, optionName: string) => { + await page.getByLabel('block-item-CardItem-general-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); + await page.getByRole('menuitem', { name: optionName }).click(); +}; + +test.describe('creation form block schema settings', () => { + test('edit block title', async ({ page, mockPage }) => { + await mockPage(oneTableBlockWithActionsAndFormBlocks).goto(); + await page.getByRole('button', { name: 'Add new' }).click(); + + // 打开编辑弹窗 + await clickOption(page, 'Edit block title'); + await page.getByRole('textbox').click(); + await page.getByRole('textbox').fill('Block title 123'); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + const runExpect = async () => { + // 设置成功后,显示在区块顶部 + await expect( + page.getByLabel('block-item-CardItem-general-form').getByText('Block title 123', { exact: true }), + ).toBeVisible(); + + // 再次打开编辑弹窗时,显示的是上次设置的值 + await clickOption(page, 'Edit block title'); + await expect(page.getByRole('textbox')).toHaveValue('Block title 123'); + }; + + await runExpect(); + + // 刷新页面后,显示的应该依然是上次设置的值 + await page.reload(); + await page.getByRole('button', { name: 'Add new' }).click(); + await runExpect(); + }); + + test.describe('linkage rules', () => { + test('basic usage', async ({ page, mockPage }) => { + const openLinkageRules = async () => { + await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); + await page.getByRole('menuitem', { name: 'Linkage rules' }).click(); + }; + + await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).goto(); + + await page.getByRole('button', { name: 'Add new' }).click(); + + // 设置第一组规则 -------------------------------------------------------------------------- + // 打开联动规则弹窗 + await page.getByLabel('block-item-CardItem-general-form').hover(); + await openLinkageRules(); + + // 增加一组规则 + // 条件:singleLineText 字段的值包含 123 时 + await page.getByRole('button', { name: 'plus Add linkage rule' }).click(); + await page.getByText('Add condition', { exact: true }).click(); + await page.getByTestId('select-filter-field').click(); + await page.getByRole('menuitemcheckbox', { name: 'singleLineText' }).click(); + await page.getByLabel('Linkage rules').locator('input[type="text"]').click(); + await page.getByLabel('Linkage rules').locator('input[type="text"]').fill('123'); + + // action:禁用 longText 字段 + await page.getByText('Add property').click(); + await page.getByTestId('select-linkage-property-field').click(); + await page.getByRole('tree').getByText('longText').click(); + await page.getByTestId('select-linkage-action-field').click(); + await page.getByRole('option', { name: 'Disabled' }).click(); + + // 保存规则 + await page.getByRole('button', { name: 'OK' }).click(); + + // 验证第一组规则 -------------------------------------------------------------------------- + // 初始状态下,longText 字段是可编辑的 + await expect( + page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), + ).toBeEditable(); + + // 输入 123,longText 字段被禁用 + await page + .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') + .getByRole('textbox') + .click(); + await page + .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') + .getByRole('textbox') + .fill('123'); + await expect( + page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), + ).toBeDisabled(); + + // 清空输入,longText 字段应该恢复成可编辑状态 + await page + .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') + .getByRole('textbox') + .clear(); + await expect( + page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), + ).toBeEditable(); + + // 修改第一组规则,使其条件中包含一个变量 -------------------------------------------------------------------------- + // 当 singleLineText 字段的值包含 longText 字段的值时,禁用 longText 字段 + await openLinkageRules(); + await page.getByLabel('variable-button').click(); + await page.getByRole('menuitemcheckbox', { name: 'Current form' }).click(); + await page.getByRole('menuitemcheckbox', { name: 'longText' }).click(); + await page.getByRole('button', { name: 'OK' }).click(); + + // singleLineText 字段和 longText 字段都为空的情况下,longText 字段应该是可编辑的 + await expect( + page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), + ).toBeEditable(); + + // 先为 longText 字段填入 123,然后为 singleLineText 字段填入 1,longText 字段应该是可编辑的 + await page + .getByLabel('block-item-CollectionField-general-form-general.longText-longText') + .getByRole('textbox') + .fill('123'); + await page + .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') + .getByRole('textbox') + .fill('1'); + await expect( + page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), + ).toBeEditable(); + + // 改变变量的值:即将 longText 字段的值改为 1,longText 字段应该是禁用的 + await page + .getByLabel('block-item-CollectionField-general-form-general.longText-longText') + .getByRole('textbox') + .click(); + await page.keyboard.press('Backspace'); + await page.keyboard.press('Backspace'); + await expect( + page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), + ).toBeDisabled(); + + // 添加第二组规则 ------------------------------------------------------------------------------------------- + await openLinkageRules(); + + // 增加一条规则:当 number 字段的值等于 123 时 + await page.getByRole('button', { name: 'plus Add linkage rule' }).click(); + await page.locator('.ant-collapse-header').nth(1).getByRole('img', { name: 'right' }).click(); + + await page.getByLabel('Linkage rules').getByRole('tabpanel').getByText('Add condition', { exact: true }).click(); + await page.getByRole('button', { name: 'Search Select field' }).click(); + await page.getByRole('menuitemcheckbox', { name: 'number' }).click(); + await page.getByLabel('Linkage rules').getByRole('spinbutton').click(); + await page.getByLabel('Linkage rules').getByRole('spinbutton').fill('123'); + + // action:使 longText 字段可编辑 + await page.getByLabel('Linkage rules').getByRole('tabpanel').getByText('Add property').click(); + await page.getByRole('button', { name: 'Search Select field' }).click(); + await page.getByRole('tree').getByText('longText').click(); + await page.getByRole('button', { name: 'Search action' }).click(); + await page.getByRole('option', { name: 'Editable' }).click(); + + // action: 为 longText 字段赋上常量值 + await page.getByLabel('Linkage rules').getByRole('tabpanel').getByText('Add property').click(); + await page.getByRole('button', { name: 'Search Select field' }).click(); + await page.getByRole('tree').getByText('longText').click(); + await page.getByRole('button', { name: 'Search action' }).click(); + await page.getByRole('option', { name: 'Value', exact: true }).click(); + await page.getByLabel('dynamic-component-linkage-rules').getByRole('textbox').fill('456'); + + // action: 为 integer 字段附上一个表达式,使其值等于 number 字段的值 + await page.getByLabel('Linkage rules').getByRole('tabpanel').getByText('Add property').click(); + + await page.getByRole('button', { name: 'Search Select field' }).click(); + await page.getByRole('tree').getByText('integer').click(); + await page.getByRole('button', { name: 'Search action' }).click(); + await page.getByRole('option', { name: 'Value', exact: true }).click(); + await page.getByTestId('select-linkage-value-type').nth(1).click(); + await page.getByText('Expression').click(); + + await page.getByText('xSelect a variable').click(); + await page.getByRole('menuitemcheckbox', { name: 'Current form right' }).click(); + await page.getByRole('menuitemcheckbox', { name: 'number' }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 验证第二组规则 ------------------------------------------------------------------------------------------- + // 此时 longText 字段是禁用状态,当满足第二组规则时,longText 字段应该是可编辑的 + await page + .getByLabel('block-item-CollectionField-general-form-general.number-number') + .getByRole('spinbutton') + .fill('123'); + await expect( + page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), + ).toBeEditable(); + + // 并且 longText 字段的值应该是 456 + await expect( + page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), + ).toHaveValue('456'); + + // integer 字段的值应该等于 number 字段的值 + await expect( + page.getByLabel('block-item-CollectionField-general-form-general.integer-integer').getByRole('spinbutton'), + ).toHaveValue('123'); + }); + + // fix https://nocobase.height.app/T-2165 + test('BUG: variable labels should be displayed normally', async ({ page, mockPage }) => { + await mockPage(T2165).goto(); + + await page.getByLabel('block-item-CardItem-users-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-users').hover(); + await page.getByRole('menuitem', { name: 'Linkage rules' }).click(); + + await expect(page.getByText('Current form / Nickname')).toBeVisible(); + await expect(page.getByText('Current form / Phone')).toBeVisible(); + }); + }); + + test('convert reference to duplicate & Save as block template', async ({ page, mockPage }) => { + await mockPage(oneTableBlockWithActionsAndFormBlocks).goto(); + await page.getByRole('button', { name: 'Add new' }).click(); + + // 打开编辑弹窗 + await clickOption(page, 'Save as block template'); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 设置成功后,不再显示 Save as block template 选项,而是显示 Convert reference to duplicate 选项 + await page.getByLabel('block-item-CardItem-general-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); + await expect(page.getByRole('menuitem', { name: 'Save as block template' })).not.toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Convert reference to duplicate' })).toBeVisible(); + + // 刷新页面 + await page.reload(); + await page.getByRole('button', { name: 'Add new' }).click(); + await page.getByLabel('block-item-CardItem-general-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); + await expect(page.getByRole('menuitem', { name: 'Save as block template' })).not.toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Convert reference to duplicate' })).toBeVisible(); + + // Convert reference to duplicate + await clickOption(page, 'Convert reference to duplicate'); + await expect(page.getByRole('menuitem', { name: 'Save as block template' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Convert reference to duplicate' })).not.toBeVisible(); + + // 刷新页面 + await page.reload(); + await page.getByRole('button', { name: 'Add new' }).click(); + await page.getByLabel('block-item-CardItem-general-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); + await expect(page.getByRole('menuitem', { name: 'Save as block template' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Convert reference to duplicate' })).not.toBeVisible(); + }); + + test('delete', async ({ page, mockPage }) => { + await mockPage(oneTableBlockWithActionsAndFormBlocks).goto(); + + await page.getByRole('button', { name: 'Add new' }).click(); + await page.getByLabel('block-item-CardItem-general-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); + + // 打开编辑弹窗 + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 设置成功后,显示在区块顶部 + await expect(page.getByLabel('block-item-CardItem-general-form')).not.toBeVisible(); + + // 刷新页面后,区块依然是被删除状态 + await page.reload(); + await page.getByRole('button', { name: 'Add new' }).click(); + await expect(page.getByLabel('block-item-CardItem-general-form')).not.toBeVisible(); + }); + + test('save as block Template', async ({ page, mockPage }) => { + await mockPage(oneEmptyForm).goto(); + + // 先保存为模板 ------------------------------------------------------------------------ + await showSettingsMenu(page); + await page.getByRole('menuitem', { name: 'Save as block template' }).click(); + // 输入框中应该有一个默认的名字 + await expect(page.getByRole('dialog').getByRole('textbox')).toHaveValue('General_Form'); + // 设置一个新的名字 + await page.getByRole('dialog').getByRole('textbox').click(); + await page.getByRole('dialog').getByRole('textbox').fill('new_form_template'); + await page.getByRole('dialog').getByRole('button', { name: 'OK', exact: true }).click(); + + // 区块左上角应该显示一个文案 + await page.getByLabel('block-item-CardItem-general-form').hover(); + await expect( + page + .getByLabel('block-item-CardItem-general-form') + .getByText('Reference template: new_form_template (Fields only)'), + ).toBeVisible(); + + // settings 菜单中 Save as block template 应该变为 Convert reference to duplicate + await showSettingsMenu(page); + await expect(page.getByRole('menuitem', { name: 'Save as block template' })).toBeHidden(); + await expect(page.getByRole('menuitem', { name: 'Convert reference to duplicate' })).toBeVisible(); + + // 创建区块的时候,可以选择刚才保存的模板 -------------------------------------------------- + await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); + await page.getByRole('menuitem', { name: 'form Form right' }).first().hover(); + await page.getByRole('menuitem', { name: 'General right' }).hover(); + + // Duplicate template + await page.getByRole('menuitem', { name: 'Duplicate template right' }).hover(); + await page.getByRole('menuitem', { name: 'new_form_template (Fields only)' }).click(); + + // Reference template + await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); + await page.getByRole('menuitem', { name: 'form Form right' }).first().hover(); + await page.getByRole('menuitem', { name: 'General right' }).hover(); + await page.getByRole('menuitem', { name: 'General right' }).click(); + await page.getByRole('menuitem', { name: 'Reference template right' }).click(); + await page.getByRole('menuitem', { name: 'new_form_template (Fields only)' }).click(); + + // 页面中的区块应该成功被创建 + await expect(page.getByLabel('block-item-CardItem-general-form')).toHaveCount(3); + + // 保存为模板之后,应该在 ui-schema-storage 页面显示出来 ----------------------------------------- + await page.goto('/admin/settings/ui-schema-storage'); + await expect(page.getByRole('row', { name: 'new_form_template' })).toBeVisible(); + + async function showSettingsMenu(page) { + await page.getByLabel('block-item-CardItem-general-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); + } + }); + + test.describe('form data templates', () => { + test('basic usage', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); + const records = await mockRecords('general', 3); + await nocoPage.goto(); + + const record = records.find((item) => item.id === 2); + + const openDialog = async () => { + await page.getByLabel('block-item-CardItem-general-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); + await page.getByRole('menuitem', { name: 'Form data templates' }).click(); + }; + + await page.getByRole('button', { name: 'Add new' }).click(); + await openDialog(); + await page.getByRole('button', { name: 'plus Add template' }).click(); + + // 非继承表是不需要显示 Collection 选项的 + await expect(page.getByText('Collection:')).toBeHidden(); + + // 添加一个数据范围,条件是:ID = 2 + await page.getByText('Add condition', { exact: true }).click(); + await page.getByTestId('select-filter-field').getByLabel('Search').click(); + await page.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); + await page.getByLabel('Form data templates').getByRole('spinbutton').click(); + await page.getByLabel('Form data templates').getByRole('spinbutton').fill('2'); + + // 选择 ID 作为 title field + await page.getByTestId('select-single').click(); + await page.getByRole('option', { name: 'ID', exact: true }).click(); + + // 仅选中一个字段 + await page.getByRole('button', { name: 'singleLineText (Duplicate)' }).click(); + + // 保存 + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 保存成功后应该显示 Data template 选项 + await expect(page.getByText('Data template:')).toBeVisible(); + + // 选择一个模板 + await page.getByTestId('select-form-data-template').click(); + await page.getByRole('option', { name: 'Template name 1' }).click(); + await page.getByTestId('select-object-undefined').click(); + + // 因为添加了数据范围,所以只显示一个选项 + await expect(page.getByRole('option')).toHaveCount(1); + + // 选中数据 + await page.getByRole('option', { name: '2' }).click(); + + await expect( + page + .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') + .getByRole('textbox'), + ).toHaveValue(record.singleLineText); + + // 其它未选中的字段的数据应该是空的 + await expect( + page.getByLabel('block-item-CollectionField-general-form-general.integer-integer').getByRole('spinbutton'), + ).toBeEmpty(); + + // 同步表单字段 + await openDialog(); + await page.getByLabel('action-Action.Link-Sync from form fields-general').click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 重新选择一下数据,字段值才会被填充 + // TODO: 保存后,数据应该直接被填充上 + await page.getByLabel('icon-close-select').click(); + await page.getByTestId('select-object-undefined').getByLabel('Search').click(); + await page.getByRole('option', { name: '2' }).click(); + + await expect( + page.getByLabel('block-item-CollectionField-general-form-general.email-email').getByRole('textbox'), + ).toHaveValue(record.email); + await expect( + page.getByLabel('block-item-CollectionField-general-form-general.integer-integer').getByRole('spinbutton'), + ).toHaveValue(String(record.integer)); + await expect( + page.getByLabel('block-item-CollectionField-general-form-general.number-number').getByRole('spinbutton'), + ).toHaveValue(String(record.number)); + + // 隐藏模板选项 + await openDialog(); + await page.getByLabel('Display data template selector').click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + await expect(page.getByText('Data template:')).toBeHidden(); + }); + }); + + test.describe('set default value', () => { + test('basic fields', async ({ page, mockPage }) => { + await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).goto(); + + const openDialog = async (fieldName: string) => { + await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) + .hover(); + await page.getByRole('menuitem', { name: 'Set default value', exact: true }).click(); + }; + + await page.getByRole('button', { name: 'Add new' }).click(); + await openDialog('singleLineText'); + await page.getByLabel('Set default value').getByRole('textbox').click(); + await page.getByLabel('Set default value').getByRole('textbox').fill('test default value'); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 关闭弹窗在打开,应该显示默认值 + await page.getByLabel('drawer-Action.Container-general-Add record-mask').click(); + await page.getByRole('button', { name: 'Add new' }).click(); + await expect( + page + .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') + .getByRole('textbox'), + ).toHaveValue('test default value'); + + // 为 longText 设置一个变量默认值: {{ currentForm.singleLineText }} + await openDialog('longText'); + await page.getByLabel('variable-button').click(); + await page.getByRole('menuitemcheckbox', { name: 'Current form' }).click(); + await page.getByRole('menuitemcheckbox', { name: 'singleLineText' }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + await page.getByLabel('drawer-Action.Container-general-Add record-mask').click(); + await page.getByRole('button', { name: 'Add new' }).click(); + // 值应该和 singleLineText 一致 + await expect( + page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), + ).toHaveValue('test default value'); + + // 更改变量的值,longText 的值也应该跟着变化 + await page + .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') + .getByRole('textbox') + .fill('new value'); + await expect( + page.getByLabel('block-item-CollectionField-general-form-general.longText-longText').getByRole('textbox'), + ).toHaveValue('new value'); + }); + + test('subform: basic fields', async ({ page, mockPage }) => { + await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).goto(); + + await page.getByRole('button', { name: 'Add new' }).click(); + + // 先切换为子表单 + await page.getByLabel('block-item-CollectionField-general-form-general.manyToOne-manyToOne').hover(); + await page + .getByLabel('designer-schema-settings-CollectionField-FormItem.Designer-general-general.manyToOne') + .hover(); + await page.getByRole('menuitem', { name: 'Field component' }).click(); + await page.getByRole('option', { name: 'Sub-form', exact: true }).click(); + + // 关闭下拉菜单 + await page.getByLabel('block-item-CollectionField-general-form-general.manyToOne-manyToOne').hover(); + await page + .getByLabel('designer-schema-settings-CollectionField-FormItem.Designer-general-general.manyToOne') + .hover(); + await page.mouse.move(100, 0); + + await page.getByLabel('schema-initializer-Grid-FormItemInitializers-users').hover(); + await page.getByRole('menuitem', { name: 'Nickname' }).click(); + await page.getByRole('menuitem', { name: 'Username' }).click(); + + // 子表单状态下,没有默认值选项 + await page.getByLabel('block-item-CollectionField-general-form-general.manyToOne-manyToOne').hover(); + await expect(page.getByRole('menuitem', { name: 'Set default value' })).not.toBeVisible(); + + // 测试子表单字段默认值 ------------------------------------------------------------------------------------------ + await page.getByLabel(`block-item-CollectionField-users-form-users.nickname-Nickname`).hover(); + await page.getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-users-users.Nickname`).hover(); + await page.getByRole('menuitem', { name: 'Set default value', exact: true }).click(); + await page.getByLabel('Set default value').getByRole('textbox').click(); + await page.getByLabel('Set default value').getByRole('textbox').fill('test default value'); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 关闭弹窗在打开,应该显示默认值 + await page.getByLabel('drawer-Action.Container-general-Add record-mask').click(); + await page.getByRole('button', { name: 'Add new' }).click(); + await expect( + page.getByLabel('block-item-CollectionField-users-form-users.nickname-Nickname').getByRole('textbox'), + ).toHaveValue('test default value'); + + // 为 username 设置一个变量默认值: {{ currentObject.nickname }} + await page.getByLabel(`block-item-CollectionField-users-form-users.username-Username`).hover(); + await page.getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-users-users.Username`).hover(); + await page.getByRole('menuitem', { name: 'Set default value', exact: true }).click(); + await page.getByLabel('variable-button').click(); + await page.getByRole('menuitemcheckbox', { name: 'Current object' }).click(); + await page.getByRole('menuitemcheckbox', { name: 'Nickname' }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + await page.getByLabel('drawer-Action.Container-general-Add record-mask').click(); + await page.getByRole('button', { name: 'Add new' }).click(); + // 值应该和 Nickname 一致 + await expect( + page.getByLabel('block-item-CollectionField-users-form-users.username-Username').getByRole('textbox'), + ).toHaveValue('test default value'); + + // 更改变量的值,longText 的值也应该跟着变化 + await page + .getByLabel('block-item-CollectionField-users-form-users.nickname-Nickname') + .getByRole('textbox') + .fill('new value'); + await expect( + page.getByLabel('block-item-CollectionField-users-form-users.username-Username').getByRole('textbox'), + ).toHaveValue('new value'); + }); + + test('subtable: basic fields', async ({ page, mockPage }) => { + await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).goto(); + + await page.getByRole('button', { name: 'Add new' }).click(); + + // 先切换为子表格 + await page.getByLabel('block-item-CollectionField-general-form-general.oneToMany-oneToMany').hover(); + await page + .getByLabel('designer-schema-settings-CollectionField-FormItem.Designer-general-general.oneToMany') + .hover(); + await page.getByRole('menuitem', { name: 'Field component' }).click(); + await page.getByRole('option', { name: 'Sub-table' }).click(); + + // 关闭下拉菜单 + await page.getByLabel('block-item-CollectionField-general-form-general.oneToMany-oneToMany').hover(); + await page + .getByLabel('designer-schema-settings-CollectionField-FormItem.Designer-general-general.oneToMany') + .hover(); + await page.mouse.move(100, 0); + + await page.getByLabel('schema-initializer-AssociationField.SubTable-TableColumnInitializers-users').hover(); + await page.getByRole('menuitem', { name: 'Nickname' }).click(); + await page.getByRole('menuitem', { name: 'Username' }).click(); + + // 子表格状态下,没有默认值选项 + await page.getByLabel('block-item-CollectionField-general-form-general.oneToMany-oneToMany').hover(); + await expect(page.getByRole('menuitem', { name: 'Set default value' })).not.toBeVisible(); + + // 测试子表格字段默认值 ------------------------------------------------------------------------------------------ + await page.getByRole('button', { name: 'Nickname', exact: true }).hover(); + await page + .getByRole('button', { name: 'designer-schema-settings-TableV2.Column-TableV2.Column.Designer-users' }) + .hover(); + await page.getByRole('menuitem', { name: 'Set default value', exact: true }).click(); + await page.getByLabel('Set default value').getByRole('textbox').click(); + await page.getByLabel('Set default value').getByRole('textbox').fill('test default value'); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 当新增一行时,应该显示默认值 + await page.getByRole('button', { name: 'plus' }).click(); + await expect( + page + .getByRole('cell', { name: 'block-item-CollectionField-users-form-users.nickname-Nickname' }) + .getByRole('textbox'), + ).toHaveValue('test default value'); + + // 为 username 设置一个变量默认值: {{ currentObject.nickname }} + await page.getByRole('button', { name: 'Username', exact: true }).hover(); + await page + .getByRole('button', { name: 'designer-schema-settings-TableV2.Column-TableV2.Column.Designer-users' }) + .hover(); + await page.getByRole('menuitem', { name: 'Set default value', exact: true }).click(); + await page.mouse.move(300, 0); + await page.getByLabel('variable-button').click(); + await page.getByRole('menuitemcheckbox', { name: 'Current object' }).click(); + await page.getByRole('menuitemcheckbox', { name: 'Nickname' }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 值应该和 Nickname 一致 + await expect( + page + .getByRole('cell', { name: 'block-item-CollectionField-users-form-users.username-Username' }) + .getByRole('textbox'), + ).toHaveValue('test default value'); + + // 更改变量的值,longText 的值也应该跟着变化 + await page + .getByRole('cell', { name: 'block-item-CollectionField-users-form-users.username-Username' }) + .getByRole('textbox') + .fill('new value'); + await expect( + page + .getByRole('cell', { name: 'block-item-CollectionField-users-form-users.username-Username' }) + .getByRole('textbox'), + ).toHaveValue('new value'); + }); + + // fix https://nocobase.height.app/T-2174 + test('BUG: should show default value option', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(T2174).waitForInit(); + await mockRecord('test2174'); + await nocoPage.goto(); + + await page.getByLabel('action-Action.Link-View details-view-test2174-table-0').click(); + await page.getByLabel('block-item-CollectionField-test2174-form-test2174.singleSelect-Single select').hover(); + await page + .getByLabel('designer-schema-settings-CollectionField-FormItem.Designer-test2174-test2174.singleSelect') + .hover(); + + await expect(page.getByRole('menuitem', { name: 'Set default value' })).toBeVisible(); + }); + }); + + test('save block template & using block template', async ({ page, mockPage }) => { + await mockPage({ + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + bg76x03o9f2: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + gdj0ceke8ac: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + ftx8xnesvev: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + tu0dxua38tw: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + 'x-acl-action': 'users:create', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + resource: 'users', + collection: 'users', + }, + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-component-props': {}, + properties: { + avv3vpk0nlv: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + properties: { + gnw25oyqe56: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + rdbe3gg1qv5: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + nickname: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'users.nickname', + 'x-component-props': {}, + 'x-uid': 'okrljzl6j7s', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '1zjdduck27k', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'l0cyy3gzz86', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '4wrgwkyyf81', + 'x-async': false, + 'x-index': 1, + }, + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'FormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + 'x-uid': '2apymtcq35d', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '1tnmbrvb9ad', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'vo1pyqmoe28', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'z59pkpc8uhq', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'vsfafj9qcx9', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'sdj6iw5b0gs', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'uz4dyz41vt1', + 'x-async': true, + 'x-index': 1, + }, + }).goto(); + await page.getByLabel('block-item-CardItem-users-form').hover(); + await page + .getByLabel('block-item-CardItem-users-form') + .getByLabel('designer-schema-settings-CardItem-FormV2.Designer-users') + .hover(); + await page.getByRole('menuitem', { name: 'Save as block template' }).click(); + await page.getByLabel('Save as template').getByRole('textbox').fill('Users_Form'); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + await page.getByLabel('block-item-CardItem-users-form').hover(); + + //保存模板后当前区块为引用区块 + const titleTag = await page.getByLabel('block-item-CardItem-users-form').locator('.title-tag').nth(1).innerText(); + expect(titleTag).toContain('Reference template'); + + // using block template + await mockPage({ + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + mwxaaxb9y9v: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + ibb0kjq3kyl: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + p39cigcjpij: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + '237ec1x538e': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'users:list', + 'x-decorator-props': { + collection: 'users', + resource: 'users', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + properties: { + lmeom75gry5: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-action': 'create', + 'x-acl-action': 'create', + title: "{{t('Add new')}}", + 'x-designer': 'Action.Designer', + 'x-component': 'Action', + 'x-decorator': 'ACLActionProvider', + 'x-component-props': { + openMode: 'drawer', + type: 'primary', + component: 'CreateRecordAction', + icon: 'PlusOutlined', + }, + 'x-align': 'right', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Add record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializersForCreateFormBlock', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Add new")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'CreateFormBlockInitializers', + 'x-uid': 'w224zhqyair', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'lll44vre1t6', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'c025dgp5tyk', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'og2z02rfxhx', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'vn9wxzx83y3', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '7s3fcxfjc0y', + 'x-async': false, + 'x-index': 1, + }, + zqdtqsjqgc1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Actions") }}', + 'x-action-column': 'actions', + 'x-decorator': 'TableV2.Column.ActionBar', + 'x-component': 'TableV2.Column', + 'x-designer': 'TableV2.ActionColumnDesigner', + 'x-initializer': 'TableActionColumnInitializers', + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + properties: { + kdcs236lihl: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Edit") }}', + 'x-action': 'update', + 'x-designer': 'Action.Designer', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + icon: 'EditOutlined', + }, + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Edit record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializers', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Edit")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + 'x-uid': 's49vs6v3qs0', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '33qff1grgqn', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '3z1hbrs3bre', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '09vwzm2det2', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'bgdfnken9ua', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'tn98i5lgydw', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ubmt489cxzn', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 't6eg1ye4wf4', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'h4yvac2sy2g', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '3xei2593vgu', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'm67du7wrojo', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '7aige8a5w3q', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'qpbgsjdsgaq', + 'x-async': true, + 'x-index': 1, + }, + }).goto(); + await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); + //使用复制模板 + await page.getByRole('menuitem', { name: 'form Form' }).first().hover(); + await page.getByRole('menuitem', { name: 'Users' }).hover(); + await page.getByRole('menuitem', { name: 'Duplicate template' }).hover(); + await page.getByRole('menuitem', { name: 'Users_Form (Fields only)' }).click(); + await expect(page.getByLabel('block-item-CardItem-users-form')).toBeVisible(); + + //在新建操作中使用引用模板 + await page.getByLabel('action-Action-Add new-create-users-table').click(); + await page.getByLabel('schema-initializer-Grid-CreateFormBlockInitializers-users').click(); + await page.getByRole('menuitem', { name: 'form Form' }).hover(); + await page.getByRole('menuitem', { name: 'Reference template' }).hover(); + await page.getByRole('menuitem', { name: 'Users_Form (Fields only)' }).click(); + await page.getByLabel('schema-initializer-Grid-CreateFormBlockInitializers-users').hover(); + await expect(page.locator('.ant-drawer').getByLabel('block-item-CardItem-users-form')).toBeVisible(); + await page.locator('.ant-drawer-mask').click(); + + //在编辑操作中使用引用模板 + await page.getByLabel('action-Action.Link-Edit-update-users-table-0').click(); + await page.getByLabel('schema-initializer-Grid-RecordBlockInitializers-users').click(); + await page.getByRole('menuitem', { name: 'form Form' }).hover(); + await page.getByRole('menuitem', { name: 'Reference template' }).hover(); + await page.getByRole('menuitem', { name: 'Users_Form (Fields only)' }).click(); + await page.getByLabel('schema-initializer-Grid-RecordBlockInitializers-users').hover(); + + //修改引用模板 + await page.locator('.ant-drawer').getByLabel('schema-initializer-Grid-FormItemInitializers-users').click(); + await page.getByRole('menuitem', { name: 'Phone' }).click(); + await page.locator('.ant-drawer-mask').click(); + //复制模板不同步,引用模板同步 + await expect( + page.getByLabel('block-item-CardItem-users-form').getByLabel('block-item-CollectionField-users-form-users.phone'), + ).not.toBeVisible(); + await page.getByLabel('block-item-CardItem-users-table').getByLabel('action-Action-Add').click(); + await expect(page.getByLabel('block-item-CollectionField-users-form-users.phone')).toBeVisible(); + await page.locator('.ant-drawer-mask').click(); + + //删除模板 + await page.getByTestId('plugin-settings-button').click(); + await page.getByLabel('ui-schema-storage').click(); + await page.getByRole('menuitem', { name: 'layout Block templates' }).click(); + await page.getByLabel('action-Action.Link-Delete-destroy-uiSchemaTemplates-table-Users_Form').click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + }); +}); + +test.describe('actions schema settings', () => { + test('submit', async ({ page, mockPage }) => { + await mockPage(oneEmptyFormWithActions).goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByRole('button', { name: 'Submit' }).hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action-Action.Designer-users' }).hover(); + }, + supportedOptions: ['Edit button', 'Linkage rules', 'Bind workflows', 'Delete'], + }); + }); + + test('customize: save record', async ({ page, mockPage }) => { + await mockPage(oneEmptyFormWithActions).goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByRole('button', { name: 'Save record' }).hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action-Action.Designer-users' }).hover(); + }, + supportedOptions: [ + 'Edit button', + 'Linkage rules', + 'Assign field values', + 'Skip required validation', + 'After successful submission', + 'Bind workflows', + 'Delete', + ], + }); + }); +}); diff --git a/packages/core/client/src/modules/form-creation/__e2e__/templatesOfBug.ts b/packages/core/client/src/modules/form-creation/__e2e__/templatesOfBug.ts new file mode 100644 index 000000000..9e2ee5df1 --- /dev/null +++ b/packages/core/client/src/modules/form-creation/__e2e__/templatesOfBug.ts @@ -0,0 +1,2921 @@ +import { PageConfig } from '@nocobase/test/client'; + +export const T2165 = { + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + '4nd32b2msmb': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + psn8ekavlq6: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '78sh75l4aye': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + x1bef0fr3mp: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + 'x-acl-action': 'users:create', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + resource: 'users', + collection: 'users', + }, + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-component-props': {}, + properties: { + dmzuakwhn67: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + grid: { + 'x-uid': 'hjzgxol8pmk', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + 'x-linkage-rules': [ + { + condition: { + $and: [], + }, + actions: [ + { + targetFields: ['nickname'], + operator: 'value', + value: { + mode: 'express', + value: '{{$nForm.nickname}}', + result: '{{$nForm.nickname}}', + }, + }, + { + targetFields: ['username'], + operator: 'value', + value: { + mode: 'express', + value: '{{$nForm.phone}}', + result: '{{$nForm.phone}}', + }, + }, + ], + }, + ], + properties: { + ghhc0yhkzo3: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + cogs086ympz: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + nickname: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'users.nickname', + 'x-component-props': {}, + 'x-uid': 'uham04eoezy', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '2skfzuw7qxe', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ejr3cir9ka5', + 'x-async': false, + 'x-index': 1, + }, + ffhaknxhqpx: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + i3ryir3ak3d: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + username: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'users.username', + 'x-component-props': {}, + 'x-uid': 'kw6xnym0d2b', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'l7w26sen1yq', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'agrwgc6u5nh', + 'x-async': false, + 'x-index': 2, + }, + duw19c22p3a: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '64y498coobd': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + email: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'users.email', + 'x-component-props': {}, + 'x-uid': 'yw4htrn4yus', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'co2ntoxojzd', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '1ma4kg0h049', + 'x-async': false, + 'x-index': 3, + }, + gkcvoutlsnn: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '0wpsholkerv': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + phone: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'users.phone', + 'x-component-props': {}, + 'x-uid': 'vuakogudr4a', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'pjbv5opckij', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '7r2oycam1jj', + 'x-async': false, + 'x-index': 4, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'FormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + 'x-uid': 'q2ln2amp70q', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'ftb89wttlgb', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '7xk8np3hom7', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'etlsqr2svs6', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'vnqpjz7rukb', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xq6asyjoszu', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'audztrgao6i', + 'x-async': true, + 'x-index': 1, + }, +}; +export const T2174 = { + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + 'x-index': 1, + properties: { + x9ersztdq7x: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + 'x-index': 1, + properties: { + ppgwx2drpng: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-index': 1, + properties: { + c25gfj884oe: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-index': 1, + properties: { + urmc26btvb5: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'test2174:list', + 'x-decorator-props': { + collection: 'test2174', + resource: 'test2174', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + 'x-index': 1, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + 'x-index': 1, + 'x-uid': '7wfu81uqxox', + 'x-async': false, + }, + yxgybgmfhkp: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + 'x-index': 2, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Actions") }}', + 'x-action-column': 'actions', + 'x-decorator': 'TableV2.Column.ActionBar', + 'x-component': 'TableV2.Column', + 'x-designer': 'TableV2.ActionColumnDesigner', + 'x-initializer': 'TableActionColumnInitializers', + 'x-index': 1, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + 'x-index': 1, + properties: { + r51kgwrhpgd: { + 'x-uid': 'udzm8hggmmb', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: 'View details', + 'x-action': 'view', + 'x-designer': 'Action.Designer', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + danger: false, + }, + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + 'x-index': 1, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("View record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + 'x-index': 1, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializers', + 'x-index': 1, + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Details")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + 'x-index': 1, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + 'x-index': 1, + properties: { + g8w7wq09bgo: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-index': 1, + properties: { + '42t1ais26x8': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-index': 1, + properties: { + zmq6hmh2i3a: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + 'x-acl-action': 'test2174.f_q32e4ieq49n:create', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + useSourceId: '{{ useSourceIdFromParentRecord }}', + useParams: '{{ useParamsFromRecord }}', + action: null, + resource: 'test2174.f_q32e4ieq49n', + collection: 'test2174', + association: 'test2174.f_q32e4ieq49n', + }, + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-component-props': {}, + 'x-index': 1, + properties: { + qii0gw1cb8e: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + 'x-index': 1, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + 'x-index': 1, + properties: { + s3hhb0ohnv1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-index': 1, + properties: { + t2qtgv250s0: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-index': 1, + properties: { + singleSelect: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': + 'test2174.singleSelect', + 'x-component-props': { + style: { + width: '100%', + }, + }, + 'x-index': 1, + 'x-uid': '75ls3qlq3kw', + 'x-async': false, + }, + }, + 'x-uid': 'ndb8zhrxgq0', + 'x-async': false, + }, + }, + 'x-uid': '14q94mijyx4', + 'x-async': false, + }, + }, + 'x-uid': '6vfyrsrkw29', + 'x-async': false, + }, + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'CreateFormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + 'x-index': 2, + properties: { + afuxokt3osc: { + _isJSONSchemaObject: true, + version: '2.0', + title: '{{ t("Submit") }}', + 'x-action': 'submit', + 'x-component': 'Action', + 'x-designer': 'Action.Designer', + 'x-component-props': { + type: 'primary', + htmlType: 'submit', + useProps: '{{ useCreateActionProps }}', + }, + 'x-action-settings': { + triggerWorkflows: [], + }, + type: 'void', + 'x-index': 1, + 'x-uid': '6idd8u0fs5v', + 'x-async': false, + }, + }, + 'x-uid': '8xm66k2wcbq', + 'x-async': false, + }, + }, + 'x-uid': 'ia7qdocnj0k', + 'x-async': false, + }, + }, + 'x-uid': 'ai78ycshc04', + 'x-async': false, + }, + }, + 'x-uid': 'gipnqnxa7c7', + 'x-async': false, + }, + }, + 'x-uid': '4fztm3s6pqr', + 'x-async': false, + }, + }, + 'x-uid': 'yiwh3chdjzg', + 'x-async': false, + }, + }, + 'x-uid': 'mar9ww8zdd6', + 'x-async': false, + }, + }, + 'x-uid': '29brl1obftp', + 'x-async': false, + }, + }, + 'x-uid': 'r4qbds05tcz', + 'x-async': false, + }, + }, + 'x-async': false, + }, + }, + 'x-uid': 'hp7glbaipmc', + 'x-async': false, + }, + }, + 'x-uid': 'k9u1fta4jdq', + 'x-async': false, + }, + x6soi4xw3yn: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableV2.Column.Decorator', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + 'x-index': 2, + properties: { + singleSelect: { + _isJSONSchemaObject: true, + version: '2.0', + 'x-collection-field': 'test2174.singleSelect', + 'x-component': 'CollectionField', + 'x-component-props': { + style: { + width: '100%', + }, + ellipsis: true, + }, + 'x-read-pretty': true, + 'x-decorator': null, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + default: 'np55dbbny0e', + 'x-index': 1, + 'x-uid': 'ots1wvv436n', + 'x-async': false, + }, + }, + 'x-uid': 'yx4mdriq3jp', + 'x-async': false, + }, + aoj0myt8kgn: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableV2.Column.Decorator', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + 'x-index': 3, + properties: { + f_q32e4ieq49n: { + _isJSONSchemaObject: true, + version: '2.0', + 'x-collection-field': 'test2174.f_q32e4ieq49n', + 'x-component': 'CollectionField', + 'x-component-props': { + ellipsis: true, + size: 'small', + fieldNames: { + label: 'singleSelect', + value: 'id', + }, + }, + 'x-read-pretty': true, + 'x-decorator': null, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-index': 1, + properties: { + ony7hpl5247: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("View record") }}', + 'x-component': 'AssociationField.Viewer', + 'x-component-props': { + className: 'nb-action-popup', + }, + 'x-index': 1, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializers', + 'x-index': 1, + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Details")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + 'x-index': 1, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + 'x-index': 1, + 'x-uid': 'roog7uz0d2o', + 'x-async': false, + }, + }, + 'x-uid': 'x05lq9x1n0n', + 'x-async': false, + }, + }, + 'x-uid': 'hrymp5hthg3', + 'x-async': false, + }, + }, + 'x-uid': 'ujkf9096qwq', + 'x-async': false, + }, + }, + 'x-uid': '02kpdjz33yd', + 'x-async': false, + }, + }, + 'x-uid': 'e366r5cz2cv', + 'x-async': false, + }, + }, + 'x-uid': 'wkdjjugn3l8', + 'x-async': false, + }, + }, + 'x-uid': 'n3f07077krt', + 'x-async': false, + }, + }, + 'x-uid': 'i920mrykzkp', + 'x-async': false, + }, + }, + 'x-uid': '8a5n45kb55h', + 'x-async': false, + }, + }, + 'x-uid': 'wcobb00rn5y', + 'x-async': false, + }, + }, + 'x-uid': 'pfr9jap0zsf', + 'x-async': true, + }, + collections: [ + { + name: 'test2174', + title: 'Test', + fields: [ + { + name: 'f_lkqy3eh4ag7', + interface: 'integer', + isForeignKey: true, + uiSchema: { + type: 'number', + title: 'f_lkqy3eh4ag7', + 'x-component': 'InputNumber', + 'x-read-pretty': true, + }, + }, + { + name: 'f_rathx54cqpy', + interface: 'integer', + isForeignKey: true, + uiSchema: { + type: 'number', + title: 'f_rathx54cqpy', + 'x-component': 'InputNumber', + 'x-read-pretty': true, + }, + }, + { + name: 'singleSelect', + interface: 'select', + uiSchema: { + enum: [ + { + value: 'np55dbbny0e', + label: 'option1', + }, + { + value: 'zxteco8rjfc', + label: 'option2', + }, + { + value: 'p7pi40zd91q', + label: 'option3', + }, + ], + type: 'string', + 'x-component': 'Select', + title: 'Single select', + }, + }, + { + name: 'f_q32e4ieq49n', + interface: 'o2m', + foreignKey: 'f_rathx54cqpy', + uiSchema: { + 'x-component': 'AssociationField', + 'x-component-props': { + multiple: true, + fieldNames: { + label: 'id', + value: 'id', + }, + }, + title: 'One to many', + }, + target: 'test2174', + targetKey: 'id', + sourceKey: 'id', + }, + ], + }, + ], +}; +export const T2614: PageConfig = { + collections: [ + { + name: 'T2614', + fields: [ + { + name: 'm2o', + interface: 'm2o', + target: 'T2614Target1', + }, + ], + }, + { + name: 'T2614Target1', + fields: [ + { + name: 'm2oOfTarget1', + interface: 'm2o', + target: 'T2614Target2', + }, + ], + }, + { + name: 'T2614Target2', + fields: [ + { + name: 'm2oOfTarget2', + interface: 'm2o', + target: 'users', + }, + ], + }, + ], + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + oaeetth18tf: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + vv0l8wohslb: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '7se9siwa4ce': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + '249fb0vofov': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'T2614:list', + 'x-decorator-props': { + collection: 'T2614', + resource: 'T2614', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + 'x-uid': 'vq4vg5mpbxz', + 'x-async': false, + 'x-index': 1, + }, + v76qyn133dr: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Actions") }}', + 'x-action-column': 'actions', + 'x-decorator': 'TableV2.Column.ActionBar', + 'x-component': 'TableV2.Column', + 'x-designer': 'TableV2.ActionColumnDesigner', + 'x-initializer': 'TableActionColumnInitializers', + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + properties: { + '02okcjna453': { + 'x-uid': 'xowhnp7a686', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: 'View record', + 'x-action': 'view', + 'x-designer': 'Action.Designer', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + danger: false, + }, + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("View record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializers', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Details")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + properties: { + qbl84fadyr0: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + pfnr7qcapp2: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + eomkz742tgm: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action': 'T2614:get', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + resource: 'T2614', + collection: 'T2614', + readPretty: true, + action: 'get', + useParams: '{{ useParamsFromRecord }}', + useSourceId: '{{ useSourceIdFromParentRecord }}', + }, + 'x-designer': 'FormV2.ReadPrettyDesigner', + 'x-component': 'CardItem', + properties: { + sekfkpv5dh2: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-read-pretty': true, + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': + 'ReadPrettyFormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 24, + }, + }, + 'x-uid': 'mt321nhie11', + 'x-async': false, + 'x-index': 1, + }, + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': + 'ReadPrettyFormItemInitializers', + properties: { + i39cn9ve66b: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + h6aq6z28saw: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + m2o: { + 'x-uid': '5zamj2l0hxp', + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'T2614.m2o', + 'x-component-props': { + mode: 'Nester', + }, + properties: { + sgu8ssav8z3: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': + 'AssociationField.Nester', + 'x-index': 1, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': + 'FormItemInitializers', + properties: { + e5kqdzyj562: { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'Grid.Row', + properties: { + '36nwk5wtcze': { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'Grid.Col', + properties: { + m2oOfTarget1: { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'string', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-collection-field': + 'T2614Target1.m2oOfTarget1', + 'x-component-props': + {}, + 'x-uid': + '9x1i9kks2io', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'gnqmqaqs49i', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'sku445zzg07', + 'x-async': false, + 'x-index': 1, + }, + bnd1dnje70d: { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'Grid.Row', + properties: { + ygyvra5m18v: { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'Grid.Col', + properties: { + 'm2oOfTarget1.id': + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'string', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-read-pretty': + true, + 'x-component-props': + { + 'pattern-disable': + true, + }, + 'x-decorator': + 'FormItem', + 'x-collection-field': + 'T2614Target1.m2oOfTarget1.id', + 'x-uid': + '0trg79yim60', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'auigm7t6blc', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '6ll6h4ii2td', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'wxo0qlrm5ss', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '73iro2istbt', + 'x-async': false, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'h3feczketbc', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'nb5fbboc504', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'dehspo2sh69', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'lyvcisiy2mz', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'u78ad3fqfdo', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'r8s2aj79b9q', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'fgsdtpfae0q', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'dzzom03ln6q', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'u8h5d2ecch0', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '1dlp1swsc68', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'qa2uyudep13', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + '697zke71z0l': { + 'x-uid': '7o63dwge91d', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: 'Edit record', + 'x-action': 'update', + 'x-designer': 'Action.Designer', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + danger: false, + }, + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Edit record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializers', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Edit")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + properties: { + z79dioevb4n: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + krzxk68va81: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + '7ms7r5wolwa': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: false, + }, + 'x-acl-action': 'T2614:update', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + useSourceId: '{{ useSourceIdFromParentRecord }}', + useParams: '{{ useParamsFromRecord }}', + action: 'get', + resource: 'T2614', + collection: 'T2614', + }, + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-component-props': {}, + properties: { + '4pxevnwkd12': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + properties: { + j9egu0k0tkq: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + zpv9u8httu7: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + m2o: { + 'x-uid': '1pyjlpyhxue', + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'T2614.m2o', + 'x-component-props': { + mode: 'Nester', + }, + properties: { + ts1e7dq92gw: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': + 'AssociationField.Nester', + 'x-index': 1, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': + 'FormItemInitializers', + properties: { + esgv9d2n3jl: { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'Grid.Row', + properties: { + fvjf1i0u5tj: { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'Grid.Col', + properties: { + m2oOfTarget1: { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'string', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-collection-field': + 'T2614Target1.m2oOfTarget1', + 'x-component-props': + {}, + 'x-uid': + 'tbl4cxpqqhr', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + '0inwt7v6zx1', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ooid2e23vzk', + 'x-async': false, + 'x-index': 1, + }, + '8jo9e13m9pu': { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'Grid.Row', + properties: { + dbwz7xfmcsf: { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'Grid.Col', + properties: { + 'm2oOfTarget1.id': + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'string', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-read-pretty': + true, + 'x-component-props': + { + 'pattern-disable': + true, + }, + 'x-decorator': + 'FormItem', + 'x-collection-field': + 'T2614Target1.m2oOfTarget1.id', + 'x-uid': + 'no1h1z3kbqn', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'f1w8n47pxgk', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'v6x8pzyim4q', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'ixnvtkde6ut', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'a0765a01l4v', + 'x-async': false, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'nhq72b5xej7', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '0rchr17dcvr', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'fvfqd52uoaa', + 'x-async': false, + 'x-index': 1, + }, + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'UpdateFormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + 'x-uid': 'bm93ifuifak', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '6s8ie14bci8', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'hljdd9nlub3', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'h14avrpxyu9', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'n54e5yj7uo8', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'o6q0ebwuei0', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ej65121swhj', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '521m41b059u', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '6ddt1wgx8zu', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '1oj9b60cf3w', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'qdzdffxf5da', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 't7svx0a3pce', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'w8kzfaxgchd', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'hg44qtd6uw6', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'vv4zzxbtbja', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '6klhg23a43i', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '9ebjl68x43b', + 'x-async': true, + 'x-index': 1, + }, +}; +export const T2615: PageConfig = { + collections: [ + { + name: 'T2615', + fields: [ + { + name: 'm2o', + interface: 'm2o', + target: 'T2615Target1', + }, + ], + }, + { + name: 'T2615Target1', + fields: [ + { + name: 'm2oOfTarget1', + interface: 'm2o', + target: 'T2615Target2', + }, + ], + }, + { + name: 'T2615Target2', + fields: [ + { + name: 'm2oOfTarget2', + interface: 'm2o', + target: 'users', + }, + ], + }, + ], + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + eoe6sphevnd: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + '1valv0kj8vs': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + nkq10mh10ps: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + '22lk2du0ib3': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'T2615:list', + 'x-decorator-props': { + collection: 'T2615', + resource: 'T2615', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + properties: { + unexw8b0ued: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-action': 'create', + 'x-acl-action': 'create', + title: "{{t('Add new')}}", + 'x-designer': 'Action.Designer', + 'x-component': 'Action', + 'x-decorator': 'ACLActionProvider', + 'x-component-props': { + openMode: 'drawer', + type: 'primary', + component: 'CreateRecordAction', + icon: 'PlusOutlined', + }, + 'x-align': 'right', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Add record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializersForCreateFormBlock', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Add new")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'CreateFormBlockInitializers', + properties: { + '8ei3tsaojf6': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '5u0ju1wsgkl': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + zxwg35f8sg7: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + 'x-acl-action': 'T2615:create', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + resource: 'T2615', + collection: 'T2615', + }, + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-component-props': {}, + properties: { + '9i2u8628hoz': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + properties: { + i7cb2o172ey: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + enue1mnnt4g: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + m2o: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'T2615.m2o', + 'x-component-props': {}, + 'x-uid': 'tif3ncbwwru', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'jh5w5yne4qt', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'aqo2rtciew5', + 'x-async': false, + 'x-index': 1, + }, + qfr6n6ymx77: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + ldlk5ifn56r: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + 'm2o.m2oOfTarget1': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-read-pretty': true, + 'x-component-props': { + 'pattern-disable': true, + fieldNames: { + label: 'id', + value: 'id', + }, + }, + 'x-decorator': 'FormItem', + 'x-collection-field': + 'T2615.m2o.m2oOfTarget1', + 'x-uid': 'gii2rk1q4fx', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'k2k4hzsmxzw', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'tysg8zh5wpp', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '7ff0fvn1ci1', + 'x-async': false, + 'x-index': 1, + }, + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'CreateFormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + 'x-uid': '6u35dl8quee', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '5syf9qhcwch', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '26kgmi2guwg', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'i1hdum7ju7d', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '8e7td05t5rv', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'nlgcjcl7sm2', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'hzn4uinj3i7', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'qkv3lilo9ew', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'k945b89wggu', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'pz18nxb0x51', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '94386mg3n6z', + 'x-async': false, + 'x-index': 1, + }, + '3m6w3iz4c5t': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Actions") }}', + 'x-action-column': 'actions', + 'x-decorator': 'TableV2.Column.ActionBar', + 'x-component': 'TableV2.Column', + 'x-designer': 'TableV2.ActionColumnDesigner', + 'x-initializer': 'TableActionColumnInitializers', + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + properties: { + yych9x95hrp: { + 'x-uid': 'uv7zmtj0r5u', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: 'Edit record', + 'x-action': 'update', + 'x-designer': 'Action.Designer', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + danger: false, + }, + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Edit record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializers', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Edit")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + properties: { + l79xm6sfjst: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '7cyquusb2ca': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + '8dxzx9t0571': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: false, + }, + 'x-acl-action': 'T2615:update', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + useSourceId: '{{ useSourceIdFromParentRecord }}', + useParams: '{{ useParamsFromRecord }}', + action: 'get', + resource: 'T2615', + collection: 'T2615', + }, + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-component-props': {}, + properties: { + '21sxtdkbcw0': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + properties: { + '7eayo28dgzo': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + oj9yj21ujd8: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + m2o: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'T2615.m2o', + 'x-component-props': {}, + 'x-uid': 'qxn8qacg682', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'axx7wvrxnem', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'qgkr6iz0e1t', + 'x-async': false, + 'x-index': 1, + }, + zsdbhvdvaru: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '082hatydnd0': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + 'm2o.m2oOfTarget1': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-read-pretty': true, + 'x-component-props': { + 'pattern-disable': true, + fieldNames: { + label: 'id', + value: 'id', + }, + }, + 'x-decorator': 'FormItem', + 'x-collection-field': + 'T2615.m2o.m2oOfTarget1', + 'x-uid': 'n5s7j4n193r', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'nm9qq5hao2e', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ey3595qsqyk', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'w8zdw4dr89d', + 'x-async': false, + 'x-index': 1, + }, + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'UpdateFormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + 'x-uid': 'conyu4tdnsb', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '6jeoainb2oa', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '27azok1hcrs', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'x0gpfgjc0n1', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '0up3rbfoby1', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'tul7kvn3s6m', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'jz2lb20hu1s', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ssbzj9yrh8r', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'dak290d9mnz', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + t452of8muaq: { + 'x-uid': 'q4op427zlfp', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: 'View record', + 'x-action': 'view', + 'x-designer': 'Action.Designer', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + danger: false, + }, + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("View record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializers', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Details")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + properties: { + nlnfd9hnl53: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + o1mvvolrr3n: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + '02tm0tr9gie': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action': 'T2615:get', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + resource: 'T2615', + collection: 'T2615', + readPretty: true, + action: 'get', + useParams: '{{ useParamsFromRecord }}', + useSourceId: '{{ useSourceIdFromParentRecord }}', + }, + 'x-designer': 'FormV2.ReadPrettyDesigner', + 'x-component': 'CardItem', + properties: { + xa10ops1tmr: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-read-pretty': true, + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': + 'ReadPrettyFormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 24, + }, + }, + 'x-uid': 'jq1vdqw4oyy', + 'x-async': false, + 'x-index': 1, + }, + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': + 'ReadPrettyFormItemInitializers', + properties: { + j9mxulol74m: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + r4alweypz03: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + m2o: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'T2615.m2o', + 'x-component-props': {}, + 'x-uid': 'ttv0hjsnnsy', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'p9yvxr8b7vg', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'r198z5pv6c4', + 'x-async': false, + 'x-index': 1, + }, + xb97qr5ustn: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + wje8oyfbn1d: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + 'm2o.m2oOfTarget1': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-read-pretty': true, + 'x-component-props': { + 'pattern-disable': true, + fieldNames: { + label: 'id', + value: 'id', + }, + }, + 'x-decorator': 'FormItem', + 'x-collection-field': + 'T2615.m2o.m2oOfTarget1', + 'x-uid': '6pdlbj34175', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'p2alwntoxkg', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'rgsbhuo0lzv', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'a39j3mj83xp', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'd6xf1x23yzx', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '5esxphd790l', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'pzr8i6utc83', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'u8wkbbgvb05', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'boh5n3tkmgu', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'd0cfvm929ca', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'wt7e6356t9k', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'cqnlqotquv9', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'x8yf6ex62ju', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 't4gcpw7ji0u', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '8d8oe7qocry', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'vyf1ac9nsl5', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '8zp6xvttwvi', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'axknjuou42g', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xtxm0hd6lbi', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'lbdmizeodxy', + 'x-async': true, + 'x-index': 1, + }, +}; +export const T2200 = { + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + n7k4be0tpgt: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + ai6ojrzwkiv: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + amsy67ggjr3: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + ajob701dt18: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'users:list', + 'x-decorator-props': { + collection: 'users', + resource: 'users', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + 'x-uid': 'farfrcvsydq', + 'x-async': false, + 'x-index': 1, + }, + t1o3f4r1j4q: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Actions") }}', + 'x-action-column': 'actions', + 'x-decorator': 'TableV2.Column.ActionBar', + 'x-component': 'TableV2.Column', + 'x-designer': 'TableV2.ActionColumnDesigner', + 'x-initializer': 'TableActionColumnInitializers', + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + properties: { + ezur2k7gz8k: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Edit") }}', + 'x-action': 'update', + 'x-designer': 'Action.Designer', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + icon: 'EditOutlined', + }, + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Edit record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializers', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Edit")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + properties: { + dv88ljcl0qw: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '548w29v01eb': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + q83tzsynghl: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: false, + }, + 'x-acl-action': 'users:update', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + useSourceId: '{{ useSourceIdFromParentRecord }}', + useParams: '{{ useParamsFromRecord }}', + action: 'get', + resource: 'users', + collection: 'users', + }, + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-component-props': {}, + properties: { + '8kzqujhwsyl': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + properties: { + '3i87cpmv87x': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + am7wls8qu12: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + roles: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'users.roles', + 'x-component-props': {}, + 'x-uid': 'e196r19yspx', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ato3s57xtbt', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'dx3bqu24t50', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'rjbjrnn88sq', + 'x-async': false, + 'x-index': 1, + }, + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'UpdateFormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + 'x-uid': 'zh8o2drtd9h', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'ytafkst3w0s', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ioqb8wteiwr', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'iavf0r5sl2n', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '994dlhgh1iz', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'k390f3n1rz7', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xm264vyzmkf', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'asl2rgfrz7p', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xfre469n0yi', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'gdjgqvxv6b1', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'fnctj4uc8xy', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '2dc4d3mlw3k', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '51i2scjmis1', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '75owqo6visj', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'r4bvdbzinup', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'h066j2xouwn', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'qrkik5iy790', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '3vzzy7tipgq', + 'x-async': true, + 'x-index': 1, + }, +}; diff --git a/packages/core/client/src/modules/form-edit/__e2e__/schemaInitializer.test.ts b/packages/core/client/src/modules/form-edit/__e2e__/schemaInitializer.test.ts new file mode 100644 index 000000000..eae35838d --- /dev/null +++ b/packages/core/client/src/modules/form-edit/__e2e__/schemaInitializer.test.ts @@ -0,0 +1,20 @@ +import { expect, oneEmptyTableBlockWithActions, test } from '@nocobase/test/client'; + +test.describe('where edit form block can be added', () => { + test('popup', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneEmptyTableBlockWithActions).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + + await page.getByLabel('action-Action.Link-Edit-update-general-table-0').click(); + await page.getByLabel('schema-initializer-Grid-RecordBlockInitializers-general').hover(); + await page.getByText('Form').click(); + await page.mouse.move(300, 0); + + await expect(page.getByLabel('block-item-CardItem-general-form')).toBeVisible(); + }); +}); + +test.describe('configure actions', () => {}); + +test.describe('configure fields', () => {}); diff --git a/packages/core/client/src/modules/form-edit/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/form-edit/__e2e__/schemaSettings.test.ts new file mode 100644 index 000000000..be0009974 --- /dev/null +++ b/packages/core/client/src/modules/form-edit/__e2e__/schemaSettings.test.ts @@ -0,0 +1,175 @@ +import { + Page, + expect, + expectSettingsMenu, + oneEmptyFormWithActions, + oneTableBlockWithActionsAndFormBlocks, + test, +} from '@nocobase/test/client'; + +const clickOption = async (page: Page, optionName: string) => { + await page.getByLabel('block-item-CardItem-general-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); + await page.getByRole('menuitem', { name: optionName }).click(); +}; + +test.describe('edit form block schema settings', () => { + test('Edit block title', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneTableBlockWithActionsAndFormBlocks).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + await page.getByText('Edit', { exact: true }).click(); + + // 打开编辑弹窗 + await clickOption(page, 'Edit block title'); + await page.getByRole('textbox').click(); + await page.getByRole('textbox').fill('Block title 123'); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + const runExpect = async () => { + // 设置成功后,显示在区块顶部 + await expect( + page.getByLabel('block-item-CardItem-general-form').getByText('Block title 123', { exact: true }), + ).toBeVisible(); + + // 再次打开编辑弹窗时,显示的是上次设置的值 + await clickOption(page, 'Edit block title'); + await expect(page.getByRole('textbox')).toHaveValue('Block title 123'); + }; + + await runExpect(); + + // 刷新页面后,显示的应该依然是上次设置的值 + await page.reload(); + await page.getByText('Edit', { exact: true }).click(); + await runExpect(); + }); + + test('Linkage rules', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneTableBlockWithActionsAndFormBlocks).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + await page.getByText('Edit', { exact: true }).click(); + + // 打开编辑弹窗 + await clickOption(page, 'Linkage rules'); + await page.getByRole('button', { name: 'Add linkage rule' }).click(); + await page.getByText('Add property').click(); + await page.getByTestId('select-linkage-property-field').click(); + await page.getByText('singleLineText', { exact: true }).click(); + await page.getByTestId('select-linkage-action-field').click(); + await page.getByRole('option', { name: 'Visible' }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + const runExpect = async () => { + await expect(page.getByTestId('select-linkage-property-field').getByText('singleLineText')).toBeVisible(); + await expect(page.getByTestId('select-linkage-action-field').getByText('Visible')).toBeVisible(); + }; + + // 再次打开,设置的值应该存在 + await clickOption(page, 'Linkage rules'); + await runExpect(); + + // 刷新页面后,设置的值应该依然存在 + await page.reload(); + await page.getByText('Edit', { exact: true }).click(); + await clickOption(page, 'Linkage rules'); + await runExpect(); + }); + + test('Convert reference to duplicate & Save as block template', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneTableBlockWithActionsAndFormBlocks).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + await page.getByText('Edit', { exact: true }).click(); + + // 打开编辑弹窗 + await clickOption(page, 'Save as block template'); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 设置成功后,不再显示 Save as block template 选项,而是显示 Convert reference to duplicate 选项 + await page.getByLabel('block-item-CardItem-general-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); + await expect(page.getByRole('menuitem', { name: 'Save as block template' })).not.toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Convert reference to duplicate' })).toBeVisible(); + + // 刷新页面 + await page.reload(); + await page.getByText('Edit', { exact: true }).click(); + await page.getByLabel('block-item-CardItem-general-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); + await expect(page.getByRole('menuitem', { name: 'Save as block template' })).not.toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Convert reference to duplicate' })).toBeVisible(); + + // Convert reference to duplicate + await clickOption(page, 'Convert reference to duplicate'); + await expect(page.getByRole('menuitem', { name: 'Save as block template' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Convert reference to duplicate' })).not.toBeVisible(); + + // 刷新页面 + await page.reload(); + await page.getByText('Edit', { exact: true }).click(); + await page.getByLabel('block-item-CardItem-general-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); + await expect(page.getByRole('menuitem', { name: 'Save as block template' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Convert reference to duplicate' })).not.toBeVisible(); + }); + + test('Delete', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneTableBlockWithActionsAndFormBlocks).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + + await page.getByText('Edit', { exact: true }).click(); + await page.getByLabel('block-item-CardItem-general-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-FormV2.Designer-general').hover(); + + // 打开编辑弹窗 + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 设置成功后,显示在区块顶部 + await expect(page.getByLabel('block-item-CardItem-general-form')).not.toBeVisible(); + + // 刷新页面后,区块依然是被删除状态 + await page.reload(); + await page.getByText('Edit', { exact: true }).click(); + await expect(page.getByLabel('block-item-CardItem-general-form')).not.toBeVisible(); + }); +}); + +test.describe('actions schema settings', () => { + test('submit', async ({ page, mockPage }) => { + await mockPage(oneEmptyFormWithActions).goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByRole('button', { name: 'Submit' }).hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action-Action.Designer-users' }).hover(); + }, + supportedOptions: ['Edit button', 'Linkage rules', 'Bind workflows', 'Delete'], + }); + }); + + test('customize: save record', async ({ page, mockPage }) => { + await mockPage(oneEmptyFormWithActions).goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByRole('button', { name: 'Save record' }).hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action-Action.Designer-users' }).hover(); + }, + supportedOptions: [ + 'Edit button', + 'Linkage rules', + 'Assign field values', + 'Skip required validation', + 'After successful submission', + 'Bind workflows', + 'Delete', + ], + }); + }); +}); diff --git a/packages/core/client/src/modules/form-edit/__e2e__/templatesOfBug.ts b/packages/core/client/src/modules/form-edit/__e2e__/templatesOfBug.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/core/client/src/__tests__/e2e/schemaInitializer/filterFormBlock.test.ts b/packages/core/client/src/modules/form-filter/__e2e__/schemaInitializer.test.ts similarity index 74% rename from packages/core/client/src/__tests__/e2e/schemaInitializer/filterFormBlock.test.ts rename to packages/core/client/src/modules/form-filter/__e2e__/schemaInitializer.test.ts index 704e43b5e..f034a2ebe 100644 --- a/packages/core/client/src/__tests__/e2e/schemaInitializer/filterFormBlock.test.ts +++ b/packages/core/client/src/modules/form-filter/__e2e__/schemaInitializer.test.ts @@ -1,23 +1,33 @@ -import { expect, oneEmptyFilterFormBlock, test } from '@nocobase/test/client'; +import { createBlockInPage, expect, oneEmptyFilterFormBlock, test } from '@nocobase/test/client'; -test.describe('Filter Form Block', () => { - test('add fields', async ({ page, mockPage }) => { +test.describe('where filter form block can be added', () => { + test('page', async ({ page, mockPage }) => { + await mockPage().goto(); + + await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); + await createBlockInPage(page, 'Filter form'); + await expect(page.getByLabel('block-item-CardItem-users-filter-form')).toBeVisible(); + }); +}); + +test.describe('configure fields', () => { + test('display collection fields & display association fields & add text', async ({ page, mockPage }) => { await mockPage(oneEmptyFilterFormBlock).goto(); const formItemInitializer = page.getByLabel('schema-initializer-Grid-FilterFormItemInitializers-general'); // add fields await formItemInitializer.hover(); - await page.getByRole('menuitem', { name: 'ID' }).click(); - await expect(page.getByRole('menuitem', { name: 'ID' }).getByRole('switch')).toBeChecked(); + await page.getByRole('menuitem', { name: 'ID', exact: true }).click(); + await expect(page.getByRole('menuitem', { name: 'ID', exact: true }).getByRole('switch')).toBeChecked(); await page.mouse.move(300, 0); await expect(page.getByLabel('block-item-CollectionField-general-filter-form-general.id-ID')).toBeVisible(); // delete fields await formItemInitializer.hover(); - await page.getByRole('menuitem', { name: 'ID' }).click(); - await expect(page.getByRole('menuitem', { name: 'ID' }).getByRole('switch')).not.toBeChecked(); + await page.getByRole('menuitem', { name: 'ID', exact: true }).click(); + await expect(page.getByRole('menuitem', { name: 'ID', exact: true }).getByRole('switch')).not.toBeChecked(); await page.mouse.move(300, 0); await expect(page.getByLabel('block-item-CollectionField-general-filter-form-general.id-ID')).not.toBeVisible(); @@ -55,9 +65,11 @@ test.describe('Filter Form Block', () => { await expect(page.getByLabel('block-item-Markdown.Void-general-filter-form')).toBeVisible(); }); - test.pgOnly('add inherit fields', async ({ page, mockPage }) => {}); + test.pgOnly('display inherit fields', async ({ page, mockPage }) => {}); +}); - test('add action buttons', async ({ page, mockPage }) => { +test.describe('configure actions', () => { + test('filter & reset', async ({ page, mockPage }) => { await mockPage(oneEmptyFilterFormBlock).goto(); await page.getByLabel('schema-initializer-ActionBar-FilterFormActionInitializers-general').hover(); diff --git a/packages/core/client/src/modules/form-filter/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/form-filter/__e2e__/schemaSettings.test.ts new file mode 100644 index 000000000..86fa40e29 --- /dev/null +++ b/packages/core/client/src/modules/form-filter/__e2e__/schemaSettings.test.ts @@ -0,0 +1,108 @@ +import { + expect, + expectSettingsMenu, + oneEmptyFilterFormBlock, + oneFormAndOneTableWithSameCollection, + test, +} from '@nocobase/test/client'; + +test.describe('filter block schema settings', () => { + test('supported options', async ({ page, mockPage }) => { + await mockPage(oneEmptyFilterFormBlock).goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByLabel('block-item-CardItem-general-filter-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-FormV2.FilterDesigner-general').hover(); + }, + supportedOptions: [ + 'Edit block title', + 'Save as block template', + 'Linkage rules', + 'Connect data blocks', + 'Delete', + ], + }); + }); + + test.describe('connect data blocks', () => { + test('connecting two blocks of the same collection', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(oneFormAndOneTableWithSameCollection).waitForInit(); + const records = await mockRecords('general', 3); + await nocoPage.goto(); + + // 将上面的 Form 连接到下面的 Table + await page.getByLabel('block-item-CardItem-general-filter-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-FormV2.FilterDesigner-general').hover(); + await page.getByRole('menuitem', { name: 'Connect data blocks' }).hover(); + await page.getByRole('menuitem', { name: 'General' }).click(); + + // 输入值,点击筛选按钮 + await page + .getByLabel('block-item-CollectionField-general-filter-form-general.singleLineText-singleLineText') + .getByRole('textbox') + .click(); + await page + .getByLabel('block-item-CollectionField-general-filter-form-general.singleLineText-singleLineText') + .getByRole('textbox') + .fill(records[0].singleLineText); + + // 点击筛选按钮 + await page.getByLabel('action-Action-Filter records-submit-general-filter-form').click(); + + await expect( + page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: records[1].singleLineText }), + ).toBeHidden(); + await expect( + page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: records[2].singleLineText }), + ).toBeHidden(); + await expect( + page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: records[0].singleLineText }), + ).toBeVisible(); + + // 点击重置按钮 + await page.getByLabel('action-Action-Reset records-general-filter-form').click(); + await expect( + page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: records[1].singleLineText }), + ).toBeVisible(); + await expect( + page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: records[2].singleLineText }), + ).toBeVisible(); + await expect( + page.getByLabel('block-item-CardItem-general-table').getByRole('row', { name: records[0].singleLineText }), + ).toBeVisible(); + }); + }); +}); + +test.describe('actions schema settings', () => { + test('supported options', async ({ page, mockPage }) => { + await mockPage(oneEmptyFilterFormBlock).goto(); + + // 创建 Filter & Reset 两个按钮 + await page.getByLabel('schema-initializer-ActionBar-FilterFormActionInitializers-general').hover(); + await page.getByRole('menuitem', { name: 'Filter' }).click(); + await page.getByRole('menuitem', { name: 'Reset' }).click(); + + // Filter settings ------------------------------------------------------------------- + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByLabel('action-Action-Filter-submit-general-filter-form').hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action' }).hover(); + }, + supportedOptions: ['Edit button', 'Linkage rules', 'Delete'], + }); + + // Reset settings -------------------------------------------------------------------- + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByLabel('action-Action-Reset-general-filter-form').hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action' }).hover(); + }, + supportedOptions: ['Edit button', 'Linkage rules', 'Delete'], + }); + }); +}); diff --git a/packages/core/client/src/modules/form-filter/__e2e__/templatesOfBug.ts b/packages/core/client/src/modules/form-filter/__e2e__/templatesOfBug.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/core/client/src/__tests__/e2e/schemaInitializer/gridCardBlock.test.ts b/packages/core/client/src/modules/grid-card/__e2e__/schemaInitializer.test.ts similarity index 81% rename from packages/core/client/src/__tests__/e2e/schemaInitializer/gridCardBlock.test.ts rename to packages/core/client/src/modules/grid-card/__e2e__/schemaInitializer.test.ts index ceb3f98e2..747d27983 100644 --- a/packages/core/client/src/__tests__/e2e/schemaInitializer/gridCardBlock.test.ts +++ b/packages/core/client/src/modules/grid-card/__e2e__/schemaInitializer.test.ts @@ -1,7 +1,19 @@ -import { expect, oneEmptyGridCardBlock, test } from '@nocobase/test/client'; +import { createBlockInPage, expect, oneEmptyGridCardBlock, test } from '@nocobase/test/client'; -test.describe('Grid Card', () => { - test('add actions', async ({ page, mockPage }) => { +test.describe('where grid card block can be added', () => { + test('page', async ({ page, mockPage }) => { + await mockPage().goto(); + + await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); + await createBlockInPage(page, 'Grid Card'); + await expect(page.getByLabel('block-item-BlockItem-users-grid-card')).toBeVisible(); + }); + + test('data selector popup', async ({ page, mockPage }) => {}); +}); + +test.describe('configure global actions', () => { + test('filter & add new & refresh', async ({ page, mockPage }) => { await mockPage(oneEmptyGridCardBlock).goto(); await page.getByLabel('schema-initializer-ActionBar-GridCardActionInitializers-general').hover(); @@ -33,66 +45,10 @@ test.describe('Grid Card', () => { await expect(page.getByRole('button', { name: 'Add new' })).not.toBeVisible(); await expect(page.getByRole('button', { name: 'Refresh' })).not.toBeVisible(); }); +}); - test('add item fields', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(oneEmptyGridCardBlock).waitForInit(); - await mockRecord('general'); - await nocoPage.goto(); - - const formItemInitializer = page - .getByLabel('schema-initializer-Grid-ReadPrettyFormItemInitializers-general') - .first(); - - await formItemInitializer.hover(); - await page.getByRole('menuitem', { name: 'ID' }).click(); - await expect(page.getByRole('menuitem', { name: 'ID' }).getByRole('switch')).toBeChecked(); - - // add association fields - await page.mouse.wheel(0, 300); - await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); - await page.getByRole('menuitem', { name: 'Nickname' }).click(); - - await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); - await expect(page.getByRole('menuitem', { name: 'Nickname' }).getByRole('switch')).toBeChecked(); - - await page.mouse.move(300, 0); - await expect(page.getByLabel('block-item-CollectionField-general-grid-card-general.id-ID').first()).toBeVisible(); - await expect( - page.getByLabel('block-item-CollectionField-general-grid-card-general.manyToOne.nickname').first(), - ).toBeVisible(); - - // delete fields - await formItemInitializer.hover(); - await page.getByRole('menuitem', { name: 'ID' }).click(); - await expect(page.getByRole('menuitem', { name: 'ID' }).getByRole('switch')).not.toBeChecked(); - - await page.mouse.wheel(0, 300); - await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); - await page.getByRole('menuitem', { name: 'Nickname' }).click(); - - await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); - await expect(page.getByRole('menuitem', { name: 'Nickname' }).getByRole('switch')).not.toBeChecked(); - - await page.mouse.move(300, 0); - await expect( - page.getByLabel('block-item-CollectionField-general-grid-card-general.id-ID').first(), - ).not.toBeVisible(); - await expect( - page.getByLabel('block-item-CollectionField-general-grid-card-general.manyToOne.nickname').first(), - ).not.toBeVisible(); - - // add text - await formItemInitializer.hover(); - await page.getByRole('menuitem', { name: 'ID' }).hover(); - await page.mouse.wheel(0, 300); - await page.getByRole('menuitem', { name: 'Add text' }).click(); - - await expect(page.getByLabel('block-item-Markdown.Void-general-grid-card').first()).toBeVisible(); - }); - - test.pgOnly('add inherit fields', async ({ page, mockPage }) => {}); - - test('add item actions', async ({ page, mockPage, mockRecord }) => { +test.describe('configure item actions', () => { + test('view & edit & delete', async ({ page, mockPage, mockRecord }) => { const nocoPage = await mockPage(oneEmptyGridCardBlock).waitForInit(); await mockRecord('general'); await nocoPage.goto(); @@ -127,7 +83,7 @@ test.describe('Grid Card', () => { await expect(page.getByLabel('action-Action.Link-Delete-destroy-general-grid-card').first()).not.toBeVisible(); }); - test('add item custom action buttons', async ({ page, mockPage, mockRecord }) => { + test('customize: popup & update record', async ({ page, mockPage, mockRecord }) => { const nocoPage = await mockPage(oneEmptyGridCardBlock).waitForInit(); await mockRecord('general'); await nocoPage.goto(); @@ -144,3 +100,62 @@ test.describe('Grid Card', () => { ).toBeVisible(); }); }); + +test.describe('configure fields', () => { + test('display collection fields & display association fields & add text', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneEmptyGridCardBlock).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + + const formItemInitializer = page + .getByLabel('schema-initializer-Grid-ReadPrettyFormItemInitializers-general') + .first(); + + await formItemInitializer.hover(); + await page.getByRole('menuitem', { name: 'ID', exact: true }).click(); + await expect(page.getByRole('menuitem', { name: 'ID', exact: true }).getByRole('switch')).toBeChecked(); + + // add association fields + await page.mouse.wheel(0, 300); + await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); + await page.getByRole('menuitem', { name: 'Nickname' }).click(); + + await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); + await expect(page.getByRole('menuitem', { name: 'Nickname' }).getByRole('switch')).toBeChecked(); + + await page.mouse.move(300, 0); + await expect(page.getByLabel('block-item-CollectionField-general-grid-card-general.id-ID').first()).toBeVisible(); + await expect( + page.getByLabel('block-item-CollectionField-general-grid-card-general.manyToOne.nickname').first(), + ).toBeVisible(); + + // delete fields + await formItemInitializer.hover(); + await page.getByRole('menuitem', { name: 'ID', exact: true }).click(); + await expect(page.getByRole('menuitem', { name: 'ID', exact: true }).getByRole('switch')).not.toBeChecked(); + + await page.mouse.wheel(0, 300); + await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); + await page.getByRole('menuitem', { name: 'Nickname' }).click(); + + await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); + await expect(page.getByRole('menuitem', { name: 'Nickname' }).getByRole('switch')).not.toBeChecked(); + + await page.mouse.move(300, 0); + await expect( + page.getByLabel('block-item-CollectionField-general-grid-card-general.id-ID').first(), + ).not.toBeVisible(); + await expect( + page.getByLabel('block-item-CollectionField-general-grid-card-general.manyToOne.nickname').first(), + ).not.toBeVisible(); + + // add text + await formItemInitializer.hover(); + await page.getByRole('menuitem', { name: 'ID', exact: true }).hover(); + await page.mouse.wheel(0, 300); + await page.getByRole('menuitem', { name: 'Add text' }).click(); + + await expect(page.getByLabel('block-item-Markdown.Void-general-grid-card').first()).toBeVisible(); + }); + test.pgOnly('display inherit fields', async () => {}); +}); diff --git a/packages/core/client/src/modules/grid-card/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/grid-card/__e2e__/schemaSettings.test.ts new file mode 100644 index 000000000..7c69c9cff --- /dev/null +++ b/packages/core/client/src/modules/grid-card/__e2e__/schemaSettings.test.ts @@ -0,0 +1,51 @@ +import { expect, expectSettingsMenu, oneEmptyGridCardBlock, test } from '@nocobase/test/client'; + +test.describe('grid card block schema settings', () => { + test('supported options', async ({ page, mockPage }) => { + await mockPage(oneEmptyGridCardBlock).goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByLabel('block-item-BlockItem-general-grid-card').hover(); + await page.getByLabel('designer-schema-settings-BlockItem-GridCard.Designer-general').hover(); + }, + supportedOptions: [ + 'Set the count of columns displayed in a row', + 'Set the data scope', + 'Set default sorting rules', + 'Records per page', + 'Save as template', + 'Delete', + ], + }); + }); + + test('set the count of columns displayed in a row', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(oneEmptyGridCardBlock).waitForInit(); + await mockRecords('general', 10); + await nocoPage.goto(); + + let boxSize = await page.getByLabel('grid-card-item').first().boundingBox(); + // 默认是 3 列 + // 之所以这样断言,是因为不同平台的浏览器渲染的 width 可能会有一点点差异,所以这里只能用一个范围来判断 + expect(boxSize.width).toBeGreaterThan(400); + expect(boxSize.width).toBeLessThan(410); + + // 修改成 2 列(在桌面端) + await page.getByLabel('block-item-BlockItem-general-grid-card').hover(); + await page.getByLabel('designer-schema-settings-BlockItem-GridCard.Designer-general').hover(); + await page.getByRole('menuitem', { name: 'Set the count of columns displayed in a row' }).click(); + await page.getByLabel('block-item-Slider-general-Desktop device').getByText('2', { exact: true }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 需要刷新页面才会生效 + await page.reload(); + + boxSize = await page.getByLabel('grid-card-item').first().boundingBox(); + expect(boxSize.width).toBeGreaterThan(600); + expect(boxSize.width).toBeLessThan(620); + }); +}); + +test.describe('actions schema settings', () => {}); diff --git a/packages/core/client/src/modules/grid-card/__e2e__/templatesOfBug.ts b/packages/core/client/src/modules/grid-card/__e2e__/templatesOfBug.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/core/client/src/__tests__/e2e/schemaInitializer/listBlock.test.ts b/packages/core/client/src/modules/list/__e2e__/schemaInitializer.test.ts similarity index 83% rename from packages/core/client/src/__tests__/e2e/schemaInitializer/listBlock.test.ts rename to packages/core/client/src/modules/list/__e2e__/schemaInitializer.test.ts index 6faef7980..cf0b9760d 100644 --- a/packages/core/client/src/__tests__/e2e/schemaInitializer/listBlock.test.ts +++ b/packages/core/client/src/modules/list/__e2e__/schemaInitializer.test.ts @@ -1,7 +1,17 @@ -import { expect, oneEmptyListBlock, test } from '@nocobase/test/client'; +import { createBlockInPage, expect, oneEmptyListBlock, test } from '@nocobase/test/client'; -test.describe('List', () => { - test('add list actions', async ({ page, mockPage }) => { +test.describe('where list block can be added', () => { + test('page', async ({ page, mockPage }) => { + await mockPage().goto(); + + await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); + await createBlockInPage(page, 'List'); + await expect(page.getByLabel('block-item-CardItem-users-list')).toBeVisible(); + }); +}); + +test.describe('configure global actions', () => { + test('filter & add new & refresh', async ({ page, mockPage }) => { await mockPage(oneEmptyListBlock).goto(); await page.getByLabel('schema-initializer-ActionBar-ListActionInitializers-general').hover(); @@ -33,61 +43,10 @@ test.describe('List', () => { await expect(page.getByRole('button', { name: 'Add new' })).not.toBeVisible(); await expect(page.getByRole('button', { name: 'Refresh' })).not.toBeVisible(); }); +}); - test('add fields', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(oneEmptyListBlock).waitForInit(); - await mockRecord('general'); - await nocoPage.goto(); - - const formItemInitializer = page - .getByLabel('schema-initializer-Grid-ReadPrettyFormItemInitializers-general') - .first(); - - // add fields - await formItemInitializer.hover(); - await page.getByRole('menuitem', { name: 'ID' }).click(); - await expect(page.getByRole('menuitem', { name: 'ID' }).getByRole('switch')).toBeChecked(); - - // add association fields - await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); - await page.getByRole('menuitem', { name: 'Nickname' }).click(); - - // TODO: 二级菜单点击后,不应该被关闭;只有在鼠标移出下拉列表的时候,才应该被关闭 - await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); - await expect(page.getByRole('menuitem', { name: 'Nickname' }).getByRole('switch')).toBeChecked(); - - await page.mouse.move(300, 0); - await expect(page.getByLabel('block-item-CollectionField-general-list-general.id-ID').first()).toBeVisible(); - await expect( - page.getByLabel('block-item-CollectionField-general-list-general.manyToOne.nickname').first(), - ).toBeVisible(); - - // delete fields - await formItemInitializer.hover(); - await page.getByRole('tooltip').getByText('Display association fields').hover(); - await page.mouse.wheel(0, -300); - await page.getByRole('menuitem', { name: 'ID' }).click(); - await expect(page.getByRole('menuitem', { name: 'ID' }).getByRole('switch')).not.toBeChecked(); - - await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); - await page.getByRole('menuitem', { name: 'Nickname' }).click(); - - await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); - await expect(page.getByRole('menuitem', { name: 'Nickname' }).getByRole('switch')).not.toBeChecked(); - - await page.mouse.move(300, 0); - await expect(page.getByLabel('block-item-CollectionField-general-list-general.id-ID').first()).not.toBeVisible(); - await expect( - page.getByLabel('block-item-CollectionField-general-list-general.manyToOne.nickname').first(), - ).not.toBeVisible(); - - // add text - await formItemInitializer.hover(); - await page.getByRole('menuitem', { name: 'Add text' }).click(); - await expect(page.getByLabel('block-item-Markdown.Void-general-list').first()).toBeVisible(); - }); - - test('add item actions', async ({ page, mockPage, mockRecord }) => { +test.describe('configure item actions', () => { + test('view & edit & delete', async ({ page, mockPage, mockRecord }) => { const nocoPage = await mockPage(oneEmptyListBlock).waitForInit(); await mockRecord('general'); await nocoPage.goto(); @@ -122,7 +81,7 @@ test.describe('List', () => { await expect(page.getByLabel('action-Action.Link-Delete-destroy-general-list').first()).not.toBeVisible(); }); - test('add custom action buttons', async ({ page, mockPage, mockRecord }) => { + test('customize: popup & update record', async ({ page, mockPage, mockRecord }) => { const nocoPage = await mockPage(oneEmptyListBlock).waitForInit(); await mockRecord('general'); await nocoPage.goto(); @@ -139,3 +98,58 @@ test.describe('List', () => { ).toBeVisible(); }); }); + +test.describe('configure fields', () => { + test('display collection fields & display association fields & add text', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneEmptyListBlock).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + + const formItemInitializer = page + .getByLabel('schema-initializer-Grid-ReadPrettyFormItemInitializers-general') + .first(); + + // add fields + await formItemInitializer.hover(); + await page.getByRole('menuitem', { name: 'ID', exact: true }).click(); + await expect(page.getByRole('menuitem', { name: 'ID', exact: true }).getByRole('switch')).toBeChecked(); + + // add association fields + await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); + await page.getByRole('menuitem', { name: 'Nickname' }).click(); + + // TODO: 二级菜单点击后,不应该被关闭;只有在鼠标移出下拉列表的时候,才应该被关闭 + await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); + await expect(page.getByRole('menuitem', { name: 'Nickname' }).getByRole('switch')).toBeChecked(); + + await page.mouse.move(300, 0); + await expect(page.getByLabel('block-item-CollectionField-general-list-general.id-ID').first()).toBeVisible(); + await expect( + page.getByLabel('block-item-CollectionField-general-list-general.manyToOne.nickname').first(), + ).toBeVisible(); + + // delete fields + await formItemInitializer.hover(); + await page.getByRole('tooltip').getByText('Display association fields').hover(); + await page.mouse.wheel(0, -300); + await page.getByRole('menuitem', { name: 'ID', exact: true }).click(); + await expect(page.getByRole('menuitem', { name: 'ID', exact: true }).getByRole('switch')).not.toBeChecked(); + + await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); + await page.getByRole('menuitem', { name: 'Nickname' }).click(); + + await page.getByRole('menuitem', { name: 'Many to one' }).nth(1).hover(); + await expect(page.getByRole('menuitem', { name: 'Nickname' }).getByRole('switch')).not.toBeChecked(); + + await page.mouse.move(300, 0); + await expect(page.getByLabel('block-item-CollectionField-general-list-general.id-ID').first()).not.toBeVisible(); + await expect( + page.getByLabel('block-item-CollectionField-general-list-general.manyToOne.nickname').first(), + ).not.toBeVisible(); + + // add text + await formItemInitializer.hover(); + await page.getByRole('menuitem', { name: 'Add text' }).click(); + await expect(page.getByLabel('block-item-Markdown.Void-general-list').first()).toBeVisible(); + }); +}); diff --git a/packages/core/client/src/modules/list/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/list/__e2e__/schemaSettings.test.ts new file mode 100644 index 000000000..886c485fd --- /dev/null +++ b/packages/core/client/src/modules/list/__e2e__/schemaSettings.test.ts @@ -0,0 +1,25 @@ +import { expectSettingsMenu, oneEmptyListBlock, test } from '@nocobase/test/client'; + +test.describe('list block schema settings', () => { + test('supported options', async ({ page, mockPage }) => { + await mockPage(oneEmptyListBlock).goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByLabel('block-item-CardItem-general-list').hover(); + await page.getByLabel('designer-schema-settings-CardItem-List.Designer-general').hover(); + }, + supportedOptions: [ + 'Edit block title', + 'Set the data scope', + 'Set default sorting rules', + 'Records per page', + 'Save as template', + 'Delete', + ], + }); + }); +}); + +test.describe('actions schema settings', () => {}); diff --git a/packages/core/client/src/modules/list/__e2e__/templatesOfBug.ts b/packages/core/client/src/modules/list/__e2e__/templatesOfBug.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/core/client/src/modules/markdown/__e2e__/schemaInitializer.test.ts b/packages/core/client/src/modules/markdown/__e2e__/schemaInitializer.test.ts new file mode 100644 index 000000000..65b370910 --- /dev/null +++ b/packages/core/client/src/modules/markdown/__e2e__/schemaInitializer.test.ts @@ -0,0 +1,11 @@ +import { createBlockInPage, expect, test } from '@nocobase/test/client'; + +test.describe('where markdown block can be added', () => { + test('page', async ({ page, mockPage }) => { + await mockPage().goto(); + + await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); + await createBlockInPage(page, 'Markdown'); + await expect(page.getByLabel('block-item-Markdown.Void-markdown')).toBeVisible(); + }); +}); diff --git a/packages/core/client/src/modules/markdown/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/markdown/__e2e__/schemaSettings.test.ts new file mode 100644 index 000000000..b9382fdeb --- /dev/null +++ b/packages/core/client/src/modules/markdown/__e2e__/schemaSettings.test.ts @@ -0,0 +1,31 @@ +import { expect, expectSettingsMenu, oneEmptyMarkdown, test } from '@nocobase/test/client'; + +test.describe('markdown block schema settings', () => { + test('supported options', async ({ page, mockPage }) => { + await mockPage(oneEmptyMarkdown).goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByLabel('block-item-Markdown.Void-markdown').hover(); + await page.getByLabel('designer-schema-settings-Markdown.Void-Markdown.Void.Designer').hover(); + }, + supportedOptions: ['Edit markdown', 'Delete'], + }); + }); + + test('edit markdown', async ({ page, mockPage }) => { + await mockPage(oneEmptyMarkdown).goto(); + + await page.getByLabel('block-item-Markdown.Void-markdown').hover(); + await page.getByLabel('designer-schema-settings-Markdown.Void-Markdown.Void.Designer').hover(); + await page.getByRole('menuitem', { name: 'Edit markdown' }).click(); + + // 输入新的值,并保存 + await page.getByLabel('block-item-Markdown.Void-markdown').getByRole('textbox').click(); + await page.getByLabel('block-item-Markdown.Void-markdown').getByRole('textbox').fill('hello markdown'); + await page.getByRole('button', { name: 'Save' }).click(); + + await expect(page.getByLabel('block-item-Markdown.Void-markdown').getByText('hello markdown')).toBeVisible(); + }); +}); diff --git a/packages/core/client/src/modules/markdown/__e2e__/templatesOfBug.ts b/packages/core/client/src/modules/markdown/__e2e__/templatesOfBug.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/core/client/src/modules/menu/__e2e__/dragAndDrop.test.ts b/packages/core/client/src/modules/menu/__e2e__/dragAndDrop.test.ts new file mode 100644 index 000000000..df999bd1f --- /dev/null +++ b/packages/core/client/src/modules/menu/__e2e__/dragAndDrop.test.ts @@ -0,0 +1,22 @@ +import { expect, test } from '@nocobase/test/client'; + +test('single page', async ({ page, mockPage }) => { + const pageTitle1 = 'page1'; + const pageTitle2 = 'page2'; + await mockPage({ + name: pageTitle1, + }).goto(); + await mockPage({ name: pageTitle2 }).goto(); + await page.getByRole('menu').getByText(pageTitle1).click(); + await page.getByRole('menu').getByText(pageTitle1).hover(); + await page.getByLabel(pageTitle1).getByLabel('designer-schema-settings').hover(); + await page.getByRole('menuitem', { name: 'Move to' }).click(); + await page.getByRole('dialog').click(); + await page.getByLabel('Search').click(); + await page.locator('.ant-select-dropdown').getByText(pageTitle2).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + const page1 = await page.getByRole('menu').getByText(pageTitle1).boundingBox(); + const page2 = await page.getByRole('menu').getByText(pageTitle2).boundingBox(); + //拖拽菜单排序符合预期 + expect(page2.x).toBeLessThan(page1.x); +}); diff --git a/packages/core/client/src/__tests__/e2e/schemaInitializer/menu.test.ts b/packages/core/client/src/modules/menu/__e2e__/schemaInitializer.test.ts similarity index 98% rename from packages/core/client/src/__tests__/e2e/schemaInitializer/menu.test.ts rename to packages/core/client/src/modules/menu/__e2e__/schemaInitializer.test.ts index 713b0c788..ed8db1585 100644 --- a/packages/core/client/src/__tests__/e2e/schemaInitializer/menu.test.ts +++ b/packages/core/client/src/modules/menu/__e2e__/schemaInitializer.test.ts @@ -1,6 +1,6 @@ import { expect, groupPageEmpty, test } from '@nocobase/test/client'; -test.describe('Menu', () => { +test.describe('add menu item', () => { test('header', async ({ page, deletePage }) => { await page.goto('/'); diff --git a/packages/core/client/src/modules/menu/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/menu/__e2e__/schemaSettings.test.ts new file mode 100644 index 000000000..9f3c5069b --- /dev/null +++ b/packages/core/client/src/modules/menu/__e2e__/schemaSettings.test.ts @@ -0,0 +1,225 @@ +import { Page, PageConfig, expect, expectSettingsMenu, test } from '@nocobase/test/client'; + +test.describe('group page menus schema settings', () => { + test('edit', async ({ page, mockPage }) => { + await mockPage({ type: 'group', name: 'group page' }).goto(); + await showSettings(page, 'group page'); + await page.getByRole('menuitem', { name: 'Edit' }).click(); + await page.mouse.move(300, 0); + + // 设置一个新名称 + await page.getByRole('textbox').click(); + await page.getByRole('textbox').fill('new group page'); + // 设置一个图标 + await page.getByRole('button', { name: 'Select icon' }).click(); + await page.getByRole('tooltip').getByLabel('account-book').locator('svg').click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + await page.reload(); + + await expect(page.getByLabel('new group page')).toBeVisible(); + await expect(page.getByLabel('new group page').getByLabel('account-book').locator('svg')).toBeVisible(); + }); + + test('move to', async ({ page, mockPage }) => { + await mockPage({ type: 'group', name: 'anchor page' }).waitForInit(); + await mockPage({ type: 'group', name: 'a other group page' }).waitForInit(); + await mockPage({ type: 'group', name: 'group page' }).goto(); + + // 默认情况下的排列顺序:anchor page, group page + await expect(page.getByText('anchor pagea other group pagegroup page')).toBeVisible(); + + // 移动到 anchor page 之前 -------------------------------------------- + await showSettings(page, 'group page'); + await page.getByRole('menuitem', { name: 'Move to' }).click(); + await page.mouse.move(300, 0); + await page.getByRole('dialog').getByLabel('Search').click(); + await page.locator('.ant-select-dropdown').getByText('anchor page').click(); + await page.getByLabel('Before').click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + await expect(page.getByText('group pageanchor pagea other group page')).toBeVisible(); + + // 移动到 anchor page 之后 + await showSettings(page, 'group page'); + await page.getByRole('menuitem', { name: 'Move to' }).click(); + await page.mouse.move(300, 0); + await page.getByRole('dialog').getByLabel('Search').click(); + await page.locator('.ant-select-dropdown').getByText('anchor page').click(); + await page.getByLabel('After').click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + await expect(page.getByText('anchor pagegroup pagea other group page')).toBeVisible(); + + // 移动到 anchor page 内部 -------------------------------------------- + await showSettings(page, 'group page'); + await page.getByRole('menuitem', { name: 'Move to' }).click(); + await page.mouse.move(300, 0); + await page.getByLabel('Search').click(); + await page.locator('.ant-select-dropdown').getByText('anchor page').click(); + await page.getByLabel('Inner').click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + // 当前页面菜单会消失 + await expect(page.getByLabel('group page', { exact: true })).not.toBeVisible(); + // 跳转到 anchor page 页面,会有一个名为 group page 的子页面菜单 + await page.getByLabel('anchor page').click(); + await expect(page.locator('.ant-layout-sider').getByLabel('group page')).toBeVisible(); + + // 移动到子页面菜单之前 -------------------------------------------- + await showSettings(page, 'a other group page'); + await page.getByRole('menuitem', { name: 'Move to' }).click(); + await page.mouse.move(300, 0); + await page.getByRole('dialog').getByLabel('Search').click(); + await page.getByLabel('caret-down').locator('svg').click(); + await page.locator('.ant-select-dropdown').getByText('group page', { exact: true }).click(); + await page.getByLabel('Before').click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + await expect(page.locator('.ant-layout-sider').getByText('a other group pagegroup page')).toBeVisible(); + }); + + test('insert before', async ({ page, mockPage, deletePage }) => { + await mockPage({ name: 'single page' }).goto(); + + // 在 single page 之前插入一个 group page + await showSettings(page, 'single page'); + await page.getByRole('menuitem', { name: 'Insert before' }).hover(); + await page.getByRole('menuitem', { name: 'Group', exact: true }).click(); + await page.getByLabel('block-item-Input-Menu item title').getByRole('textbox').click(); + await page.getByLabel('block-item-Input-Menu item title').getByRole('textbox').fill('group page'); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + await expect(page.locator('.ant-layout-header').getByText('group pagesingle page')).toBeVisible(); + + await deletePage('group page'); + }); + + test('insert after', async ({ page, mockPage, deletePage }) => { + await mockPage({ name: 'single page' }).goto(); + + // 在 single page 之后插入一个 group page + await showSettings(page, 'single page'); + await page.getByRole('menuitem', { name: 'Insert after' }).hover(); + await page.getByRole('menuitem', { name: 'Group', exact: true }).click(); + await page.getByLabel('block-item-Input-Menu item title').getByRole('textbox').click(); + await page.getByLabel('block-item-Input-Menu item title').getByRole('textbox').fill('group page'); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + await expect(page.locator('.ant-layout-header').getByText('single pagegroup page')).toBeVisible(); + + await deletePage('group page'); + }); + + test('insert inner', async ({ page, mockPage }) => { + await mockPage({ type: 'group', name: 'group page' }).goto(); + + // 在 group page 内部插入一个 single page + await showSettings(page, 'group page'); + await page.getByRole('menuitem', { name: 'Insert inner' }).hover(); + await page.getByRole('menuitem', { name: 'Page', exact: true }).click(); + await page.getByLabel('block-item-Input-Menu item title').getByRole('textbox').click(); + await page.getByLabel('block-item-Input-Menu item title').getByRole('textbox').fill('single page'); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + await expect(page.locator('.ant-layout-sider').getByText('single page')).toBeVisible(); + }); + + test('delete', async ({ page, mockPage }) => { + await mockPage({ type: 'group', name: 'group page' }).goto(); + await expect(page.getByLabel('group page')).toBeVisible(); + + await showSettings(page, 'group page'); + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 现在需要刷新一下页面,被删除的页面内容才会消失 + await page.reload(); + await expect(page.getByLabel('group page')).not.toBeVisible(); + }); +}); + +test.describe('group page side menus schema settings', () => { + test('group page', async ({ page, mockPage }) => { + await mockPage({ type: 'group', name: 'group page' }).goto(); + await createSubPage({ page, type: 'group', name: 'group page in side' }); + + await expectSettingsMenu({ + page, + showMenu: () => showSettingsInSide(page, 'group page in side'), + supportedOptions: ['Edit', 'Move to', 'Insert before', 'Insert after', 'Insert inner', 'Delete'], + }); + }); + + test('link page', async ({ page, mockPage }) => { + await mockPage({ type: 'group', name: 'group page' }).goto(); + await createSubPage({ page, type: 'link', name: 'link page in side' }); + + await expectSettingsMenu({ + page, + showMenu: () => showSettingsInSide(page, 'link page in side'), + supportedOptions: ['Edit', 'Move to', 'Insert before', 'Insert after', 'Delete'], + }); + }); + + test('single page', async ({ page, mockPage }) => { + await mockPage({ type: 'group', name: 'group page' }).goto(); + await createSubPage({ page, type: 'page', name: 'single page in side' }); + + await expectSettingsMenu({ + page, + showMenu: () => showSettingsInSide(page, 'single page in side'), + supportedOptions: ['Edit', 'Move to', 'Insert before', 'Insert after', 'Delete'], + }); + }); +}); + +test.describe('link page menu schema settings', () => { + test('supported options', async ({ page, mockPage }) => { + await mockPage({ type: 'link', name: 'link page' }).goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.locator('.ant-layout-header').getByText('link page', { exact: true }).hover(); + await page.getByRole('button', { name: 'designer-schema-settings-' }).hover(); + }, + supportedOptions: ['Edit', 'Move to', 'Insert before', 'Insert after', 'Delete'], + }); + }); +}); + +test.describe('single page menu schema settings', () => { + test('supported options', async ({ page, mockPage }) => { + await mockPage({ name: 'single page' }).goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.locator('.ant-layout-header').getByText('single page', { exact: true }).hover(); + await page.getByRole('button', { name: 'designer-schema-settings-' }).hover(); + }, + supportedOptions: ['Edit', 'Move to', 'Insert before', 'Insert after', 'Delete'], + }); + }); +}); + +async function showSettingsInSide(page: Page, pageName: string) { + await page.locator('.ant-layout-sider').getByText(pageName, { exact: true }).hover(); + await page.getByRole('button', { name: 'designer-schema-settings-' }).hover(); +} + +async function showSettings(page: Page, pageName: string) { + await page.locator('.ant-layout-header').getByText(pageName, { exact: true }).hover(); + await page.getByRole('button', { name: 'designer-schema-settings-' }).hover(); +} + +async function createSubPage({ page, name, type }: { page: Page; name: string; type: PageConfig['type'] }) { + const typeToOptionName = { + group: 'Group', + page: 'Page', + link: 'Link', + }; + + await page.getByTestId('schema-initializer-Menu-side').hover(); + await page.getByRole('menuitem', { name: typeToOptionName[type], exact: true }).click(); + await page.getByLabel('block-item-Input-Menu item title').getByRole('textbox').click(); + await page.getByLabel('block-item-Input-Menu item title').getByRole('textbox').fill(name); + await page.getByRole('button', { name: 'OK', exact: true }).click(); +} diff --git a/packages/core/client/src/modules/menu/__e2e__/templatesOfBug.ts b/packages/core/client/src/modules/menu/__e2e__/templatesOfBug.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/core/client/src/modules/page/__e2e__/dragAndDrop.test.ts b/packages/core/client/src/modules/page/__e2e__/dragAndDrop.test.ts new file mode 100644 index 000000000..6d41a8158 --- /dev/null +++ b/packages/core/client/src/modules/page/__e2e__/dragAndDrop.test.ts @@ -0,0 +1,21 @@ +import { expect, test, twoTabsPage } from '@nocobase/test/client'; + +test('tabs', async ({ page, mockPage }) => { + await mockPage(twoTabsPage).goto(); + + const sourceElement = page.locator('span:has-text("tab 2")'); + await sourceElement.hover(); + const source = page.getByRole('button', { name: 'drag' }); + await source.hover(); + const targetElement = page.locator('span:has-text("tab 1")'); + const sourceBoundingBox = await sourceElement.boundingBox(); + const targetBoundingBox = await targetElement.boundingBox(); + //拖拽标签调整排序 拖拽前 1-2 + expect(targetBoundingBox.x).toBeLessThan(sourceBoundingBox.x); + await source.dragTo(targetElement); + await sourceElement.dragTo(targetElement); + const tab2 = await page.locator('span:has-text("tab 2")').boundingBox(); + const tab1 = await page.locator('span:has-text("tab 1")').boundingBox(); + //拖拽后 2-1 + expect(tab2.x).toBeLessThan(tab1.x); +}); diff --git a/packages/core/client/src/modules/page/__e2e__/schemaInitailizer.test.ts b/packages/core/client/src/modules/page/__e2e__/schemaInitailizer.test.ts new file mode 100644 index 000000000..f166ec45c --- /dev/null +++ b/packages/core/client/src/modules/page/__e2e__/schemaInitailizer.test.ts @@ -0,0 +1,13 @@ +import { expect, tabPageEmpty, test } from '@nocobase/test/client'; + +test('add tab', async ({ page, mockPage }) => { + await mockPage(tabPageEmpty).goto(); + + // add tab page + await page.getByLabel('schema-initializer-Page-tabs').click(); + await page.getByRole('textbox').click(); + await page.getByRole('textbox').fill('tab1'); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + await expect(page.getByText('tab1', { exact: true })).toBeVisible(); +}); diff --git a/packages/core/client/src/modules/page/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/page/__e2e__/schemaSettings.test.ts new file mode 100644 index 000000000..370ff09f8 --- /dev/null +++ b/packages/core/client/src/modules/page/__e2e__/schemaSettings.test.ts @@ -0,0 +1,103 @@ +import { Page, expect, test } from '@nocobase/test/client'; + +test.describe('page schema settings', () => { + const showMenu = async (page: Page) => { + await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); + await page.getByLabel('designer-schema-settings-Page').hover(); + }; + + test('enable page header & display page title & edit page title & enable page tabs', async ({ page, mockPage }) => { + await mockPage({ name: 'page' }).goto(); + + // 选项:Enable page header --------------------------------------------------------------------------------- + await expect(page.locator('.ant-page-header')).toBeVisible(); + await showMenu(page); + // 默认开启 + await expect(page.getByRole('menuitem', { name: 'Enable page header' }).getByRole('switch')).toBeChecked(); + await page.getByRole('menuitem', { name: 'Enable page header' }).click(); + await expect(page.getByRole('menuitem', { name: 'Enable page header' }).getByRole('switch')).not.toBeChecked(); + // 标题应该被隐藏 + await expect(page.locator('.ant-page-header')).not.toBeVisible(); + // 其它开关也应该被隐藏 + await expect(page.getByRole('menuitem', { name: 'Display page title' })).not.toBeVisible(); + + // 选项:Display page title --------------------------------------------------------------------------------- + // 再次开启,显示出 Display page title + await page.getByRole('menuitem', { name: 'Enable page header' }).click(); + await expect(page.getByRole('menuitem', { name: 'Display page title' }).getByRole('switch')).toBeChecked(); + await page.getByRole('menuitem', { name: 'Display page title' }).click(); + await expect(page.getByRole('menuitem', { name: 'Display page title' }).getByRole('switch')).not.toBeChecked(); + // 标题应该被隐藏 + await expect(page.locator('.ant-page-header').getByText('page')).not.toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Edit page title' })).not.toBeVisible(); + + // 选项:Edit page title ------------------------------------------------------------------------------------ + // 再次开启,显示出 Edit page title + await page.getByRole('menuitem', { name: 'Display page title' }).click(); + await page.getByRole('menuitem', { name: 'Edit page title' }).click(); + await page.getByLabel('block-item-Input-Title').getByRole('textbox').fill('new page title'); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + await expect(page.getByText('new page title')).toBeVisible(); + + // 选项:Enable page tabs ----------------------------------------------------------------------------------- + await showMenu(page); + // 默认关闭 + await expect(page.getByRole('menuitem', { name: 'Enable page tabs' }).getByRole('switch')).not.toBeChecked(); + await page.getByRole('menuitem', { name: 'Enable page tabs' }).click(); + await expect(page.getByRole('menuitem', { name: 'Enable page tabs' }).getByRole('switch')).toBeChecked(); + await page.mouse.move(300, 0); + // 标签选项应该显示 + await expect(page.getByLabel('schema-initializer-Page-tabs')).toBeVisible(); + // 添加一个新的 tab 页 + await page.getByLabel('schema-initializer-Page-tabs').click(); + await page.getByLabel('block-item-Input-Tab name').getByRole('textbox').click(); + await page.getByLabel('block-item-Input-Tab name').getByRole('textbox').fill('new tab'); + // 选择一个图标 + await page.getByRole('button', { name: 'Select icon' }).click(); + await page.getByLabel('account-book').locator('svg').click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + await expect(page.getByText('new tab')).toBeVisible(); + await expect(page.getByLabel('account-book').locator('svg')).toBeVisible(); + }); +}); + +test.describe('tabs schema settings', () => { + async function showSettings(page: Page) { + await page.getByText('Unnamed').hover(); + await page.getByRole('tab').getByLabel('designer-schema-settings-Page').hover(); + } + + async function enablePageTabs(page) { + await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Page' }).hover(); + await page.getByRole('menuitem', { name: 'Enable page tabs' }).click(); + await page.mouse.move(300, 0); + } + + test('edit', async ({ page, mockPage }) => { + await mockPage().goto(); + await enablePageTabs(page); + + await showSettings(page); + await page.getByRole('menuitem', { name: 'Edit', exact: true }).click(); + await page.getByLabel('block-item-Input-Tab name').getByRole('textbox').click(); + await page.getByLabel('block-item-Input-Tab name').getByRole('textbox').fill('new name of page tab'); + await page.getByRole('button', { name: 'Select icon' }).click(); + await page.getByLabel('account-book').locator('svg').click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + await expect(page.getByText('new name of page tab')).toBeVisible(); + await expect(page.getByLabel('account-book').locator('svg')).toBeVisible(); + }); + + test('delete', async ({ page, mockPage }) => { + await mockPage().goto(); + await enablePageTabs(page); + + await showSettings(page); + await page.getByRole('menuitem', { name: 'Delete', exact: true }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + await expect(page.getByText('Unnamed')).toBeHidden(); + }); +}); diff --git a/packages/core/client/src/modules/page/__e2e__/templatesOfBug.ts b/packages/core/client/src/modules/page/__e2e__/templatesOfBug.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/core/client/src/__tests__/e2e/pm.test.ts b/packages/core/client/src/modules/plugin-manager/__e2e__/pluginManager.test.ts similarity index 78% rename from packages/core/client/src/__tests__/e2e/pm.test.ts rename to packages/core/client/src/modules/plugin-manager/__e2e__/pluginManager.test.ts index e80d3af34..87c4f7d69 100644 --- a/packages/core/client/src/__tests__/e2e/pm.test.ts +++ b/packages/core/client/src/modules/plugin-manager/__e2e__/pluginManager.test.ts @@ -7,13 +7,13 @@ async function waitForModalToBeHidden(page) { const computedStyle = window.getComputedStyle(modal); return computedStyle.display === 'none' || computedStyle.visibility === 'hidden'; } - return true; // 如果找不到modal,也算作不可见 + return true; // if the modal cannot be found, consider it hidden }); } test.describe('add plugin in front', () => { test.slow(); - test('add plugin npm registry,then remove plugin', async ({ page, mockPage }) => { + test('add plugin from npm registry, then remove plugin', async ({ page, mockPage }) => { await mockPage().goto(); await page.getByTestId('plugin-manager-button').click(); await expect(page.getByLabel('sample-custom-collection-template')).not.toBeVisible(); @@ -23,70 +23,70 @@ test.describe('add plugin in front', () => { .getByRole('textbox') .fill('@nocobase/plugin-sample-custom-collection-template'); await page.getByLabel('Submit').click(); - //等待页面刷新结束 + // wait for the page to finish refreshing await page.waitForFunction(() => { const modal = document.querySelector('.ant-modal'); if (modal) { const computedStyle = window.getComputedStyle(modal); return computedStyle.display === 'none' || computedStyle.visibility === 'hidden'; } - return true; // 如果找不到modal,也算作不可见 + return true; // if the modal cannot be found, consider it hidden }); await page.waitForLoadState('load'); await page.getByPlaceholder('Search plugin').fill('sample-custom-collection-template'); await expect(page.getByLabel('sample-custom-collection-template')).toBeVisible(); - //将添加的插件删除 + // remove the added plugin await page.getByLabel('sample-custom-collection-template').getByText('Remove').click(); await page.getByRole('button', { name: 'Yes' }).click(); await page.waitForTimeout(300); - //等待页面刷新结束 + // wait for the page to finish refreshing await waitForModalToBeHidden(page); await page.waitForLoadState('load'); await page.getByPlaceholder('Search plugin').fill('sample-custom-collection-template'); await expect(page.getByLabel('sample-custom-collection-template')).not.toBeVisible(); }); - test.skip('add plugin local upload', async ({ page, mockPage }) => {}); - test.skip('add plugin file url', async ({ page, mockPage }) => {}); + test.skip('add plugin from local upload', async ({ page, mockPage }) => {}); + test.skip('add plugin from file URL', async ({ page, mockPage }) => {}); }); test.describe('remove plugin', () => { test.slow(); - test('remove plugin,then add plugin', async ({ page, mockPage }) => { + test('remove plugin, then add plugin', async ({ page, mockPage }) => { await mockPage().goto(); await page.getByTestId('plugin-manager-button').click(); - //hello插件默认安装未启用 + // the Hello plugin is not enabled by default await page.getByPlaceholder('Search plugin').fill('Hello'); await expect(page.getByLabel('Hello')).toBeVisible(); const isActive = await page.getByLabel('Hello').getByLabel('enable').isChecked(); expect(isActive).toBe(false); - //将hello插件remove + // remove the Hello plugin await page.getByLabel('Hello').getByText('Remove').click(); await page.getByRole('button', { name: 'Yes' }).click(); - //等待页面刷新结束 + // wait for the page to finish refreshing await waitForModalToBeHidden(page); await page.waitForLoadState('load'); await page.getByPlaceholder('Search plugin').fill('hello'); await expect(page.getByLabel('Hello')).not.toBeVisible(); - //将删除的插件加回来 + // add the removed plugin back await page.getByRole('button', { name: 'Add new' }).click(); await page .getByLabel('block-item-Input-Npm package name') .getByRole('textbox') .fill('@nocobase/plugin-sample-hello'); await page.getByLabel('Submit').click(); - //等待弹窗消失和页面刷新结束 + // wait for the modal to disappear and the page to finish refreshing await page.waitForFunction(() => { const modal = document.querySelector('.ant-modal'); if (modal) { const computedStyle = window.getComputedStyle(modal); return computedStyle.display === 'none' || computedStyle.visibility === 'hidden'; } - return true; // 如果找不到modal,也算作不可见 + return true; // if the modal cannot be found, consider it hidden }); await page.waitForLoadState('load'); await page.getByPlaceholder('Search plugin').fill('hello'); await expect(page.getByLabel('Hello')).toBeVisible(); - //已启用的插件不能remove,如ACL + // cannot remove enabled plugins like ACL await page.getByPlaceholder('Search plugin').fill('ACL'); await expect(page.getByLabel('ACL')).toBeVisible(); const isAclActive = await page.getByLabel('ACL').getByLabel('enable').isChecked(); @@ -95,7 +95,7 @@ test.describe('remove plugin', () => { }); }); -test.describe('enable & disabled plugin', () => { +test.describe('enable & disable plugin', () => { test.slow(); test('enable plugin', async ({ page, mockPage }) => { await mockPage().goto(); @@ -103,17 +103,17 @@ test.describe('enable & disabled plugin', () => { await page.getByPlaceholder('Search plugin').fill('hello'); await expect(page.getByLabel('Hello')).toBeVisible(); await expect(page.getByLabel('Hello').getByLabel('enable')).not.toBeChecked(); - //激活插件 + // activate the plugin await page.getByLabel('Hello').getByLabel('enable').click(); - await page.waitForTimeout(1000); // 等待1秒钟 - //等待弹窗消失和页面刷新结束 + await page.waitForTimeout(1000); // Wait for 1 second + // wait for the modal to disappear and the page to finish refreshing await waitForModalToBeHidden(page); await page.waitForLoadState('load'); await page.getByPlaceholder('Search plugin').fill('hello'); await expect(page.getByLabel('Hello').getByLabel('enable')).toBeChecked(); - //将激活的插件禁用 + // disable the activated plugin await page.getByLabel('Hello').getByLabel('enable').click(); - //等待弹窗消失和页面刷新结束 + // wait for the modal to disappear and the page to finish refreshing await waitForModalToBeHidden(page); await page.waitForLoadState('load'); await expect(page.getByLabel('Hello').getByLabel('enable')).not.toBeChecked(); diff --git a/packages/core/client/src/modules/plugin-manager/__e2e__/templatesOfBug.ts b/packages/core/client/src/modules/plugin-manager/__e2e__/templatesOfBug.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/core/client/src/modules/table-data-selector/__e2e__/schemaInitializer.test.ts b/packages/core/client/src/modules/table-data-selector/__e2e__/schemaInitializer.test.ts new file mode 100644 index 000000000..fedafe862 --- /dev/null +++ b/packages/core/client/src/modules/table-data-selector/__e2e__/schemaInitializer.test.ts @@ -0,0 +1,101 @@ +import { Page, expect, test } from '@nocobase/test/client'; +import { createTable } from './utils'; + +test.describe('where table data selector can be added', () => { + test('popup', async ({ page, mockPage, mockRecord }) => { + await createTable({ page, mockPage, fieldName: 'manyToOne' }); + + // 选中一行数据之后,弹窗自动关闭,且数据被填充到关联字段中 + await page.getByLabel('checkbox').click(); + await expect( + page + .getByLabel('block-item-CollectionField-general-form-general.manyToOne-manyToOne') + .getByTestId('select-data-picker'), + ).toHaveText(`1`); + }); +}); + +test.describe('configure actions', () => { + test('filter & add new & delete & refresh', async ({ page, mockPage }) => { + await createTable({ page, mockPage, fieldName: 'manyToOne' }); + + // add buttons + await page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-users').hover(); + await page.getByRole('menuitem', { name: 'Filter' }).click(); + await page.getByRole('menuitem', { name: 'Add new' }).click(); + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.getByRole('menuitem', { name: 'Refresh' }).click(); + + await expect(page.getByRole('menuitem', { name: 'Filter' }).getByRole('switch')).toBeChecked(); + await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).toBeChecked(); + await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).toBeChecked(); + await expect(page.getByRole('menuitem', { name: 'Refresh' }).getByRole('switch')).toBeChecked(); + + await page.mouse.move(300, 0); + await expect(page.getByRole('button', { name: 'Filter' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Add new' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Delete' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Refresh' })).toBeVisible(); + + // delete buttons + await page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-users').hover(); + await page.getByRole('menuitem', { name: 'Filter' }).click(); + await page.getByRole('menuitem', { name: 'Add new' }).click(); + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.getByRole('menuitem', { name: 'Refresh' }).click(); + + await expect(page.getByRole('menuitem', { name: 'Filter' }).getByRole('switch')).not.toBeChecked(); + await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).not.toBeChecked(); + await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).not.toBeChecked(); + await expect(page.getByRole('menuitem', { name: 'Refresh' }).getByRole('switch')).not.toBeChecked(); + + await page.mouse.move(300, 0); + await expect(page.getByRole('button', { name: 'Filter' })).not.toBeVisible(); + await expect(page.getByRole('button', { name: 'Add new' })).not.toBeVisible(); + await expect(page.getByRole('button', { name: 'Delete' })).not.toBeVisible(); + await expect(page.getByRole('button', { name: 'Refresh' })).not.toBeVisible(); + }); + + test('customize: bulk update', async ({ page, mockPage }) => { + await createTable({ page, mockPage, fieldName: 'manyToOne' }); + + await page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-users').hover(); + await page.getByRole('menuitem', { name: 'Customize' }).hover(); + await page.getByRole('menuitem', { name: 'Bulk update' }).click(); + + await page.mouse.move(300, 0); + await expect(page.getByRole('button', { name: 'Bulk update' })).toBeVisible(); + }); +}); + +test.describe('configure actions column', () => { + test('column width', async ({ page, mockPage }) => { + await createTable({ page, mockPage, fieldName: 'manyToOne' }); + await createActionColumn(page); + + // 列宽度默认为 200 + await expect(page.getByRole('columnheader', { name: 'Actions', exact: true })).toHaveJSProperty('offsetWidth', 200); + + await page.getByText('Actions', { exact: true }).hover(); + await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-users').hover(); + await page.getByRole('menuitem', { name: 'Column width' }).click(); + + await expect(page.getByRole('dialog').getByText('Column width')).toBeVisible(); + + // 修改列宽度为 400 + await page.getByRole('dialog').getByRole('spinbutton').click(); + await page.getByRole('dialog').getByRole('spinbutton').fill('400'); + await page.getByTestId('modal-Action.Modal-users-Column width').getByRole('button', { name: 'Submit' }).click(); + + // 关闭 settings 设置的下拉列表,不然获取不到宽度值 + await page.getByRole('menuitem', { name: 'Column width' }).hover(); + await page.mouse.move(300, 0); + + await expect(page.getByRole('columnheader', { name: 'Actions', exact: true })).toHaveJSProperty('offsetWidth', 400); + }); +}); + +async function createActionColumn(page: Page) { + await page.getByLabel('schema-initializer-TableV2.Selector-TableColumnInitializers-users').hover(); + await page.getByRole('menuitem', { name: 'Action column' }).click(); +} diff --git a/packages/core/client/src/modules/table-data-selector/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/table-data-selector/__e2e__/schemaSettings.test.ts new file mode 100644 index 000000000..f2bd3974d --- /dev/null +++ b/packages/core/client/src/modules/table-data-selector/__e2e__/schemaSettings.test.ts @@ -0,0 +1,19 @@ +import { expectSettingsMenu, test } from '@nocobase/test/client'; +import { createTable } from './utils'; + +test.describe('table data selector schema settings', () => { + test('supported options', async ({ page, mockPage }) => { + await createTable({ page, mockPage, fieldName: 'manyToOne' }); + + await expectSettingsMenu({ + page, + showMenu: () => showSettingsMenu(page), + supportedOptions: ['Set the data scope', 'Set default sorting rules', 'Records per page', 'Delete'], + }); + }); +}); + +async function showSettingsMenu(page) { + await page.getByLabel('block-item-CardItem-users-table-selector').hover(); + await page.getByLabel('designer-schema-settings-CardItem-TableSelectorDesigner-users').hover(); +} diff --git a/packages/core/client/src/modules/table-data-selector/__e2e__/templatesOfBug.ts b/packages/core/client/src/modules/table-data-selector/__e2e__/templatesOfBug.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/core/client/src/modules/table-data-selector/__e2e__/utils.ts b/packages/core/client/src/modules/table-data-selector/__e2e__/utils.ts new file mode 100644 index 000000000..4bdbb2e42 --- /dev/null +++ b/packages/core/client/src/modules/table-data-selector/__e2e__/utils.ts @@ -0,0 +1,24 @@ +import { NocoPage, Page, PageConfig, oneFormBlockWithAllAssociationFieldsAndSelectorMode } from '@nocobase/test/client'; + +export async function createTable({ + page, + mockPage, + fieldName, +}: { + fieldName: string; + page: Page; + mockPage: (config?: PageConfig) => NocoPage; +}) { + await mockPage(oneFormBlockWithAllAssociationFieldsAndSelectorMode).goto(); + + // open dialog + await page + .getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`) + .getByTestId('select-data-picker') + .click(); + + // create a table block + await page.getByLabel('schema-initializer-Grid-TableSelectorInitializers-users').hover(); + await page.getByRole('menuitem', { name: 'form Table' }).click(); + await page.mouse.move(300, 0); +} diff --git a/packages/core/client/src/modules/table-tree/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/table-tree/__e2e__/schemaSettings.test.ts new file mode 100644 index 000000000..a45472d42 --- /dev/null +++ b/packages/core/client/src/modules/table-tree/__e2e__/schemaSettings.test.ts @@ -0,0 +1,45 @@ +import { Page, expect, expectSettingsMenu, oneEmptyTableWithTreeCollection, test } from '@nocobase/test/client'; + +test.describe('tree table block schema settings', () => { + test('supported options', async ({ page, mockPage }) => { + await mockPage(oneEmptyTableWithTreeCollection).goto(); + + await expectSettingsMenu({ + page, + showMenu: () => showSettingsMenu(page), + supportedOptions: [ + 'Edit block title', + 'Tree table', + 'Enable drag and drop sorting', + 'Fix block', + 'Set the data scope', + 'Set default sorting rules', + 'Records per page', + 'Connect data blocks', + 'Save as template', + 'Delete', + ], + }); + }); + + // TODO: 这里的问题是:使用 mockRecords 生成固定数据,但是表格中的展开按钮有时显示有时不显示,导致测试不稳定,所以先注释掉了 + test('tree table', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(oneEmptyTableWithTreeCollection).waitForInit(); + // await mockRecords('treeCollection', 30); + await nocoPage.goto(); + + // 默认情况下的 tree table 是开启状态,且有显示展开按钮 + // await expect(page.getByLabel('Expand row').first()).toBeVisible({ timeout: 1000 * 60 }); + + await showSettingsMenu(page); + await expect(page.getByRole('menuitem', { name: 'Tree table' }).getByRole('switch')).toBeChecked(); + await page.getByRole('menuitem', { name: 'Tree table' }).click(); + await expect(page.getByRole('menuitem', { name: 'Tree table' }).getByRole('switch')).not.toBeChecked(); + // await expect(page.getByLabel('Expand row')).toBeHidden(); + }); +}); + +async function showSettingsMenu(page: Page) { + await page.getByLabel('block-item-CardItem-treeCollection-table').hover(); + await page.getByLabel('designer-schema-settings-CardItem-TableBlockDesigner-treeCollection').hover(); +} diff --git a/packages/core/client/src/modules/table-tree/__e2e__/templatesOfBug.ts b/packages/core/client/src/modules/table-tree/__e2e__/templatesOfBug.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/core/client/src/modules/table/__e2e__/actions/duplicate.test.ts b/packages/core/client/src/modules/table/__e2e__/actions/duplicate.test.ts new file mode 100644 index 000000000..c446851cd --- /dev/null +++ b/packages/core/client/src/modules/table/__e2e__/actions/duplicate.test.ts @@ -0,0 +1,14 @@ +import { expect, test } from '@nocobase/test/client'; +import { T2187 } from '../templatesOfBug'; + +// fix https://nocobase.height.app/T-2187 +test('BUG: in the Duplicate mode, the Roles field should not have a value after clicking it because it is not selected', async ({ + page, + mockPage, +}) => { + await mockPage(T2187).goto(); + + await page.getByLabel('action-Action.Link-Duplicate-duplicate-users-table-0').click(); + await expect(page.getByRole('textbox')).toHaveValue('Super Admin'); + await expect(page.getByTestId('select-object-multiple')).toHaveText(''); +}); diff --git a/packages/core/client/src/modules/table/__e2e__/actions/filter.test.ts b/packages/core/client/src/modules/table/__e2e__/actions/filter.test.ts new file mode 100644 index 000000000..b847cac00 --- /dev/null +++ b/packages/core/client/src/modules/table/__e2e__/actions/filter.test.ts @@ -0,0 +1,31 @@ +import { expect, test } from '@nocobase/test/client'; +import { T2183, T2186 } from '../templatesOfBug'; + +// fix https://nocobase.height.app/T-2183 +test('BUG: should save conditions', async ({ page, mockPage }) => { + await mockPage(T2183).goto(); + await page.getByLabel('action-Filter.Action-Filter-filter-users-table').click(); + await page.getByText('Add condition', { exact: true }).click(); + await page.getByTestId('select-filter-field').getByLabel('Search').click(); + await page.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); + await page.getByRole('button', { name: 'Save conditions' }).click(); + + await page.reload(); + await page.getByLabel('action-Filter.Action-Filter-filter-users-table').click(); + + // After refreshing the browser, the set field and operator should still be visible + await expect(page.getByTestId('select-filter-field').getByText('ID')).toBeVisible(); + await expect(page.getByTestId('select-filter-operator').getByText('is')).toBeVisible(); +}); + +// fix https://nocobase.height.app/T-2186 +test('BUG: the input box displayed should correspond to the field type', async ({ page, mockPage }) => { + await mockPage(T2186).goto(); + + await page.getByLabel('action-Filter.Action-Filter-filter-users-table').click(); + await page.getByTestId('select-filter-field').getByLabel('Search').click(); + await page.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); + + // 应该显示数字输入框 + await expect(page.getByRole('spinbutton')).toBeVisible(); +}); diff --git a/packages/core/client/src/modules/table/__e2e__/checkboxForTableRow.test.ts b/packages/core/client/src/modules/table/__e2e__/checkboxForTableRow.test.ts new file mode 100644 index 000000000..f920a059e --- /dev/null +++ b/packages/core/client/src/modules/table/__e2e__/checkboxForTableRow.test.ts @@ -0,0 +1,22 @@ +import { checkboxForTableRow, expect, test } from '@nocobase/test/client'; + +test('selects the checkbox of a table row and deletes the selected row', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(checkboxForTableRow).waitForInit(); + const records = await mockRecords('t_fhdhd0nk7b9', 3); + await nocoPage.goto(); + + await expect(page.getByText(records[0].f_vbrlno0zej9)).toBeVisible(); + + await page.getByLabel('table-index-1').hover(); + await page.getByRole('checkbox', { name: 'checkbox' }).click(); + await page.getByLabel('action-Action-Delete-destroy-t_fhdhd0nk7b9-table').click(); + + // 显示确认弹窗 + await expect(page.getByText('Are you sure you want to delete it?')).toBeVisible(); + + // 点击确认 + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 确认内容已被删除 + await expect(page.getByText(records[0].f_vbrlno0zej9)).not.toBeVisible(); +}); diff --git a/packages/core/client/src/modules/table/__e2e__/dragAndDrop.test.ts b/packages/core/client/src/modules/table/__e2e__/dragAndDrop.test.ts new file mode 100644 index 000000000..52bc2ba7b --- /dev/null +++ b/packages/core/client/src/modules/table/__e2e__/dragAndDrop.test.ts @@ -0,0 +1,32 @@ +import { expect, oneEmptyTableBlockBasedOnUsers, test } from '@nocobase/test/client'; + +test('actions', async ({ page, mockPage }) => { + await mockPage(oneEmptyTableBlockBasedOnUsers).goto(); + await page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-users').hover(); + //添加按钮 + await page.getByRole('menuitem', { name: 'Add new' }).click(); + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.getByRole('menuitem', { name: 'Refresh' }).click(); + // 向右挪动鼠标指针,用以关闭下拉列表 + await page.mouse.move(300, 0); + + const addNewBtn = page.getByLabel('action-Action-Add new-create-users-table'); + await addNewBtn.hover(); + const addNewDrag = page.getByLabel('action-Action-Add new-create-users-table').getByLabel('designer-drag'); + await addNewDrag.hover(); + + const delBtn = page.getByLabel('action-Action-Delete-destroy-users-table'); + await addNewDrag.dragTo(delBtn); + const refreshBtn = page.getByLabel('action-Action-Refresh-refresh-users-table'); + await addNewBtn.hover(); + await addNewBtn.getByLabel('designer-drag').dragTo(refreshBtn); + + const addNew = await addNewBtn.boundingBox(); + const del = await delBtn.boundingBox(); + const refresh = await refreshBtn.boundingBox(); + const max = Math.max(addNew.x, refresh.x, del.x); + //拖拽调整排序符合预期 + expect(addNew.x).toBe(max); +}); + +test('fields', async () => {}); diff --git a/packages/core/client/src/__tests__/e2e/schemaInitializer/tableBlock.test.ts b/packages/core/client/src/modules/table/__e2e__/schemaInitializer.test.ts similarity index 86% rename from packages/core/client/src/__tests__/e2e/schemaInitializer/tableBlock.test.ts rename to packages/core/client/src/modules/table/__e2e__/schemaInitializer.test.ts index 58b8a5806..bc5f0d296 100644 --- a/packages/core/client/src/__tests__/e2e/schemaInitializer/tableBlock.test.ts +++ b/packages/core/client/src/modules/table/__e2e__/schemaInitializer.test.ts @@ -1,7 +1,72 @@ -import { expect, oneEmptyTable, test } from '@nocobase/test/client'; +import { createBlockInPage, expect, oneEmptyTable, test } from '@nocobase/test/client'; -test.describe('Table', () => { - test('add column', async ({ page, mockPage }) => { +test.describe('where table block can be added', () => { + test('page', async ({ page, mockPage }) => { + await mockPage().goto(); + + await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); + await createBlockInPage(page, 'Table'); + await expect(page.getByLabel('block-item-CardItem-users-table')).toBeVisible(); + }); + + test('popup', async () => {}); +}); + +test.describe('configure actions', () => { + test('filter & add new & delete & refresh', async ({ page, mockPage }) => { + await mockPage(oneEmptyTable).goto(); + + // add buttons + await page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-t_unp4scqamw9').hover(); + await page.getByRole('menuitem', { name: 'Filter' }).click(); + await page.getByRole('menuitem', { name: 'Add new' }).click(); + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.getByRole('menuitem', { name: 'Refresh' }).click(); + + await expect(page.getByRole('menuitem', { name: 'Filter' }).getByRole('switch')).toBeChecked(); + await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).toBeChecked(); + await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).toBeChecked(); + await expect(page.getByRole('menuitem', { name: 'Refresh' }).getByRole('switch')).toBeChecked(); + + await page.mouse.move(300, 0); + await expect(page.getByRole('button', { name: 'Filter' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Add new' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Delete' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Refresh' })).toBeVisible(); + + // delete buttons + await page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-t_unp4scqamw9').hover(); + await page.getByRole('menuitem', { name: 'Filter' }).click(); + await page.getByRole('menuitem', { name: 'Add new' }).click(); + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.getByRole('menuitem', { name: 'Refresh' }).click(); + + await expect(page.getByRole('menuitem', { name: 'Filter' }).getByRole('switch')).not.toBeChecked(); + await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).not.toBeChecked(); + await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).not.toBeChecked(); + await expect(page.getByRole('menuitem', { name: 'Refresh' }).getByRole('switch')).not.toBeChecked(); + + await page.mouse.move(300, 0); + await expect(page.getByRole('button', { name: 'Filter' })).not.toBeVisible(); + await expect(page.getByRole('button', { name: 'Add new' })).not.toBeVisible(); + await expect(page.getByRole('button', { name: 'Delete' })).not.toBeVisible(); + await expect(page.getByRole('button', { name: 'Refresh' })).not.toBeVisible(); + }); + + test('customize: add record', async ({ page, mockPage }) => { + await mockPage(oneEmptyTable).goto(); + + await page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-t_unp4scqamw9').hover(); + await page.getByRole('menuitem', { name: 'Customize' }).hover(); + await page.getByRole('menuitem', { name: 'add record' }).click(); + + await page.mouse.move(300, 0); + await expect(page.getByRole('button', { name: 'Add record' })).toBeVisible(); + }); +}); + +test.describe('configure columns', () => { + test('action column & display collection fields & display association fields', async ({ page, mockPage }) => { await mockPage(oneEmptyTable).goto(); const configureColumnButton = page.getByLabel('schema-initializer-TableV2-TableColumnInitializers-t_unp4scqamw9'); @@ -11,10 +76,6 @@ test.describe('Table', () => { await expect(page.getByText('Actions', { exact: true })).toBeVisible(); await configureColumnButton.hover(); - // 滚动鼠标,以把底部的 Action column 选项显示出来 - await page.getByText('Display collection fields', { exact: true }).hover(); - await page.mouse.wheel(0, 300); - await expect(page.getByRole('menuitem', { name: 'Action column' }).getByRole('switch')).toBeChecked(); await page.getByRole('menuitem', { name: 'Action column' }).click(); await expect(page.getByRole('menuitem', { name: 'Action column' }).getByRole('switch')).not.toBeChecked(); @@ -25,19 +86,18 @@ test.describe('Table', () => { // 再次开启 Action column await configureColumnButton.hover(); - await page.mouse.wheel(0, 300); await page.getByRole('menuitem', { name: 'Action column' }).click(); await expect(page.getByRole('menuitem', { name: 'Action column' }).getByRole('switch')).toBeChecked(); await page.mouse.move(300, 0); await expect(page.getByText('Actions', { exact: true })).toBeVisible(); - // collection fields ------------------------------------------------------------- + // display collection fields ------------------------------------------------------------- await configureColumnButton.hover(); - await page.getByRole('menuitem', { name: 'ID' }).click(); + await page.getByRole('menuitem', { name: 'ID', exact: true }).click(); await page.getByRole('menuitem', { name: 'One to one (belongs to)' }).first().click(); await page.getByRole('menuitem', { name: 'One to one (has one)' }).first().click(); await page.getByRole('menuitem', { name: 'Many to one' }).first().click(); - await expect(page.getByRole('menuitem', { name: 'ID' }).getByRole('switch')).toBeChecked(); + await expect(page.getByRole('menuitem', { name: 'ID', exact: true }).getByRole('switch')).toBeChecked(); await expect(page.getByRole('menuitem', { name: 'One to one (belongs to)' }).getByRole('switch')).toBeChecked(); await expect(page.getByRole('menuitem', { name: 'One to one (has one)' }).getByRole('switch')).toBeChecked(); await expect(page.getByRole('menuitem', { name: 'Many to one' }).getByRole('switch')).toBeChecked(); @@ -48,11 +108,11 @@ test.describe('Table', () => { // 点击开关,删除创建的字段 await configureColumnButton.hover(); - await page.getByRole('menuitem', { name: 'ID' }).click(); + await page.getByRole('menuitem', { name: 'ID', exact: true }).click(); await page.getByRole('menuitem', { name: 'One to one (belongs to)' }).first().click(); await page.getByRole('menuitem', { name: 'One to one (has one)' }).first().click(); await page.getByRole('menuitem', { name: 'Many to one' }).first().click(); - await expect(page.getByRole('menuitem', { name: 'ID' }).getByRole('switch')).not.toBeChecked(); + await expect(page.getByRole('menuitem', { name: 'ID', exact: true }).getByRole('switch')).not.toBeChecked(); await expect(page.getByRole('menuitem', { name: 'One to one (belongs to)' }).getByRole('switch')).not.toBeChecked(); await expect(page.getByRole('menuitem', { name: 'One to one (has one)' }).getByRole('switch')).not.toBeChecked(); await expect(page.getByRole('menuitem', { name: 'Many to one' }).getByRole('switch')).not.toBeChecked(); @@ -62,7 +122,7 @@ test.describe('Table', () => { await expect(page.getByRole('button', { name: 'One to one (has one)', exact: true })).not.toBeVisible(); await expect(page.getByRole('button', { name: 'Many to one', exact: true })).not.toBeVisible(); - // association fields ------------------------------------------------------------- + // display association fields ------------------------------------------------------------- await configureColumnButton.hover(); await page.getByText('Display collection fields', { exact: true }).hover(); @@ -86,10 +146,11 @@ test.describe('Table', () => { await expect(page.getByRole('menuitem', { name: 'Nickname' }).getByRole('switch')).not.toBeChecked(); }); - // TODO: 继承表相关测试 - test.pgOnly('inherit column', async ({ page, mockPage }) => {}); + test.pgOnly('display inherit fields', async ({ page, mockPage }) => {}); +}); - test('add column action buttons', async ({ page, mockPage, mockRecord }) => { +test.describe('configure actions column', () => { + test('view & edit & delete & duplicate & customize', async ({ page, mockPage, mockRecord }) => { const nocoPage = await mockPage(oneEmptyTable).waitForInit(); await mockRecord('t_unp4scqamw9'); await nocoPage.goto(); @@ -148,7 +209,7 @@ test.describe('Table', () => { ).toBeVisible(); }); - test('adjust column width', async ({ page, mockPage }) => { + test('column width', async ({ page, mockPage }) => { await mockPage(oneEmptyTable).goto(); // 列宽度默认为 200 @@ -166,55 +227,4 @@ test.describe('Table', () => { await expect(page.getByRole('columnheader', { name: 'Actions', exact: true })).toHaveJSProperty('offsetWidth', 400); }); - - test('add action buttons', async ({ page, mockPage }) => { - await mockPage(oneEmptyTable).goto(); - - // add buttons - await page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-t_unp4scqamw9').hover(); - await page.getByRole('menuitem', { name: 'Filter' }).click(); - await page.getByRole('menuitem', { name: 'Add new' }).click(); - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await page.getByRole('menuitem', { name: 'Refresh' }).click(); - - await expect(page.getByRole('menuitem', { name: 'Filter' }).getByRole('switch')).toBeChecked(); - await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).toBeChecked(); - await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).toBeChecked(); - await expect(page.getByRole('menuitem', { name: 'Refresh' }).getByRole('switch')).toBeChecked(); - - await page.mouse.move(300, 0); - await expect(page.getByRole('button', { name: 'Filter' })).toBeVisible(); - await expect(page.getByRole('button', { name: 'Add new' })).toBeVisible(); - await expect(page.getByRole('button', { name: 'Delete' })).toBeVisible(); - await expect(page.getByRole('button', { name: 'Refresh' })).toBeVisible(); - - // delete buttons - await page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-t_unp4scqamw9').hover(); - await page.getByRole('menuitem', { name: 'Filter' }).click(); - await page.getByRole('menuitem', { name: 'Add new' }).click(); - await page.getByRole('menuitem', { name: 'Delete' }).click(); - await page.getByRole('menuitem', { name: 'Refresh' }).click(); - - await expect(page.getByRole('menuitem', { name: 'Filter' }).getByRole('switch')).not.toBeChecked(); - await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).not.toBeChecked(); - await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).not.toBeChecked(); - await expect(page.getByRole('menuitem', { name: 'Refresh' }).getByRole('switch')).not.toBeChecked(); - - await page.mouse.move(300, 0); - await expect(page.getByRole('button', { name: 'Filter' })).not.toBeVisible(); - await expect(page.getByRole('button', { name: 'Add new' })).not.toBeVisible(); - await expect(page.getByRole('button', { name: 'Delete' })).not.toBeVisible(); - await expect(page.getByRole('button', { name: 'Refresh' })).not.toBeVisible(); - }); - - test('add custom action buttons', async ({ page, mockPage }) => { - await mockPage(oneEmptyTable).goto(); - - await page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-t_unp4scqamw9').hover(); - await page.getByRole('menuitem', { name: 'Customize' }).hover(); - await page.getByRole('menuitem', { name: 'Bulk update' }).click(); - - await page.mouse.move(300, 0); - await expect(page.getByRole('button', { name: 'Bulk update' })).toBeVisible(); - }); }); diff --git a/packages/core/client/src/modules/table/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/table/__e2e__/schemaSettings.test.ts new file mode 100644 index 000000000..1ffe63155 --- /dev/null +++ b/packages/core/client/src/modules/table/__e2e__/schemaSettings.test.ts @@ -0,0 +1,713 @@ +import { + Page, + expect, + expectSettingsMenu, + oneEmptyTableBlockWithActions, + oneEmptyTableWithTreeCollection, + oneTableBlockWithActionsAndFormBlocks, + oneTableBlockWithAddNewAndViewAndEditAndBasicFields, + test, + twoTableWithAssociationFields, + twoTableWithSameCollection, +} from '@nocobase/test/client'; + +test.describe('table block schema settings', () => { + test('supported options', async ({ page, mockPage }) => { + await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).goto(); + + await expectSettingsMenu({ + page, + showMenu: () => showSettingsMenu(page), + supportedOptions: [ + 'Edit block title', + 'Enable drag and drop sorting', + 'Fix block', + 'Set the data scope', + 'Records per page', + 'Connect data blocks', + 'Save as template', + 'Delete', + ], + }); + }); + + test('fix block', async ({ page, mockPage }) => { + await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).goto(); + + const tableSize = await page.getByLabel('block-item-CardItem-general-table').boundingBox(); + + await showSettingsMenu(page); + await page.getByRole('menuitem', { name: 'Fix block' }).click(); + await expect(page.getByRole('menuitem', { name: 'Fix block' }).getByRole('switch')).toBeChecked(); + + // 等待页面重新渲染 + await page.waitForTimeout(100); + const fixedTableSize = await page.getByLabel('block-item-CardItem-general-table').boundingBox(); + expect(fixedTableSize.height).toBeGreaterThan(570); + expect(fixedTableSize.height).toBeLessThan(575); + + // 取消固定 + await page.getByRole('menuitem', { name: 'Fix block' }).click(); + await expect(page.getByRole('menuitem', { name: 'Fix block' }).getByRole('switch')).not.toBeChecked(); + + // 等待页面重新渲染 + await page.waitForTimeout(100); + const unfixedTableSize = await page.getByLabel('block-item-CardItem-general-table').boundingBox(); + + expect(unfixedTableSize.height).toBe(tableSize.height); + }); + + test('records per page', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); + await mockRecords('general', 40); + await nocoPage.goto(); + + // 默认每页显示 20 条(算上顶部 head 一共 21 行) + await expect(page.getByRole('row')).toHaveCount(21); + // 底部 pagination 的显示布局:[Total 40 items] [1] [2] [20 / page] + await expect(page.locator('.ant-pagination')).toHaveText('Total 40 items1220 / page'); + + await showSettingsMenu(page); + await page.getByRole('menuitem', { name: 'Records per page' }).click(); + await page.getByRole('option', { name: '10', exact: true }).click(); + + await expect(page.getByRole('row')).toHaveCount(11); + // 底部 pagination 的显示布局:[Total 40 items] [1] [2] [3] [4] [10 / page] + await expect(page.locator('.ant-pagination')).toHaveText('Total 40 items123410 / page'); + }); + + test('enable drag and drop sorting', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); + const records = await mockRecords('general', 3); + await nocoPage.goto(); + + await page.getByLabel('block-item-CardItem-general-table').hover(); + await page.getByLabel('designer-schema-settings-CardItem-TableBlockDesigner-general').hover(); + + // 默认是关闭状态 + await expect( + page.getByRole('menuitem', { name: 'Enable drag and drop sorting' }).getByRole('switch'), + ).not.toBeChecked(); + + // 开启之后,隐藏 Set default sorting rules 选项 + await page.getByRole('menuitem', { name: 'Enable drag and drop sorting' }).click(); + await expect( + page.getByRole('menuitem', { name: 'Enable drag and drop sorting' }).getByRole('switch'), + ).toBeChecked(); + await expect(page.getByRole('menuitem', { name: 'Set default sorting rules' })).toBeHidden(); + + // 显示出来 email 和 ID + await page.getByLabel('schema-initializer-TableV2-TableColumnInitializers-general').hover(); + await page.getByRole('menuitem', { name: 'email' }).click(); + await page.getByRole('menuitem', { name: 'ID', exact: true }).click(); + await page.mouse.move(300, 0); + + // 默认的排序 + let email1 = await page.getByText(records[0].email).boundingBox(); + let email2 = await page.getByText(records[1].email).boundingBox(); + let email3 = await page.getByText(records[2].email).boundingBox(); + + expect(email1.y).toBeLessThan(email2.y); + expect(email2.y).toBeLessThan(email3.y); + + // 将第二行拖动到第一行 + await page + .getByLabel('table-index-2') + .getByRole('img', { name: 'menu' }) + .dragTo(page.getByLabel('table-index-1').getByRole('img', { name: 'menu' })); + + // 等待表格刷新 + await page.waitForTimeout(1000); + + email1 = await page.getByText(records[0].email).boundingBox(); + email2 = await page.getByText(records[1].email).boundingBox(); + email3 = await page.getByText(records[2].email).boundingBox(); + + expect(email2.y).toBeLessThan(email1.y); + expect(email1.y).toBeLessThan(email3.y); + }); + + test.describe('set the data scope', () => { + async function showDialog(page: Page) { + await page.getByLabel('block-item-CardItem-general-table').hover(); + await page.getByLabel('designer-schema-settings-CardItem-TableBlockDesigner-general').hover(); + await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); + } + + async function createColumnItem(page: Page, fieldName: string) { + await page.getByLabel('schema-initializer-TableV2-TableColumnInitializers-general').hover(); + await page.getByRole('menuitem', { name: fieldName, exact: true }).click(); + await page.mouse.move(300, 0); + } + + test('use constants', async ({ page, mockRecords, mockPage }) => { + const nocoPage = await mockPage(oneTableBlockWithActionsAndFormBlocks).waitForInit(); + await mockRecords('general', 3); + await nocoPage.goto(); + await createColumnItem(page, 'ID'); + + await showDialog(page); + + // 添加一个 ID 为 1 的条件 + await page.getByText('Add condition', { exact: true }).click(); + await page.getByTestId('select-filter-field').click(); + await page.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); + await page.getByRole('spinbutton').click(); + await page.getByRole('spinbutton').fill('1'); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 被筛选之后数据只有一条(有一行是空的) + await expect(page.getByRole('row')).toHaveCount(2); + // 有一行 id 为 1 的数据 + await expect(page.getByRole('cell', { name: '1', exact: true })).toBeVisible(); + }); + + test('use variable called current user', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(oneTableBlockWithActionsAndFormBlocks).waitForInit(); + // Super Admin 是当前的用户的名字 + await mockRecords('general', [{ singleLineText: 'Super Admin' }, {}, {}]); + await nocoPage.goto(); + await createColumnItem(page, 'singleLineText'); + + await showDialog(page); + + // 添加一个 singleLineText 为 current user 的 Nickname 的条件 + await page.getByText('Add condition', { exact: true }).click(); + await page.getByTestId('select-filter-field').click(); + await page.getByRole('menuitemcheckbox', { name: 'singleLineText' }).click(); + await page.getByLabel('variable-button').click(); + await page.getByRole('menuitemcheckbox', { name: 'Current user' }).click(); + await page.getByRole('menuitemcheckbox', { name: 'Nickname' }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 被筛选之后数据只有一条(有一行是空的) + await expect(page.getByRole('row')).toHaveCount(2); + await expect(page.getByRole('cell', { name: 'Super Admin', exact: true })).toBeVisible(); + }); + }); + + test('set default sorting rules', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); + const records = await mockRecords('general', 3); + await nocoPage.goto(); + + // 打开配置弹窗 + await page.getByLabel('block-item-CardItem-general-table').hover(); + await page.getByLabel('designer-schema-settings-CardItem-TableBlockDesigner-general').hover(); + await page.getByRole('menuitem', { name: 'Set default sorting rules' }).click(); + + // 设置一个按 ID 降序的规则 + await page.getByRole('button', { name: 'plus Add sort field' }).click(); + await page.getByTestId('select-single').click(); + await page.getByRole('option', { name: 'ID', exact: true }).click(); + await page.getByText('DESC', { exact: true }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 显示出来 email 和 ID + await page.getByLabel('schema-initializer-TableV2-TableColumnInitializers-general').hover(); + await page.getByRole('menuitem', { name: 'email' }).click(); + await page.getByRole('menuitem', { name: 'ID', exact: true }).click(); + await page.mouse.move(300, 0); + + // 规则生效后的顺序:3,2,1 + const email1 = await page.getByText(records[0].email).boundingBox(); + const email2 = await page.getByText(records[1].email).boundingBox(); + const email3 = await page.getByText(records[2].email).boundingBox(); + + expect(email3.y).toBeLessThan(email2.y); + expect(email2.y).toBeLessThan(email1.y); + }); + + test.describe('connect data blocks', () => { + test('connecting two blocks of the same collection', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(twoTableWithSameCollection).waitForInit(); + const records = await mockRecords('users', 3); + await nocoPage.goto(); + + // 将左边的 Table 连接到右边的 Table + await page.getByLabel('block-item-CardItem-users-table').first().hover(); + await page.getByRole('button', { name: 'designer-schema-settings-CardItem-TableBlockDesigner-users' }).hover(); + await page.getByRole('menuitem', { name: 'Connect data blocks' }).hover(); + await page.getByRole('menuitem', { name: 'Users' }).click(); + + // 点击左边 Table 的某一行,右边 Table 的数据会被筛选为当前点中行的数据 + await page.getByLabel('block-item-CardItem-users-table').nth(0).getByText('Super Admin').click(); + await expect( + page.getByLabel('block-item-CardItem-users-table').nth(1).getByText(records[0].nickname), + ).toBeHidden(); + await expect( + page.getByLabel('block-item-CardItem-users-table').nth(1).getByText(records[1].nickname), + ).toBeHidden(); + await expect( + page.getByLabel('block-item-CardItem-users-table').nth(1).getByText(records[2].nickname), + ).toBeHidden(); + await expect(page.getByLabel('block-item-CardItem-users-table').nth(1).getByText('Super Admin')).toBeVisible(); + }); + + test('connecting two blocks connected by a relationship field', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(twoTableWithAssociationFields).waitForInit(); + await mockRecords('users', 3); + await nocoPage.goto(); + + // 将左边的 Table 连接到右边的 Table + await page.getByLabel('block-item-CardItem-roles-table').hover(); + await page.getByRole('button', { name: 'designer-schema-settings-CardItem-TableBlockDesigner-roles' }).hover(); + await page.getByRole('menuitem', { name: 'Connect data blocks' }).hover(); + await page.getByRole('menuitem', { name: 'Users' }).click(); + await page.getByRole('option', { name: 'Roles' }).click(); + + // 点击左边 Table 的某一行 + await page.getByLabel('block-item-CardItem-roles-table').getByRole('cell', { name: 'Root', exact: true }).click(); + await expect( + page + .getByLabel('block-item-CardItem-users-table') + .getByRole('row', { name: 'Member' }) + .filter({ hasNotText: 'Root' }), + ).toHaveCount(0, { timeout: 1000 * 10 }); + await expect(page.getByLabel('block-item-CardItem-users-table').getByRole('row', { name: 'Root' })).toBeVisible(); + + // 再次点击,会取消筛选效果 + await page.getByLabel('block-item-CardItem-roles-table').getByRole('cell', { name: 'Root', exact: true }).click(); + await expect( + page + .getByLabel('block-item-CardItem-users-table') + .getByRole('row', { name: 'Member' }) + .filter({ hasNotText: 'Root' }), + ).toHaveCount(3, { timeout: 1000 * 10 }); + await expect(page.getByLabel('block-item-CardItem-users-table').getByRole('row', { name: 'Root' })).toBeVisible(); + }); + + test('connecting two blocks connected by a foreign key', async ({ page, mockPage, mockRecords }) => {}); + }); +}); + +test.describe('actions schema settings', () => { + test.describe('add new', () => { + const showMenu = async (page: Page) => { + await page.getByRole('button', { name: 'Add new' }).hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action-Action.Designer-general' }).hover(); + }; + + test('supported options', async ({ page, mockPage, mockRecord }) => { + await mockPage(oneEmptyTableBlockWithActions).goto(); + + await expectSettingsMenu({ + page, + showMenu: () => showMenu(page), + supportedOptions: ['Edit button', 'Open mode', 'Popup size', 'Delete'], + }); + }); + + test('edit button', async ({ page, mockPage, mockRecord }) => { + await mockPage(oneEmptyTableBlockWithActions).goto(); + + await showMenu(page); + await page.getByRole('menuitem', { name: 'Edit button' }).click(); + await page.getByLabel('block-item-Input-general-Button title').getByRole('textbox').click(); + await page.getByLabel('block-item-Input-general-Button title').getByRole('textbox').fill('1234'); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + await expect(page.getByRole('button', { name: '1234' })).toBeVisible(); + }); + + test('open mode', async ({ page, mockPage, mockRecord }) => { + await mockPage(oneEmptyTableBlockWithActions).goto(); + await showMenu(page); + + // 默认是 drawer + await expect(page.getByRole('menuitem', { name: 'Open mode' }).getByText('Drawer')).toBeVisible(); + + // 切换为 dialog + await page.getByRole('menuitem', { name: 'Open mode' }).click(); + await page.getByRole('option', { name: 'Dialog' }).click(); + + await page.getByRole('button', { name: 'Add new' }).click(); + await expect(page.getByTestId('modal-Action.Container-general-Add record')).toBeVisible(); + }); + + test('popup size', async ({ page, mockPage, mockRecord }) => { + await mockPage(oneEmptyTableBlockWithActions).goto(); + + await showMenu(page); + // 默认值 middle + await expect(page.getByRole('menuitem', { name: 'Popup size' }).getByText('Middle')).toBeVisible(); + + // 切换为 small + await page.getByRole('menuitem', { name: 'Popup size' }).click(); + await page.getByRole('option', { name: 'Small' }).click(); + + await page.getByRole('button', { name: 'Add new' }).click(); + const drawerWidth = + (await page.getByTestId('drawer-Action.Container-general-Add record').boundingBox())?.width || 0; + expect(drawerWidth).toBeLessThanOrEqual(400); + + await page.getByLabel('drawer-Action.Container-general-Add record-mask').click(); + + // 切换为 large + await showMenu(page); + await page.getByRole('menuitem', { name: 'Popup size' }).click(); + await page.getByRole('option', { name: 'Large' }).click(); + + await page.getByRole('button', { name: 'Add new' }).click(); + const drawerWidth2 = + (await page.getByTestId('drawer-Action.Container-general-Add record').boundingBox())?.width || 0; + expect(drawerWidth2).toBeGreaterThanOrEqual(800); + }); + + test('delete', async ({ page, mockPage, mockRecord }) => { + await mockPage(oneEmptyTableBlockWithActions).goto(); + + await showMenu(page); + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.mouse.move(300, 0); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + await expect(page.getByRole('button', { name: 'Add new' })).toBeHidden(); + }); + }); + + test.describe('bulk delete', () => { + test('supported options', async ({ page, mockPage }) => { + await mockPage(oneEmptyTableBlockWithActions).goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByRole('button', { name: 'Delete' }).hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action-Action.Designer-general' }).hover(); + }, + supportedOptions: ['Edit button', 'Delete'], + }); + }); + }); + + test.describe('filter', () => { + const showMenu = async (page: Page) => { + await page.getByRole('button', { name: 'Filter' }).hover(); + await page.getByLabel('designer-schema-settings-Filter.Action-Filter.Action.Designer-general').hover(); + }; + + test('supported options', async ({ page, mockPage, mockRecord }) => { + await mockPage(oneEmptyTableBlockWithActions).goto(); + + await expectSettingsMenu({ + page, + showMenu: () => showMenu(page), + supportedOptions: [ + 'Edit button', + 'Delete', + 'Many to one', + 'One to many', + 'Single select', + 'ID', + 'Created at', + 'Last updated at', + 'Created by', + 'Last updated by', + ], + }); + }); + }); + + test.describe('delete', () => { + const showMenu = async (page: Page) => { + await page.getByLabel('action-Action.Link-Delete-destroy-general-table-0').hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }).hover(); + }; + + test('supported options', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneEmptyTableBlockWithActions).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + + await expectSettingsMenu({ + page, + showMenu: () => showMenu(page), + supportedOptions: ['Edit button', 'Linkage rules', 'Delete'], + }); + }); + + test('edit button', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneEmptyTableBlockWithActions).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + + await showMenu(page); + await page.getByRole('menuitem', { name: 'Edit button' }).click(); + await page.getByLabel('block-item-Input-general-Button title').getByRole('textbox').click(); + await page.getByLabel('block-item-Input-general-Button title').getByRole('textbox').fill('Delete record'); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + await expect(page.getByLabel('action-Action.Link-Delete record-destroy-general-table-0')).toBeVisible(); + }); + }); + + test.describe('edit', () => { + const showMenu = async (page: Page) => { + await page.getByLabel('action-Action.Link-Edit-update-general-table-0').hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }).hover(); + }; + + test('supported options', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneEmptyTableBlockWithActions).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + + await expectSettingsMenu({ + page, + showMenu: () => showMenu(page), + supportedOptions: ['Edit button', 'Linkage rules', 'Open mode', 'Popup size', 'Delete'], + }); + }); + }); + + test.describe('refresh', () => { + test('supported options', async ({ page, mockPage }) => { + await mockPage(oneEmptyTableBlockWithActions).goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByRole('button', { name: 'Refresh' }).hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action-Action.Designer-general' }).hover(); + }, + supportedOptions: ['Edit button', 'Delete'], + }); + }); + }); + + test.describe('view', () => { + const showMenu = async (page: Page) => { + await page.getByLabel('action-Action.Link-View-view-general-table-0').hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }).hover(); + }; + + test('supported options', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneEmptyTableBlockWithActions).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + + await expectSettingsMenu({ + page, + showMenu: () => showMenu(page), + supportedOptions: ['Edit button', 'Linkage rules', 'Open mode', 'Popup size', 'Delete'], + }); + }); + + test('linkage rules', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + + const openLinkageRules = async () => { + await page.getByLabel('action-Action.Link-View record-view-general-table-0').hover(); + await page + .getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }) + .hover(); + await page.getByRole('menuitem', { name: 'Linkage rules' }).click(); + }; + + // 设置第一组规则 -------------------------------------------------------------------------- + await openLinkageRules(); + await page.getByRole('button', { name: 'plus Add linkage rule' }).click(); + + // 添加一个条件:ID 等于 1 + await page.getByText('Add condition', { exact: true }).click(); + await page.getByTestId('select-filter-field').click(); + await page.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); + await page.getByRole('spinbutton').click(); + await page.getByRole('spinbutton').fill('1'); + + // action: 禁用按钮 + await page.getByText('Add property').click(); + await page.getByLabel('block-item-ArrayCollapse-general').click(); + await page.getByTestId('select-linkage-properties').getByLabel('Search').click(); + await page.getByRole('option', { name: 'Disabled' }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + await expect(page.getByLabel('action-Action.Link-View record-view-general-table-0')).toHaveAttribute( + 'disabled', + '', + ); + + // 设置第二组规则 -------------------------------------------------------------------------- + await openLinkageRules(); + await page.getByRole('button', { name: 'plus Add linkage rule' }).click(); + await page.locator('.ant-collapse-header').nth(1).getByRole('img', { name: 'right' }).click(); + + // 添加一个条件:ID 等于 1 + await page.getByRole('tabpanel').getByText('Add condition', { exact: true }).click(); + await page.getByRole('button', { name: 'Search Select field' }).getByLabel('Search').click(); + await page.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); + await page.getByRole('spinbutton').click(); + await page.getByRole('spinbutton').fill('1'); + + // action: 使按钮可用 + await page.getByRole('tabpanel').getByText('Add property').click(); + await page.getByRole('combobox', { name: 'Search' }).click(); + await page.getByRole('option', { name: 'Enabled' }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 后面的 action 会覆盖前面的 + await expect(page.getByLabel('action-Action.Link-View record-view-general-table-0')).not.toHaveAttribute( + 'disabled', + '', + ); + }); + }); + + test.describe('popup', () => { + const addSomeCustomActions = async (page: Page) => { + // 先删除掉之前的 actions + await page.getByRole('button', { name: 'Actions' }).hover(); + await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-general').hover(); + await page.getByRole('menuitem', { name: 'View' }).click(); + await page.getByRole('menuitem', { name: 'Edit' }).click(); + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.getByRole('menuitem', { name: 'Duplicate' }).click(); + + // 再增加两个自定义的 actions + await page.getByRole('menuitem', { name: 'Customize' }).hover(); + await page.getByRole('menuitem', { name: 'Popup' }).click(); + await page.getByRole('menuitem', { name: 'Update record' }).click(); + }; + + const showMenu = async (page: Page) => { + await page.getByLabel('action-Action.Link-Popup-customize:popup-general-table-0').hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }).hover(); + }; + + test('supported options', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneEmptyTableBlockWithActions).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + await addSomeCustomActions(page); + + await showMenu(page); + await expectSettingsMenu({ + page, + showMenu: () => showMenu(page), + supportedOptions: ['Edit button', 'Linkage rules', 'Open mode', 'Popup size', 'Delete'], + }); + }); + }); + + test.describe('duplicate', () => { + const showMenu = async (page: Page) => { + await page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0').hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }).hover(); + }; + + test('supported options', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneEmptyTableBlockWithActions).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + + await expectSettingsMenu({ + page, + showMenu: () => showMenu(page), + supportedOptions: ['Edit button', 'Linkage rules', 'Duplicate mode', 'Open mode', 'Popup size', 'Delete'], + }); + }); + }); + + test.describe('update record', () => { + const addSomeCustomActions = async (page: Page) => { + // 先删除掉之前的 actions + await page.getByRole('button', { name: 'Actions' }).hover(); + await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-general').hover(); + await page.getByRole('menuitem', { name: 'View' }).click(); + await page.getByRole('menuitem', { name: 'Edit' }).click(); + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.getByRole('menuitem', { name: 'Duplicate' }).click(); + + // 再增加两个自定义的 actions + await page.getByRole('menuitem', { name: 'Customize' }).hover(); + await page.getByRole('menuitem', { name: 'Popup' }).click(); + await page.getByRole('menuitem', { name: 'Update record' }).click(); + }; + + const showMenu = async (page: Page) => { + await page.getByLabel('action-Action.Link-Update record-customize:update-general-table-0').hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }).hover(); + }; + + test('supported options', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneEmptyTableBlockWithActions).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + await addSomeCustomActions(page); + + await showMenu(page); + await expectSettingsMenu({ + page, + showMenu: () => showMenu(page), + supportedOptions: [ + 'Edit button', + 'Linkage rules', + 'Assign field values', + 'After successful submission', + 'Delete', + ], + }); + }); + }); + + test.describe('add child', () => { + const showMenu = async (page: Page) => { + await page.getByLabel('action-Action.Link-Add child-create-treeCollection-table-0').hover(); + await page.getByLabel('designer-schema-settings-Action.Link-Action.Designer-tree').hover(); + }; + + test('supported options', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneEmptyTableWithTreeCollection).waitForInit(); + await nocoPage.goto(); + + // 添加一行数据 + // TODO: 使用 mockRecord 为 tree 表添加一行数据无效 + await page.getByLabel('schema-initializer-ActionBar-TableActionInitializers-treeCollection').hover(); + await page.getByRole('menuitem', { name: 'Add new' }).click(); + await page.getByRole('button', { name: 'Add new' }).click(); + await page.getByLabel('schema-initializer-Grid-CreateFormBlockInitializers-treeCollection').hover(); + await page.getByRole('menuitem', { name: 'form Form' }).click(); + await page.mouse.move(300, 0); + await page.getByLabel('schema-initializer-ActionBar-CreateFormActionInitializers-treeCollection').hover(); + await page.getByRole('menuitem', { name: 'Submit' }).click(); + await page.mouse.move(300, 0); + await page.getByRole('button', { name: 'Submit' }).click(); + + // 添加 add child 按钮 + await page.getByRole('button', { name: 'Actions' }).hover(); + await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-tree').hover(); + await page.getByRole('menuitem', { name: 'Add child' }).click(); + + await expectSettingsMenu({ + page, + showMenu: () => showMenu(page), + supportedOptions: ['Edit button', 'Linkage rules', 'Open mode', 'Popup size', 'Delete'], + }); + }); + }); + + test.describe('add record', () => { + const showMenu = async (page: Page) => { + await page.getByRole('button', { name: 'Add record' }).hover(); + await page.getByRole('button', { name: 'designer-schema-settings-Action-Action.Designer-general' }).hover(); + }; + + test('supported options', async ({ page, mockPage, mockRecord }) => { + await mockPage(oneEmptyTableBlockWithActions).goto(); + + await expectSettingsMenu({ + page, + showMenu: () => showMenu(page), + supportedOptions: ['Edit button', 'Open mode', 'Popup size', 'Delete'], + }); + }); + }); +}); + +async function showSettingsMenu(page) { + await page.getByLabel('block-item-CardItem-general-table').hover(); + await page.getByLabel('designer-schema-settings-CardItem-TableBlockDesigner-general').hover(); +} diff --git a/packages/core/client/src/__tests__/e2e/bugs/T-2187.test.ts b/packages/core/client/src/modules/table/__e2e__/templatesOfBug.ts similarity index 64% rename from packages/core/client/src/__tests__/e2e/bugs/T-2187.test.ts rename to packages/core/client/src/modules/table/__e2e__/templatesOfBug.ts index b208ed5e2..213b21f58 100644 --- a/packages/core/client/src/__tests__/e2e/bugs/T-2187.test.ts +++ b/packages/core/client/src/modules/table/__e2e__/templatesOfBug.ts @@ -1,6 +1,322 @@ -import { expect, test } from '@nocobase/test/client'; - -const config = { +export const T2183 = { + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + '3c1ivjciciu': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + '1n5r9s23amo': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + bsmuf6ly8b2: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + ppv3te8l7mo: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'users:list', + 'x-decorator-props': { + collection: 'users', + resource: 'users', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + properties: { + o8wqytvd6as: { + 'x-uid': '9vghmn6u5eo', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Filter") }}', + 'x-action': 'filter', + 'x-designer': 'Filter.Action.Designer', + 'x-component': 'Filter.Action', + 'x-component-props': { + icon: 'FilterOutlined', + useProps: '{{ useFilterActionProps }}', + }, + 'x-align': 'left', + default: { + $and: [], + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'qq7hs80xlut', + 'x-async': false, + 'x-index': 1, + }, + r02zx6qq4ql: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Actions") }}', + 'x-action-column': 'actions', + 'x-decorator': 'TableV2.Column.ActionBar', + 'x-component': 'TableV2.Column', + 'x-designer': 'TableV2.ActionColumnDesigner', + 'x-initializer': 'TableActionColumnInitializers', + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + 'x-uid': '4fcw4u63f3p', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'pxqbve61e9i', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'kta6g2v3m9s', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'yu418id0x3t', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xrvoeyz6uop', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'u64df000i8u', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'hofapxvp8p7', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'w7nv1c98j2g', + 'x-async': true, + 'x-index': 1, + }, +}; +export const T2186 = { + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + cglzmr757wp: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + '0r1mwh6fgdj': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + kjjiumynoor: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + qzbbcmvyy7n: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'users:list', + 'x-decorator-props': { + collection: 'users', + resource: 'users', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + properties: { + '8yt1cl9miol': { + 'x-uid': 'pcebb2lm84j', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Filter") }}', + 'x-action': 'filter', + 'x-designer': 'Filter.Action.Designer', + 'x-component': 'Filter.Action', + 'x-component-props': { + icon: 'FilterOutlined', + useProps: '{{ useFilterActionProps }}', + }, + 'x-align': 'left', + default: { + $and: [{}], + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'sz9p441he7c', + 'x-async': false, + 'x-index': 1, + }, + fqmmittx9pb: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Actions") }}', + 'x-action-column': 'actions', + 'x-decorator': 'TableV2.Column.ActionBar', + 'x-component': 'TableV2.Column', + 'x-designer': 'TableV2.ActionColumnDesigner', + 'x-initializer': 'TableActionColumnInitializers', + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + 'x-uid': 'r4m451vcj6l', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'fogxvhca4sg', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '6ywen03do22', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '47n8qnj6q20', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xnc0acxgrxz', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '5dy05u5q2b2', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'rue5m4yfin6', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '3xce5ru15d6', + 'x-async': true, + 'x-index': 1, + }, +}; +export const T2187 = { pageSchema: { _isJSONSchemaObject: true, version: '2.0', @@ -354,15 +670,3 @@ const config = { 'x-index': 1, }, }; - -// fix https://nocobase.height.app/T-2187 -test('BUG: in the Duplicate mode, the Roles field should not have a value after clicking it because it is not selected', async ({ - page, - mockPage, -}) => { - await mockPage(config).goto(); - - await page.getByLabel('action-Action.Link-Duplicate-duplicate-users-table-0').click(); - await expect(page.getByRole('textbox')).toHaveValue('Super Admin'); - await expect(page.getByTestId('select-object-multiple')).toHaveText(''); -}); diff --git a/packages/core/client/src/schema-component/antd/association-field/InternalViewer.tsx b/packages/core/client/src/schema-component/antd/association-field/InternalViewer.tsx index b6d19a634..c1304b84e 100644 --- a/packages/core/client/src/schema-component/antd/association-field/InternalViewer.tsx +++ b/packages/core/client/src/schema-component/antd/association-field/InternalViewer.tsx @@ -44,7 +44,7 @@ export const ReadPrettyInternalViewer: React.FC = observer( const { designable } = useDesignable(); const { snapshot } = useActionContext(); const targetCollection = getCollection(collectionField?.target); - const isTreeCollection = targetCollection.template === 'tree'; + const isTreeCollection = targetCollection?.template === 'tree'; const ellipsisWithTooltipRef = useRef(); const renderRecords = () => toArr(props.value).map((record, index, arr) => { diff --git a/packages/core/client/src/schema-component/antd/grid-card/GridCard.Item.tsx b/packages/core/client/src/schema-component/antd/grid-card/GridCard.Item.tsx index adc72a515..bb81dc507 100644 --- a/packages/core/client/src/schema-component/antd/grid-card/GridCard.Item.tsx +++ b/packages/core/client/src/schema-component/antd/grid-card/GridCard.Item.tsx @@ -18,6 +18,8 @@ export const GridCardItem = (props) => { const field = useField(); return ( .ant-card-body { diff --git a/packages/core/test/src/client/e2eUtils.ts b/packages/core/test/src/client/e2eUtils.ts index e986e87bb..c6c0b13ef 100644 --- a/packages/core/test/src/client/e2eUtils.ts +++ b/packages/core/test/src/client/e2eUtils.ts @@ -1,6 +1,6 @@ import { faker } from '@faker-js/faker'; import { uid } from '@formily/shared'; -import { Page, test as base, request } from '@playwright/test'; +import { Page, test as base, expect, request } from '@playwright/test'; import _ from 'lodash'; export * from '@playwright/test'; @@ -125,18 +125,80 @@ interface CreatePageOptions { pageSchema?: any; } +interface ExtendUtils { + /** + * 根据配置,生成一个 NocoBase 的页面 + * @param pageConfig 页面配置 + * @returns + */ + mockPage: (pageConfig?: PageConfig) => NocoPage; + /** + * 根据配置,生成一个需要手动销毁的 NocoPage 页面 + * @param pageConfig + * @returns + */ + mockManualDestroyPage: (pageConfig?: PageConfig) => NocoPage; + /** + * 根据配置,生成多个 collections + * @param collectionSettings + * @returns 返回一个 destroy 方法,用于销毁创建的 collections + */ + mockCollections: (collectionSettings: CollectionSetting[]) => Promise; + /** + * 根据配置,生成一个 collection + * @param collectionSetting + * @returns 返回一个 destroy 方法,用于销毁创建的 collection + */ + mockCollection: (collectionSetting: CollectionSetting) => Promise; + /** + * 自动生成一条对应 collection 的数据 + * @param collectionName 数据表名称 + * @param data 自定义的数据,缺失时会生成随机数据 + * @returns 返回一条生成的数据 + */ + mockRecord: (collectionName: string, data?: any) => Promise; + /** + * 自动生成多条对应 collection 的数据 + */ + mockRecords: { + /** + * @param collectionName - 数据表名称 + * @param count - 生成的数据条数 + */ + (collectionName: string, count?: number): Promise; + /** + * @param collectionName - 数据表名称 + * @param data - 指定生成的数据 + */ + (collectionName: string, data?: any[]): Promise; + }; + /** + * 该方法已弃用,请使用 mockCollections + * @deprecated + * @param collectionSettings + * @returns + */ + createCollections: (collectionSettings: CollectionSetting | CollectionSetting[]) => Promise; + /** + * 根据页面 title 删除对应的页面 + * @param pageName 显示在页面菜单中的名称 + * @returns + */ + deletePage: (pageName: string) => Promise; +} + const PORT = process.env.APP_PORT || 20000; const APP_BASE_URL = process.env.APP_BASE_URL || `http://localhost:${PORT}`; -class NocoPage { +export class NocoPage { private url: string; private uid: string; private collectionsName: string[]; private _waitForInit: Promise; constructor( - private page: Page, private options?: PageConfig, + private page?: Page, ) { this._waitForInit = this.init(); } @@ -149,7 +211,7 @@ class NocoPage { await createCollections(collections); } - this.uid = await createPage(this.page, { + this.uid = await createPage({ type: this.options?.type, name: this.options?.name, pageSchema: this.options?.pageSchema, @@ -160,7 +222,12 @@ class NocoPage { async goto() { await this._waitForInit; - await this.page.goto(this.url); + await this.page?.goto(this.url); + } + + async getUrl() { + await this._waitForInit; + return this.url; } async waitForInit(this: NocoPage) { @@ -180,44 +247,14 @@ class NocoPage { } } -const _test = base.extend<{ - page: Page; - mockPage: (config?: PageConfig) => NocoPage; - mockCollections: (collectionSettings: CollectionSetting[]) => Promise; - mockCollection: (collectionSetting: CollectionSetting) => Promise; - mockRecord: (collectionName: string, data?: any) => Promise; - mockRecords: { - /** - * @param collectionName - 数据表名称 - * @param count - 生成的数据条数 - */ - (collectionName: string, count?: number): Promise; - /** - * @param collectionName - 数据表名称 - * @param data - 指定生成的数据 - */ - (collectionName: string, data?: any[]): Promise; - }; - createCollections: (collectionSettings: CollectionSetting | CollectionSetting[]) => Promise; - deletePage: (pageName: string) => Promise; -}>({ - page: async ({ page: _page }, use) => { - const page: Page = Object.create(_page); - page.goto = async function goto(url: string, options?: any) { - const result = await _page.goto(url, options); - await enableToConfig(_page); - return result; - }; - - await use(page); - }, +const _test = base.extend({ mockPage: async ({ page }, use) => { // 保证每个测试运行时 faker 的随机值都是一样的 faker.seed(1); const nocoPages: NocoPage[] = []; const mockPage = (config?: PageConfig) => { - const nocoPage = new NocoPage(page, config); + const nocoPage = new NocoPage(config, page); nocoPages.push(nocoPage); return nocoPage; }; @@ -229,6 +266,14 @@ const _test = base.extend<{ await nocoPage.destroy(); } }, + mockManualDestroyPage: async ({ browser }, use) => { + const mockManualDestroyPage = (config?: PageConfig) => { + const nocoPage = new NocoPage(config); + return nocoPage; + }; + + await use(mockManualDestroyPage); + }, createCollections: async ({ page }, use) => { let collectionsName = []; @@ -248,6 +293,11 @@ const _test = base.extend<{ }, mockCollections: async ({ page }, use) => { let collectionsName = []; + const destroy = async () => { + if (collectionsName.length) { + await deleteCollections(collectionsName); + } + }; const mockCollections = async (collectionSettings: CollectionSetting[]) => { collectionSettings = omitSomeFields(collectionSettings); @@ -256,25 +306,24 @@ const _test = base.extend<{ }; await use(mockCollections); - - if (collectionsName.length) { - await deleteCollections(collectionsName); - } + await destroy(); }, mockCollection: async ({ page }, use) => { let collectionsName = []; + const destroy = async () => { + if (collectionsName.length) { + await deleteCollections(collectionsName); + } + }; - const mockCollection = async (collectionSetting: CollectionSetting) => { + const mockCollection = async (collectionSetting: CollectionSetting, options?: { manualDestroy: boolean }) => { const collectionSettings = omitSomeFields([collectionSetting]); collectionsName = collectionSettings.map((item) => item.name); return createCollections(collectionSettings); }; await use(mockCollection); - - if (collectionsName.length) { - await deleteCollections(collectionsName); - } + await destroy(); }, mockRecords: async ({ page }, use) => { const mockRecords = async (collectionName: string, count: any = 3, data?: any) => { @@ -286,6 +335,13 @@ const _test = base.extend<{ }; await use(mockRecords); + + // 删除掉 id 不是 1 的 users 和 name 不是 root admin member 的 roles + const deletePromises = [ + deleteRecords('users', { id: { $ne: 1 } }), + deleteRecords('roles', { name: { $ne: ['root', 'admin', 'member'] } }), + ]; + await Promise.all(deletePromises); }, mockRecord: async ({ page }, use) => { const mockRecord = async (collectionName: string, data?: any) => { @@ -294,6 +350,13 @@ const _test = base.extend<{ }; await use(mockRecord); + + // 删除掉 id 不是 1 的 users 和 name 不是 root admin member 的 roles + const deletePromises = [ + deleteRecords('users', { id: { $ne: 1 } }), + deleteRecords('roles', { name: { $ne: ['root', 'admin', 'member'] } }), + ]; + await Promise.all(deletePromises); }, deletePage: async ({ page }, use) => { const deletePage = async (pageName: string) => { @@ -304,6 +367,13 @@ const _test = base.extend<{ }; await use(deletePage); + + // 删除掉 id 不是 1 的 users 和 name 不是 root admin member 的 roles + const deletePromises = [ + deleteRecords('users', { id: { $ne: 1 } }), + deleteRecords('roles', { name: { $ne: ['root', 'admin', 'member'] } }), + ]; + await Promise.all(deletePromises); }, }); @@ -342,7 +412,7 @@ const updateUidOfPageSchema = (uiSchema: any) => { /** * 在 NocoBase 中创建一个页面 */ -const createPage = async (page: Page, options?: CreatePageOptions) => { +const createPage = async (options?: CreatePageOptions) => { const { type = 'page', url, name, pageSchema } = options || {}; const api = await request.newContext({ storageState: require.resolve('../../../../../playwright/.auth/admin.json'), @@ -426,9 +496,6 @@ const createPage = async (page: Page, options?: CreatePageOptions) => { throw new Error('systemSettings is not ok'); } - // @ts-ignore - (page._currentPageUidList || (page._currentPageUidList = [])).push(pageUid); - return pageUid; }; @@ -470,6 +537,28 @@ const deleteCollections = async (collectionNames: string[]) => { } }; +/** + * 将数据表中 mock 出来的 records 删除掉 + * @param collectionName + * @param records + */ +const deleteRecords = async (collectionName: string, filter: any) => { + const api = await request.newContext({ + storageState: require.resolve('../../../../../playwright/.auth/admin.json'), + }); + + const state = await api.storageState(); + const headers = getHeaders(state); + + const result = await api.post(`/api/${collectionName}:destroy?filter=${JSON.stringify(filter)}`, { + headers, + }); + + if (!result.ok()) { + throw new Error(await result.text()); + } +}; + /** * 删除一些不需要的字段,如 key * @param collectionSettings @@ -594,23 +683,6 @@ const createRandomData = async (collectionName: string, count = 10, data?: any) return (await result.json()).data; }; -/** - * 使页面成为可配置态 - */ -export async function enableToConfig(page: Page) { - try { - // 根据是否有 style 判断是否已经是可配置态(因为配置状态的按钮样式是通过 style 属性设置的) - const style = await page.getByTestId('ui-editor-button').getAttribute('style', { - timeout: 2000, - }); - if (!style) { - await page.getByTestId('ui-editor-button').click(); - } - } catch (e) { - // ignore - } -} - function getHeaders(storageState: any) { const headers: any = {}; const token = getStorageItem('NOCOBASE_TOKEN', storageState); @@ -649,3 +721,50 @@ function getHeaders(storageState: any) { return headers; } + +/** + * 辅助断言 SchemaSettings 的菜单项是否存在 + * @param param0 + */ +export async function expectSettingsMenu({ showMenu, supportedOptions, page }) { + await showMenu(); + for (const option of supportedOptions) { + await expect(page.getByRole('menuitem', { name: option })).toBeVisible(); + } +} + +/** + * 辅助断言 Initializer 的菜单项是否存在 + * @param param0 + */ +export async function expectInitializerMenu({ showMenu, supportedOptions, page }) { + await showMenu(); + for (const option of supportedOptions) { + await expect(page.getByRole('menuitem', { name: option })).toBeVisible(); + } +} + +/** + * 用于辅助在 page 中创建区块 + * @param page + * @param name + */ +export const createBlockInPage = async (page: Page, name: string) => { + await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover(); + + if (name === 'Form') { + await page.getByText('Form', { exact: true }).first().hover(); + } else if (name === 'Filter form') { + await page.getByText('Form', { exact: true }).nth(1).hover(); + } else { + await page.getByText(name, { exact: true }).hover(); + } + + if (name === 'Markdown') { + await page.getByRole('menuitem', { name: 'Markdown' }).click(); + } else { + await page.getByRole('menuitem', { name: 'Users' }).click(); + } + + await page.mouse.move(300, 0); +}; diff --git a/packages/core/test/src/client/index.ts b/packages/core/test/src/client/index.ts index 9f50c3d65..37246f4de 100644 --- a/packages/core/test/src/client/index.ts +++ b/packages/core/test/src/client/index.ts @@ -1,4 +1,3 @@ export * from './e2eUtils'; -export * from './templatesOfBug'; export * from './templatesOfCollection'; export * from './templatesOfPage'; diff --git a/packages/core/test/src/client/templatesOfBug/T-2614.ts b/packages/core/test/src/client/templatesOfBug/T-2614.ts deleted file mode 100644 index 0c17e88b9..000000000 --- a/packages/core/test/src/client/templatesOfBug/T-2614.ts +++ /dev/null @@ -1,836 +0,0 @@ -import { PageConfig } from '../e2eUtils'; - -export const T2614: PageConfig = { - collections: [ - { - name: 'T2614', - fields: [ - { - name: 'm2o', - interface: 'm2o', - target: 'T2614Target1', - }, - ], - }, - { - name: 'T2614Target1', - fields: [ - { - name: 'm2oOfTarget1', - interface: 'm2o', - target: 'T2614Target2', - }, - ], - }, - { - name: 'T2614Target2', - fields: [ - { - name: 'm2oOfTarget2', - interface: 'm2o', - target: 'users', - }, - ], - }, - ], - pageSchema: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Page', - properties: { - oaeetth18tf: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'BlockInitializers', - properties: { - vv0l8wohslb: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - '7se9siwa4ce': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - '249fb0vofov': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'TableBlockProvider', - 'x-acl-action': 'T2614:list', - 'x-decorator-props': { - collection: 'T2614', - resource: 'T2614', - action: 'list', - params: { - pageSize: 20, - }, - rowKey: 'id', - showIndex: true, - dragSort: false, - disableTemplate: false, - }, - 'x-designer': 'TableBlockDesigner', - 'x-component': 'CardItem', - 'x-filter-targets': [], - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'TableActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 'var(--nb-spacing)', - }, - }, - 'x-uid': 'vq4vg5mpbxz', - 'x-async': false, - 'x-index': 1, - }, - v76qyn133dr: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'array', - 'x-initializer': 'TableColumnInitializers', - 'x-component': 'TableV2', - 'x-component-props': { - rowKey: 'id', - rowSelection: { - type: 'checkbox', - }, - useProps: '{{ useTableBlockProps }}', - }, - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Actions") }}', - 'x-action-column': 'actions', - 'x-decorator': 'TableV2.Column.ActionBar', - 'x-component': 'TableV2.Column', - 'x-designer': 'TableV2.ActionColumnDesigner', - 'x-initializer': 'TableActionColumnInitializers', - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'DndContext', - 'x-component': 'Space', - 'x-component-props': { - split: '|', - }, - properties: { - '02okcjna453': { - 'x-uid': 'xowhnp7a686', - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: 'View record', - 'x-action': 'view', - 'x-designer': 'Action.Designer', - 'x-component': 'Action.Link', - 'x-component-props': { - openMode: 'drawer', - danger: false, - }, - 'x-decorator': 'ACLActionProvider', - 'x-designer-props': { - linkageAction: true, - }, - properties: { - drawer: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("View record") }}', - 'x-component': 'Action.Container', - 'x-component-props': { - className: 'nb-action-popup', - }, - properties: { - tabs: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Tabs', - 'x-component-props': {}, - 'x-initializer': 'TabPaneInitializers', - properties: { - tab1: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{t("Details")}}', - 'x-component': 'Tabs.TabPane', - 'x-designer': 'Tabs.Designer', - 'x-component-props': {}, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'RecordBlockInitializers', - properties: { - qbl84fadyr0: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - pfnr7qcapp2: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - eomkz742tgm: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-acl-action': 'T2614:get', - 'x-decorator': 'FormBlockProvider', - 'x-decorator-props': { - resource: 'T2614', - collection: 'T2614', - readPretty: true, - action: 'get', - useParams: '{{ useParamsFromRecord }}', - useSourceId: '{{ useSourceIdFromParentRecord }}', - }, - 'x-designer': 'FormV2.ReadPrettyDesigner', - 'x-component': 'CardItem', - properties: { - sekfkpv5dh2: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'FormV2', - 'x-read-pretty': true, - 'x-component-props': { - useProps: '{{ useFormBlockProps }}', - }, - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': - 'ReadPrettyFormActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 24, - }, - }, - 'x-uid': 'mt321nhie11', - 'x-async': false, - 'x-index': 1, - }, - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': - 'ReadPrettyFormItemInitializers', - properties: { - i39cn9ve66b: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - h6aq6z28saw: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - m2o: { - 'x-uid': '5zamj2l0hxp', - _isJSONSchemaObject: true, - version: '2.0', - type: 'string', - 'x-designer': 'FormItem.Designer', - 'x-component': 'CollectionField', - 'x-decorator': 'FormItem', - 'x-collection-field': 'T2614.m2o', - 'x-component-props': { - mode: 'Nester', - }, - properties: { - sgu8ssav8z3: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': - 'AssociationField.Nester', - 'x-index': 1, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': - 'FormItemInitializers', - properties: { - e5kqdzyj562: { - _isJSONSchemaObject: - true, - version: '2.0', - type: 'void', - 'x-component': - 'Grid.Row', - properties: { - '36nwk5wtcze': { - _isJSONSchemaObject: - true, - version: '2.0', - type: 'void', - 'x-component': - 'Grid.Col', - properties: { - m2oOfTarget1: { - _isJSONSchemaObject: - true, - version: '2.0', - type: 'string', - 'x-designer': - 'FormItem.Designer', - 'x-component': - 'CollectionField', - 'x-decorator': - 'FormItem', - 'x-collection-field': - 'T2614Target1.m2oOfTarget1', - 'x-component-props': - {}, - 'x-uid': - '9x1i9kks2io', - 'x-async': - false, - 'x-index': 1, - }, - }, - 'x-uid': - 'gnqmqaqs49i', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'sku445zzg07', - 'x-async': false, - 'x-index': 1, - }, - bnd1dnje70d: { - _isJSONSchemaObject: - true, - version: '2.0', - type: 'void', - 'x-component': - 'Grid.Row', - properties: { - ygyvra5m18v: { - _isJSONSchemaObject: - true, - version: '2.0', - type: 'void', - 'x-component': - 'Grid.Col', - properties: { - 'm2oOfTarget1.id': - { - _isJSONSchemaObject: - true, - version: - '2.0', - type: 'string', - 'x-designer': - 'FormItem.Designer', - 'x-component': - 'CollectionField', - 'x-read-pretty': - true, - 'x-component-props': - { - 'pattern-disable': - true, - }, - 'x-decorator': - 'FormItem', - 'x-collection-field': - 'T2614Target1.m2oOfTarget1.id', - 'x-uid': - '0trg79yim60', - 'x-async': - false, - 'x-index': 1, - }, - }, - 'x-uid': - 'auigm7t6blc', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '6ll6h4ii2td', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'wxo0qlrm5ss', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '73iro2istbt', - 'x-async': false, - }, - }, - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'h3feczketbc', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'nb5fbboc504', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'dehspo2sh69', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'lyvcisiy2mz', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'u78ad3fqfdo', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'r8s2aj79b9q', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'fgsdtpfae0q', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'dzzom03ln6q', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'u8h5d2ecch0', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '1dlp1swsc68', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'qa2uyudep13', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-async': false, - 'x-index': 1, - }, - '697zke71z0l': { - 'x-uid': '7o63dwge91d', - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: 'Edit record', - 'x-action': 'update', - 'x-designer': 'Action.Designer', - 'x-component': 'Action.Link', - 'x-component-props': { - openMode: 'drawer', - danger: false, - }, - 'x-decorator': 'ACLActionProvider', - 'x-designer-props': { - linkageAction: true, - }, - properties: { - drawer: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Edit record") }}', - 'x-component': 'Action.Container', - 'x-component-props': { - className: 'nb-action-popup', - }, - properties: { - tabs: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Tabs', - 'x-component-props': {}, - 'x-initializer': 'TabPaneInitializers', - properties: { - tab1: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{t("Edit")}}', - 'x-component': 'Tabs.TabPane', - 'x-designer': 'Tabs.Designer', - 'x-component-props': {}, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'RecordBlockInitializers', - properties: { - z79dioevb4n: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - krzxk68va81: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - '7ms7r5wolwa': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-acl-action-props': { - skipScopeCheck: false, - }, - 'x-acl-action': 'T2614:update', - 'x-decorator': 'FormBlockProvider', - 'x-decorator-props': { - useSourceId: '{{ useSourceIdFromParentRecord }}', - useParams: '{{ useParamsFromRecord }}', - action: 'get', - resource: 'T2614', - collection: 'T2614', - }, - 'x-designer': 'FormV2.Designer', - 'x-component': 'CardItem', - 'x-component-props': {}, - properties: { - '4pxevnwkd12': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'FormV2', - 'x-component-props': { - useProps: '{{ useFormBlockProps }}', - }, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'FormItemInitializers', - properties: { - j9egu0k0tkq: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - zpv9u8httu7: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - m2o: { - 'x-uid': '1pyjlpyhxue', - _isJSONSchemaObject: true, - version: '2.0', - type: 'string', - 'x-designer': 'FormItem.Designer', - 'x-component': 'CollectionField', - 'x-decorator': 'FormItem', - 'x-collection-field': 'T2614.m2o', - 'x-component-props': { - mode: 'Nester', - }, - properties: { - ts1e7dq92gw: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': - 'AssociationField.Nester', - 'x-index': 1, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': - 'FormItemInitializers', - properties: { - esgv9d2n3jl: { - _isJSONSchemaObject: - true, - version: '2.0', - type: 'void', - 'x-component': - 'Grid.Row', - properties: { - fvjf1i0u5tj: { - _isJSONSchemaObject: - true, - version: '2.0', - type: 'void', - 'x-component': - 'Grid.Col', - properties: { - m2oOfTarget1: { - _isJSONSchemaObject: - true, - version: '2.0', - type: 'string', - 'x-designer': - 'FormItem.Designer', - 'x-component': - 'CollectionField', - 'x-decorator': - 'FormItem', - 'x-collection-field': - 'T2614Target1.m2oOfTarget1', - 'x-component-props': - {}, - 'x-uid': - 'tbl4cxpqqhr', - 'x-async': - false, - 'x-index': 1, - }, - }, - 'x-uid': - '0inwt7v6zx1', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'ooid2e23vzk', - 'x-async': false, - 'x-index': 1, - }, - '8jo9e13m9pu': { - _isJSONSchemaObject: - true, - version: '2.0', - type: 'void', - 'x-component': - 'Grid.Row', - properties: { - dbwz7xfmcsf: { - _isJSONSchemaObject: - true, - version: '2.0', - type: 'void', - 'x-component': - 'Grid.Col', - properties: { - 'm2oOfTarget1.id': - { - _isJSONSchemaObject: - true, - version: - '2.0', - type: 'string', - 'x-designer': - 'FormItem.Designer', - 'x-component': - 'CollectionField', - 'x-read-pretty': - true, - 'x-component-props': - { - 'pattern-disable': - true, - }, - 'x-decorator': - 'FormItem', - 'x-collection-field': - 'T2614Target1.m2oOfTarget1.id', - 'x-uid': - 'no1h1z3kbqn', - 'x-async': - false, - 'x-index': 1, - }, - }, - 'x-uid': - 'f1w8n47pxgk', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'v6x8pzyim4q', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'ixnvtkde6ut', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'a0765a01l4v', - 'x-async': false, - }, - }, - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'nhq72b5xej7', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '0rchr17dcvr', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'fvfqd52uoaa', - 'x-async': false, - 'x-index': 1, - }, - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'UpdateFormActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - layout: 'one-column', - style: { - marginTop: 24, - }, - }, - 'x-uid': 'bm93ifuifak', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': '6s8ie14bci8', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'hljdd9nlub3', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'h14avrpxyu9', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'n54e5yj7uo8', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'o6q0ebwuei0', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'ej65121swhj', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '521m41b059u', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '6ddt1wgx8zu', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': '1oj9b60cf3w', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'qdzdffxf5da', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 't7svx0a3pce', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'w8kzfaxgchd', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'hg44qtd6uw6', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'vv4zzxbtbja', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '6klhg23a43i', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '9ebjl68x43b', - 'x-async': true, - 'x-index': 1, - }, -}; diff --git a/packages/core/test/src/client/templatesOfBug/T-2615.ts b/packages/core/test/src/client/templatesOfBug/T-2615.ts deleted file mode 100644 index 5f6e059c8..000000000 --- a/packages/core/test/src/client/templatesOfBug/T-2615.ts +++ /dev/null @@ -1,904 +0,0 @@ -import { PageConfig } from '../e2eUtils'; - -export const T2615: PageConfig = { - collections: [ - { - name: 'T2615', - fields: [ - { - name: 'm2o', - interface: 'm2o', - target: 'T2615Target1', - }, - ], - }, - { - name: 'T2615Target1', - fields: [ - { - name: 'm2oOfTarget1', - interface: 'm2o', - target: 'T2615Target2', - }, - ], - }, - { - name: 'T2615Target2', - fields: [ - { - name: 'm2oOfTarget2', - interface: 'm2o', - target: 'users', - }, - ], - }, - ], - pageSchema: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Page', - properties: { - eoe6sphevnd: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'BlockInitializers', - properties: { - '1valv0kj8vs': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - nkq10mh10ps: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - '22lk2du0ib3': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'TableBlockProvider', - 'x-acl-action': 'T2615:list', - 'x-decorator-props': { - collection: 'T2615', - resource: 'T2615', - action: 'list', - params: { - pageSize: 20, - }, - rowKey: 'id', - showIndex: true, - dragSort: false, - disableTemplate: false, - }, - 'x-designer': 'TableBlockDesigner', - 'x-component': 'CardItem', - 'x-filter-targets': [], - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'TableActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 'var(--nb-spacing)', - }, - }, - properties: { - unexw8b0ued: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-action': 'create', - 'x-acl-action': 'create', - title: "{{t('Add new')}}", - 'x-designer': 'Action.Designer', - 'x-component': 'Action', - 'x-decorator': 'ACLActionProvider', - 'x-component-props': { - openMode: 'drawer', - type: 'primary', - component: 'CreateRecordAction', - icon: 'PlusOutlined', - }, - 'x-align': 'right', - 'x-acl-action-props': { - skipScopeCheck: true, - }, - properties: { - drawer: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Add record") }}', - 'x-component': 'Action.Container', - 'x-component-props': { - className: 'nb-action-popup', - }, - properties: { - tabs: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Tabs', - 'x-component-props': {}, - 'x-initializer': 'TabPaneInitializersForCreateFormBlock', - properties: { - tab1: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{t("Add new")}}', - 'x-component': 'Tabs.TabPane', - 'x-designer': 'Tabs.Designer', - 'x-component-props': {}, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'CreateFormBlockInitializers', - properties: { - '8ei3tsaojf6': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - '5u0ju1wsgkl': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - zxwg35f8sg7: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-acl-action-props': { - skipScopeCheck: true, - }, - 'x-acl-action': 'T2615:create', - 'x-decorator': 'FormBlockProvider', - 'x-decorator-props': { - resource: 'T2615', - collection: 'T2615', - }, - 'x-designer': 'FormV2.Designer', - 'x-component': 'CardItem', - 'x-component-props': {}, - properties: { - '9i2u8628hoz': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'FormV2', - 'x-component-props': { - useProps: '{{ useFormBlockProps }}', - }, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'FormItemInitializers', - properties: { - i7cb2o172ey: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - enue1mnnt4g: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - m2o: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'string', - 'x-designer': 'FormItem.Designer', - 'x-component': 'CollectionField', - 'x-decorator': 'FormItem', - 'x-collection-field': 'T2615.m2o', - 'x-component-props': {}, - 'x-uid': 'tif3ncbwwru', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'jh5w5yne4qt', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'aqo2rtciew5', - 'x-async': false, - 'x-index': 1, - }, - qfr6n6ymx77: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - ldlk5ifn56r: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - 'm2o.m2oOfTarget1': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'string', - 'x-designer': 'FormItem.Designer', - 'x-component': 'CollectionField', - 'x-read-pretty': true, - 'x-component-props': { - 'pattern-disable': true, - fieldNames: { - label: 'id', - value: 'id', - }, - }, - 'x-decorator': 'FormItem', - 'x-collection-field': - 'T2615.m2o.m2oOfTarget1', - 'x-uid': 'gii2rk1q4fx', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'k2k4hzsmxzw', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'tysg8zh5wpp', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': '7ff0fvn1ci1', - 'x-async': false, - 'x-index': 1, - }, - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'CreateFormActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - layout: 'one-column', - style: { - marginTop: 24, - }, - }, - 'x-uid': '6u35dl8quee', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': '5syf9qhcwch', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '26kgmi2guwg', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'i1hdum7ju7d', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '8e7td05t5rv', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'nlgcjcl7sm2', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'hzn4uinj3i7', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'qkv3lilo9ew', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'k945b89wggu', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'pz18nxb0x51', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '94386mg3n6z', - 'x-async': false, - 'x-index': 1, - }, - '3m6w3iz4c5t': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'array', - 'x-initializer': 'TableColumnInitializers', - 'x-component': 'TableV2', - 'x-component-props': { - rowKey: 'id', - rowSelection: { - type: 'checkbox', - }, - useProps: '{{ useTableBlockProps }}', - }, - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Actions") }}', - 'x-action-column': 'actions', - 'x-decorator': 'TableV2.Column.ActionBar', - 'x-component': 'TableV2.Column', - 'x-designer': 'TableV2.ActionColumnDesigner', - 'x-initializer': 'TableActionColumnInitializers', - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-decorator': 'DndContext', - 'x-component': 'Space', - 'x-component-props': { - split: '|', - }, - properties: { - yych9x95hrp: { - 'x-uid': 'uv7zmtj0r5u', - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: 'Edit record', - 'x-action': 'update', - 'x-designer': 'Action.Designer', - 'x-component': 'Action.Link', - 'x-component-props': { - openMode: 'drawer', - danger: false, - }, - 'x-decorator': 'ACLActionProvider', - 'x-designer-props': { - linkageAction: true, - }, - properties: { - drawer: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("Edit record") }}', - 'x-component': 'Action.Container', - 'x-component-props': { - className: 'nb-action-popup', - }, - properties: { - tabs: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Tabs', - 'x-component-props': {}, - 'x-initializer': 'TabPaneInitializers', - properties: { - tab1: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{t("Edit")}}', - 'x-component': 'Tabs.TabPane', - 'x-designer': 'Tabs.Designer', - 'x-component-props': {}, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'RecordBlockInitializers', - properties: { - l79xm6sfjst: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - '7cyquusb2ca': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - '8dxzx9t0571': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-acl-action-props': { - skipScopeCheck: false, - }, - 'x-acl-action': 'T2615:update', - 'x-decorator': 'FormBlockProvider', - 'x-decorator-props': { - useSourceId: '{{ useSourceIdFromParentRecord }}', - useParams: '{{ useParamsFromRecord }}', - action: 'get', - resource: 'T2615', - collection: 'T2615', - }, - 'x-designer': 'FormV2.Designer', - 'x-component': 'CardItem', - 'x-component-props': {}, - properties: { - '21sxtdkbcw0': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'FormV2', - 'x-component-props': { - useProps: '{{ useFormBlockProps }}', - }, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'FormItemInitializers', - properties: { - '7eayo28dgzo': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - oj9yj21ujd8: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - m2o: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'string', - 'x-designer': 'FormItem.Designer', - 'x-component': 'CollectionField', - 'x-decorator': 'FormItem', - 'x-collection-field': 'T2615.m2o', - 'x-component-props': {}, - 'x-uid': 'qxn8qacg682', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'axx7wvrxnem', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'qgkr6iz0e1t', - 'x-async': false, - 'x-index': 1, - }, - zsdbhvdvaru: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - '082hatydnd0': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - 'm2o.m2oOfTarget1': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'string', - 'x-designer': 'FormItem.Designer', - 'x-component': 'CollectionField', - 'x-read-pretty': true, - 'x-component-props': { - 'pattern-disable': true, - fieldNames: { - label: 'id', - value: 'id', - }, - }, - 'x-decorator': 'FormItem', - 'x-collection-field': - 'T2615.m2o.m2oOfTarget1', - 'x-uid': 'n5s7j4n193r', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'nm9qq5hao2e', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'ey3595qsqyk', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'w8zdw4dr89d', - 'x-async': false, - 'x-index': 1, - }, - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': 'UpdateFormActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - layout: 'one-column', - style: { - marginTop: 24, - }, - }, - 'x-uid': 'conyu4tdnsb', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': '6jeoainb2oa', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '27azok1hcrs', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'x0gpfgjc0n1', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '0up3rbfoby1', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'tul7kvn3s6m', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'jz2lb20hu1s', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'ssbzj9yrh8r', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'dak290d9mnz', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-async': false, - 'x-index': 1, - }, - t452of8muaq: { - 'x-uid': 'q4op427zlfp', - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: 'View record', - 'x-action': 'view', - 'x-designer': 'Action.Designer', - 'x-component': 'Action.Link', - 'x-component-props': { - openMode: 'drawer', - danger: false, - }, - 'x-decorator': 'ACLActionProvider', - 'x-designer-props': { - linkageAction: true, - }, - properties: { - drawer: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{ t("View record") }}', - 'x-component': 'Action.Container', - 'x-component-props': { - className: 'nb-action-popup', - }, - properties: { - tabs: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Tabs', - 'x-component-props': {}, - 'x-initializer': 'TabPaneInitializers', - properties: { - tab1: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - title: '{{t("Details")}}', - 'x-component': 'Tabs.TabPane', - 'x-designer': 'Tabs.Designer', - 'x-component-props': {}, - properties: { - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': 'RecordBlockInitializers', - properties: { - nlnfd9hnl53: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - o1mvvolrr3n: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - '02tm0tr9gie': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-acl-action': 'T2615:get', - 'x-decorator': 'FormBlockProvider', - 'x-decorator-props': { - resource: 'T2615', - collection: 'T2615', - readPretty: true, - action: 'get', - useParams: '{{ useParamsFromRecord }}', - useSourceId: '{{ useSourceIdFromParentRecord }}', - }, - 'x-designer': 'FormV2.ReadPrettyDesigner', - 'x-component': 'CardItem', - properties: { - xa10ops1tmr: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'FormV2', - 'x-read-pretty': true, - 'x-component-props': { - useProps: '{{ useFormBlockProps }}', - }, - properties: { - actions: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-initializer': - 'ReadPrettyFormActionInitializers', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - marginBottom: 24, - }, - }, - 'x-uid': 'jq1vdqw4oyy', - 'x-async': false, - 'x-index': 1, - }, - grid: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid', - 'x-initializer': - 'ReadPrettyFormItemInitializers', - properties: { - j9mxulol74m: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - r4alweypz03: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - m2o: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'string', - 'x-designer': 'FormItem.Designer', - 'x-component': 'CollectionField', - 'x-decorator': 'FormItem', - 'x-collection-field': 'T2615.m2o', - 'x-component-props': {}, - 'x-uid': 'ttv0hjsnnsy', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'p9yvxr8b7vg', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'r198z5pv6c4', - 'x-async': false, - 'x-index': 1, - }, - xb97qr5ustn: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Row', - properties: { - wje8oyfbn1d: { - _isJSONSchemaObject: true, - version: '2.0', - type: 'void', - 'x-component': 'Grid.Col', - properties: { - 'm2o.m2oOfTarget1': { - _isJSONSchemaObject: true, - version: '2.0', - type: 'string', - 'x-designer': 'FormItem.Designer', - 'x-component': 'CollectionField', - 'x-read-pretty': true, - 'x-component-props': { - 'pattern-disable': true, - fieldNames: { - label: 'id', - value: 'id', - }, - }, - 'x-decorator': 'FormItem', - 'x-collection-field': - 'T2615.m2o.m2oOfTarget1', - 'x-uid': '6pdlbj34175', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'p2alwntoxkg', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'rgsbhuo0lzv', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'a39j3mj83xp', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'd6xf1x23yzx', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '5esxphd790l', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'pzr8i6utc83', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'u8wkbbgvb05', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'boh5n3tkmgu', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'd0cfvm929ca', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'wt7e6356t9k', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'cqnlqotquv9', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'x8yf6ex62ju', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 't4gcpw7ji0u', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '8d8oe7qocry', - 'x-async': false, - 'x-index': 2, - }, - }, - 'x-uid': 'vyf1ac9nsl5', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': '8zp6xvttwvi', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'axknjuou42g', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'xtxm0hd6lbi', - 'x-async': false, - 'x-index': 1, - }, - }, - 'x-uid': 'lbdmizeodxy', - 'x-async': true, - 'x-index': 1, - }, -}; diff --git a/packages/core/test/src/client/templatesOfBug/index.ts b/packages/core/test/src/client/templatesOfBug/index.ts deleted file mode 100644 index 1c6357183..000000000 --- a/packages/core/test/src/client/templatesOfBug/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './T-2614'; -export * from './T-2615'; diff --git a/packages/core/test/src/client/templatesOfCollection.ts b/packages/core/test/src/client/templatesOfCollection.ts index 8d8444f3a..83b4fcace 100644 --- a/packages/core/test/src/client/templatesOfCollection.ts +++ b/packages/core/test/src/client/templatesOfCollection.ts @@ -373,7 +373,7 @@ export const generalWithDatetime: CollectionSetting[] = [ /** * 创建一个名为 general 的 collection,其包含所有 relation 类型的字段 */ -export const generalWithRelation: CollectionSetting[] = [ +export const generalWithAssociation: CollectionSetting[] = [ { name: 'general', title: 'General', @@ -611,7 +611,7 @@ export const tree: CollectionSetting[] = [ }, ]; -export const generalWithMultiLevelRelationshipFields: CollectionSetting[] = [ +export const generalWithMultiLevelM2oFields: CollectionSetting[] = [ { name: 'general', title: 'General', @@ -649,4 +649,55 @@ export const generalWithMultiLevelRelationshipFields: CollectionSetting[] = [ }, ], }, + { + name: 'm2oField3', + title: 'M2o field 3', + fields: [ + { + name: 'm2oField3', + interface: 'm2o', + target: 'users', + }, + ], + }, +]; + +export const generalWithMultiLevelM2mFields: CollectionSetting[] = [ + { + name: 'general', + title: 'General', + fields: [ + { + name: 'm2mField0', + interface: 'm2m', + target: 'm2mField1', + }, + { + name: 'singleLineText', + interface: 'input', + }, + ], + }, + { + name: 'm2mField1', + title: 'M2o field 1', + fields: [ + { + name: 'm2mField1', + interface: 'm2m', + target: 'm2mField2', + }, + ], + }, + { + name: 'm2mField2', + title: 'M2o field 2', + fields: [ + { + name: 'm2mField2', + interface: 'm2m', + target: 'users', + }, + ], + }, ]; diff --git a/packages/core/test/src/client/templatesOfPage.ts b/packages/core/test/src/client/templatesOfPage.ts index 63c6e027d..51c4b6e78 100644 --- a/packages/core/test/src/client/templatesOfPage.ts +++ b/packages/core/test/src/client/templatesOfPage.ts @@ -1,12 +1,14 @@ import { PageConfig } from './e2eUtils'; import { generalWithAdvanced, + generalWithAssociation, generalWithBasic, generalWithChoices, generalWithDatetime, generalWithM2oSingleSelect, generalWithMedia, - generalWithRelation, + generalWithMultiLevelM2mFields, + generalWithMultiLevelM2oFields, generalWithSingleLineText, generalWithSystemInfo, tree, @@ -3084,6 +3086,637 @@ export const oneFormBlockWithRolesFieldBasedUsers: PageConfig = { }, }; +/** + * 一个 Form 区块,包含所有的关系字段,且都是数据选择器模式 + */ +export const oneFormBlockWithAllAssociationFieldsAndSelectorMode: PageConfig = { + collections: generalWithAssociation, + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + '7non4os38qt': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + f3fq1mwccgr: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '4zy7hvm9tx2': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + ektj73b5e1w: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + 'x-acl-action': 'general:create', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + resource: 'general', + collection: 'general', + }, + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-component-props': {}, + properties: { + v52zzjstogu: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + properties: { + '7dnk9dcjavn': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + ij6ncczze6e: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + oneToOneBelongsTo: { + 'x-uid': '143clhz211l', + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.oneToOneBelongsTo', + 'x-component-props': { + mode: 'Picker', + }, + properties: { + y7l93di0jy3: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'AssociationField.Selector', + title: '{{ t("Select record") }}', + 'x-component-props': { + className: 'nb-record-picker-selector', + }, + 'x-index': 1, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'TableSelectorInitializers', + 'x-uid': 'dge1apckyd3', + 'x-async': false, + 'x-index': 1, + }, + footer: { + _isJSONSchemaObject: true, + version: '2.0', + 'x-component': 'Action.Container.Footer', + 'x-component-props': {}, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'ActionBar', + 'x-component-props': {}, + properties: { + submit: { + _isJSONSchemaObject: true, + version: '2.0', + title: '{{ t("Submit") }}', + 'x-action': 'submit', + 'x-component': 'Action', + 'x-designer': 'Action.Designer', + 'x-component-props': { + type: 'primary', + htmlType: 'submit', + useProps: '{{ usePickActionProps }}', + }, + 'x-uid': 'ityf1rjxx9e', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '7eyrtro2425', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xtux56bcbs6', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'i1hn3l571i9', + 'x-async': false, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '1cqnoy3qwvi', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '4ofhak58svv', + 'x-async': false, + 'x-index': 1, + }, + xvm7es7p2rw: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + wq17uuljd30: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + oneToOneHasOne: { + 'x-uid': 'bcdr6m4vr0a', + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.oneToOneHasOne', + 'x-component-props': { + mode: 'Picker', + }, + properties: { + ufa9x5wndk6: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'AssociationField.Selector', + title: '{{ t("Select record") }}', + 'x-component-props': { + className: 'nb-record-picker-selector', + }, + 'x-index': 1, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'TableSelectorInitializers', + 'x-uid': 'k6nd50abevi', + 'x-async': false, + 'x-index': 1, + }, + footer: { + _isJSONSchemaObject: true, + version: '2.0', + 'x-component': 'Action.Container.Footer', + 'x-component-props': {}, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'ActionBar', + 'x-component-props': {}, + properties: { + submit: { + _isJSONSchemaObject: true, + version: '2.0', + title: '{{ t("Submit") }}', + 'x-action': 'submit', + 'x-component': 'Action', + 'x-designer': 'Action.Designer', + 'x-component-props': { + type: 'primary', + htmlType: 'submit', + useProps: '{{ usePickActionProps }}', + }, + 'x-uid': 'hateux13exj', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'jxdj2cedz62', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ljoe19o0h40', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'mg1nuzcin8g', + 'x-async': false, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'nxhgpjm9aeg', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '1uj6qvl8bmr', + 'x-async': false, + 'x-index': 2, + }, + o2m9t4nwgei: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + lsi89mszpzc: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + oneToMany: { + 'x-uid': 'zbmdk1p1k2a', + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.oneToMany', + 'x-component-props': { + mode: 'Picker', + }, + properties: { + cf1x4mk0011: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'AssociationField.Selector', + title: '{{ t("Select record") }}', + 'x-component-props': { + className: 'nb-record-picker-selector', + }, + 'x-index': 1, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'TableSelectorInitializers', + 'x-uid': '2i6td26ppt2', + 'x-async': false, + 'x-index': 1, + }, + footer: { + _isJSONSchemaObject: true, + version: '2.0', + 'x-component': 'Action.Container.Footer', + 'x-component-props': {}, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'ActionBar', + 'x-component-props': {}, + properties: { + submit: { + _isJSONSchemaObject: true, + version: '2.0', + title: '{{ t("Submit") }}', + 'x-action': 'submit', + 'x-component': 'Action', + 'x-designer': 'Action.Designer', + 'x-component-props': { + type: 'primary', + htmlType: 'submit', + useProps: '{{ usePickActionProps }}', + }, + 'x-uid': 'sikmm76pn5w', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '9od0jar1mxv', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'zb0onwdbxe0', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'cgtaqsm51aq', + 'x-async': false, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '7bc0wsuyi05', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'kpk6a996usj', + 'x-async': false, + 'x-index': 3, + }, + ksb1lkyg2vm: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + vn3bxo620dc: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + manyToOne: { + 'x-uid': 'ih8j26llioa', + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.manyToOne', + 'x-component-props': { + mode: 'Picker', + }, + properties: { + vqru1eq9jya: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'AssociationField.Selector', + title: '{{ t("Select record") }}', + 'x-component-props': { + className: 'nb-record-picker-selector', + }, + 'x-index': 1, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'TableSelectorInitializers', + 'x-uid': 'zlj99lap4yq', + 'x-async': false, + 'x-index': 1, + }, + footer: { + _isJSONSchemaObject: true, + version: '2.0', + 'x-component': 'Action.Container.Footer', + 'x-component-props': {}, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'ActionBar', + 'x-component-props': {}, + properties: { + submit: { + _isJSONSchemaObject: true, + version: '2.0', + title: '{{ t("Submit") }}', + 'x-action': 'submit', + 'x-component': 'Action', + 'x-designer': 'Action.Designer', + 'x-component-props': { + type: 'primary', + htmlType: 'submit', + useProps: '{{ usePickActionProps }}', + }, + 'x-uid': '18rs8r8zva9', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'pt5rwnfsygp', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'lqmsnk6ca2u', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '68i421byiu9', + 'x-async': false, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'akt9xyppt0v', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'wmmjgunfbnh', + 'x-async': false, + 'x-index': 4, + }, + '2fn1cwmcenb': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '6pvgl9hhm1r': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + manyToMany: { + 'x-uid': 'b1fmm3pv8uz', + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.manyToMany', + 'x-component-props': { + mode: 'Picker', + }, + properties: { + '50xctb931w0': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'AssociationField.Selector', + title: '{{ t("Select record") }}', + 'x-component-props': { + className: 'nb-record-picker-selector', + }, + 'x-index': 1, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'TableSelectorInitializers', + 'x-uid': 'ssclmlysxxl', + 'x-async': false, + 'x-index': 1, + }, + footer: { + _isJSONSchemaObject: true, + version: '2.0', + 'x-component': 'Action.Container.Footer', + 'x-component-props': {}, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'ActionBar', + 'x-component-props': {}, + properties: { + submit: { + _isJSONSchemaObject: true, + version: '2.0', + title: '{{ t("Submit") }}', + 'x-action': 'submit', + 'x-component': 'Action', + 'x-designer': 'Action.Designer', + 'x-component-props': { + type: 'primary', + htmlType: 'submit', + useProps: '{{ usePickActionProps }}', + }, + 'x-uid': 'rhdgnyvz0ib', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'iah8805lt74', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '21zl8yc1s8k', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'nmlfc6qeilk', + 'x-async': false, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '31k7h3q9vdw', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'nc4h9wb9dgq', + 'x-async': false, + 'x-index': 5, + }, + }, + 'x-uid': '5jd4lt19ve1', + 'x-async': false, + 'x-index': 1, + }, + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'FormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + 'x-uid': 'vkgqkkmdesn', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'd6l3sj7v0cd', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'y0xkk137pjg', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'hnch4c24yam', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ofe2k0c6tn4', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '2048m38uv0a', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '8alveq1e0ma', + 'x-async': true, + 'x-index': 1, + }, +}; + /** * 页面中有一个详情区块,且有一个名为 toGeneral 的关系字段(m2o),指向 General 表 */ @@ -8716,8 +9349,8 @@ export const oneTableBlockWithAddNewAndViewAndEditAndDatetimeFields: PageConfig * 4. 点击 Edit 有一个 Form 区块 * 5. 所有字段都是 relation 字段 */ -export const oneTableBlockWithAddNewAndViewAndEditAndRelationFields: PageConfig = { - collections: generalWithRelation, +export const oneTableBlockWithAddNewAndViewAndEditAndAssociationFields: PageConfig = { + collections: generalWithAssociation, pageSchema: { _isJSONSchemaObject: true, version: '2.0', @@ -13155,3 +13788,5471 @@ export const oneEmptyTableWithTreeCollection: PageConfig = { 'x-index': 1, }, }; + +export const oneEmptyMarkdown: PageConfig = { + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + r012bjo390e: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + eocwxdkmped: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + neyr2va5ugv: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + wlxm2dr507u: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-designer': 'Markdown.Void.Designer', + 'x-decorator': 'CardItem', + 'x-decorator-props': { + name: 'markdown', + }, + 'x-component': 'Markdown.Void', + 'x-editable': false, + 'x-component-props': { + content: 'This is a demo text, **supports Markdown syntax**.', + }, + 'x-uid': 'xqed6ep1ui1', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'fq0chc8fsg8', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'be71fm1px7o', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'elcgo0eecw2', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'tqyjlhd7eyj', + 'x-async': true, + 'x-index': 1, + }, +}; + +/** + * 一个 collapse block 和一个 table block 且它们的数据表相同 + */ +export const oneCollapseAndOneTableWithSameCollection: PageConfig = { + collections: generalWithChoices, + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + jxgbx92czdd: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + xxnsq3r1w5u: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + o5ulrlifkhp: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + x0iipsghykq: { + 'x-uid': '325t1dnvyoa', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'AssociationFilter.Provider', + 'x-decorator-props': { + collection: 'general', + blockType: 'filter', + associationFilterStyle: { + width: '100%', + }, + name: 'filter-collapse', + }, + 'x-designer': 'AssociationFilter.BlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + lsilk6r7192: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-action': 'associateFilter', + 'x-initializer': 'AssociationFilter.FilterBlockInitializer', + 'x-component': 'AssociationFilter', + properties: { + singleSelect: { + _isJSONSchemaObject: true, + version: '2.0', + title: 'singleSelect', + interface: 'select', + type: 'void', + 'x-designer': 'AssociationFilter.Item.Designer', + 'x-component': 'AssociationFilter.Item', + 'x-component-props': { + fieldNames: { + label: 'singleSelect', + }, + useProps: '{{useAssociationFilterBlockProps}}', + }, + 'x-uid': 'o4wigvr1cxo', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'f8lk8ibhgrm', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xk98n4xjp10', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'cijnohur32y', + 'x-async': false, + 'x-index': 1, + }, + r1dqoqzo9xk: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + xd8oyouhi1g: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + e0pa953qo00: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'general:list', + 'x-decorator-props': { + collection: 'general', + resource: 'general', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + 'x-uid': 'nq51lizkoo4', + 'x-async': false, + 'x-index': 1, + }, + xodu4re5kqd: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + properties: { + rwf529x2vds: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableV2.Column.Decorator', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + properties: { + singleSelect: { + _isJSONSchemaObject: true, + version: '2.0', + 'x-collection-field': 'general.singleSelect', + 'x-component': 'CollectionField', + 'x-component-props': { + style: { + width: '100%', + }, + ellipsis: true, + }, + 'x-read-pretty': true, + 'x-decorator': null, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-uid': 'e270d5dgyps', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xdamueag38i', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'pcys8enhlel', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'esqois39pf6', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'okd9rwio86x', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'wg35urizw83', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '7ta0nzl3kwd', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'jxra1wgobos', + 'x-async': true, + 'x-index': 1, + }, +}; + +/** + * 一个包含多层级关系字段的表单区块 + */ + +export const oneFormWithMultiLevelAssociationFields: PageConfig = { + collections: generalWithMultiLevelM2oFields, + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + chxe6j9szj6: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + djjvozyzzha: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + pbes49a5cl4: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + ha51vlyefac: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + 'x-acl-action': 'general:create', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + resource: 'general', + collection: 'general', + }, + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-component-props': {}, + properties: { + ih1nztqs13s: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + properties: { + grgso6wba2b: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + h8lo5808cy4: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + m2oField0: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.m2oField0', + 'x-component-props': {}, + 'x-uid': 'y2bhwuzsffe', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'z59ao0q32u3', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'lzcl42nimim', + 'x-async': false, + 'x-index': 1, + }, + utb2rtfq32g: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '9eg2gq78f2v': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + 'm2oField0.id': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-read-pretty': true, + 'x-component-props': { + 'pattern-disable': true, + }, + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.m2oField0.id', + 'x-uid': 'u32ijkyyi0m', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'zieisf6j5p6', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'bairx76ympz', + 'x-async': false, + 'x-index': 2, + }, + '9e2ea2rlrkt': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + j3wsgcewsod: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + 'm2oField0.m2oField1': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-read-pretty': true, + 'x-component-props': { + 'pattern-disable': true, + fieldNames: { + label: 'id', + value: 'id', + }, + }, + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.m2oField0.m2oField1', + 'x-uid': '6bd9e6utxs2', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'gnmrd6yupaj', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'b8tmz97m6x3', + 'x-async': false, + 'x-index': 3, + }, + }, + 'x-uid': 'lfgi8eim0mo', + 'x-async': false, + 'x-index': 1, + }, + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'FormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + properties: { + w3wtnxq77vt: { + _isJSONSchemaObject: true, + version: '2.0', + title: '{{ t("Submit") }}', + 'x-action': 'submit', + 'x-component': 'Action', + 'x-designer': 'Action.Designer', + 'x-component-props': { + type: 'primary', + htmlType: 'submit', + useProps: '{{ useCreateActionProps }}', + }, + 'x-action-settings': { + triggerWorkflows: [], + }, + type: 'void', + 'x-uid': '93e5papnmj0', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '7wqbpt1wava', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'su9jns6zj7l', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '1jpth1sbull', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'yn6nf6c4szy', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'febgraq7qvc', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'pbd6pelckfe', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'id3e7c1lwkk', + 'x-async': true, + 'x-index': 1, + }, +}; + +/** + * 一个包含多层级关系字段的子表单区块,并包含在一个表单区块中 + */ + +export const oneSubformWithMultiLevelAssociationFields: PageConfig = { + collections: generalWithMultiLevelM2oFields, + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + fg73c78h3y5: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + mxqswxl18hb: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + pvya66dzvlv: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + g5f3es7nr3r: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + 'x-acl-action': 'general:create', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + resource: 'general', + collection: 'general', + }, + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-component-props': {}, + properties: { + c5o86nxd9mb: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + properties: { + '6k12v33b6j3': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + ejv7tdy2q1g: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + m2oField0: { + 'x-uid': 'ijsezl2rah0', + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.m2oField0', + 'x-component-props': { + mode: 'Nester', + }, + default: null, + properties: { + sitlmusvkkb: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'AssociationField.Nester', + 'x-index': 1, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + properties: { + '9c4mwdnt1kf': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + zudd6bmz8hi: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + m2oField1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'm2oField1.m2oField1', + 'x-component-props': {}, + 'x-uid': 'vmmm2ps83ps', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'lfjt1mhtl1m', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '3ruo5g1rlbl', + 'x-async': false, + 'x-index': 1, + }, + klebqe3e574: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + j446pc51eyn: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + 'm2oField1.id': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-read-pretty': true, + 'x-component-props': { + 'pattern-disable': true, + }, + 'x-decorator': 'FormItem', + 'x-collection-field': 'm2oField1.m2oField1.id', + 'x-uid': '7hnxu7tlltv', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'vk58v8zpmkv', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ymxrni6xxzw', + 'x-async': false, + 'x-index': 2, + }, + qk6n0s3rvk8: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + h0g7qin8fs0: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + 'm2oField1.m2oField2': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-read-pretty': true, + 'x-component-props': { + 'pattern-disable': true, + fieldNames: { + label: 'id', + value: 'id', + }, + }, + 'x-decorator': 'FormItem', + 'x-collection-field': 'm2oField1.m2oField1.m2oField2', + 'x-uid': 'dgladqknqnn', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'bqo7plvgb0x', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'no21vaa586q', + 'x-async': false, + 'x-index': 3, + }, + }, + 'x-uid': 'awlaaufu6ay', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'cn0jjygl84n', + 'x-async': false, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'su0d33tuog3', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ht322ua6dhi', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'juoqrg2igra', + 'x-async': false, + 'x-index': 1, + }, + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'FormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + properties: { + rdn1925t3ob: { + _isJSONSchemaObject: true, + version: '2.0', + title: '{{ t("Submit") }}', + 'x-action': 'submit', + 'x-component': 'Action', + 'x-designer': 'Action.Designer', + 'x-component-props': { + type: 'primary', + htmlType: 'submit', + useProps: '{{ useCreateActionProps }}', + }, + 'x-action-settings': { + triggerWorkflows: [], + }, + type: 'void', + 'x-uid': 'e7m2uvv5pm3', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '48u4hmqlo6h', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'qsh7fle6kg5', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'vto5yeudv3q', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'fls10nmi74s', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '6f5agngf4ek', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '9ix5t83i1ts', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'f8ujqqi4tyi', + 'x-async': true, + 'x-index': 1, + }, +}; + +/** + * 一个包含多层级关系字段的子表单区块,并包含在一个表单区块中,该区块存在于一个编辑弹窗中 + */ + +export const oneTableSubformWithMultiLevelAssociationFields: PageConfig = { + collections: generalWithMultiLevelM2oFields, + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + c28btifcxho: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + spt3dncqt6g: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + uldwynws3cx: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + bzn1h0lpoks: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'general:list', + 'x-decorator-props': { + collection: 'general', + resource: 'general', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + properties: { + gia25ckb33i: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-action': 'create', + 'x-acl-action': 'create', + title: "{{t('Add new')}}", + 'x-designer': 'Action.Designer', + 'x-component': 'Action', + 'x-decorator': 'ACLActionProvider', + 'x-component-props': { + openMode: 'drawer', + type: 'primary', + component: 'CreateRecordAction', + icon: 'PlusOutlined', + }, + 'x-align': 'right', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Add record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializersForCreateFormBlock', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Add new")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'CreateFormBlockInitializers', + 'x-uid': 'ezrqm7whaxk', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'k3o2j3ki7b0', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'l4inxlbpx7u', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'rlqph2piz80', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'czs0vecrs2j', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '6dzswixui3y', + 'x-async': false, + 'x-index': 1, + }, + e9himo1vo6z: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Actions") }}', + 'x-action-column': 'actions', + 'x-decorator': 'TableV2.Column.ActionBar', + 'x-component': 'TableV2.Column', + 'x-designer': 'TableV2.ActionColumnDesigner', + 'x-initializer': 'TableActionColumnInitializers', + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + properties: { + '14v6hewqyv9': { + 'x-uid': 'eho7lu9n9w5', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: 'View record', + 'x-action': 'view', + 'x-designer': 'Action.Designer', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + danger: false, + }, + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("View record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializers', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Details")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + properties: { + rxh2yo159ct: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '69rqqe6s59n': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + cv1hoy6z73u: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action': 'general:get', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + resource: 'general', + collection: 'general', + readPretty: true, + action: 'get', + useParams: '{{ useParamsFromRecord }}', + useSourceId: '{{ useSourceIdFromParentRecord }}', + }, + 'x-designer': 'FormV2.ReadPrettyDesigner', + 'x-component': 'CardItem', + properties: { + ebfwg6en8z3: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-read-pretty': true, + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': + 'ReadPrettyFormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 24, + }, + }, + 'x-uid': 'nczbuzgyi5i', + 'x-async': false, + 'x-index': 1, + }, + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': + 'ReadPrettyFormItemInitializers', + properties: { + h091lw5s3ot: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '0okszebti37': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + id: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.id', + 'x-component-props': {}, + 'x-read-pretty': true, + 'x-uid': '0i8lx83o56y', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'm6fpas6blbk', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '65osczc92cz', + 'x-async': false, + 'x-index': 1, + }, + srpbcst368p: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '4abbfjvct52': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + m2oField0: { + 'x-uid': 'xg3v3n31u5u', + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': + 'general.m2oField0', + 'x-component-props': { + mode: 'Nester', + }, + properties: { + jeamfyhg8r9: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': + 'AssociationField.Nester', + 'x-index': 1, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': + 'FormItemInitializers', + properties: { + '7gni7kgrxc6': { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'Grid.Row', + properties: { + ol9n4vgrj4a: { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'Grid.Col', + properties: { + id: { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'string', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-collection-field': + 'm2oField1.id', + 'x-component-props': + {}, + 'x-read-pretty': + true, + 'x-uid': + 'pcudj4r7tag', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'f11jr4ikfae', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '09v08ousd8s', + 'x-async': false, + 'x-index': 1, + }, + '6i64qc2t8yl': { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'Grid.Row', + properties: { + ua78t3hazyg: { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'Grid.Col', + properties: { + m2oField1: { + 'x-uid': + '6i5hvki95fm', + _isJSONSchemaObject: + true, + version: '2.0', + type: 'string', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-collection-field': + 'm2oField1.m2oField1', + 'x-component-props': + { + mode: 'Nester', + }, + properties: { + l64n7q06u69: { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'AssociationField.Nester', + 'x-index': 1, + properties: + { + grid: { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid', + 'x-initializer': + 'FormItemInitializers', + properties: + { + wfis8uozy45: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid.Row', + properties: + { + widjeb1iua5: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid.Col', + properties: + { + id: { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'string', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-collection-field': + 'm2oField2.id', + 'x-component-props': + {}, + 'x-read-pretty': + true, + 'x-uid': + 'm8wz20ffkim', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + '8zrvt9woaxx', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'qg62l58hu4n', + 'x-async': + false, + 'x-index': 1, + }, + gos46xkhf6j: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid.Row', + properties: + { + dvgf1pge350: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid.Col', + properties: + { + m2oField2: + { + 'x-uid': + 'gweez55achj', + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'string', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-collection-field': + 'm2oField2.m2oField2', + 'x-component-props': + { + mode: 'Nester', + }, + properties: + { + ipwo3aeoxd1: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'AssociationField.Nester', + 'x-index': 1, + properties: + { + grid: { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid', + 'x-initializer': + 'FormItemInitializers', + properties: + { + '8ga4k036hkh': + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid.Row', + properties: + { + msnws5m7e3n: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid.Col', + properties: + { + id: { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'string', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-collection-field': + 'm2oField3.id', + 'x-component-props': + {}, + 'x-read-pretty': + true, + 'x-uid': + '9rpoyelp388', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + '3l348ecw0f4', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'ii5542jvwe9', + 'x-async': + false, + 'x-index': 1, + }, + '08qsmq3fwps': + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid.Row', + properties: + { + f8be5hgqwzq: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid.Col', + properties: + { + m2oField3: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'string', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-collection-field': + 'm2oField3.m2oField3', + 'x-component-props': + {}, + 'x-uid': + 'ves5a1w4pmu', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'u6qilftivur', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'nbrjmpq5y84', + 'x-async': + false, + 'x-index': 2, + }, + }, + 'x-uid': + '3klghjyhn2e', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'k9ck22tm51h', + 'x-async': + false, + }, + }, + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'm4wi2pzpr87', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'sp5w23qy3i1', + 'x-async': + false, + 'x-index': 2, + }, + }, + 'x-uid': + 'oqz60xa1yfi', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'n1rdyer1njy', + 'x-async': + false, + }, + }, + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 't0kqiyg4azb', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'hix2aljl42o', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'v4l4i2y2muy', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'r92l2b1ewpw', + 'x-async': false, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'wlal3xrcd21', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'gy06o4bfvel', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'rnp98kdp6i7', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'jydd6xqpmag', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '99xcv098sqb', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ore0g08xym5', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'c4rlk8cyndy', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'auduflh6ir7', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '6lystaearad', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xu14c7orxj9', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'uqa225n3ft0', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + kry6i1da0tj: { + 'x-uid': 'stbtydj2qmh', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: 'Edit record', + 'x-action': 'update', + 'x-designer': 'Action.Designer', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + danger: false, + }, + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Edit record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializers', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Edit")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + properties: { + scqusdl60dp: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '56qqqtcv7sq': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + psqi07luu6x: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: false, + }, + 'x-acl-action': 'general:update', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + useSourceId: '{{ useSourceIdFromParentRecord }}', + useParams: '{{ useParamsFromRecord }}', + action: 'get', + resource: 'general', + collection: 'general', + }, + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-component-props': {}, + properties: { + s5yzffu11uz: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + properties: { + row_x1kzwaop93e: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-index': 1, + properties: { + o61mnyb3cna: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + id: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.id', + 'x-component-props': {}, + 'x-read-pretty': true, + 'x-uid': '2o3igjsny73', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '24k5mv82ryg', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'cv0w2l9u3rz', + 'x-async': false, + }, + x4lyvwpaszb: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + t0j05k5davx: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + m2oField0: { + 'x-uid': '5m0bfy8diwb', + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': + 'general.m2oField0', + 'x-component-props': { + mode: 'Nester', + }, + properties: { + fzpkx5l8as7: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': + 'AssociationField.Nester', + 'x-index': 1, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': + 'FormItemInitializers', + properties: { + '0o134mwdmzm': { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'Grid.Row', + properties: { + '7dxzwgyax59': { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'Grid.Col', + properties: { + id: { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'string', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-collection-field': + 'm2oField1.id', + 'x-component-props': + {}, + 'x-read-pretty': + true, + 'x-uid': + 'b7wd6150b6h', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'msf0aqn6h85', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '25a3ulhciro', + 'x-async': false, + 'x-index': 1, + }, + '3m1ohstn0b8': { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'Grid.Row', + properties: { + sqtguwxadwu: { + _isJSONSchemaObject: + true, + version: '2.0', + type: 'void', + 'x-component': + 'Grid.Col', + properties: { + m2oField1: { + 'x-uid': + 'v2nrgm7uu51', + _isJSONSchemaObject: + true, + version: '2.0', + type: 'string', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-collection-field': + 'm2oField1.m2oField1', + 'x-component-props': + { + mode: 'Nester', + }, + properties: { + f963gxcp0uz: { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'AssociationField.Nester', + 'x-index': 1, + properties: + { + grid: { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid', + 'x-initializer': + 'FormItemInitializers', + properties: + { + '2eg7xlliyk0': + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid.Row', + properties: + { + '4d008vpig0f': + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid.Col', + properties: + { + id: { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'string', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-collection-field': + 'm2oField2.id', + 'x-component-props': + {}, + 'x-read-pretty': + true, + 'x-uid': + 'eqh4uwwrdb2', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'gc19ujdgy5h', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'yykls3t9pug', + 'x-async': + false, + 'x-index': 1, + }, + kzbf5h1vbqw: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid.Row', + properties: + { + f2v2e9t8juk: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid.Col', + properties: + { + m2oField2: + { + 'x-uid': + '17ecpej7sb9', + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'string', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-collection-field': + 'm2oField2.m2oField2', + 'x-component-props': + { + mode: 'Nester', + }, + properties: + { + yp3xjukzbmo: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'AssociationField.Nester', + 'x-index': 1, + properties: + { + grid: { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid', + 'x-initializer': + 'FormItemInitializers', + properties: + { + wca260ji2ih: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid.Row', + properties: + { + j19p1r016pj: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid.Col', + properties: + { + id: { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'string', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-collection-field': + 'm2oField3.id', + 'x-component-props': + {}, + 'x-read-pretty': + true, + 'x-uid': + 'yjbtit5eri9', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + '2wj9t16qv49', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'wv2eouh5o38', + 'x-async': + false, + 'x-index': 1, + }, + ihzeejjyski: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid.Row', + properties: + { + nuwqnjguqtc: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid.Col', + properties: + { + m2oField3: + { + 'x-uid': + '2bkbiayqed2', + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'string', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-collection-field': + 'm2oField3.m2oField3', + 'x-component-props': + { + mode: 'Select', + }, + properties: + { + j1l0upv47vn: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'AssociationField.Nester', + 'x-index': 1, + properties: + { + grid: { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid', + 'x-initializer': + 'FormItemInitializers', + properties: + { + '9xq8mnnzyrw': + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid.Row', + properties: + { + nbqmql24khd: + { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'void', + 'x-component': + 'Grid.Col', + properties: + { + id: { + _isJSONSchemaObject: + true, + version: + '2.0', + type: 'string', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-collection-field': + 'users.id', + 'x-component-props': + {}, + 'x-read-pretty': + true, + 'x-uid': + 'rnkwrneb7dy', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'c5v4i42w1i1', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'lgxcefydtp0', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'w0idtr6dwa4', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'a09ma68c41f', + 'x-async': + false, + }, + }, + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'qe3hnw9xe6e', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'o5zh8m5qx6a', + 'x-async': + false, + 'x-index': 2, + }, + }, + 'x-uid': + 'nigeia3gqlm', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'rz5kiy9vh12', + 'x-async': + false, + }, + }, + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'hkjnncj6dhj', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'l4zkvdlmobo', + 'x-async': + false, + 'x-index': 2, + }, + }, + 'x-uid': + 'xw4i68d64mt', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'z3bm22to5yl', + 'x-async': + false, + }, + }, + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'fh4n239d4rs', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '4csuyzs8wi1', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'g2flsox1luw', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xk8wl43zd39', + 'x-async': false, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'hcopuvnktmu', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '3zge5v7fs2s', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'c7n7fepc8u6', + 'x-async': false, + 'x-index': 1, + }, + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'UpdateFormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + properties: { + '31gyn2416at': { + _isJSONSchemaObject: true, + version: '2.0', + title: '{{ t("Submit") }}', + 'x-action': 'submit', + 'x-component': 'Action', + 'x-designer': 'Action.Designer', + 'x-component-props': { + type: 'primary', + htmlType: 'submit', + useProps: '{{ useUpdateActionProps }}', + }, + 'x-action-settings': { + triggerWorkflows: [], + }, + type: 'void', + 'x-uid': 'sp95wa30evt', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'yjo21wnu0iq', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'o18o45z7gay', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '8alup4gy395', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'l8qffi5w837', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '1oc31zgwq73', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'f7srqre9q5e', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'pwvj69kkqfc', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'rlwyma5eyi2', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '2lhkaanjkzb', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'zf9v442mpn3', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ritxqjy6csk', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'aysju5p3ddr', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'xo84doqcapz', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '4aa7kaxeojd', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'zetvg5woo4f', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'x4r6648qveh', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '9e7bblze4m7', + 'x-async': true, + 'x-index': 1, + }, +}; + +/** + * 一个包含多层级关系字段的子表格区块,并包含在一个表单区块中,该区块存在于一个编辑弹窗中 + */ + +export const oneTableSubtableWithMultiLevelAssociationFields: PageConfig = { + collections: generalWithMultiLevelM2mFields, + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + pqkuqljhx8t: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + vp7c9oaymjr: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '5pg5gk8tyjj': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + ut0zpd6ozbs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'general:list', + 'x-decorator-props': { + collection: 'general', + resource: 'general', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + properties: { + bt10apkutj5: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-action': 'create', + 'x-acl-action': 'create', + title: "{{t('Add new')}}", + 'x-designer': 'Action.Designer', + 'x-component': 'Action', + 'x-decorator': 'ACLActionProvider', + 'x-component-props': { + openMode: 'drawer', + type: 'primary', + component: 'CreateRecordAction', + icon: 'PlusOutlined', + }, + 'x-align': 'right', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Add record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializersForCreateFormBlock', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Add new")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'CreateFormBlockInitializers', + 'x-uid': 'hhhjt2axsd2', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '8e3vah9f6sg', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '5bhmr9qkal4', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'aty440mame4', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '4bpzz2al6rz', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'pxxqw3o5ct4', + 'x-async': false, + 'x-index': 1, + }, + '4gln5nmsfd0': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Actions") }}', + 'x-action-column': 'actions', + 'x-decorator': 'TableV2.Column.ActionBar', + 'x-component': 'TableV2.Column', + 'x-designer': 'TableV2.ActionColumnDesigner', + 'x-initializer': 'TableActionColumnInitializers', + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + properties: { + '5nufl3638uf': { + 'x-uid': 'sleh6s4i886', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: 'View record', + 'x-action': 'view', + 'x-designer': 'Action.Designer', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + danger: false, + }, + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("View record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializers', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Details")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + properties: { + qd1exa12t8i: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + rww46rjmsi5: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + va1yde9ikve: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action': 'general:get', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + resource: 'general', + collection: 'general', + readPretty: true, + action: 'get', + useParams: '{{ useParamsFromRecord }}', + useSourceId: '{{ useSourceIdFromParentRecord }}', + }, + 'x-designer': 'FormV2.ReadPrettyDesigner', + 'x-component': 'CardItem', + properties: { + u054c64tmjr: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-read-pretty': true, + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': + 'ReadPrettyFormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 24, + }, + }, + properties: { + clpayatl2zs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Edit") }}', + 'x-action': 'update', + 'x-designer': 'Action.Designer', + 'x-component': 'Action', + 'x-component-props': { + openMode: 'drawer', + icon: 'EditOutlined', + type: 'primary', + }, + 'x-decorator': 'ACLActionProvider', + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Edit record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': + 'TabPaneInitializers', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Edit")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': + 'RecordBlockInitializers', + 'x-uid': 'y94je87dtvs', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'g9ryb0spspp', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'vb8ugu4ka8s', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'hdgi5gdhjed', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xb2dyl9qsnr', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'bjbq42ijyfj', + 'x-async': false, + 'x-index': 1, + }, + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': + 'ReadPrettyFormItemInitializers', + properties: { + czwqhu0r4kn: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + ja42ruze2lj: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + id: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.id', + 'x-component-props': {}, + 'x-read-pretty': true, + 'x-uid': '0nmf05unx1b', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'q3aii09cl8i', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'o09mo5ybek5', + 'x-async': false, + 'x-index': 1, + }, + lugqxowx8tb: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '7niqf4f44t7': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + m2mField0: { + 'x-uid': 'rk3hrlx07e1', + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': + 'general.m2mField0', + 'x-component-props': { + mode: 'SubTable', + }, + properties: { + h6z9soc9uru: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': + 'AssociationField.SubTable', + 'x-initializer': + 'TableColumnInitializers', + 'x-initializer-props': { + action: false, + }, + 'x-index': 1, + properties: { + o6ppin1t7ea: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': + 'TableV2.Column.Decorator', + 'x-designer': + 'TableV2.Column.Designer', + 'x-component': + 'TableV2.Column', + properties: { + id: { + _isJSONSchemaObject: + true, + version: '2.0', + 'x-collection-field': + 'm2mField1.id', + 'x-component': + 'CollectionField', + 'x-component-props': {}, + 'x-read-pretty': true, + 'x-decorator': + 'FormItem', + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-uid': 'c59jvx1etuz', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'w3rct0pyn93', + 'x-async': false, + 'x-index': 1, + }, + r60y8wl96kc: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': + 'TableV2.Column.Decorator', + 'x-designer': + 'TableV2.Column.Designer', + 'x-component': + 'TableV2.Column', + properties: { + m2mField1: { + _isJSONSchemaObject: + true, + version: '2.0', + 'x-collection-field': + 'm2mField1.m2mField1', + 'x-component': + 'CollectionField', + 'x-component-props': { + ellipsis: true, + size: 'small', + }, + 'x-read-pretty': true, + 'x-decorator': + 'FormItem', + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-uid': 'lqqi8iluuuh', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'i5ssx48b7au', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'slrokcqaa4e', + 'x-async': false, + }, + cqlj2rwq46n: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': + 'AssociationField.Nester', + 'x-index': 2, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': + 'FormItemInitializers', + 'x-uid': 'gf8iixoigrh', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '87w0ki3fo84', + 'x-async': false, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'h2q142sbwjz', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'sjndyqq3vcd', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'y45ca10njxk', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '59oemo2vsrf', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'i30gcbg1qh0', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'la37nodqtql', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'z0d2zkvvel5', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '0nkdguk88o7', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '741fjki8fe0', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '6dn3pbtjzur', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'x8qitc0u3af', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + m32gxwucih5: { + 'x-uid': 'k6brhnkqjul', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: 'Edit record', + 'x-action': 'update', + 'x-designer': 'Action.Designer', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + danger: false, + }, + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Edit record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializers', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Edit")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + properties: { + a7fabwj9osd: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + auttn6ybm0s: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + opsc6mhh6ke: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: false, + }, + 'x-acl-action': 'general:update', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + useSourceId: '{{ useSourceIdFromParentRecord }}', + useParams: '{{ useParamsFromRecord }}', + action: 'get', + resource: 'general', + collection: 'general', + }, + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-component-props': {}, + properties: { + '7uuqysw6ve2': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + properties: { + beh7yt0xrkh: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + slwimqii04z: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + id: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.id', + 'x-component-props': {}, + 'x-read-pretty': true, + 'x-uid': 'o2h3q92gl30', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '97v1psczozt', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '3hewjn3pu94', + 'x-async': false, + 'x-index': 1, + }, + wq3rmqjw2hb: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + bzhfbut9xe0: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + m2mField0: { + 'x-uid': '7n40m6suk5g', + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': + 'general.m2mField0', + 'x-component-props': { + mode: 'SubTable', + }, + properties: { + '77nfti1mc96': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': + 'AssociationField.SubTable', + 'x-initializer': + 'TableColumnInitializers', + 'x-initializer-props': { + action: false, + }, + 'x-index': 1, + properties: { + '4xphbjxpvmx': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': + 'TableV2.Column.Decorator', + 'x-designer': + 'TableV2.Column.Designer', + 'x-component': + 'TableV2.Column', + properties: { + id: { + _isJSONSchemaObject: + true, + version: '2.0', + 'x-collection-field': + 'm2mField1.id', + 'x-component': + 'CollectionField', + 'x-component-props': {}, + 'x-read-pretty': true, + 'x-decorator': + 'FormItem', + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-uid': 'jatiot8jqt0', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'a682zx36ber', + 'x-async': false, + 'x-index': 1, + }, + dpzpvqa0pjy: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': + 'TableV2.Column.Decorator', + 'x-designer': + 'TableV2.Column.Designer', + 'x-component': + 'TableV2.Column', + properties: { + m2mField1: { + _isJSONSchemaObject: + true, + version: '2.0', + 'x-collection-field': + 'm2mField1.m2mField1', + 'x-component': + 'CollectionField', + 'x-component-props': { + ellipsis: true, + size: 'small', + }, + 'x-decorator': + 'FormItem', + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-uid': 'kji8by9glzo', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'r564ajua8o1', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'iruocwi8ipq', + 'x-async': false, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ztex715ginq', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'bc7aqdgcm37', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '171j0v19b28', + 'x-async': false, + 'x-index': 1, + }, + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'UpdateFormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + properties: { + '36qnzktwpiy': { + _isJSONSchemaObject: true, + version: '2.0', + title: '{{ t("Submit") }}', + 'x-action': 'submit', + 'x-component': 'Action', + 'x-designer': 'Action.Designer', + 'x-component-props': { + type: 'primary', + htmlType: 'submit', + useProps: '{{ useUpdateActionProps }}', + }, + 'x-action-settings': { + triggerWorkflows: [], + }, + type: 'void', + 'x-uid': 'y1yyn4pdfte', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 't2dgx9gk5xn', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'sxe3ekuceii', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'g1jsbbnp55f', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '8chr3fc6i5d', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'opxmh1l0c2q', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '0uc3odlqitp', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '74xfw8e9qgq', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'itkcmvetckr', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'hatjbmi5ojd', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'upot54xetpx', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'yerg930mc8q', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'oq6bt64mcyz', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '3ioqh6kt9fd', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'i14bsiw812l', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'azgd7jza4q8', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'svmmy356h93', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'fb5ge35q7wi', + 'x-async': true, + 'x-index': 1, + }, +}; + +/** + * 一个 table block,在点击 add new 打开的弹窗中,有一个 form block,其文本字段设置了一个使用了 `当前表单` 变量的默认值 + */ + +export const formBlockDefaultValueTemplate: PageConfig = { + collections: generalWithMultiLevelM2oFields, + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + twh6vbpbeh7: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + i7hhy9qt3vm: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + zo5ry8mb8i8: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + md9lzbo43sa: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'general:list', + 'x-decorator-props': { + collection: 'general', + resource: 'general', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + properties: { + ztk6e5lq2lu: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-action': 'create', + 'x-acl-action': 'create', + title: "{{t('Add new')}}", + 'x-designer': 'Action.Designer', + 'x-component': 'Action', + 'x-decorator': 'ACLActionProvider', + 'x-component-props': { + openMode: 'drawer', + type: 'primary', + component: 'CreateRecordAction', + icon: 'PlusOutlined', + }, + 'x-align': 'right', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Add record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializersForCreateFormBlock', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Add new")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'CreateFormBlockInitializers', + properties: { + ec8k6t8hyfd: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + i0kq9r8uagp: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + kiwjcmb22ni: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + 'x-acl-action': 'general:create', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + resource: 'general', + collection: 'general', + }, + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-component-props': {}, + properties: { + q93o4rn1hum: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + properties: { + '11k61q066eh': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + ilk6g3zfb99: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + m2oField0: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.m2oField0', + 'x-component-props': {}, + 'x-uid': 'zrdwygwt68n', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'jbzdmkicrbq', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '19tec55bhv8', + 'x-async': false, + 'x-index': 1, + }, + t964dpznx8s: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + wcc2gxtezpj: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + singleLineText: { + 'x-uid': 'h6nhc1du9zi', + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': + 'general.singleLineText', + 'x-component-props': {}, + default: + '{{$nForm.m2oField0.m2oField1.id}}', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 't1fh9mrbi65', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '5pzmjkt6nk9', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'i969ieh0rfu', + 'x-async': false, + 'x-index': 1, + }, + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'CreateFormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + 'x-uid': 'lrwiyzyg7ow', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'gz3ygly62js', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'q8gn2pt12ng', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'p0gdtennahr', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'f8741pdnbcy', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'f27ge9qf7u6', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xa5ujnlaqd6', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'd6dy86bjt0b', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'aycw09vymqy', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'tzdqfr6lmjy', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '7zzwexd3e4i', + 'x-async': false, + 'x-index': 1, + }, + qoq998l2i65: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Actions") }}', + 'x-action-column': 'actions', + 'x-decorator': 'TableV2.Column.ActionBar', + 'x-component': 'TableV2.Column', + 'x-designer': 'TableV2.ActionColumnDesigner', + 'x-initializer': 'TableActionColumnInitializers', + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + properties: { + '8kaku37mdre': { + 'x-uid': 'j1n2bte2wn4', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: 'View record', + 'x-action': 'view', + 'x-designer': 'Action.Designer', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + danger: false, + }, + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("View record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializers', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Details")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + 'x-uid': '6k8q5pvnbjg', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'txzczhz6s4g', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'chdb0wf0riz', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '7jpie07p1s7', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + '0xml7nfy4gs': { + 'x-uid': 'inv9i7a8i9t', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: 'Edit record', + 'x-action': 'update', + 'x-designer': 'Action.Designer', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + danger: false, + }, + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Edit record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializers', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Edit")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + 'x-uid': 'yqsyvw7utn4', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'pb3iqfcd6a5', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '3byo77j4fh6', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '1gscyc9hw6f', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'v4zy14lc4g4', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 's2ej5h10jxd', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xoknlt7jnhh', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'ovphvqtknwh', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'y4mqu08ojko', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'mszhp81fvd9', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ylndxgnumz2', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'sj1cs0vneuv', + 'x-async': true, + 'x-index': 1, + }, +}; + +/** + * 一个基于 users 表创建的表单区块 + */ + +export const oneFormBlockBasedOnUsers: PageConfig = { + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + lyie34rtcu4: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + skmxkfr67em: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '860xnb3egb8': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + aa9rqm7bkud: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + 'x-acl-action': 'users:create', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + resource: 'users', + collection: 'users', + }, + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-component-props': {}, + properties: { + t4mi2jywqj7: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + 'x-uid': '66dozhzo5ld', + 'x-async': false, + 'x-index': 1, + }, + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'FormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + 'x-uid': 'q8am9zt6m2x', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '4ojxya0re8h', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '183n4o77awp', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'zwxgkj66isi', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '8tryd9kz9bd', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'piwq6rrjrsq', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '5cszm46yqxb', + 'x-async': true, + 'x-index': 1, + }, +}; + +/** + * 一个表单和一个表格,且使用同一个数据表创建 + */ + +export const oneFormAndOneTableWithSameCollection: PageConfig = { + collections: generalWithBasic, + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + k4rw21d8npm: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + '0qplm51g52v': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '6k1kp63fe39': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + '4bvs0awu4x3': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'FilterFormBlockProvider', + 'x-decorator-props': { + resource: 'general', + collection: 'general', + }, + 'x-designer': 'FormV2.FilterDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + 'x-filter-operators': {}, + properties: { + wsmj61aszlz: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'FilterFormItemInitializers', + properties: { + '0k8y0nlffht': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + qse6oj6e5qu: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + singleLineText: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + required: false, + 'x-designer': 'FormItem.FilterFormDesigner', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.singleLineText', + 'x-component-props': {}, + 'x-uid': 'axtueywbsku', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ghq5xu4u9q1', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'yo9rhg3o491', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'u14kmr18s8n', + 'x-async': false, + 'x-index': 1, + }, + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'FilterFormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + float: 'right', + }, + }, + properties: { + '52ugkxvnymm': { + _isJSONSchemaObject: true, + version: '2.0', + title: '{{ t("Filter records") }}', + 'x-action': 'submit', + 'x-component': 'Action', + 'x-designer': 'Action.Designer', + 'x-component-props': { + type: 'primary', + useProps: '{{ useFilterBlockActionProps }}', + }, + 'x-action-settings': {}, + type: 'void', + 'x-uid': 'x9zwb21282b', + 'x-async': false, + 'x-index': 1, + }, + ro85kbfk3ch: { + _isJSONSchemaObject: true, + version: '2.0', + title: '{{ t("Reset records") }}', + 'x-component': 'Action', + 'x-designer': 'Action.Designer', + 'x-component-props': { + useProps: '{{ useResetBlockActionProps }}', + }, + 'x-action-settings': {}, + type: 'void', + 'x-uid': 'yx5r6w259pn', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'fhd3bmfdv2l', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'hhu6h4smxk3', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'mwvcvngofcs', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'la5zbsnj43i', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'cmb5v9n7hs5', + 'x-async': false, + 'x-index': 1, + }, + ao49un8ae53: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '6ozy0fovblc': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + qqm3k28nlvw: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'general:list', + 'x-decorator-props': { + collection: 'general', + resource: 'general', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + 'x-uid': 'jd5cfyt9rvc', + 'x-async': false, + 'x-index': 1, + }, + q50obbdn5ss: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + properties: { + xx80bo2vwzo: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableV2.Column.Decorator', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + properties: { + singleLineText: { + _isJSONSchemaObject: true, + version: '2.0', + 'x-collection-field': 'general.singleLineText', + 'x-component': 'CollectionField', + 'x-component-props': { + ellipsis: true, + }, + 'x-read-pretty': true, + 'x-decorator': null, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-uid': '4abuynayx5p', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'svmhhffy26k', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'tnfoksv58jo', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '89u71juhrim', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '79f1735ed66', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '1jlx589r5yi', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'wygph7l04pt', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'hkp8w48hfxt', + 'x-async': true, + 'x-index': 1, + }, +}; + +/** + * 一个空页面,且有两个 tab 子页面,用于测试拖拽 tab 标签 + */ +export const twoTabsPage = { + pageSchema: { + 'x-uid': 'h8q2mcgo3cq', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + 'x-component-props': { + enablePageTabs: true, + }, + properties: { + bi8ep3svjee: { + 'x-uid': '9kr7xm9x4ln', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + title: 'tab 1', + 'x-async': false, + 'x-index': 1, + }, + rw91udnzpr3: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: 'tab 2', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + 'x-uid': 'o5vp90rqsjx', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-async': true, + 'x-index': 1, + }, +}; + +/** + * 页面中有两个 table block,且它们的数据表相同 + */ + +export const twoTableWithSameCollection: PageConfig = { + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + aagn23cu1au: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + jkcte869qpa: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + a7mg35xwgnh: { + 'x-uid': 'j92fu6vu5wr', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-component-props': { + width: 50, + }, + properties: { + ik3kd1mu356: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'users:list', + 'x-decorator-props': { + collection: 'users', + resource: 'users', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + 'x-uid': 'xbzkjfayl3y', + 'x-async': false, + 'x-index': 1, + }, + '6rht663sjwy': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + properties: { + '1rdl2om3xvf': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableV2.Column.Decorator', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + properties: { + nickname: { + _isJSONSchemaObject: true, + version: '2.0', + 'x-collection-field': 'users.nickname', + 'x-component': 'CollectionField', + 'x-component-props': { + ellipsis: true, + }, + 'x-read-pretty': true, + 'x-decorator': null, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-uid': 'awsapwb3vz8', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '63je0mdriu0', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'xok38mlx47f', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'w67kx2dq7v0', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + col_8aw7x1sak31: { + 'x-uid': 'aih69lrjd2p', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-index': 2, + 'x-component-props': { + width: 50, + }, + properties: { + md8bjznxwkj: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'users:list', + 'x-decorator-props': { + collection: 'users', + resource: 'users', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + 'x-uid': '5g15rd6dqli', + 'x-async': false, + 'x-index': 1, + }, + '5jpkhgs6y9l': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + properties: { + wx9rc0ypdic: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableV2.Column.Decorator', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + properties: { + nickname: { + _isJSONSchemaObject: true, + version: '2.0', + 'x-collection-field': 'users.nickname', + 'x-component': 'CollectionField', + 'x-component-props': { + ellipsis: true, + }, + 'x-read-pretty': true, + 'x-decorator': null, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-uid': 'iz76f2zk0p3', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '6l713p7h6a6', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'qtnr055ay8q', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'bvl6hoot8p7', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + }, + }, + 'x-uid': '5y30ooo4yb9', + 'x-async': false, + 'x-index': 1, + }, + zhjry50iany: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-uid': 'bqakvev9voh', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'y2lcuhlc22c', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'vfw1o87k9dl', + 'x-async': true, + 'x-index': 1, + }, +}; + +/** + * 页面中有两个 table block,且它们的数据表之间相互关联 + */ + +export const twoTableWithAssociationFields: PageConfig = { + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + mkihga8zgdc: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + qtp19qlje2y: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + bpjhe7vhk0q: { + 'x-uid': 'g3gmsg8dgvi', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-component-props': { + width: 50, + }, + properties: { + q29lyxxnoqt: { + 'x-uid': 'xq1rnptcf7a', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'roles:list', + 'x-decorator-props': { + collection: 'roles', + resource: 'roles', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'name', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + 'x-uid': 'u8xfso0a35t', + 'x-async': false, + 'x-index': 1, + }, + ev414dhhdkt: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + properties: { + t23whe7t7tm: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableV2.Column.Decorator', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + properties: { + title: { + _isJSONSchemaObject: true, + version: '2.0', + 'x-collection-field': 'roles.title', + 'x-component': 'CollectionField', + 'x-component-props': { + ellipsis: true, + }, + 'x-read-pretty': true, + 'x-decorator': null, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-uid': '5jl8zmnh38i', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '9y1uck15r14', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'l7wpauy51gd', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + col_2fu9sdcu99u: { + 'x-uid': 'q1snbst31eh', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-index': 2, + 'x-component-props': { + width: 50, + }, + properties: { + ifxs1ltyzyu: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'users:list', + 'x-decorator-props': { + collection: 'users', + resource: 'users', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + 'x-uid': 'oqdv3tu3laz', + 'x-async': false, + 'x-index': 1, + }, + wyykccq1j91: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + properties: { + '4k1roap63h2': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableV2.Column.Decorator', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + properties: { + roles: { + _isJSONSchemaObject: true, + version: '2.0', + 'x-collection-field': 'users.roles', + 'x-component': 'CollectionField', + 'x-component-props': { + ellipsis: true, + size: 'small', + }, + 'x-read-pretty': true, + 'x-decorator': null, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-uid': '9jgtp03g8pi', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'qrdojan2b5g', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'abdcpql91wn', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '5el8hue6945', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + }, + }, + 'x-uid': 'pmexhqiaq52', + 'x-async': false, + 'x-index': 1, + }, + ef6epohn0yr: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-uid': 'u7cdjkdpztt', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'epjhxs40qys', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'anxt1ecq7hd', + 'x-async': true, + 'x-index': 1, + }, +}; + +/** + * 页面中有两个 table block,且它们的数据表之间通过外键关联 + */ + +export const twoTableWithForeignKey: PageConfig = {}; + +/** + * 一个空的 table block,且基于 users 表创建 + */ +export const oneEmptyTableBlockBasedOnUsers = { + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + '3r0yxum84w2': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + vduni5v1u2v: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + qwrauugqc1k: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + '92vs3ej14vo': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'users:list', + 'x-decorator-props': { + collection: 'users', + resource: 'users', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + 'x-uid': 'gzu2uanef12', + 'x-async': false, + 'x-index': 1, + }, + vlkh4fiq98e: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Actions") }}', + 'x-action-column': 'actions', + 'x-decorator': 'TableV2.Column.ActionBar', + 'x-component': 'TableV2.Column', + 'x-designer': 'TableV2.ActionColumnDesigner', + 'x-initializer': 'TableActionColumnInitializers', + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + 'x-uid': 'q44b0dv50za', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'i8tnis8ymcm', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'u60i2x1lo97', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '6jb6jfh1770', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '9oykdej2ufq', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '8iolmzoelll', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '0dhkzj75zh7', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'n8gs3wg1sxp', + 'x-async': true, + 'x-index': 1, + }, +}; + +/** + * 用于测试 table 行的 checkbox + */ +export const checkboxForTableRow = { + collections: [ + { + name: 't_fhdhd0nk7b9', + title: 'test', + fields: [ + { + name: 'f_vbrlno0zej9', + interface: 'input', + }, + ], + }, + ], + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + nrwnyusnbrd: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + w85tu6tnlfp: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + q9vljapijwj: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + zia3dyel3jr: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 't_fhdhd0nk7b9:list', + 'x-decorator-props': { + collection: 't_fhdhd0nk7b9', + resource: 't_fhdhd0nk7b9', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + disableTemplate: false, + }, + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-filter-targets': [], + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'TableActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + properties: { + '5210td4a1ms': { + _isJSONSchemaObject: true, + version: '2.0', + title: '{{ t("Delete") }}', + 'x-action': 'destroy', + 'x-component': 'Action', + 'x-designer': 'Action.Designer', + 'x-decorator': 'ACLActionProvider', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + 'x-component-props': { + icon: 'DeleteOutlined', + confirm: { + title: "{{t('Delete record')}}", + content: "{{t('Are you sure you want to delete it?')}}", + }, + useProps: '{{ useBulkDestroyActionProps }}', + }, + 'x-acl-action': 't_fhdhd0nk7b9:destroy', + 'x-align': 'right', + type: 'void', + 'x-uid': 'aud7zy2m18z', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'j10gefyy50y', + 'x-async': false, + 'x-index': 1, + }, + k88f9zdl4k1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'TableColumnInitializers', + 'x-component': 'TableV2', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + useProps: '{{ useTableBlockProps }}', + }, + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Actions") }}', + 'x-action-column': 'actions', + 'x-decorator': 'TableV2.Column.ActionBar', + 'x-component': 'TableV2.Column', + 'x-designer': 'TableV2.ActionColumnDesigner', + 'x-initializer': 'TableActionColumnInitializers', + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + 'x-uid': 'lky44f6h6kh', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'fvkqaxe6bo1', + 'x-async': false, + 'x-index': 1, + }, + wwn0ajwixxl: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableV2.Column.Decorator', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + properties: { + f_vbrlno0zej9: { + _isJSONSchemaObject: true, + version: '2.0', + 'x-collection-field': 't_fhdhd0nk7b9.f_vbrlno0zej9', + 'x-component': 'CollectionField', + 'x-component-props': { + ellipsis: true, + }, + 'x-read-pretty': true, + 'x-decorator': null, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-uid': 'emphc9g52u7', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'q7h24jnc070', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'a9qdzmt4vai', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '98ta7h4ba1f', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'mo6eowotbqd', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '2nmkby45kce', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'zyukds9t2ln', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'd0j1mfitnmr', + 'x-async': true, + 'x-index': 1, + }, +}; diff --git a/packages/plugins/@nocobase/plugin-auth/src/client/__tests__/e2e/auth.test.ts b/packages/plugins/@nocobase/plugin-auth/src/client/__e2e__/auth.test.ts similarity index 100% rename from packages/plugins/@nocobase/plugin-auth/src/client/__tests__/e2e/auth.test.ts rename to packages/plugins/@nocobase/plugin-auth/src/client/__e2e__/auth.test.ts diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/commonTesting.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/commonTesting.ts similarity index 100% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/commonTesting.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/commonTesting.ts diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/advanced.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/advanced.test.ts similarity index 96% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/advanced.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/advanced.test.ts index 6324d0c32..0d34d7391 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/advanced.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/advanced.test.ts @@ -1,6 +1,22 @@ import { Page, oneTableBlockWithAddNewAndViewAndEditAndAdvancedFields, test } from '@nocobase/test/client'; import { commonTesting } from '../commonTesting'; +test.describe('collection', () => { + commonTesting({ openDialogAndShowMenu, fieldName: 'collection', blockType: 'viewing', mode: 'options' }); +}); + +test.describe('JSON', () => { + commonTesting({ openDialogAndShowMenu, fieldName: 'JSON', blockType: 'viewing', mode: 'options' }); +}); + +test.describe('formula', () => { + commonTesting({ openDialogAndShowMenu, fieldName: 'formula', blockType: 'viewing', mode: 'options' }); +}); + +test.describe('sequence', () => { + commonTesting({ openDialogAndShowMenu, fieldName: 'sequence', blockType: 'viewing', mode: 'options' }); +}); + const gotoPage = async (mockPage, mockRecord) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAdvancedFields).waitForInit(); await mockRecord('general'); @@ -18,7 +34,7 @@ const showMenu = async (page: Page, fieldName: string) => { .hover(); }; -const openDialogAndShowMenu = async ({ +async function openDialogAndShowMenu({ page, mockPage, mockRecord, @@ -28,21 +44,8 @@ const openDialogAndShowMenu = async ({ mockPage; mockRecord; fieldName: string; -}) => { +}) { await gotoPage(mockPage, mockRecord); await openDialog(page); await showMenu(page, fieldName); -}; - -test.describe('collection', () => { - commonTesting({ openDialogAndShowMenu, fieldName: 'collection', blockType: 'viewing', mode: 'options' }); -}); -test.describe('JSON', () => { - commonTesting({ openDialogAndShowMenu, fieldName: 'JSON', blockType: 'viewing', mode: 'options' }); -}); -test.describe('formula', () => { - commonTesting({ openDialogAndShowMenu, fieldName: 'formula', blockType: 'viewing', mode: 'options' }); -}); -test.describe('sequence', () => { - commonTesting({ openDialogAndShowMenu, fieldName: 'sequence', blockType: 'viewing', mode: 'options' }); -}); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/basic.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/basic.test.ts similarity index 98% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/basic.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/basic.test.ts index 6a4d0f707..f31b6f4eb 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/basic.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/basic.test.ts @@ -1,41 +1,6 @@ import { Page, oneTableBlockWithAddNewAndViewAndEditAndBasicFields, test } from '@nocobase/test/client'; import { commonTesting } from '../commonTesting'; -const gotoPage = async (mockPage, mockRecord) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); - const record = await mockRecord('general'); - await nocoPage.goto(); - - return record; -}; - -const openDialog = async (page: Page) => { - await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecord, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - fieldName: string; -}) => { - await gotoPage(mockPage, mockRecord); - await openDialog(page); - await showMenu(page, fieldName); -}; - test.describe('color', () => { commonTesting({ openDialogAndShowMenu, fieldName: 'color', blockType: 'viewing' }); }); @@ -79,3 +44,38 @@ test.describe('long text', () => { test.describe('URL', () => { commonTesting({ openDialogAndShowMenu, fieldName: 'url', blockType: 'viewing', mode: 'options' }); }); + +const gotoPage = async (mockPage, mockRecord) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); + const record = await mockRecord('general'); + await nocoPage.goto(); + + return record; +}; + +const openDialog = async (page: Page) => { + await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecord, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + fieldName: string; +}) { + await gotoPage(mockPage, mockRecord); + await openDialog(page); + await showMenu(page, fieldName); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/choices.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/choices.test.ts similarity index 97% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/choices.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/choices.test.ts index 5d90f93eb..44e1516d5 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/choices.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/choices.test.ts @@ -1,45 +1,6 @@ import { Page, oneTableBlockWithAddNewAndViewAndEditAndChoicesFields, test } from '@nocobase/test/client'; import { commonTesting } from '../commonTesting'; -const gotoPage = async (mockPage, mockRecord) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndChoicesFields).waitForInit(); - const record = await mockRecord('general'); - await nocoPage.goto(); - - return record; -}; - -const openDialog = async (page: Page) => { - await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - await page - .getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`, { exact: true }) - .hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`, { - exact: true, - }) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecord, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - fieldName: string; -}) => { - await gotoPage(mockPage, mockRecord); - await openDialog(page); - await showMenu(page, fieldName); -}; - test.describe('checkbox', () => { commonTesting({ openDialogAndShowMenu, fieldName: 'checkbox', blockType: 'viewing', mode: 'options' }); }); @@ -63,3 +24,42 @@ test.describe('radio group', () => { test.describe('single select', () => { commonTesting({ openDialogAndShowMenu, fieldName: 'singleSelect', blockType: 'viewing', mode: 'options' }); }); + +const gotoPage = async (mockPage, mockRecord) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndChoicesFields).waitForInit(); + const record = await mockRecord('general'); + await nocoPage.goto(); + + return record; +}; + +const openDialog = async (page: Page) => { + await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + await page + .getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`, { exact: true }) + .hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`, { + exact: true, + }) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecord, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + fieldName: string; +}) { + await gotoPage(mockPage, mockRecord); + await openDialog(page); + await showMenu(page, fieldName); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/datetime.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/datetime.test.ts similarity index 97% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/datetime.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/datetime.test.ts index 45563e409..220285418 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/datetime.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/datetime.test.ts @@ -2,6 +2,25 @@ import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndDatetimeFields, t import dayjs from 'dayjs'; import { commonTesting } from '../commonTesting'; +test.describe('datetime', () => { + commonTesting({ openDialogAndShowMenu, fieldName: 'datetime', blockType: 'viewing', mode: 'options' }); + + test('date display format', async ({ page, mockPage, mockRecord }) => { + const record = await openDialogAndShowMenu({ page, mockPage, mockRecord, fieldName: 'datetime' }); + await page.getByRole('menuitem', { name: 'Date display format' }).click(); + await page.getByLabel('YYYY/MM/DD').click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + await expect(page.getByLabel('block-item-CollectionField-general-form-general.datetime-datetime')).toHaveText( + `datetime:${dayjs(record.datetime).format('YYYY/MM/DD')}`, + ); + }); +}); + +test.describe('time', () => { + commonTesting({ openDialogAndShowMenu, fieldName: 'time', blockType: 'viewing', mode: 'options' }); +}); + const gotoPage = async (mockPage, mockRecord) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndDatetimeFields).waitForInit(); const record = await mockRecord('general'); @@ -21,7 +40,7 @@ const showMenu = async (page: Page, fieldName: string) => { .hover(); }; -const openDialogAndShowMenu = async ({ +async function openDialogAndShowMenu({ page, mockPage, mockRecord, @@ -31,29 +50,10 @@ const openDialogAndShowMenu = async ({ mockPage; mockRecord; fieldName: string; -}) => { +}) { const record = await gotoPage(mockPage, mockRecord); await openDialog(page); await showMenu(page, fieldName); return record; -}; - -test.describe('datetime', () => { - commonTesting({ openDialogAndShowMenu, fieldName: 'datetime', blockType: 'viewing', mode: 'options' }); - - test('date display format', async ({ page, mockPage, mockRecord }) => { - const record = await openDialogAndShowMenu({ page, mockPage, mockRecord, fieldName: 'datetime' }); - await page.getByRole('menuitem', { name: 'Date display format' }).click(); - await page.getByLabel('YYYY/MM/DD').click(); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - await expect(page.getByLabel('block-item-CollectionField-general-form-general.datetime-datetime')).toHaveText( - `datetime:${dayjs(record.datetime).format('YYYY/MM/DD')}`, - ); - }); -}); - -test.describe('time', () => { - commonTesting({ openDialogAndShowMenu, fieldName: 'time', blockType: 'viewing', mode: 'options' }); -}); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/media.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/media.test.ts similarity index 98% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/media.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/media.test.ts index c06964495..8f08b5af4 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/media.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/media.test.ts @@ -1,47 +1,6 @@ import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndMediaFields, test } from '@nocobase/test/client'; import { commonTesting } from '../commonTesting'; -const gotoPage = async (mockPage, mockRecord) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndMediaFields).waitForInit(); - const record = await mockRecord('general'); - await nocoPage.goto(); - - return record; -}; - -const openDialog = async (page: Page) => { - await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - // 这里是为了等弹窗中的内容渲染稳定后,再去 hover,防止错位导致测试报错 - await page.waitForTimeout(1000); - await page - .getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`, { exact: true }) - .hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`, { - exact: true, - }) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecord, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - fieldName: string; -}) => { - await gotoPage(mockPage, mockRecord); - await openDialog(page); - await showMenu(page, fieldName); -}; - test.describe('markdown', () => { commonTesting({ openDialogAndShowMenu, fieldName: 'markdown', blockType: 'viewing', mode: 'options' }); }); @@ -122,3 +81,44 @@ test.describe('attachment', () => { } }); }); + +const gotoPage = async (mockPage, mockRecord) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndMediaFields).waitForInit(); + const record = await mockRecord('general'); + await nocoPage.goto(); + + return record; +}; + +const openDialog = async (page: Page) => { + await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + // 这里是为了等弹窗中的内容渲染稳定后,再去 hover,防止错位导致测试报错 + await page.waitForTimeout(1000); + await page + .getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`, { exact: true }) + .hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`, { + exact: true, + }) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecord, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + fieldName: string; +}) { + await gotoPage(mockPage, mockRecord); + await openDialog(page); + await showMenu(page, fieldName); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/relation.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/relation.test.ts similarity index 97% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/relation.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/relation.test.ts index 4c5db02a8..58464d788 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/relation.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/relation.test.ts @@ -1,42 +1,6 @@ -import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndRelationFields, test } from '@nocobase/test/client'; +import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, test } from '@nocobase/test/client'; import { commonTesting } from '../commonTesting'; -const gotoPage = async (mockPage, mockRecords) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndRelationFields).waitForInit(); - const record = (await mockRecords('general', 1))[0]; - await nocoPage.goto(); - - return record; -}; - -const openDialog = async (page: Page) => { - await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecords, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - mockRecords; - fieldName: string; -}) => { - await gotoPage(mockPage, mockRecords); - await openDialog(page); - await showMenu(page, fieldName); -}; - test.describe('many to many', () => { commonTesting({ openDialogAndShowMenu, @@ -254,3 +218,39 @@ test.describe('one to one (has one)', () => { await expect(page.getByRole('menuitem', { name: 'Enable link' }).getByRole('switch')).toBeChecked(); }); }); + +const gotoPage = async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const record = (await mockRecords('general', 1))[0]; + await nocoPage.goto(); + + return record; +}; + +const openDialog = async (page: Page) => { + await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecords, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + mockRecords; + fieldName: string; +}) { + await gotoPage(mockPage, mockRecords); + await openDialog(page); + await showMenu(page, fieldName); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/systemInfo.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/systemInfo.test.ts similarity index 98% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/systemInfo.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/systemInfo.test.ts index 88f2cc885..2eb2127c8 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/details/systemInfo.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/details-single-data/systemInfo.test.ts @@ -1,41 +1,6 @@ import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndSystemInfoFields, test } from '@nocobase/test/client'; import { commonTesting } from '../commonTesting'; -const gotoPage = async (mockPage, mockRecord) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndSystemInfoFields).waitForInit(); - const record = await mockRecord('general'); - await nocoPage.goto(); - - return record; -}; - -const openDialog = async (page: Page) => { - await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-`).hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecord, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - fieldName: string; -}) => { - await gotoPage(mockPage, mockRecord); - await openDialog(page); - await showMenu(page, fieldName); -}; - test.describe('created at', () => { commonTesting({ openDialogAndShowMenu, @@ -104,3 +69,38 @@ test.describe('last updated by', () => { await expect(page.getByRole('menuitem', { name: 'Enable link' })).toBeVisible(); }); }); + +const gotoPage = async (mockPage, mockRecord) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndSystemInfoFields).waitForInit(); + const record = await mockRecord('general'); + await nocoPage.goto(); + + return record; +}; + +const openDialog = async (page: Page) => { + await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecord, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + fieldName: string; +}) { + await gotoPage(mockPage, mockRecord); + await openDialog(page); + await showMenu(page, fieldName); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/advanced.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/advanced.test.ts similarity index 98% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/advanced.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/advanced.test.ts index 4b08773e7..0743b20e8 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/advanced.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/advanced.test.ts @@ -1,38 +1,6 @@ import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndAdvancedFields, test } from '@nocobase/test/client'; import { commonTesting } from '../commonTesting'; -const gotoPage = async (mockPage) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAdvancedFields).waitForInit(); - await nocoPage.goto(); -}; - -const openDialog = async (page: Page) => { - await page.getByRole('button', { name: 'Add new' }).click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecord, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - fieldName: string; -}) => { - await gotoPage(mockPage); - await openDialog(page); - await showMenu(page, fieldName); -}; - test.describe('collection', () => { commonTesting({ openDialogAndShowMenu, fieldName: 'collection', mode: 'options' }); }); @@ -60,3 +28,35 @@ test.describe('sequence', () => { await expect(page.getByRole('menuitem', { name: 'required' })).toBeVisible(); }); }); + +const gotoPage = async (mockPage) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAdvancedFields).waitForInit(); + await nocoPage.goto(); +}; + +const openDialog = async (page: Page) => { + await page.getByRole('button', { name: 'Add new' }).click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecord, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + fieldName: string; +}) { + await gotoPage(mockPage); + await openDialog(page); + await showMenu(page, fieldName); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/basic.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/basic.test.ts similarity index 99% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/basic.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/basic.test.ts index a750ddf28..f6e50a500 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/basic.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/basic.test.ts @@ -1,38 +1,6 @@ -import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndBasicFields, test } from '@nocobase/test/client'; +import { expect, oneTableBlockWithAddNewAndViewAndEditAndBasicFields, test } from '@nocobase/test/client'; import { commonTesting, testDefaultValue, testPattern, testSetValidationRules } from '../commonTesting'; -const gotoPage = async (mockPage) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); - await nocoPage.goto(); -}; - -const openDialog = async (page: Page) => { - await page.getByRole('button', { name: 'Add new' }).click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecord, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - fieldName: string; -}) => { - await gotoPage(mockPage); - await openDialog(page); - await showMenu(page, fieldName); -}; - test.describe('color', () => { commonTesting({ openDialogAndShowMenu, fieldName: 'color' }); @@ -748,3 +716,35 @@ test.describe('URL', () => { }); }); }); + +const gotoPage = async (mockPage) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); + await nocoPage.goto(); +}; + +const openDialog = async (page: Page) => { + await page.getByRole('button', { name: 'Add new' }).click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecord, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + fieldName: string; +}) { + await gotoPage(mockPage); + await openDialog(page); + await showMenu(page, fieldName); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/choices.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/choices.test.ts similarity index 99% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/choices.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/choices.test.ts index 5f5eacd82..f194bb2ad 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/choices.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/choices.test.ts @@ -1,42 +1,6 @@ import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndChoicesFields, test } from '@nocobase/test/client'; import { commonTesting, testDefaultValue, testPattern } from '../commonTesting'; -const gotoPage = async (mockPage) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndChoicesFields).waitForInit(); - await nocoPage.goto(); -}; - -const openDialog = async (page: Page) => { - await page.getByRole('button', { name: 'Add new' }).click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - await page - .getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`, { exact: true }) - .hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`, { - exact: true, - }) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecord, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - fieldName: string; -}) => { - await gotoPage(mockPage); - await openDialog(page); - await showMenu(page, fieldName); -}; - test.describe('checkbox', () => { commonTesting({ openDialogAndShowMenu, fieldName: 'checkbox', mode: 'options' }); @@ -391,3 +355,39 @@ test.describe('single select', () => { }); }); }); + +const gotoPage = async (mockPage) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndChoicesFields).waitForInit(); + await nocoPage.goto(); +}; + +const openDialog = async (page: Page) => { + await page.getByRole('button', { name: 'Add new' }).click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + await page + .getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`, { exact: true }) + .hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`, { + exact: true, + }) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecord, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + fieldName: string; +}) { + await gotoPage(mockPage); + await openDialog(page); + await showMenu(page, fieldName); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/datetime.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/datetime.test.ts similarity index 99% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/datetime.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/datetime.test.ts index dca0f9691..bb956dee1 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/datetime.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/datetime.test.ts @@ -2,38 +2,6 @@ import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndDatetimeFields, t import dayjs from 'dayjs'; import { commonTesting, testDefaultValue, testPattern } from '../commonTesting'; -const gotoPage = async (mockPage) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndDatetimeFields).waitForInit(); - await nocoPage.goto(); -}; - -const openDialog = async (page: Page) => { - await page.getByRole('button', { name: 'Add new' }).click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecord, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - fieldName: string; -}) => { - await gotoPage(mockPage); - await openDialog(page); - await showMenu(page, fieldName); -}; - test.describe('datetime', () => { commonTesting({ openDialogAndShowMenu, fieldName: 'datetime', blockType: 'creating', mode: 'options' }); @@ -156,3 +124,35 @@ test.describe('time', () => { }); }); }); + +const gotoPage = async (mockPage) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndDatetimeFields).waitForInit(); + await nocoPage.goto(); +}; + +const openDialog = async (page: Page) => { + await page.getByRole('button', { name: 'Add new' }).click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecord, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + fieldName: string; +}) { + await gotoPage(mockPage); + await openDialog(page); + await showMenu(page, fieldName); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/media.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/media.test.ts similarity index 99% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/media.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/media.test.ts index 4412b9b1a..3cc1700c3 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/media.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/media.test.ts @@ -1,42 +1,6 @@ import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndMediaFields, test } from '@nocobase/test/client'; import { commonTesting, testDefaultValue, testPattern, testSetValidationRules } from '../commonTesting'; -const gotoPage = async (mockPage) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndMediaFields).waitForInit(); - await nocoPage.goto(); -}; - -const openDialog = async (page: Page) => { - await page.getByRole('button', { name: 'Add new' }).click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - await page - .getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`, { exact: true }) - .hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`, { - exact: true, - }) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecord, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - fieldName: string; -}) => { - await gotoPage(mockPage); - await openDialog(page); - await showMenu(page, fieldName); -}; - test.describe('markdown', () => { commonTesting({ openDialogAndShowMenu, fieldName: 'markdown', mode: 'options' }); @@ -182,3 +146,39 @@ test.describe('attachment', () => { }); }); }); + +const gotoPage = async (mockPage) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndMediaFields).waitForInit(); + await nocoPage.goto(); +}; + +const openDialog = async (page: Page) => { + await page.getByRole('button', { name: 'Add new' }).click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + await page + .getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`, { exact: true }) + .hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`, { + exact: true, + }) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecord, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + fieldName: string; +}) { + await gotoPage(mockPage); + await openDialog(page); + await showMenu(page, fieldName); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/relation.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/relation.test.ts similarity index 85% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/relation.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/relation.test.ts index cce8c12ec..c222ccbd4 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/relation.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/relation.test.ts @@ -1,69 +1,41 @@ -import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndRelationFields, test } from '@nocobase/test/client'; +import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, test } from '@nocobase/test/client'; import { commonTesting, testDefaultValue, testPattern } from '../commonTesting'; -const gotoPage = async (mockPage, mockRecords) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndRelationFields).waitForInit(); - await mockRecords('users', 3); - await nocoPage.goto(); -}; - -const openDialog = async (page: Page) => { - await page.getByRole('button', { name: 'Add new' }).click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecords, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - mockRecords; - fieldName: string; -}) => { - await gotoPage(mockPage, mockRecords); - await openDialog(page); - await showMenu(page, fieldName); -}; - test.describe('many to many', () => { commonTesting({ openDialogAndShowMenu, fieldName: 'manyToMany', fieldType: 'relation', mode: 'options' }); test('set default value', async ({ page, mockPage, mockRecords }) => { + let recordsOfUser; await testDefaultValue({ page, - gotoPage: () => gotoPage(mockPage, mockRecords), + gotoPage: async () => { + recordsOfUser = await gotoPage(mockPage, mockRecords); + }, openDialog: () => openDialog(page), closeDialog: () => page.getByLabel('drawer-Action.Container-general-Add record-mask').click(), showMenu: () => showMenu(page, 'manyToMany'), supportVariables: ['Constant', 'Current user', 'Date variables', 'Current form'], inputConstantValue: async () => { await page.getByLabel('block-item-VariableInput-').getByTestId('select-object-multiple').click(); - await page.getByRole('option', { name: '1', exact: true }).click(); - await page.getByRole('option', { name: '2', exact: true }).click(); - await page.getByRole('option', { name: '3', exact: true }).click(); + await page.getByRole('option', { name: String(recordsOfUser[0].id), exact: true }).click(); + await page.getByRole('option', { name: String(recordsOfUser[1].id), exact: true }).click(); + await page.getByRole('option', { name: String(recordsOfUser[2].id), exact: true }).click(); }, expectConstantValue: async () => { await expect( page.getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany'), - ).toHaveText(`manyToMany:123`); + ).toHaveText(`manyToMany:${recordsOfUser.map((record) => record.id).join('')}`); }, }); }); test('pattern', async ({ page, mockPage, mockRecords }) => { + let records; await testPattern({ page, - gotoPage: () => gotoPage(mockPage, mockRecords), + gotoPage: async () => { + records = await gotoPage(mockPage, mockRecords); + }, openDialog: () => openDialog(page), showMenu: () => showMenu(page, 'manyToMany'), expectEditable: async () => { @@ -71,9 +43,9 @@ test.describe('many to many', () => { .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') .getByTestId('select-object-multiple') .click(); - await page.getByRole('option', { name: '1', exact: true }).click(); - await page.getByRole('option', { name: '2', exact: true }).click(); - await page.getByRole('option', { name: '3', exact: true }).click(); + await page.getByRole('option', { name: String(records[0].id), exact: true }).click(); + await page.getByRole('option', { name: String(records[1].id), exact: true }).click(); + await page.getByRole('option', { name: String(records[2].id), exact: true }).click(); }, expectReadonly: async () => { await expect( @@ -87,13 +59,13 @@ test.describe('many to many', () => { expectEasyReading: async () => { await expect( page.getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany'), - ).toHaveText(`manyToMany:1,2,3`); + ).toHaveText(`manyToMany:${records.map((record) => record.id).join(',')}`); }, }); }); test('Set the data scope', async ({ page, mockPage, mockRecords }) => { - await gotoPage(mockPage, mockRecords); + const records = await gotoPage(mockPage, mockRecords); await openDialog(page); await showMenu(page, 'manyToMany'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); @@ -101,14 +73,14 @@ test.describe('many to many', () => { await page.getByTestId('select-filter-field').click(); await page.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); await page.getByRole('spinbutton').click(); - await page.getByRole('spinbutton').fill('3'); + await page.getByRole('spinbutton').fill(String(records[0].id)); await page.getByRole('button', { name: 'OK', exact: true }).click(); // 再次打开弹窗,设置的值应该还在 await showMenu(page, 'manyToMany'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); await expect(page.getByTestId('select-filter-field')).toHaveText('ID'); - await expect(page.getByRole('spinbutton')).toHaveValue('3'); + await expect(page.getByRole('spinbutton')).toHaveValue(String(records[0].id)); await page.getByRole('button', { name: 'Cancel', exact: true }).click(); // 数据应该被过滤了 @@ -116,7 +88,7 @@ test.describe('many to many', () => { .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') .getByTestId('select-object-multiple') .click(); - await expect(page.getByRole('option', { name: '3', exact: true })).toBeVisible(); + await expect(page.getByRole('option', { name: String(records[0].id), exact: true })).toBeVisible(); await expect(page.getByRole('option')).toHaveCount(1); }); @@ -129,7 +101,7 @@ test.describe('many to many', () => { // 配置 await page.getByRole('button', { name: 'Add sort field' }).click(); await page.getByTestId('select-single').getByLabel('Search').click(); - await page.getByRole('option', { name: 'ID' }).click(); + await page.getByRole('option', { name: 'ID', exact: true }).click(); await page.getByText('DESC', { exact: true }).click(); await page.getByRole('button', { name: 'OK', exact: true }).click(); @@ -218,9 +190,12 @@ test.describe('many to one', () => { commonTesting({ openDialogAndShowMenu, fieldName: 'manyToOne', fieldType: 'relation', mode: 'options' }); test('set default value', async ({ page, mockPage, mockRecords }) => { + let records; await testDefaultValue({ page, - gotoPage: () => gotoPage(mockPage, mockRecords), + gotoPage: async () => { + records = await gotoPage(mockPage, mockRecords); + }, openDialog: () => openDialog(page), closeDialog: () => page.getByLabel('drawer-Action.Container-general-Add record-mask').click(), showMenu: () => showMenu(page, 'manyToOne'), @@ -230,32 +205,35 @@ test.describe('many to one', () => { .getByLabel('block-item-VariableInput-') .getByTestId(/select-object/) .click(); - await page.getByRole('option', { name: '1', exact: true }).click(); + await page.getByRole('option', { name: String(records[0].id), exact: true }).click(); await page .getByLabel('block-item-VariableInput-') .getByTestId(/select-object/) .click(); - await page.getByRole('option', { name: '2', exact: true }).click(); + await page.getByRole('option', { name: String(records[1].id), exact: true }).click(); await page .getByLabel('block-item-VariableInput-') .getByTestId(/select-object/) .click(); - await page.getByRole('option', { name: '3', exact: true }).click(); + await page.getByRole('option', { name: String(records[2].id), exact: true }).click(); }, expectConstantValue: async () => { await expect( page .getByLabel('block-item-CollectionField-general-form-general.manyToOne-manyToOne') .getByTestId(/select-object/), - ).toHaveText(`3`); + ).toHaveText(String(records[2].id)); }, }); }); test('pattern', async ({ page, mockPage, mockRecords }) => { + let records; await testPattern({ page, - gotoPage: () => gotoPage(mockPage, mockRecords), + gotoPage: async () => { + records = await gotoPage(mockPage, mockRecords); + }, openDialog: () => openDialog(page), showMenu: () => showMenu(page, 'manyToOne'), expectEditable: async () => { @@ -263,7 +241,7 @@ test.describe('many to one', () => { .getByLabel('block-item-CollectionField-general-form-general.manyToOne-manyToOne') .getByTestId(/select-object/) .click(); - await page.getByRole('option', { name: '1', exact: true }).click(); + await page.getByRole('option', { name: String(records[0].id), exact: true }).click(); }, expectReadonly: async () => { await expect( @@ -276,14 +254,14 @@ test.describe('many to one', () => { }, expectEasyReading: async () => { await expect(page.getByLabel('block-item-CollectionField-general-form-general.manyToOne-manyToOne')).toHaveText( - `manyToOne:1`, + `manyToOne:${String(records[0].id)}`, ); }, }); }); test('Set the data scope', async ({ page, mockPage, mockRecords }) => { - await gotoPage(mockPage, mockRecords); + const records = await gotoPage(mockPage, mockRecords); await openDialog(page); await showMenu(page, 'manyToOne'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); @@ -291,14 +269,14 @@ test.describe('many to one', () => { await page.getByTestId('select-filter-field').click(); await page.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); await page.getByRole('spinbutton').click(); - await page.getByRole('spinbutton').fill('3'); + await page.getByRole('spinbutton').fill(String(records[0].id)); await page.getByRole('button', { name: 'OK', exact: true }).click(); // 再次打开弹窗,设置的值应该还在 await showMenu(page, 'manyToOne'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); await expect(page.getByTestId('select-filter-field')).toHaveText('ID'); - await expect(page.getByRole('spinbutton')).toHaveValue('3'); + await expect(page.getByRole('spinbutton')).toHaveValue(String(records[0].id)); await page.getByRole('button', { name: 'Cancel', exact: true }).click(); // 数据应该被过滤了 @@ -306,7 +284,7 @@ test.describe('many to one', () => { .getByLabel('block-item-CollectionField-general-form-general.manyToOne-manyToOne') .getByLabel('Search') .click(); - await expect(page.getByRole('option', { name: '3', exact: true })).toBeVisible(); + await expect(page.getByRole('option', { name: String(records[0].id), exact: true })).toBeVisible(); await expect(page.getByRole('option')).toHaveCount(1); }); @@ -350,7 +328,9 @@ test.describe('one to many', () => { test('pattern', async ({ page, mockPage, mockRecords }) => { await testPattern({ page, - gotoPage: () => gotoPage(mockPage, mockRecords), + gotoPage: async () => { + await gotoPage(mockPage, mockRecords); + }, openDialog: () => openDialog(page), showMenu: () => showMenu(page, 'oneToMany'), expectEditable: async () => { @@ -358,9 +338,8 @@ test.describe('one to many', () => { .getByLabel('block-item-CollectionField-general-form-general.oneToMany-oneToMany') .getByTestId('select-object-multiple') .click(); + // 目前的情况下,在 one to many 的字段中,只有 ID 为 1 的数据可以被选中 await page.getByRole('option', { name: '1', exact: true }).click(); - await page.getByRole('option', { name: '2', exact: true }).click(); - await page.getByRole('option', { name: '3', exact: true }).click(); }, expectReadonly: async () => { await expect( @@ -373,14 +352,14 @@ test.describe('one to many', () => { }, expectEasyReading: async () => { await expect(page.getByLabel('block-item-CollectionField-general-form-general.oneToMany-oneToMany')).toHaveText( - `oneToMany:1,2,3`, + `oneToMany:1`, ); }, }); }); test('Set the data scope', async ({ page, mockPage, mockRecords }) => { - await gotoPage(mockPage, mockRecords); + const records = await gotoPage(mockPage, mockRecords); await openDialog(page); await showMenu(page, 'oneToMany'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); @@ -388,14 +367,14 @@ test.describe('one to many', () => { await page.getByTestId('select-filter-field').click(); await page.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); await page.getByRole('spinbutton').click(); - await page.getByRole('spinbutton').fill('3'); + await page.getByRole('spinbutton').fill(String(records[0].id)); await page.getByRole('button', { name: 'OK', exact: true }).click(); // 再次打开弹窗,设置的值应该还在 await showMenu(page, 'oneToMany'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); await expect(page.getByTestId('select-filter-field')).toHaveText('ID'); - await expect(page.getByRole('spinbutton')).toHaveValue('3'); + await expect(page.getByRole('spinbutton')).toHaveValue(String(records[0].id)); await page.getByRole('button', { name: 'Cancel', exact: true }).click(); // 数据应该被过滤了 @@ -403,7 +382,7 @@ test.describe('one to many', () => { .getByLabel('block-item-CollectionField-general-form-general.oneToMany-oneToMany') .getByTestId('select-object-multiple') .click(); - // 默认只显示 id 为 1 的数据,因为设置了只过滤 id 为 3 的数据,所以这里的下拉列表应该为空 + // 默认只显示 id 为 1 的数据,因为设置了只过滤 id 为 3 的数据,所以这里的下拉列表应该为空,mock 的数据无法被选中 await expect(page.getByRole('option')).toHaveCount(0); }); @@ -453,9 +432,12 @@ test.describe('one to one (belongs to)', () => { }); test('pattern', async ({ page, mockPage, mockRecords }) => { + let records; await testPattern({ page, - gotoPage: () => gotoPage(mockPage, mockRecords), + gotoPage: async () => { + records = await gotoPage(mockPage, mockRecords); + }, openDialog: () => openDialog(page), showMenu: () => showMenu(page, 'oneToOneBelongsTo'), expectEditable: async () => { @@ -463,7 +445,7 @@ test.describe('one to one (belongs to)', () => { .getByLabel('block-item-CollectionField-general-form-general.oneToOneBelongsTo-oneToOneBelongsTo') .getByTestId(/select-object/) .click(); - await page.getByRole('option', { name: '1', exact: true }).click(); + await page.getByRole('option', { name: String(records[0].id), exact: true }).click(); }, expectReadonly: async () => { await expect( @@ -477,13 +459,13 @@ test.describe('one to one (belongs to)', () => { expectEasyReading: async () => { await expect( page.getByLabel('block-item-CollectionField-general-form-general.oneToOneBelongsTo-oneToOneBelongsTo'), - ).toHaveText(`oneToOneBelongsTo:1`); + ).toHaveText(`oneToOneBelongsTo:${String(records[0].id)}`); }, }); }); test('Set the data scope', async ({ page, mockPage, mockRecords }) => { - await gotoPage(mockPage, mockRecords); + const records = await gotoPage(mockPage, mockRecords); await openDialog(page); await showMenu(page, 'oneToOneBelongsTo'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); @@ -491,14 +473,14 @@ test.describe('one to one (belongs to)', () => { await page.getByTestId('select-filter-field').click(); await page.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); await page.getByRole('spinbutton').click(); - await page.getByRole('spinbutton').fill('3'); + await page.getByRole('spinbutton').fill(String(records[0].id)); await page.getByRole('button', { name: 'OK', exact: true }).click(); // 再次打开弹窗,设置的值应该还在 await showMenu(page, 'oneToOneBelongsTo'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); await expect(page.getByTestId('select-filter-field')).toHaveText('ID'); - await expect(page.getByRole('spinbutton')).toHaveValue('3'); + await expect(page.getByRole('spinbutton')).toHaveValue(String(records[0].id)); await page.getByRole('button', { name: 'Cancel', exact: true }).click(); // 数据应该被过滤了 @@ -506,7 +488,7 @@ test.describe('one to one (belongs to)', () => { .getByLabel('block-item-CollectionField-general-form-general.oneToOneBelongsTo-oneToOneBelongsTo') .getByLabel('Search') .click(); - await expect(page.getByRole('option', { name: '3', exact: true })).toBeVisible(); + await expect(page.getByRole('option', { name: String(records[0].id), exact: true })).toBeVisible(); await expect(page.getByRole('option')).toHaveCount(1); }); @@ -548,9 +530,12 @@ test.describe('one to one (has one)', () => { }); test('pattern', async ({ page, mockPage, mockRecords }) => { + let records; await testPattern({ page, - gotoPage: () => gotoPage(mockPage, mockRecords), + gotoPage: async () => { + records = await gotoPage(mockPage, mockRecords); + }, openDialog: () => openDialog(page), showMenu: () => showMenu(page, 'oneToOneHasOne'), expectEditable: async () => { @@ -558,6 +543,8 @@ test.describe('one to one (has one)', () => { .getByLabel('block-item-CollectionField-general-form-general.oneToOneHasOne-oneToOneHasOne') .getByTestId(/select-object/) .click(); + + // 目前的情况下,在 one to one (has one) 的字段中,只有 ID 为 1 的数据可以被选中,mock 的数据无法被选中 await page.getByRole('option', { name: '1', exact: true }).click(); }, expectReadonly: async () => { @@ -578,7 +565,7 @@ test.describe('one to one (has one)', () => { }); test('Set the data scope', async ({ page, mockPage, mockRecords }) => { - await gotoPage(mockPage, mockRecords); + const records = await gotoPage(mockPage, mockRecords); await openDialog(page); await showMenu(page, 'oneToOneHasOne'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); @@ -586,14 +573,14 @@ test.describe('one to one (has one)', () => { await page.getByTestId('select-filter-field').click(); await page.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); await page.getByRole('spinbutton').click(); - await page.getByRole('spinbutton').fill('3'); + await page.getByRole('spinbutton').fill(String(records[0].id)); await page.getByRole('button', { name: 'OK', exact: true }).click(); // 再次打开弹窗,设置的值应该还在 await showMenu(page, 'oneToOneHasOne'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); await expect(page.getByTestId('select-filter-field')).toHaveText('ID'); - await expect(page.getByRole('spinbutton')).toHaveValue('3'); + await expect(page.getByRole('spinbutton')).toHaveValue(String(records[0].id)); await page.getByRole('button', { name: 'Cancel', exact: true }).click(); // 数据应该被过滤了 @@ -633,3 +620,39 @@ test.describe('one to one (has one)', () => { await expect(page.getByRole('menuitem', { name: 'Title field' })).toBeVisible(); }); }); + +const gotoPage = async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const recordsOfUser = await mockRecords('users', 3); + await nocoPage.goto(); + + return recordsOfUser; +}; + +const openDialog = async (page: Page) => { + await page.getByRole('button', { name: 'Add new' }).click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecords, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + mockRecords; + fieldName: string; +}) { + await gotoPage(mockPage, mockRecords); + await openDialog(page); + await showMenu(page, fieldName); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/systemInfo.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/systemInfo.test.ts similarity index 98% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/systemInfo.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/systemInfo.test.ts index 5f97200dd..0126beb09 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/creatingForm/systemInfo.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-creation/systemInfo.test.ts @@ -1,38 +1,6 @@ import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndSystemInfoFields, test } from '@nocobase/test/client'; import { commonTesting } from '../commonTesting'; -const gotoPage = async (mockPage) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndSystemInfoFields).waitForInit(); - await nocoPage.goto(); -}; - -const openDialog = async (page: Page) => { - await page.getByRole('button', { name: 'Add new' }).click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-`).hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecord, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - fieldName: string; -}) => { - await gotoPage(mockPage); - await openDialog(page); - await showMenu(page, fieldName); -}; - test.describe('created at', () => { commonTesting({ openDialogAndShowMenu, fieldName: 'createdAt', fieldType: 'system', mode: 'options' }); @@ -79,3 +47,35 @@ test.describe('last updated by', () => { await expect(page.getByRole('menuitem', { name: 'Enable link' })).toBeVisible(); }); }); + +const gotoPage = async (mockPage) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndSystemInfoFields).waitForInit(); + await nocoPage.goto(); +}; + +const openDialog = async (page: Page) => { + await page.getByRole('button', { name: 'Add new' }).click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecord, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + fieldName: string; +}) { + await gotoPage(mockPage); + await openDialog(page); + await showMenu(page, fieldName); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/advanced.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/advanced.test.ts similarity index 98% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/advanced.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/advanced.test.ts index b43fd1776..b41d0e25b 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/advanced.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/advanced.test.ts @@ -1,39 +1,6 @@ import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndAdvancedFields, test } from '@nocobase/test/client'; import { commonTesting } from '../commonTesting'; -const gotoPage = async (mockPage, mockRecord) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAdvancedFields).waitForInit(); - await mockRecord('general'); - await nocoPage.goto(); -}; - -const openDialog = async (page: Page) => { - await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecord, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - fieldName: string; -}) => { - await gotoPage(mockPage, mockRecord); - await openDialog(page); - await showMenu(page, fieldName); -}; - test.describe('collection', () => { commonTesting({ openDialogAndShowMenu, fieldName: 'collection', blockType: 'editing', mode: 'options' }); }); @@ -61,3 +28,36 @@ test.describe('sequence', () => { await expect(page.getByRole('menuitem', { name: 'required' })).toBeVisible(); }); }); + +const gotoPage = async (mockPage, mockRecord) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAdvancedFields).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); +}; + +const openDialog = async (page: Page) => { + await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecord, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + fieldName: string; +}) { + await gotoPage(mockPage, mockRecord); + await openDialog(page); + await showMenu(page, fieldName); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/basic.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/basic.test.ts similarity index 99% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/basic.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/basic.test.ts index 0d9ffb729..18a96fd70 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/basic.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/basic.test.ts @@ -1,41 +1,6 @@ import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndBasicFields, test } from '@nocobase/test/client'; import { commonTesting, testPattern, testSetValidationRules } from '../commonTesting'; -const gotoPage = async (mockPage, mockRecord) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); - const record = await mockRecord('general'); - await nocoPage.goto(); - - return record; -}; - -const openDialog = async (page: Page) => { - await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecord, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - fieldName: string; -}) => { - await gotoPage(mockPage, mockRecord); - await openDialog(page); - await showMenu(page, fieldName); -}; - test.describe('color', () => { commonTesting({ openDialogAndShowMenu, fieldName: 'color', blockType: 'editing' }); @@ -540,3 +505,38 @@ test.describe('URL', () => { }); }); }); + +const gotoPage = async (mockPage, mockRecord) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); + const record = await mockRecord('general'); + await nocoPage.goto(); + + return record; +}; + +const openDialog = async (page: Page) => { + await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecord, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + fieldName: string; +}) { + await gotoPage(mockPage, mockRecord); + await openDialog(page); + await showMenu(page, fieldName); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/choices.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/choices.test.ts similarity index 99% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/choices.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/choices.test.ts index 2b743d520..ad376e976 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/choices.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/choices.test.ts @@ -1,45 +1,6 @@ import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndChoicesFields, test } from '@nocobase/test/client'; import { commonTesting, testPattern } from '../commonTesting'; -const gotoPage = async (mockPage, mockRecord) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndChoicesFields).waitForInit(); - const record = await mockRecord('general'); - await nocoPage.goto(); - - return record; -}; - -const openDialog = async (page: Page) => { - await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - await page - .getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`, { exact: true }) - .hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`, { - exact: true, - }) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecord, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - fieldName: string; -}) => { - await gotoPage(mockPage, mockRecord); - await openDialog(page); - await showMenu(page, fieldName); -}; - test.describe('checkbox', () => { commonTesting({ openDialogAndShowMenu, fieldName: 'checkbox', blockType: 'editing', mode: 'options' }); @@ -285,3 +246,42 @@ test.describe('single select', () => { }); }); }); + +const gotoPage = async (mockPage, mockRecord) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndChoicesFields).waitForInit(); + const record = await mockRecord('general'); + await nocoPage.goto(); + + return record; +}; + +const openDialog = async (page: Page) => { + await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + await page + .getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`, { exact: true }) + .hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`, { + exact: true, + }) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecord, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + fieldName: string; +}) { + await gotoPage(mockPage, mockRecord); + await openDialog(page); + await showMenu(page, fieldName); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/datetime.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/datetime.test.ts similarity index 98% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/datetime.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/datetime.test.ts index 8a1ccf283..da2aca89d 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/datetime.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/datetime.test.ts @@ -2,43 +2,6 @@ import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndDatetimeFields, t import dayjs from 'dayjs'; import { commonTesting, testPattern } from '../commonTesting'; -const gotoPage = async (mockPage, mockRecord) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndDatetimeFields).waitForInit(); - const record = await mockRecord('general'); - await nocoPage.goto(); - - return record; -}; - -const openDialog = async (page: Page) => { - await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecord, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - fieldName: string; -}) => { - const record = await gotoPage(mockPage, mockRecord); - await openDialog(page); - await showMenu(page, fieldName); - - return record; -}; - test.describe('datetime', () => { commonTesting({ openDialogAndShowMenu, fieldName: 'datetime', blockType: 'editing', mode: 'options' }); @@ -117,3 +80,40 @@ test.describe('time', () => { }); }); }); + +const gotoPage = async (mockPage, mockRecord) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndDatetimeFields).waitForInit(); + const record = await mockRecord('general'); + await nocoPage.goto(); + + return record; +}; + +const openDialog = async (page: Page) => { + await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecord, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + fieldName: string; +}) { + const record = await gotoPage(mockPage, mockRecord); + await openDialog(page); + await showMenu(page, fieldName); + + return record; +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/media.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/media.test.ts similarity index 99% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/media.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/media.test.ts index f3c8c5f3e..f24d59dce 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/media.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/media.test.ts @@ -1,45 +1,6 @@ import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndMediaFields, test } from '@nocobase/test/client'; import { commonTesting, testPattern, testSetValidationRules } from '../commonTesting'; -const gotoPage = async (mockPage, mockRecord) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndMediaFields).waitForInit(); - const record = await mockRecord('general'); - await nocoPage.goto(); - - return record; -}; - -const openDialog = async (page: Page) => { - await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - await page - .getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`, { exact: true }) - .hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`, { - exact: true, - }) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecord, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - fieldName: string; -}) => { - await gotoPage(mockPage, mockRecord); - await openDialog(page); - await showMenu(page, fieldName); -}; - test.describe('markdown', () => { commonTesting({ openDialogAndShowMenu, fieldName: 'markdown', blockType: 'editing', mode: 'options' }); @@ -173,3 +134,42 @@ test.describe('attachment', () => { }); }); }); + +const gotoPage = async (mockPage, mockRecord) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndMediaFields).waitForInit(); + const record = await mockRecord('general'); + await nocoPage.goto(); + + return record; +}; + +const openDialog = async (page: Page) => { + await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + await page + .getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`, { exact: true }) + .hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`, { + exact: true, + }) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecord, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + fieldName: string; +}) { + await gotoPage(mockPage, mockRecord); + await openDialog(page); + await showMenu(page, fieldName); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/relation.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/relation.test.ts similarity index 91% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/relation.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/relation.test.ts index 92ad38f0a..7e1e48bad 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/relation.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/relation.test.ts @@ -1,43 +1,6 @@ -import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndRelationFields, test } from '@nocobase/test/client'; +import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, test } from '@nocobase/test/client'; import { commonTesting, testPattern } from '../commonTesting'; -const gotoPage = async (mockPage, mockRecords) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndRelationFields).waitForInit(); - await mockRecords('users', 3); - const record = (await mockRecords('general', 1))[0]; - await nocoPage.goto(); - - return record; -}; - -const openDialog = async (page: Page) => { - await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecords, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - mockRecords; - fieldName: string; -}) => { - await gotoPage(mockPage, mockRecords); - await openDialog(page); - await showMenu(page, fieldName); -}; - test.describe('many to many', () => { commonTesting({ openDialogAndShowMenu, @@ -52,7 +15,7 @@ test.describe('many to many', () => { await testPattern({ page, gotoPage: async () => { - record = await gotoPage(mockPage, mockRecords); + record = (await gotoPage(mockPage, mockRecords)).record; }, openDialog: () => openDialog(page), showMenu: () => showMenu(page, 'manyToMany'), @@ -81,7 +44,7 @@ test.describe('many to many', () => { }); test('Set the data scope', async ({ page, mockPage, mockRecords }) => { - await gotoPage(mockPage, mockRecords); + const { recordsOfUser } = await gotoPage(mockPage, mockRecords); await openDialog(page); await showMenu(page, 'manyToMany'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); @@ -89,14 +52,14 @@ test.describe('many to many', () => { await page.getByTestId('select-filter-field').click(); await page.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); await page.getByRole('spinbutton').click(); - await page.getByRole('spinbutton').fill('3'); + await page.getByRole('spinbutton').fill(String(recordsOfUser[0].id)); await page.getByRole('button', { name: 'OK', exact: true }).click(); // 再次打开弹窗,设置的值应该还在 await showMenu(page, 'manyToMany'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); await expect(page.getByTestId('select-filter-field')).toHaveText('ID'); - await expect(page.getByRole('spinbutton')).toHaveValue('3'); + await expect(page.getByRole('spinbutton')).toHaveValue(String(recordsOfUser[0].id)); await page.getByRole('button', { name: 'Cancel', exact: true }).click(); // 数据应该被过滤了 @@ -104,7 +67,7 @@ test.describe('many to many', () => { .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') .getByTestId('select-object-multiple') .click(); - await expect(page.getByRole('option', { name: '3', exact: true })).toBeVisible(); + await expect(page.getByRole('option', { name: String(recordsOfUser[0].id), exact: true })).toBeVisible(); }); test('set default sorting rules', async ({ page, mockPage, mockRecords }) => { @@ -116,7 +79,7 @@ test.describe('many to many', () => { // 配置 await page.getByRole('button', { name: 'Add sort field' }).click(); await page.getByTestId('select-single').getByLabel('Search').click(); - await page.getByRole('option', { name: 'ID' }).click(); + await page.getByRole('option', { name: 'ID', exact: true }).click(); await page.getByText('DESC', { exact: true }).click(); await page.getByRole('button', { name: 'OK', exact: true }).click(); @@ -177,7 +140,7 @@ test.describe('many to one', () => { await testPattern({ page, gotoPage: async () => { - record = await gotoPage(mockPage, mockRecords); + record = (await gotoPage(mockPage, mockRecords)).record; }, openDialog: () => openDialog(page), showMenu: () => showMenu(page, 'manyToOne'), @@ -206,7 +169,7 @@ test.describe('many to one', () => { }); test('Set the data scope', async ({ page, mockPage, mockRecords }) => { - await gotoPage(mockPage, mockRecords); + const { recordsOfUser } = await gotoPage(mockPage, mockRecords); await openDialog(page); await showMenu(page, 'manyToOne'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); @@ -214,14 +177,14 @@ test.describe('many to one', () => { await page.getByTestId('select-filter-field').click(); await page.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); await page.getByRole('spinbutton').click(); - await page.getByRole('spinbutton').fill('3'); + await page.getByRole('spinbutton').fill(String(recordsOfUser[0].id)); await page.getByRole('button', { name: 'OK', exact: true }).click(); // 再次打开弹窗,设置的值应该还在 await showMenu(page, 'manyToOne'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); await expect(page.getByTestId('select-filter-field')).toHaveText('ID'); - await expect(page.getByRole('spinbutton')).toHaveValue('3'); + await expect(page.getByRole('spinbutton')).toHaveValue(String(recordsOfUser[0].id)); await page.getByRole('button', { name: 'Cancel', exact: true }).click(); // 数据应该被过滤了 @@ -229,7 +192,7 @@ test.describe('many to one', () => { .getByLabel('block-item-CollectionField-general-form-general.manyToOne-manyToOne') .getByTestId(/select-object/) .click(); - await expect(page.getByRole('option', { name: '3', exact: true })).toBeVisible(); + await expect(page.getByRole('option', { name: String(recordsOfUser[0].id), exact: true })).toBeVisible(); await expect(page.getByRole('option')).toHaveCount(2); }); @@ -276,7 +239,7 @@ test.describe('one to many', () => { await testPattern({ page, gotoPage: async () => { - record = await gotoPage(mockPage, mockRecords); + record = (await gotoPage(mockPage, mockRecords)).record; }, openDialog: () => openDialog(page), showMenu: () => showMenu(page, 'oneToMany'), @@ -305,7 +268,7 @@ test.describe('one to many', () => { }); test('Set the data scope', async ({ page, mockPage, mockRecords }) => { - const record = await gotoPage(mockPage, mockRecords); + const { record } = await gotoPage(mockPage, mockRecords); await openDialog(page); await showMenu(page, 'oneToMany'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); @@ -313,14 +276,14 @@ test.describe('one to many', () => { await page.getByTestId('select-filter-field').click(); await page.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); await page.getByRole('spinbutton').click(); - await page.getByRole('spinbutton').fill('3'); + await page.getByRole('spinbutton').fill('1'); await page.getByRole('button', { name: 'OK', exact: true }).click(); // 再次打开弹窗,设置的值应该还在 await showMenu(page, 'oneToMany'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); await expect(page.getByTestId('select-filter-field')).toHaveText('ID'); - await expect(page.getByRole('spinbutton')).toHaveValue('3'); + await expect(page.getByRole('spinbutton')).toHaveValue('1'); await page.getByRole('button', { name: 'Cancel', exact: true }).click(); // 数据应该被过滤了 @@ -383,7 +346,7 @@ test.describe('one to one (belongs to)', () => { await testPattern({ page, gotoPage: async () => { - record = await gotoPage(mockPage, mockRecords); + record = (await gotoPage(mockPage, mockRecords)).record; }, openDialog: () => openDialog(page), showMenu: () => showMenu(page, 'oneToOneBelongsTo'), @@ -412,7 +375,7 @@ test.describe('one to one (belongs to)', () => { }); test('Set the data scope', async ({ page, mockPage, mockRecords }) => { - await gotoPage(mockPage, mockRecords); + const { recordsOfUser } = await gotoPage(mockPage, mockRecords); await openDialog(page); await showMenu(page, 'oneToOneBelongsTo'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); @@ -420,14 +383,14 @@ test.describe('one to one (belongs to)', () => { await page.getByTestId('select-filter-field').click(); await page.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); await page.getByRole('spinbutton').click(); - await page.getByRole('spinbutton').fill('3'); + await page.getByRole('spinbutton').fill(String(recordsOfUser[0].id)); await page.getByRole('button', { name: 'OK', exact: true }).click(); // 再次打开弹窗,设置的值应该还在 await showMenu(page, 'oneToOneBelongsTo'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); await expect(page.getByTestId('select-filter-field')).toHaveText('ID'); - await expect(page.getByRole('spinbutton')).toHaveValue('3'); + await expect(page.getByRole('spinbutton')).toHaveValue(String(recordsOfUser[0].id)); await page.getByRole('button', { name: 'Cancel', exact: true }).click(); // 数据应该被过滤了 @@ -435,7 +398,7 @@ test.describe('one to one (belongs to)', () => { .getByLabel('block-item-CollectionField-general-form-general.oneToOneBelongsTo-oneToOneBelongsTo') .getByTestId(/select-object/) .click(); - await expect(page.getByRole('option', { name: '3', exact: true })).toBeVisible(); + await expect(page.getByRole('option', { name: String(recordsOfUser[0].id), exact: true })).toBeVisible(); await expect(page.getByRole('option')).toHaveCount(2); }); @@ -482,7 +445,7 @@ test.describe('one to one (has one)', () => { await testPattern({ page, gotoPage: async () => { - record = await gotoPage(mockPage, mockRecords); + record = (await gotoPage(mockPage, mockRecords)).record; }, openDialog: () => openDialog(page), showMenu: () => showMenu(page, 'oneToOneHasOne'), @@ -519,14 +482,14 @@ test.describe('one to one (has one)', () => { await page.getByTestId('select-filter-field').click(); await page.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); await page.getByRole('spinbutton').click(); - await page.getByRole('spinbutton').fill('3'); + await page.getByRole('spinbutton').fill('1'); await page.getByRole('button', { name: 'OK', exact: true }).click(); // 再次打开弹窗,设置的值应该还在 await showMenu(page, 'oneToOneHasOne'); await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); await expect(page.getByTestId('select-filter-field')).toHaveText('ID'); - await expect(page.getByRole('spinbutton')).toHaveValue('3'); + await expect(page.getByRole('spinbutton')).toHaveValue('1'); await page.getByRole('button', { name: 'Cancel', exact: true }).click(); // 数据应该被过滤了 @@ -565,3 +528,40 @@ test.describe('one to one (has one)', () => { await expect(page.getByRole('menuitem', { name: 'Title field' })).toBeVisible(); }); }); + +const gotoPage = async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const recordsOfUser = await mockRecords('users', 3); + const record = (await mockRecords('general', 1))[0]; + await nocoPage.goto(); + + return { record, recordsOfUser }; +}; + +const openDialog = async (page: Page) => { + await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecords, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + mockRecords; + fieldName: string; +}) { + await gotoPage(mockPage, mockRecords); + await openDialog(page); + await showMenu(page, fieldName); +} diff --git a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/systemInfo.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/systemInfo.test.ts similarity index 98% rename from packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/systemInfo.test.ts rename to packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/systemInfo.test.ts index ec0f4ab73..298ab11fc 100644 --- a/packages/core/client/src/__tests__/e2e/schemaSettings/formItem/editingForm/systemInfo.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/form-item/form-edit/systemInfo.test.ts @@ -1,41 +1,6 @@ import { Page, expect, oneTableBlockWithAddNewAndViewAndEditAndSystemInfoFields, test } from '@nocobase/test/client'; import { commonTesting } from '../commonTesting'; -const gotoPage = async (mockPage, mockRecord) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndSystemInfoFields).waitForInit(); - const record = await mockRecord('general'); - await nocoPage.goto(); - - return record; -}; - -const openDialog = async (page: Page) => { - await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); -}; - -const showMenu = async (page: Page, fieldName: string) => { - await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-`).hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) - .hover(); -}; - -const openDialogAndShowMenu = async ({ - page, - mockPage, - mockRecord, - fieldName, -}: { - page: Page; - mockPage; - mockRecord; - fieldName: string; -}) => { - await gotoPage(mockPage, mockRecord); - await openDialog(page); - await showMenu(page, fieldName); -}; - test.describe('created at', () => { commonTesting({ openDialogAndShowMenu, @@ -112,3 +77,38 @@ test.describe('last updated by', () => { await expect(page.getByRole('menuitem', { name: 'Enable link' })).toBeVisible(); }); }); + +const gotoPage = async (mockPage, mockRecord) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndSystemInfoFields).waitForInit(); + const record = await mockRecord('general'); + await nocoPage.goto(); + + return record; +}; + +const openDialog = async (page: Page) => { + await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); +}; + +const showMenu = async (page: Page, fieldName: string) => { + await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`) + .hover(); +}; + +async function openDialogAndShowMenu({ + page, + mockPage, + mockRecord, + fieldName, +}: { + page: Page; + mockPage; + mockRecord; + fieldName: string; +}) { + await gotoPage(mockPage, mockRecord); + await openDialog(page); + await showMenu(page, fieldName); +} diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/advanced.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/advanced.test.ts new file mode 100644 index 000000000..995d5ce94 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/advanced.test.ts @@ -0,0 +1,34 @@ +import { oneTableBlockWithAddNewAndViewAndEditAndAdvancedFields, test } from '@nocobase/test/client'; +import { testSupportedOptions } from './utils'; + +test.describe('collection', () => { + testSupportedOptions({ + name: 'collection', + options: ['Custom column title', 'Column width', 'Sortable', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndAdvancedFields, + }); +}); + +test.describe('JSON', () => { + testSupportedOptions({ + name: 'JSON', + options: ['Custom column title', 'Column width', 'Sortable', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndAdvancedFields, + }); +}); + +test.describe('formula', () => { + testSupportedOptions({ + name: 'formula', + options: ['Custom column title', 'Column width', 'Sortable', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndAdvancedFields, + }); +}); + +test.describe('sequence', () => { + testSupportedOptions({ + name: 'sequence', + options: ['Custom column title', 'Column width', 'Sortable', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndAdvancedFields, + }); +}); diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/basic.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/basic.test.ts new file mode 100644 index 000000000..8249e60d3 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/basic.test.ts @@ -0,0 +1,171 @@ +import { expect, oneTableBlockWithAddNewAndViewAndEditAndBasicFields, test } from '@nocobase/test/client'; +import { createColumnItem, showSettingsMenu, testSupportedOptions } from './utils'; + +test.describe('single line text', () => { + testSupportedOptions({ + name: 'singleLineText', + options: ['Custom column title', 'Column width', 'Sortable', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndBasicFields, + }); + + test('custom column title', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); + await mockRecords('general'); + await nocoPage.goto(); + + await createColumnItem(page, 'singleLineText'); + await showSettingsMenu(page, 'singleLineText'); + await page.getByRole('menuitem', { name: 'Custom column title' }).click(); + + // 显示出原字段名称 + await expect(page.getByRole('dialog').getByText('Original field title: singleLineText')).toBeVisible(); + // 输入新字段名称 + await page.getByLabel('block-item-Input-general-column title').getByRole('textbox').click(); + await page.getByLabel('block-item-Input-general-column title').getByRole('textbox').fill('new column title'); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 新名称应该显示出来 + await expect(page.getByRole('button', { name: 'new column title', exact: true })).toBeVisible(); + }); + + test('column width', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); + await mockRecords('general'); + await nocoPage.goto(); + + await createColumnItem(page, 'singleLineText'); + await showSettingsMenu(page, 'singleLineText'); + await page.getByRole('menuitem', { name: 'Column width' }).click(); + await page.getByRole('dialog').getByRole('spinbutton').click(); + await page.getByRole('dialog').getByRole('spinbutton').fill('600'); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + const columnHeadSize = await page.getByRole('columnheader', { name: 'singleLineText' }).boundingBox(); + expect(Math.floor(columnHeadSize.width)).toBe(600); + }); + + test('sortable', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); + await mockRecords('general', [{ singleLineText: 'a' }, { singleLineText: 'b' }]); + await nocoPage.goto(); + + await createColumnItem(page, 'singleLineText'); + await showSettingsMenu(page, 'singleLineText'); + + // 默认不可排序 + await expect(page.getByRole('menuitem', { name: 'Sortable' }).getByRole('switch')).not.toBeChecked(); + + // 开启排序 + await page.getByRole('menuitem', { name: 'Sortable' }).click(); + // TODO: 此处菜单在点击后不应该消失 + // await expect(page.getByRole('menuitem', { name: 'Sortable' }).getByRole('switch')).toBeChecked(); + + // 鼠标 hover 时,有提示 + await page.getByRole('columnheader', { name: 'singleLineText' }).hover(); + await expect(page.getByRole('tooltip', { name: 'Click to sort ascending' })).toBeVisible(); + + // 点击第一下,升序 + await page.getByRole('columnheader', { name: 'singleLineText' }).click(); + let sizeA = await page.getByRole('cell', { name: 'a', exact: true }).boundingBox(); + let sizeB = await page.getByRole('cell', { name: 'b', exact: true }).boundingBox(); + expect(sizeA.y).toBeLessThan(sizeB.y); + + // 点击第二下,降序 + await page.getByRole('columnheader', { name: 'singleLineText' }).click(); + sizeA = await page.getByRole('cell', { name: 'a', exact: true }).boundingBox(); + sizeB = await page.getByRole('cell', { name: 'b', exact: true }).boundingBox(); + expect(sizeA.y).toBeGreaterThan(sizeB.y); + }); + + test('delete', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); + await mockRecords('general'); + await nocoPage.goto(); + + await createColumnItem(page, 'singleLineText'); + await showSettingsMenu(page, 'singleLineText'); + await page.getByRole('menuitem', { name: 'Delete' }).click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + await expect(page.getByRole('columnheader', { name: 'singleLineText' })).toBeHidden(); + }); +}); + +test.describe('color', () => { + testSupportedOptions({ + name: 'color', + options: ['Custom column title', 'Column width', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndBasicFields, + }); +}); + +test.describe('email', () => { + testSupportedOptions({ + name: 'email', + options: ['Custom column title', 'Column width', 'Sortable', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndBasicFields, + }); +}); + +test.describe('icon', () => { + testSupportedOptions({ + name: 'icon', + options: ['Custom column title', 'Column width', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndBasicFields, + }); +}); + +test.describe('integer', () => { + testSupportedOptions({ + name: 'integer', + options: ['Custom column title', 'Column width', 'Sortable', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndBasicFields, + }); +}); + +test.describe('number', () => { + testSupportedOptions({ + name: 'number', + options: ['Custom column title', 'Column width', 'Sortable', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndBasicFields, + }); +}); + +test.describe('password', () => { + testSupportedOptions({ + name: 'password', + options: ['Custom column title', 'Column width', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndBasicFields, + }); +}); + +test.describe('percent', () => { + testSupportedOptions({ + name: 'percent', + options: ['Custom column title', 'Column width', 'Sortable', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndBasicFields, + }); +}); + +test.describe('phone', () => { + testSupportedOptions({ + name: 'phone', + options: ['Custom column title', 'Column width', 'Sortable', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndBasicFields, + }); +}); + +test.describe('long text', () => { + testSupportedOptions({ + name: 'longText', + options: ['Custom column title', 'Column width', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndBasicFields, + }); +}); + +test.describe('url', () => { + testSupportedOptions({ + name: 'url', + options: ['Custom column title', 'Column width', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndBasicFields, + }); +}); diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/choices.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/choices.test.ts new file mode 100644 index 000000000..f91a9fc3b --- /dev/null +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/choices.test.ts @@ -0,0 +1,50 @@ +import { oneTableBlockWithAddNewAndViewAndEditAndChoicesFields, test } from '@nocobase/test/client'; +import { testSupportedOptions } from './utils'; + +test.describe('checkbox', () => { + testSupportedOptions({ + name: 'checkbox', + options: ['Custom column title', 'Column width', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndChoicesFields, + }); +}); + +test.describe('checkbox group', () => { + testSupportedOptions({ + name: 'checkboxGroup', + options: ['Custom column title', 'Column width', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndChoicesFields, + }); +}); + +test.describe('china region', () => { + testSupportedOptions({ + name: 'chinaRegion', + options: ['Custom column title', 'Column width', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndChoicesFields, + }); +}); + +test.describe('multiple select', () => { + testSupportedOptions({ + name: 'multipleSelect', + options: ['Custom column title', 'Column width', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndChoicesFields, + }); +}); + +test.describe('radio group', () => { + testSupportedOptions({ + name: 'radioGroup', + options: ['Custom column title', 'Column width', 'Sortable', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndChoicesFields, + }); +}); + +test.describe('single select', () => { + testSupportedOptions({ + name: 'singleSelect', + options: ['Custom column title', 'Column width', 'Sortable', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndChoicesFields, + }); +}); diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/datetime.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/datetime.test.ts new file mode 100644 index 000000000..0745942b6 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/datetime.test.ts @@ -0,0 +1,34 @@ +import { expect, oneTableBlockWithAddNewAndViewAndEditAndDatetimeFields, test } from '@nocobase/test/client'; +import dayjs from 'dayjs'; +import { createColumnItem, showSettingsMenu, testSupportedOptions } from './utils'; + +test.describe('datetime', () => { + testSupportedOptions({ + name: 'datetime', + options: ['Custom column title', 'Column width', 'Sortable', 'Date display format', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndDatetimeFields, + }); + + test('date display format', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndDatetimeFields).waitForInit(); + const records = await mockRecords('general', 1); + await nocoPage.goto(); + + await createColumnItem(page, 'datetime'); + await showSettingsMenu(page, 'datetime'); + await page.getByRole('menuitem', { name: 'Date display format' }).click(); + await page.getByLabel('MM/DD/YY').click(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + await expect( + page.getByRole('cell', { name: dayjs(records[0].datetime).format('MM/DD/YY'), exact: true }), + ).toBeVisible(); + }); +}); + +test.describe('time', () => { + testSupportedOptions({ + name: 'time', + options: ['Custom column title', 'Column width', 'Sortable', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndDatetimeFields, + }); +}); diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/media.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/media.test.ts new file mode 100644 index 000000000..a11294635 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/media.test.ts @@ -0,0 +1,26 @@ +import { oneTableBlockWithAddNewAndViewAndEditAndMediaFields, test } from '@nocobase/test/client'; +import { testSupportedOptions } from './utils'; + +test.describe('markdown', () => { + testSupportedOptions({ + name: 'markdown', + options: ['Custom column title', 'Column width', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndMediaFields, + }); +}); + +test.describe('rich text', () => { + testSupportedOptions({ + name: 'richText', + options: ['Custom column title', 'Column width', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndMediaFields, + }); +}); + +test.describe('attachment', () => { + testSupportedOptions({ + name: 'attachment', + options: ['Custom column title', 'Column width', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndMediaFields, + }); +}); diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/relation.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/relation.test.ts new file mode 100644 index 000000000..af7e8073e --- /dev/null +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/relation.test.ts @@ -0,0 +1,105 @@ +import { expect, oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, test } from '@nocobase/test/client'; +import { createColumnItem, showSettingsMenu, testSupportedOptions } from './utils'; + +test.describe('many to one', () => { + testSupportedOptions({ + name: 'manyToOne', + options: ['Custom column title', 'Column width', 'Enable link', 'Title field', 'Field component', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, + }); + + test('enable link', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const record = await mockRecord('general'); + await nocoPage.goto(); + + await createColumnItem(page, 'manyToOne'); + await showSettingsMenu(page, 'manyToOne'); + + // 默认开启 enable link + await expect(page.getByRole('menuitem', { name: 'Enable link' }).getByRole('switch')).toBeChecked(); + await expect(page.locator('a').filter({ has: page.getByText(record.manyToOne.id, { exact: true }) })).toBeVisible(); + + // 关闭 enable link + await page.getByRole('menuitem', { name: 'Enable link' }).click(); + await expect(page.getByRole('menuitem', { name: 'Enable link' }).getByRole('switch')).not.toBeChecked(); + await expect(page.locator('a').filter({ has: page.getByText(record.manyToOne.id, { exact: true }) })).toBeHidden(); + + // 再次开启 + await page.getByRole('menuitem', { name: 'Enable link' }).click(); + await expect(page.getByRole('menuitem', { name: 'Enable link' }).getByRole('switch')).toBeChecked(); + await expect(page.locator('a').filter({ has: page.getByText(record.manyToOne.id, { exact: true }) })).toBeVisible(); + }); + + test('title field', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const record = await mockRecord('general'); + await nocoPage.goto(); + + await createColumnItem(page, 'manyToOne'); + await showSettingsMenu(page, 'manyToOne'); + + // 默认是 ID + await expect(page.getByRole('menuitem', { name: 'Title field' })).toHaveText('Title fieldID'); + await expect(page.getByRole('cell', { name: record.manyToOne.id, exact: true })).toBeVisible(); + + // 修改为 nickname + await page.getByRole('menuitem', { name: 'Title field' }).click(); + await page.getByRole('option', { name: 'Nickname' }).click(); + await expect(page.getByRole('menuitem', { name: 'Title field' })).toHaveText('Title fieldNickname'); + await expect(page.getByRole('cell', { name: record.manyToOne.nickname, exact: true })).toBeVisible(); + }); + + test('field component', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const record = await mockRecord('general'); + await nocoPage.goto(); + + await createColumnItem(page, 'manyToOne'); + await showSettingsMenu(page, 'manyToOne'); + + // 默认是 Title + await expect(page.getByRole('menuitem', { name: 'Field component' })).toHaveText('Field componentTitle'); + + // 修改为 Tag + await page.getByRole('menuitem', { name: 'Field component' }).click(); + await page.getByRole('option', { name: 'Tag' }).click(); + // 修改成功之后会显示 Tag color field 选项 + await expect(page.getByRole('menuitem', { name: 'Tag color field' })).toBeVisible(); + await expect( + page.getByRole('cell', { name: record.manyToOne.id, exact: true }).filter({ has: page.locator('.ant-tag') }), + ).toBeVisible(); + }); +}); + +test.describe('many to many', () => { + testSupportedOptions({ + name: 'manyToMany', + options: ['Custom column title', 'Column width', 'Enable link', 'Title field', 'Field component', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, + }); +}); + +test.describe('one to many', () => { + testSupportedOptions({ + name: 'oneToMany', + options: ['Custom column title', 'Column width', 'Enable link', 'Title field', 'Field component', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, + }); +}); + +test.describe('one to one (belongs to)', () => { + testSupportedOptions({ + name: 'oneToOneBelongsTo', + options: ['Custom column title', 'Column width', 'Enable link', 'Title field', 'Field component', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, + }); +}); + +test.describe('one to one (has one)', () => { + testSupportedOptions({ + name: 'oneToOneHasOne', + options: ['Custom column title', 'Column width', 'Enable link', 'Title field', 'Field component', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, + }); +}); diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/systemInfo.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/systemInfo.test.ts new file mode 100644 index 000000000..9a15e36a8 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/systemInfo.test.ts @@ -0,0 +1,50 @@ +import { oneTableBlockWithAddNewAndViewAndEditAndSystemInfoFields, test } from '@nocobase/test/client'; +import { testSupportedOptions } from './utils'; + +test.describe('created at', () => { + testSupportedOptions({ + name: 'Created at', + options: ['Custom column title', 'Column width', 'Sortable', 'Date display format', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndSystemInfoFields, + }); +}); + +test.describe('created by', () => { + testSupportedOptions({ + name: 'Created by', + options: ['Custom column title', 'Column width', 'Enable link', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndSystemInfoFields, + }); +}); + +test.describe('id', () => { + testSupportedOptions({ + name: 'ID', + options: ['Custom column title', 'Column width', 'Sortable', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndSystemInfoFields, + }); +}); + +test.describe('table oid', () => { + testSupportedOptions({ + name: 'Table OID', + options: ['Custom column title', 'Column width', 'Sortable', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndSystemInfoFields, + }); +}); + +test.describe('last updated at', () => { + testSupportedOptions({ + name: 'Last updated at', + options: ['Custom column title', 'Column width', 'Sortable', 'Date display format', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndSystemInfoFields, + }); +}); + +test.describe('last updated by', () => { + testSupportedOptions({ + name: 'Last updated by', + options: ['Custom column title', 'Column width', 'Enable link', 'Delete'], + template: oneTableBlockWithAddNewAndViewAndEditAndSystemInfoFields, + }); +}); diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/utils.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/utils.ts new file mode 100644 index 000000000..bc3310583 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/schema-settings/table-column-item/utils.ts @@ -0,0 +1,37 @@ +import { Page, PageConfig, expectSettingsMenu, test } from '@nocobase/test/client'; + +export function testSupportedOptions({ + name, + options, + template, +}: { + name: string; + options: string[]; + template: PageConfig; +}) { + test('supported options', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(template).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await createColumnItem(page, name); + await showSettingsMenu(page, name); + }, + supportedOptions: options, + }); + }); +} + +export async function showSettingsMenu(page: Page, fieldName: string) { + await page.getByRole('columnheader', { name: fieldName, exact: true }).hover(); + await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.Column.Designer-').hover(); +} + +export async function createColumnItem(page: Page, fieldName: string) { + await page.getByLabel('schema-initializer-TableV2-TableColumnInitializers-general').hover(); + await page.getByRole('menuitem', { name: fieldName, exact: true }).click(); + await page.mouse.move(300, 0); +} diff --git a/packages/plugins/@nocobase/plugin-mock-collections/src/server/index.ts b/packages/plugins/@nocobase/plugin-mock-collections/src/server/index.ts index 477aac4c0..d2460b09c 100644 --- a/packages/plugins/@nocobase/plugin-mock-collections/src/server/index.ts +++ b/packages/plugins/@nocobase/plugin-mock-collections/src/server/index.ts @@ -188,7 +188,7 @@ export class PluginMockCollectionsServer extends Plugin { mock: async (ctx, next) => { const { resourceName } = ctx.action; const { values, count = 10 } = ctx.action.params; - const mockCollectionData = async (collectionName, count = 1, depth = 0, maxDepth = 2) => { + const mockCollectionData = async (collectionName, count = 1, depth = 0, maxDepth = 4) => { const collection = ctx.db.getCollection(collectionName) as Collection; const items = await Promise.all( _.range(count).map(async (i) => { diff --git a/packages/plugins/@nocobase/plugin-theme-editor/src/client/__tests__/e2e/demo.test.ts b/packages/plugins/@nocobase/plugin-theme-editor/src/client/__tests__/e2e/demo.test.ts deleted file mode 100644 index 45fd76509..000000000 --- a/packages/plugins/@nocobase/plugin-theme-editor/src/client/__tests__/e2e/demo.test.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { test } from '@nocobase/test/client'; - -test('demo', async ({ page }) => {}); diff --git a/playwright.config.ts b/playwright.config.ts index 28154da8a..4cc1846df 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -6,7 +6,8 @@ export default defineConfig({ // Look for test files in the "tests" directory, relative to this configuration file. testDir: 'packages', - testMatch: /.*\/e2e\/.+\.test\.[tj]sx*$/, + // Match all test files in the e2e and __e2e__ directories. + testMatch: /(.*\/e2e\/|.*\/__e2e__\/).+\.test\.[tj]sx*$/, // Run all tests in parallel. fullyParallel: true, diff --git a/scripts/auth.setup.ts b/scripts/auth.setup.ts index 3e788dc6b..d9f667e7e 100644 --- a/scripts/auth.setup.ts +++ b/scripts/auth.setup.ts @@ -18,6 +18,11 @@ setup('admin', async ({ page }) => { await expect(page.getByTestId('user-center-button').getByText('Super Admin')).toBeVisible(); + // 开启配置状态 + await page.evaluate(() => { + localStorage.setItem('NOCOBASE_DESIGNABLE', 'true'); + }); + // 保存登录状态 await page.context().storageState({ path: adminFile }); }); diff --git a/vitest.config.ts b/vitest.config.ts index 0b6c1933a..e03e4bd56 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -42,6 +42,7 @@ export default defineConfig({ '**/lib/**', '**/es/**', '**/e2e/**', + '**/__e2e__/**', '**/{vitest,commitlint}.config.*', ], testTimeout: 300000,