diff --git a/.gitignore b/.gitignore index 9b2a0813d3..6e14faa3d0 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ storage/tmp storage/app.watch.ts storage/logs-e2e storage/uploads-e2e +storage/.pm2-* tsconfig.paths.json /playwright /storage/playwright diff --git a/packages/core/app/client/public/global.css b/packages/core/app/client/public/global.css index e938df0831..509a5af6e7 100644 --- a/packages/core/app/client/public/global.css +++ b/packages/core/app/client/public/global.css @@ -65,5 +65,5 @@ body a:active { /* fix https://nocobase.height.app/T-2838 */ /* antd 组件的层级有问题,有的弹窗是 1000 有的是 1200,会导致弹窗被覆盖的问题。弹窗这里应该使用同一个值,是比较合理的 */ .ant-modal-wrap, .ant-modal-mask { - z-index: 1000 !important; + z-index: 1150 !important; } diff --git a/packages/core/cli/src/commands/p-test.js b/packages/core/cli/src/commands/p-test.js index 99b7cf0b51..da0c32e639 100644 --- a/packages/core/cli/src/commands/p-test.js +++ b/packages/core/cli/src/commands/p-test.js @@ -1,10 +1,11 @@ const execa = require('execa'); -const { resolve, dirname } = require('path'); +const { resolve } = require('path'); const pAll = require('p-all'); const dotenv = require('dotenv'); const fs = require('fs'); const { Client } = require('pg'); const glob = require('glob'); +const _ = require('lodash'); let ENV_FILE = resolve(process.cwd(), '.env.e2e'); @@ -18,7 +19,10 @@ const config = { ...process.env, }; -async function runApp(index = 1, dir) { +async function runApp(dir, index = 0) { + // 一个进程需要占用两个端口? (一个是应用端口,一个是 socket 端口) + index = index * 2; + const database = `nocobase${index}`; const client = new Client({ host: config['DB_HOST'], @@ -54,15 +58,15 @@ exports.pTest = async (options) => { const files = glob.sync('packages/**/__e2e__/**/*.test.ts', { root: process.cwd(), }); - const fileSet = new Set(); - for (const file of files) { - fileSet.add(dirname(file)); - } - - const commands = [...fileSet.values()].map((v, i) => { - return () => runApp(i + 1, v); + const commands = splitArrayIntoParts(files, options.concurrency || 3).map((v, i) => { + return () => runApp(v.join(' '), i); }); await pAll(commands, { concurrency: 3, stopOnError: false, ...options }); }; + +function splitArrayIntoParts(array, parts) { + let chunkSize = Math.ceil(array.length / parts); + return _.chunk(array, chunkSize); +} diff --git a/packages/core/client/src/modules/form-creation/__e2e__/lazyLoadVariables.test.ts b/packages/core/client/src/modules/form-creation/__e2e__/lazyLoadVariables.test.ts index be6f03886e..c8f3bb8b5c 100644 --- a/packages/core/client/src/modules/form-creation/__e2e__/lazyLoadVariables.test.ts +++ b/packages/core/client/src/modules/form-creation/__e2e__/lazyLoadVariables.test.ts @@ -18,5 +18,31 @@ test.describe('variables with default value', () => { .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') .getByRole('textbox'), ).toHaveValue('1'); + + // https://nocobase.height.app/T-2805 ---------------------------------------------------------------------- + await page + .getByLabel('block-item-CollectionField-general-form-general.m2oField0-m2oField0') + .getByTestId('select-object-single') + .hover(); + await page.getByLabel('icon-close-select').click(); + // 等待值消失 + await page.waitForTimeout(500); + await expect( + page + .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') + .getByRole('textbox'), + ).toHaveValue(''); + + await page + .getByLabel('block-item-CollectionField-general-form-general.m2oField0-m2oField0') + .getByTestId('select-object-single') + .click(); + await page.getByRole('option', { name: '1', exact: true }).click(); + + await expect( + page + .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') + .getByRole('textbox'), + ).toHaveValue('1'); }); }); 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 index 58d601a9bb..31fa8fddb7 100644 --- a/packages/core/client/src/modules/form-creation/__e2e__/schemaSettings.test.ts +++ b/packages/core/client/src/modules/form-creation/__e2e__/schemaSettings.test.ts @@ -584,6 +584,7 @@ test.describe('creation form block schema settings', () => { .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('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(); diff --git a/packages/core/client/src/modules/table/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/table/__e2e__/schemaSettings.test.ts index 3a000241da..44b291bc8f 100644 --- a/packages/core/client/src/modules/table/__e2e__/schemaSettings.test.ts +++ b/packages/core/client/src/modules/table/__e2e__/schemaSettings.test.ts @@ -117,7 +117,7 @@ test.describe('table block schema settings', () => { .dragTo(page.getByLabel('table-index-1').getByRole('img', { name: 'menu' })); // 等待表格刷新 - await page.waitForTimeout(2000); + await page.waitForTimeout(3000); email1 = await page.getByText(records[0].email).boundingBox(); email2 = await page.getByText(records[1].email).boundingBox(); diff --git a/packages/core/client/src/schema-component/antd/action/Action.Drawer.style.ts b/packages/core/client/src/schema-component/antd/action/Action.Drawer.style.ts index 8723d4e711..cd2b80e87c 100644 --- a/packages/core/client/src/schema-component/antd/action/Action.Drawer.style.ts +++ b/packages/core/client/src/schema-component/antd/action/Action.Drawer.style.ts @@ -5,7 +5,7 @@ export const useStyles = genStyleHook('nb-action-drawer', (token) => { return { [componentCls]: { - zIndex: '1000 !important', // fix https://nocobase.height.app/T-2797 + zIndex: '1150 !important', // fix https://nocobase.height.app/T-2797 overflow: 'hidden', '&.reset': { '&.nb-action-popup': { diff --git a/packages/core/client/src/schema-component/antd/form-item/hooks/useParseDefaultValue.ts b/packages/core/client/src/schema-component/antd/form-item/hooks/useParseDefaultValue.ts index 14551be2e1..3213d6f13e 100644 --- a/packages/core/client/src/schema-component/antd/form-item/hooks/useParseDefaultValue.ts +++ b/packages/core/client/src/schema-component/antd/form-item/hooks/useParseDefaultValue.ts @@ -25,7 +25,7 @@ const useParseDefaultValue = () => { const variables = useVariables(); const localVariables = useLocalVariables(); const record = useRecord(); - const { isInAssignFieldValues, isInSetDefaultValueDialog, isInFormDataTemplate } = useFlag() || {}; + const { isInAssignFieldValues, isInSetDefaultValueDialog, isInFormDataTemplate, isInSubTable } = useFlag() || {}; const { getField } = useCollection(); const { isSpecialCase, setDefaultValue } = useSpecialCase(); const index = useRecordIndex(); @@ -52,17 +52,21 @@ const useParseDefaultValue = () => { isInFormDataTemplate || isSubMode(fieldSchema) || // 编辑状态下不需要设置默认值,否则会覆盖用户输入的值,只有新建状态下才需要设置默认值 - (formBlockType === 'update' && isFromDatabase(record) && !isInAssignFieldValues) + (formBlockType === 'update' && !isInSubTable && isFromDatabase(record) && !isInAssignFieldValues) ) { return; } - const _run = async () => { + const _run = async ({ forceUpdate = false } = {}) => { // 如果默认值是一个变量,则需要解析之后再显示出来 - if (isVariable(fieldSchema.default) && variables && field) { + if ( + variables && + field && + ((isVariable(fieldSchema.default) && field.value == null) || field.value === fieldSchema.default || forceUpdate) + ) { // 一个变量字符串如果显示出来会比较奇怪 if (isVariable(field.value)) { - field.setValue(null); + await field.reset({ forceClear: true }); } field.loading = true; @@ -79,17 +83,16 @@ const useParseDefaultValue = () => { }); if (value == null || value === '') { - field.setValue(null); + // fix https://nocobase.height.app/T-2805 + field.setInitialValue(null); + await field.reset({ forceClear: true }); } else if (isSpecialCase()) { // 只需要设置一次就可以了 if (index === 0) { setDefaultValue(value); } } else { - // eslint-disable-next-line promise/catch-or-return - Promise.resolve().then(() => { - field.setInitialValue(value); - }); + field.setInitialValue(value); } field.loading = false; @@ -128,13 +131,7 @@ const useParseDefaultValue = () => { return value; }, - _run, - { - equals: (oldValue, newValue) => { - field.setValue(newValue); - return oldValue === newValue; - }, - }, + () => run({ forceUpdate: true }), ); return dispose; diff --git a/packages/core/test/src/e2e/defineConfig.ts b/packages/core/test/src/e2e/defineConfig.ts index 8bf506ce5b..a92f96980a 100644 --- a/packages/core/test/src/e2e/defineConfig.ts +++ b/packages/core/test/src/e2e/defineConfig.ts @@ -2,7 +2,11 @@ import { devices, defineConfig as playwrightDefineConfig, type PlaywrightTestCon export const defineConfig = (config?: PlaywrightTestConfig) => { return playwrightDefineConfig({ - timeout: process.env.CI ? 2 * 60 * 1000 : 30 * 1000, + timeout: process.env.CI ? 5 * 60 * 1000 : 30 * 1000, + + expect: { + timeout: process.env.CI ? 1 * 60 * 1000 : 5000, + }, // Look for test files in the "tests" directory, relative to this configuration file. testDir: 'packages', diff --git a/packages/core/test/src/e2e/templatesOfPage.ts b/packages/core/test/src/e2e/templatesOfPage.ts index 51c4b6e78d..641839c9af 100644 --- a/packages/core/test/src/e2e/templatesOfPage.ts +++ b/packages/core/test/src/e2e/templatesOfPage.ts @@ -5834,6 +5834,432 @@ export const oneTableBlockWithAddNewAndViewAndEditAndBasicFields: PageConfig = { }, }; +/** + * 1. 一个 Table 区块 + * 2. 点击 Add new 有一个 Form 区块,里面有一个 sub-table 字段 + * 3. 点击 View 有一个 Details 区块,里面有一个 sub-table 字段 + * 4. 点击 Edit 有一个 Form 区块,里面有一个 sub-table 字段 + * 5. sub-table 中的所有字段都是 basic 字段 + */ +export const oneTableBlockWithAddNewAndViewAndEditAndBasicFieldsAndSubTable: PageConfig = { + collections: [ + ...generalWithBasic, + { + name: 'subTable', + fields: [ + { + name: 'manyToMany', + interface: 'm2m', + target: 'general', + }, + { + name: 'oneToMany', + interface: 'o2m', + target: 'general', + }, + ], + }, + ], + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + '7m533o9wcl2': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + mbtse8e9kap: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + ir5rfzx0z5o: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + yr9pww7k8mq: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'subTable:list', + 'x-decorator-props': { + collection: 'subTable', + resource: 'subTable', + 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': '0bvmtmgkrx0', + 'x-async': false, + 'x-index': 1, + }, + '39vo8hzhsor': { + _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: { + dghwbcfocgv: { + 'x-uid': 'rhc8oxdqglj', + _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: { + trny88kf0bk: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '78r8m6ecsh4': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + lj0yhupvh3o: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: false, + }, + 'x-acl-action': 'subTable:update', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + useSourceId: '{{ useSourceIdFromParentRecord }}', + useParams: '{{ useParamsFromRecord }}', + action: 'get', + resource: 'subTable', + collection: 'subTable', + }, + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-component-props': {}, + properties: { + '0ykr2ijd1qa': { + _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: { + '7mwkv9h74ki': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + '0f4fktqpnee': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + manyToMany: { + 'x-uid': 'lclf348ur56', + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': + 'subTable.manyToMany', + 'x-component-props': { + mode: 'SubTable', + }, + properties: { + ry6csw9ij4n: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': + 'AssociationField.SubTable', + 'x-initializer': + 'TableColumnInitializers', + 'x-initializer-props': { + action: false, + }, + 'x-index': 1, + properties: { + rmz41gp1stq: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': + 'TableV2.Column.Decorator', + 'x-designer': + 'TableV2.Column.Designer', + 'x-component': + 'TableV2.Column', + properties: { + singleLineText: { + 'x-uid': 'tlprzxnyyqb', + _isJSONSchemaObject: + true, + version: '2.0', + 'x-collection-field': + 'general.singleLineText', + 'x-component': + 'CollectionField', + 'x-component-props': { + ellipsis: true, + }, + 'x-decorator': + 'FormItem', + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + default: null, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'zmslu38eujy', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'vl5lkem00dr', + 'x-async': false, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'gzxknc793se', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'lr63kqkjvgo', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '8iw3zvh7vxd', + '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': '95vrlwf03yk', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '17ju1kwigyw', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'by4uluzexjq', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'nzw5judm7ah', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'keraakujlcb', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'dtc6ufrnn2w', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'kgrdpc9e834', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'h60qmmbj1ez', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'f930il0aqu3', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'gb81ougszo2', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'aa33l45v6qb', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'lm8sj8ojma9', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'z5n8ihuvx64', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'snt3mrh4ug9', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'kzi69u1gb24', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'hbmkoataojj', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'sfa1nw7kqmi', + 'x-async': true, + 'x-index': 1, + }, +}; + /** * 1. 一个 Table 区块 * 2. 点击 Add new 有一个 Form 区块 diff --git a/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/menu.test.ts b/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/menu.test.ts index bccee2b9fa..e1d0304e40 100644 --- a/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/menu.test.ts +++ b/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/menu.test.ts @@ -1,8 +1,8 @@ import { expect, test } from '@nocobase/test/e2e'; test('menu permission ', async ({ page, mockPage, mockRole, updateRole }) => { - const page2 = await mockPage({ name: 'page2' }); - const page1 = await mockPage({ name: 'page1' }); + const page2 = mockPage({ name: 'page2' }); + const page1 = mockPage({ name: 'page1' }); await page1.goto(); const uid1 = await page1.getUid(); const uid2 = await page2.getUid(); @@ -18,33 +18,29 @@ test('menu permission ', async ({ page, mockPage, mockRole, updateRole }) => { window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); }, roleData); await page.reload(); - await expect(await page.getByLabel('page1')).toBeVisible(); - await expect(await page.getByLabel('page2')).not.toBeVisible(); + await expect(page.getByLabel('page1')).toBeVisible(); + await expect(page.getByLabel('page2')).not.toBeVisible(); await page.getByTestId('plugin-settings-button').hover(); await page.getByLabel('acl').click(); await page.getByLabel(`action-Action.Link-Configure-roles-${roleData.name}`).click(); await page.getByRole('tab').getByText('Menu permissions').click(); await page.waitForSelector('.ant-table'); - const page1Menu = await page.getByRole('row', { name: 'page1' }).locator('.ant-checkbox-input'); - const page2Menu = await page.getByRole('row', { name: 'page2' }).locator('.ant-checkbox-input'); - await expect(await page1Menu.isChecked()).toBe(true); - await expect(await page2Menu.isChecked()).toBe(false); + await expect(page.getByRole('row', { name: 'page1' }).locator('.ant-checkbox-input')).toBeChecked({ checked: true }); + await expect(page.getByRole('row', { name: 'page2' }).locator('.ant-checkbox-input')).toBeChecked({ checked: false }); //修改菜单权限,page1无权限,page2有权限 await updateRole({ name: roleData.name, menuUiSchemas: [uid2] }); await page.reload(); - await expect(await page.getByLabel('page2')).toBeVisible(); - await expect(await page.getByLabel('page1')).not.toBeVisible(); + await expect(page.getByLabel('page2')).toBeVisible(); + await expect(page.getByLabel('page1')).not.toBeVisible(); await page.getByTestId('plugin-settings-button').hover(); await page.getByLabel('acl').click(); await page.getByLabel(`action-Action.Link-Configure-roles-${roleData.name}`).click(); await page.getByRole('tab').getByText('Menu permissions').click(); await page.waitForSelector('.ant-table'); - const page1Menu1 = await page.getByRole('row', { name: 'page1' }).locator('.ant-checkbox-input'); - const page2Menu1 = await page.getByRole('row', { name: 'page2' }).locator('.ant-checkbox-input'); - await expect(await page1Menu1.isChecked()).toBe(false); - await expect(await page2Menu1.isChecked()).toBe(true); + await expect(page.getByRole('row', { name: 'page1' }).locator('.ant-checkbox-input')).toBeChecked({ checked: false }); + await expect(page.getByRole('row', { name: 'page2' }).locator('.ant-checkbox-input')).toBeChecked({ checked: true }); //通过路由访问无权限的菜单,跳到有权限的第一个菜单 await page.goto(`/admin/${uid1}`); await page.waitForSelector('.nb-page-wrapper'); - await expect(await page.url()).toContain(uid2); + expect(page.url()).toContain(uid2); }); diff --git a/packages/plugins/@nocobase/plugin-action-bulk-edit/src/client/__e2e__/schemaInitailizer.test.ts b/packages/plugins/@nocobase/plugin-action-bulk-edit/src/client/__e2e__/schemaInitailizer.test.ts index caac4943a9..df47a471d2 100644 --- a/packages/plugins/@nocobase/plugin-action-bulk-edit/src/client/__e2e__/schemaInitailizer.test.ts +++ b/packages/plugins/@nocobase/plugin-action-bulk-edit/src/client/__e2e__/schemaInitailizer.test.ts @@ -8,7 +8,7 @@ test.describe('TableActionInitializers & GanttActionInitializers & MapActionInit await page.getByRole('menuitem', { name: 'Customize right' }).click(); await page.getByRole('menuitem', { name: 'Bulk edit' }).click(); await page.mouse.move(300, 0); - await expect(await page.getByLabel('Bulk edit')).toBeVisible(); + await expect(page.getByLabel('Bulk edit')).toBeVisible(); }); test('bulk edit in GanttActionInitializers', async ({ page, mockPage, mockRecords }) => { const nocoPage = await mockPage(oneEmptyGantt).waitForInit(); @@ -17,6 +17,6 @@ test.describe('TableActionInitializers & GanttActionInitializers & MapActionInit await page.getByLabel('schema-initializer-ActionBar-GanttActionInitializers-general').hover(); await page.getByRole('menuitem', { name: 'Customize right' }).click(); await page.getByRole('menuitem', { name: 'Bulk edit' }).click(); - await expect(await page.getByLabel('Bulk edit')).toBeVisible(); + await expect(page.getByLabel('Bulk edit')).toBeVisible(); }); }); diff --git a/packages/plugins/@nocobase/plugin-action-duplicate/src/client/__e2e__/schemaInitailizer.test.ts b/packages/plugins/@nocobase/plugin-action-duplicate/src/client/__e2e__/schemaInitailizer.test.ts index efbf905f92..5cc066de88 100644 --- a/packages/plugins/@nocobase/plugin-action-duplicate/src/client/__e2e__/schemaInitailizer.test.ts +++ b/packages/plugins/@nocobase/plugin-action-duplicate/src/client/__e2e__/schemaInitailizer.test.ts @@ -14,9 +14,9 @@ test.describe('TableActionColumnInitializers & DetailsActionInitializers & ReadP await page.getByRole('button', { name: 'Actions' }).hover(); await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-general').hover(); await page.getByRole('menuitem', { name: 'Duplicate' }).click(); - await expect(await page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0')).toBeVisible(); + await expect(page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0')).toBeVisible(); }); - test('duplication action in DetailsActionInitializers', async ({ page, mockPage, mockCollections, mockRecords }) => { + test('duplication action in DetailsActionInitializers', async ({ page, mockPage }) => { await mockPage(oneEmptyDetailsBlock).goto(); await page.getByLabel('schema-initializer-ActionBar-DetailsActionInitializers-general').click(); await page.getByRole('menuitem', { name: 'Duplicate' }).click(); diff --git a/packages/plugins/@nocobase/plugin-action-duplicate/src/client/__e2e__/schemaSettings.test.ts b/packages/plugins/@nocobase/plugin-action-duplicate/src/client/__e2e__/schemaSettings.test.ts index 928f7b180f..0be93eb062 100644 --- a/packages/plugins/@nocobase/plugin-action-duplicate/src/client/__e2e__/schemaSettings.test.ts +++ b/packages/plugins/@nocobase/plugin-action-duplicate/src/client/__e2e__/schemaSettings.test.ts @@ -2,11 +2,11 @@ import { expect, test } from '@nocobase/test/e2e'; import { oneEmptyTableBlockWithDuplicateActions } from './utils'; test.describe('direct duplicate & copy into the form and continue to fill in', () => { - test('direct duplicate', async ({ page, mockPage, mockCollections, mockRecords }) => { + test('direct duplicate', async ({ page, mockPage, mockRecords }) => { const nocoPage = await mockPage(oneEmptyTableBlockWithDuplicateActions).waitForInit(); const data = await mockRecords('general', 3); await nocoPage.goto(); - await expect(await page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0')).toBeVisible(); + await expect(page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0')).toBeVisible(); 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' }).click(); await page.getByRole('menuitem', { name: 'Duplicate mode' }).click(); @@ -26,7 +26,7 @@ test.describe('direct duplicate & copy into the form and continue to fill in', ( const nocoPage = await mockPage(oneEmptyTableBlockWithDuplicateActions).waitForInit(); const data = await mockRecord('general'); await nocoPage.goto(); - await expect(await page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0')).toBeVisible(); + await expect(page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0')).toBeVisible(); 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(); await page.getByRole('menuitem', { name: 'Duplicate mode' }).click(); @@ -71,11 +71,8 @@ test.describe('direct duplicate & copy into the form and continue to fill in', ( await page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0').click(); await expect( - await page - .getByLabel('block-item-CollectionField-general-form-general.singleLineText') - .getByRole('textbox') - .inputValue(), - ).toBe(data['singleLineText']); + page.getByLabel('block-item-CollectionField-general-form-general.singleLineText').getByRole('textbox'), + ).toHaveValue(data['singleLineText']); const [request] = await Promise.all([ page.waitForRequest((request) => request.url().includes('api/general:create')), page.getByLabel('action-Action-Submit-submit-general-form').click(), diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/singleLineText/schemaSettings.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/singleLineText/schemaSettings.test.ts index 3d2615de98..d9f07122c7 100644 --- a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/singleLineText/schemaSettings.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/singleLineText/schemaSettings.test.ts @@ -3,6 +3,7 @@ import { expect, expectSettingsMenu, oneTableBlockWithAddNewAndViewAndEditAndBasicFields, + oneTableBlockWithAddNewAndViewAndEditAndBasicFieldsAndSubTable, test, } from '@nocobase/test/e2e'; import { createColumnItem, showSettingsMenu, testDefaultValue, testPattern, testSetValidationRules } from '../../utils'; @@ -37,23 +38,20 @@ test.describe('form item & create form', () => { test('set default value', async ({ page, mockPage }) => { await testDefaultValue({ page, - gotoPage: () => - (async (mockPage) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); - await nocoPage.goto(); - })(mockPage), - openDialog: () => - (async (page: Page) => { - await page.getByRole('button', { name: 'Add new' }).click(); - })(page), + gotoPage: async () => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit(); + await nocoPage.goto(); + }, + openDialog: async () => { + await page.getByRole('button', { name: 'Add new' }).click(); + }, closeDialog: () => page.getByLabel('drawer-Action.Container-general-Add record-mask').click(), - 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(); - })(page, 'singleLineText'), + showMenu: async () => { + await page.getByLabel(`block-item-CollectionField-general-form-general.singleLineText-singleLineText`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.singleLineText`) + .hover(); + }, supportVariables: ['Constant', 'Current user', 'Date variables', 'Current form'], constantValue: 'test single line text', variableValue: ['Current user', 'Email'], // 值为 admin@nocobase.com @@ -374,3 +372,68 @@ test.describe('table column & table', () => { await expect(page.getByRole('columnheader', { name: 'singleLineText' })).toBeHidden(); }); }); + +test.describe('table column & sub-table in edit form', () => { + test('supported options', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFieldsAndSubTable).waitForInit(); + await mockRecord('subTable'); + await nocoPage.goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByLabel('action-Action.Link-Edit record-update-subTable-table-0').click(); + await page.getByRole('button', { name: 'singleLineText', exact: true }).hover(); + await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.Column.Designer-general').hover(); + }, + supportedOptions: ['Custom column title', 'Column width', 'Required', 'Pattern', 'Set default value', 'Delete'], + }); + }); + + test('set default value', async ({ page, mockPage, mockRecord }) => { + let record; + await testDefaultValue({ + page, + gotoPage: async () => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFieldsAndSubTable).waitForInit(); + record = await mockRecord('subTable'); + await nocoPage.goto(); + }, + openDialog: async () => { + await page.getByLabel('action-Action.Link-Edit record-update-subTable-table-0').click(); + }, + closeDialog: async () => { + await page.getByLabel('drawer-Action.Container-subTable-Edit record-mask').click(); + }, + showMenu: async () => { + await page.getByRole('button', { name: 'singleLineText', exact: true }).hover(); + await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.Column.Designer-general').hover(); + }, + supportVariables: [ + 'Constant', + 'Current user', + 'Current role', + 'Current form', + 'Current object', + 'Current record', + ], + variableValue: ['Current user', 'Nickname'], + expectVariableValue: async () => { + await page.getByRole('button', { name: 'plus' }).click(); + await expect( + page + .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') + .nth(0) + .getByRole('textbox'), + ).toHaveValue(record.manyToMany[0].singleLineText); + + await expect( + page + .getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText') + .nth(record.manyToMany.length) // 最后一行 + .getByRole('textbox'), + ).toHaveValue('Super Admin'); + }, + }); + }); +}); diff --git a/packages/plugins/@nocobase/plugin-kanban/src/client/__e2e__/schemaSettings.test.ts b/packages/plugins/@nocobase/plugin-kanban/src/client/__e2e__/schemaSettings.test.ts index bc94956a88..26a7100a74 100644 --- a/packages/plugins/@nocobase/plugin-kanban/src/client/__e2e__/schemaSettings.test.ts +++ b/packages/plugins/@nocobase/plugin-kanban/src/client/__e2e__/schemaSettings.test.ts @@ -36,7 +36,7 @@ test.describe('configure setting', () => { await page.getByRole('menuitem', { name: 'Set the data scope' }).click(); await page.getByText('Add condition', { exact: true }).click(); await page.getByTestId('select-filter-field').click(); - await page.getByTitle('ID').click(); + await page.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); await page.getByRole('spinbutton').fill('1'); const [request] = await Promise.all([ page.waitForRequest((request) => request.url().includes('api/general:list')), diff --git a/yarn.lock b/yarn.lock index 03070f55c4..bed8470860 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4215,11 +4215,6 @@ dependencies: eslint-scope "5.1.1" -"@nocobase/plugin-workflow-test@>=0.17.0-alpha.3": - version "0.17.0-alpha.7" - resolved "https://registry.yarnpkg.com/@nocobase/plugin-workflow-test/-/plugin-workflow-test-0.17.0-alpha.7.tgz#219a3a1e91e51bec08b1adbb1c4c5c9c7184ecce" - integrity sha512-krZlo1xDM66spbQG6jAYSraxazuxCuA2rD9TxptFQXjkAMTGkuDilJ+edMj6p866N3nyzvFh8lZ2/XY1HUC7Xw== - "@node-saml/node-saml@^4.0.2": version "4.0.5" resolved "https://registry.npmmirror.com/@node-saml/node-saml/-/node-saml-4.0.5.tgz#039e387095b54639b06df62b1b4a6d8941c6d907"