diff --git a/.github/workflows/nocobase-test-e2e.yml b/.github/workflows/nocobase-test-e2e.yml index 62b4964e6d..96f166406e 100644 --- a/.github/workflows/nocobase-test-e2e.yml +++ b/.github/workflows/nocobase-test-e2e.yml @@ -42,7 +42,19 @@ jobs: --health-timeout 5s --health-retries 5 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 + - name: Checkout pro-plugins + uses: actions/checkout@v3 + with: + repository: nocobase/pro-plugins + ref: main + path: packages/pro-plugins + ssh-key: ${{ secrets.SUBMODULE_SSH_KEY }} + - name: Set variables + run: | + APPEND_PRESET_LOCAL_PLUGINS=$(find ./packages/pro-plugins/@nocobase -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | sed 's/^plugin-//' | tr '\n' ',' | sed 's/,$//') + echo "var2=$APPEND_PRESET_LOCAL_PLUGINS" >> $GITHUB_OUTPUT + id: vars - name: Use Node.js ${{ matrix.node_version }} uses: actions/setup-node@v3 with: @@ -51,7 +63,6 @@ jobs: - name: Get yarn cache directory path id: yarn-cache-dir-path run: echo "::set-output name=dir::$(yarn cache dir)" - - uses: actions/cache@v3 id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) with: @@ -78,4 +89,5 @@ jobs: DB_USER: nocobase DB_PASSWORD: password DB_DATABASE: nocobase - timeout-minutes: 180 + APPEND_PRESET_LOCAL_PLUGINS: ${{ steps.vars.outputs.var2 }} + timeout-minutes: 240 diff --git a/packages/core/cli/src/commands/e2e.js b/packages/core/cli/src/commands/e2e.js index 8d70f553ae..a2c294db25 100644 --- a/packages/core/cli/src/commands/e2e.js +++ b/packages/core/cli/src/commands/e2e.js @@ -85,6 +85,7 @@ async function appReady() { async function runApp(options = {}) { console.log('installing...'); await run('nocobase', ['install', '-f']); + await run('nocobase', ['pm', 'enable-all']); if (await isPortReachable(process.env.APP_PORT)) { console.log('app started'); return; @@ -232,6 +233,7 @@ module.exports = (cli) => { e2e.command('reinstall-app').action(async (options) => { await run('nocobase', ['install', '-f'], options); + await run('nocobase', ['pm2', 'enable-all']); }); e2e.command('install-deps').action(async () => { diff --git a/packages/core/client/src/modules/blocks/BlockSchemaToolbar.tsx b/packages/core/client/src/modules/blocks/BlockSchemaToolbar.tsx index 2a9fb7d11f..3f8a5b197e 100644 --- a/packages/core/client/src/modules/blocks/BlockSchemaToolbar.tsx +++ b/packages/core/client/src/modules/blocks/BlockSchemaToolbar.tsx @@ -9,7 +9,7 @@ import { useSchemaTemplate } from '../../schema-templates'; export const BlockSchemaToolbar = (props) => { const { t } = useTranslation(); const cm = useCollectionManager(); - let { name: currentCollectionName, title: currentCollectionTitle } = useCollection(); + let { name: currentCollectionName, title: currentCollectionTitle } = useCollection() || {}; const template = useSchemaTemplate(); const { association } = useDataBlockProps() || {}; const compile = useCompile(); @@ -40,13 +40,13 @@ export const BlockSchemaToolbar = (props) => { return ; }; -function getCollectionTitle(arg0: { +export function getCollectionTitle(arg: { collectionTitle: string; collectionName: string; associationField: any; compile: any; }) { - const { collectionTitle, collectionName, associationField, compile } = arg0; + const { collectionTitle, collectionName, associationField, compile } = arg; if (associationField) { return `${compile(collectionTitle || collectionName)} > ${compile( @@ -54,5 +54,5 @@ function getCollectionTitle(arg0: { )}`; } - return collectionTitle || collectionName; + return compile(collectionTitle || collectionName); } diff --git a/packages/core/client/src/modules/blocks/__tests__/BlockSchemaToolbar.test.tsx b/packages/core/client/src/modules/blocks/__tests__/BlockSchemaToolbar.test.tsx new file mode 100644 index 0000000000..a49e791824 --- /dev/null +++ b/packages/core/client/src/modules/blocks/__tests__/BlockSchemaToolbar.test.tsx @@ -0,0 +1,38 @@ +import { getCollectionTitle } from '../BlockSchemaToolbar'; + +describe('getCollectionTitle', () => { + it('should return collectionTitle if associationField is falsy', () => { + const arg = { + collectionTitle: 'Collection Title', + collectionName: 'Collection Name', + associationField: null, + compile: vi.fn((value) => value), + }; + + const result = getCollectionTitle(arg); + + expect(result).toBe('Collection Title'); + expect(arg.compile).toHaveBeenCalledWith('Collection Title'); + }); + + it('should return compiled collectionTitle and associationField title if associationField is truthy', () => { + const arg = { + collectionTitle: 'Collection Title', + collectionName: 'Collection Name', + associationField: { + uiSchema: { + title: 'Association Field Title', + }, + name: 'Association Field Name', + }, + compile: vi.fn((value) => `Compiled: ${value}`), + }; + + const result = getCollectionTitle(arg); + + expect(result).toBe('Compiled: Collection Title > Compiled: Association Field Title'); + expect(arg.compile).toHaveBeenCalledTimes(2); + expect(arg.compile).toHaveBeenCalledWith('Collection Title'); + expect(arg.compile).toHaveBeenCalledWith('Association Field Title'); + }); +}); diff --git a/packages/core/client/src/modules/blocks/data-blocks/details-single/__e2e__/schemaInitializer.test.ts b/packages/core/client/src/modules/blocks/data-blocks/details-single/__e2e__/schemaInitializer.test.ts index ce38c23481..7dd9b2727b 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/details-single/__e2e__/schemaInitializer.test.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/details-single/__e2e__/schemaInitializer.test.ts @@ -24,7 +24,7 @@ test.describe('where single data details block can be added', () => { clearBlockTemplates, }) => { const nocoPage = await mockPage(T3848).waitForInit(); - await mockRecord('example'); + await mockRecord('example', 2); await nocoPage.goto(); // 1.打开弹窗 diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/lazyLoadAssociationFields.test.ts b/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/lazyLoadAssociationFields.test.ts index c21837c22d..0f43aa9c3f 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/lazyLoadAssociationFields.test.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/lazyLoadAssociationFields.test.ts @@ -11,7 +11,7 @@ import { T2200, T2614, T2615, T2845, T2993 } 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 mockRecord('general', 2); await nocoPage.goto(); // 为关系字段选中一个值 @@ -30,7 +30,7 @@ test.describe('display association fields', () => { test('subform: should display correctly', async ({ page, mockPage, mockRecord }) => { const nocoPage = await mockPage(oneSubformWithMultiLevelAssociationFields).waitForInit(); - await mockRecord('general'); + await mockRecord('general', 3); await nocoPage.goto(); // 为子表单中的关系字段选中一个值 @@ -52,7 +52,7 @@ test.describe('display association fields', () => { // 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 mockRecord('T2615', 2); await nocoPage.goto(); // 1. 新增表单中应该显示关系字段的数据 @@ -91,7 +91,7 @@ test.describe('display association fields', () => { test('should load association data of subform', async ({ page, mockPage, mockRecord }) => { const nocoPage = await mockPage(T2845).waitForInit(); // 和 T2615 使用一样的数据表结构 - const record = await mockRecord('T2615'); + const record = await mockRecord('T2615', 3); await nocoPage.goto(); // 1. 新增表单中应该显示关系字段的数据 @@ -139,7 +139,7 @@ test.describe('display association fields', () => { // 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 mockRecord('T2614', 2); await nocoPage.goto(); // 查看详情 @@ -167,7 +167,7 @@ test.describe('display association fields', () => { // https://nocobase.height.app/T-2993 test('should load association data of sub details', async ({ page, mockPage, mockRecord }) => { const nocoPage = await mockPage(T2993).waitForInit(); - const record = await mockRecord('T2993'); + const record = await mockRecord('T2993', 3); await nocoPage.goto(); await page.getByLabel('action-Action-Add new-create-').click(); @@ -186,7 +186,7 @@ test.describe('display association fields', () => { test.describe('association fields', () => { test('subform: load association fields', async ({ page, mockPage, mockRecord }) => { const nocoPage = await mockPage(oneTableSubformWithMultiLevelAssociationFields).waitForInit(); - const record = await mockRecord('general'); + const record = await mockRecord('general', 4); await nocoPage.goto(); // 查看详情 @@ -229,7 +229,7 @@ test.describe('association fields', () => { test('subtable: load association fields', async ({ page, mockPage, mockRecord }) => { const nocoPage = await mockPage(oneTableSubtableWithMultiLevelAssociationFields).waitForInit(); - const record = await mockRecord('general'); + const record = await mockRecord('general', 2); await nocoPage.goto(); // 查看详情 diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/lazyLoadVariables.test.ts b/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/lazyLoadVariables.test.ts index c8f3bb8b5c..d99c6fd732 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/lazyLoadVariables.test.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/lazyLoadVariables.test.ts @@ -3,7 +3,7 @@ import { expect, formBlockDefaultValueTemplate, test } from '@nocobase/test/e2e' test.describe('variables with default value', () => { test('current form', async ({ page, mockPage, mockRecord }) => { const nocoPage = await mockPage(formBlockDefaultValueTemplate).waitForInit(); - await mockRecord('general'); + await mockRecord('general', 2); await nocoPage.goto(); await page.getByRole('button', { name: 'Add new' }).click(); diff --git a/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/schemaSettings.test.ts index 6cbfe2df12..306db3f149 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/schemaSettings.test.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/schemaSettings.test.ts @@ -2,6 +2,7 @@ import { Page, expect, expectSettingsMenu, + mockUserRecordsWithoutDepartments, oneEmptyTableBlockWithActions, oneEmptyTableWithTreeCollection, oneTableBlockWithActionsAndFormBlocks, @@ -232,7 +233,7 @@ test.describe('table block schema settings', () => { 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); + const records = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); // 将左边的 Table 连接到右边的 Table @@ -257,7 +258,7 @@ test.describe('table block schema settings', () => { test('connecting two blocks connected by a relationship field', async ({ page, mockPage, mockRecords }) => { const nocoPage = await mockPage(twoTableWithAssociationFields).waitForInit(); - await mockRecords('users', 3); + await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); // 将左边的 Table 连接到右边的 Table diff --git a/packages/core/server/src/commands/pm.ts b/packages/core/server/src/commands/pm.ts index 394d09fab7..3a5c691517 100644 --- a/packages/core/server/src/commands/pm.ts +++ b/packages/core/server/src/commands/pm.ts @@ -46,6 +46,17 @@ export default (app: Application) => { } }); + pm.command('enable-all') + .ipc() + .preload() + .action(async () => { + try { + await app.pm.enable('*'); + } catch (error) { + throw new PluginCommandError(`Failed to enable plugin`, { cause: error }); + } + }); + pm.command('enable') .ipc() .preload() diff --git a/packages/core/server/src/locale/locale.ts b/packages/core/server/src/locale/locale.ts index 0cf80f285c..a71cb14639 100644 --- a/packages/core/server/src/locale/locale.ts +++ b/packages/core/server/src/locale/locale.ts @@ -75,7 +75,7 @@ export class Locale { getResources(lang: string) { const resources = {}; - const names = this.app.pm.getAliases(); + const names = this.app.pm.getPlugins().keys(); for (const name of names) { try { const p = this.app.pm.get(name); diff --git a/packages/core/server/src/plugin-manager/plugin-manager.ts b/packages/core/server/src/plugin-manager/plugin-manager.ts index 21fc20f823..d455a05d4c 100644 --- a/packages/core/server/src/plugin-manager/plugin-manager.ts +++ b/packages/core/server/src/plugin-manager/plugin-manager.ts @@ -1,3 +1,4 @@ +import Topo from '@hapi/topo'; import { CleanOptions, Collection, SyncOptions } from '@nocobase/database'; import { importModule, isURL } from '@nocobase/utils'; import { fsExists } from '@nocobase/utils/plugin-symlink'; @@ -328,6 +329,9 @@ export class PluginManager { if (options.name) { this.pluginAliases.set(options.name, instance); } + if (options.packageName) { + this.pluginAliases.set(options.packageName, instance); + } if (insert && options.name) { await this.repository.updateOrCreate({ values: { @@ -478,8 +482,27 @@ export class PluginManager { }); } + private sort(names: string | string[]) { + const pluginNames = _.castArray(names); + if (pluginNames.length === 1) { + return pluginNames; + } + const sorter = new Topo.Sorter(); + for (const pluginName of pluginNames) { + const plugin = this.get(pluginName); + const peerDependencies = Object.keys(plugin.options?.packageJson?.peerDependencies || {}); + sorter.add(pluginName, { after: peerDependencies, group: plugin.options?.packageName || pluginName }); + } + return sorter.nodes; + } + async enable(name: string | string[]) { - const pluginNames = _.castArray(name); + let pluginNames = name; + if (name === '*') { + const items = await this.repository.find(); + pluginNames = items.map((item: any) => item.name); + } + pluginNames = this.sort(pluginNames); this.app.log.debug(`enabling plugin ${pluginNames.join(',')}`); this.app.setMaintainingMessage(`enabling plugin ${pluginNames.join(',')}`); const toBeUpdated = []; @@ -492,9 +515,17 @@ export class PluginManager { continue; } await this.app.emitAsync('beforeEnablePlugin', pluginName); - await plugin.beforeEnable(); - plugin.enabled = true; - toBeUpdated.push(pluginName); + try { + await plugin.beforeEnable(); + plugin.enabled = true; + toBeUpdated.push(pluginName); + } catch (error) { + if (name === '*') { + this.app.log.error(error.message); + } else { + throw error; + } + } } if (toBeUpdated.length === 0) { return; @@ -509,10 +540,10 @@ export class PluginManager { }); try { await this.app.reload(); - this.app.log.debug(`syncing database in enable plugin ${pluginNames.join(',')}...`); - this.app.setMaintainingMessage(`syncing database in enable plugin ${pluginNames.join(',')}...`); + this.app.log.debug(`syncing database in enable plugin ${toBeUpdated.join(',')}...`); + this.app.setMaintainingMessage(`syncing database in enable plugin ${toBeUpdated.join(',')}...`); await this.app.db.sync(); - for (const pluginName of pluginNames) { + for (const pluginName of toBeUpdated) { const plugin = this.get(pluginName); if (!plugin.installed) { this.app.log.debug(`installing plugin ${pluginName}...`); @@ -529,7 +560,7 @@ export class PluginManager { installed: true, }, }); - for (const pluginName of pluginNames) { + for (const pluginName of toBeUpdated) { const plugin = this.get(pluginName); this.app.log.debug(`emit afterEnablePlugin event...`); await plugin.afterEnable(); @@ -884,7 +915,7 @@ export class PluginManager { async list(options: any = {}) { const { locale = 'en-US', isPreset = false } = options; return Promise.all( - [...this.getAliases()] + [...this.getPlugins().keys()] .map((name) => { const plugin = this.get(name); if (!isPreset && plugin.options.isPreset) { diff --git a/packages/core/test/src/e2e/e2eUtils.ts b/packages/core/test/src/e2e/e2eUtils.ts index faf5a85649..b1b5c6a222 100644 --- a/packages/core/test/src/e2e/e2eUtils.ts +++ b/packages/core/test/src/e2e/e2eUtils.ts @@ -206,11 +206,21 @@ interface ExtendUtils { mockCollection: (collectionSetting: CollectionSetting) => Promise; /** * 自动生成一条对应 collection 的数据 - * @param collectionName 数据表名称 - * @param data 自定义的数据,缺失时会生成随机数据 * @returns 返回一条生成的数据 */ - mockRecord: (collectionName: string, data?: any) => Promise; + mockRecord: { + /** + * @param collectionName 数据表名称 + * @param data 自定义的数据,缺失时会生成随机数据 + * @param maxDepth - 生成的数据的最大深度,默认为 4,当不想生成太多数据时可以设置一个较低的值 + */ + (collectionName: string, data?: any, maxDepth?: number): Promise; + /** + * @param collectionName 数据表名称 + * @param maxDepth - 生成的数据的最大深度,默认为 4,当不想生成太多数据时可以设置一个较低的值 + */ + (collectionName: string, maxDepth?: number): Promise; + }; /** * 自动生成多条对应 collection 的数据 */ @@ -218,13 +228,15 @@ interface ExtendUtils { /** * @param collectionName - 数据表名称 * @param count - 生成的数据条数 + * @param maxDepth - 生成的数据的最大深度,默认为 4,当不想生成太多数据时可以设置一个较低的值 */ - (collectionName: string, count?: number): Promise; + (collectionName: string, count?: number, maxDepth?: number): Promise; /** * @param collectionName - 数据表名称 * @param data - 指定生成的数据 + * @param maxDepth - 生成的数据的最大深度,默认为 4,当不想生成太多数据时可以设置一个较低的值 */ - (collectionName: string, data?: any[]): Promise; + (collectionName: string, data?: any[], maxDepth?: number): Promise; }; /** * 该方法已弃用,请使用 mockCollections @@ -408,18 +420,28 @@ const _test = base.extend({ }, mockRecords: async ({ page }, use) => { const mockRecords = async (collectionName: string, count: any = 3, data?: any) => { + let maxDepth: number; + if (_.isNumber(data)) { + maxDepth = data; + data = undefined; + } if (_.isArray(count)) { data = count; count = data.length; } - return createRandomData(collectionName, count, data); + return createRandomData(collectionName, count, data, maxDepth); }; await use(mockRecords); }, mockRecord: async ({ page }, use) => { - const mockRecord = async (collectionName: string, data?: any) => { - const result = await createRandomData(collectionName, 1, data); + const mockRecord = async (collectionName: string, data?: any, maxDepth?: any) => { + if (_.isNumber(data)) { + maxDepth = data; + data = undefined; + } + + const result = await createRandomData(collectionName, 1, data, maxDepth); return result[0]; }; @@ -861,7 +883,7 @@ const generateFakerData = (collectionSetting: CollectionSetting) => { return result; }; -const createRandomData = async (collectionName: string, count = 10, data?: any) => { +const createRandomData = async (collectionName: string, count = 10, data?: any, maxDepth?: number) => { const api = await request.newContext({ storageState: process.env.PLAYWRIGHT_AUTH_FILE, }); @@ -869,10 +891,13 @@ const createRandomData = async (collectionName: string, count = 10, data?: any) const state = await api.storageState(); const headers = getHeaders(state); - const result = await api.post(`/api/${collectionName}:mock?count=${count}`, { - headers, - data, - }); + const result = await api.post( + `/api/${collectionName}:mock?count=${count}&maxDepth=${_.isNumber(maxDepth) ? maxDepth : 1}`, + { + headers, + data, + }, + ); if (!result.ok()) { throw new Error(await result.text()); @@ -993,3 +1018,13 @@ export const createBlockInPage = async (page: Page, name: string) => { await page.mouse.move(300, 0); }; + +export const mockUserRecordsWithoutDepartments = (mockRecords: ExtendUtils['mockRecords'], count: number) => { + return mockRecords( + 'users', + Array.from({ length: count }).map(() => ({ + departments: null, + mainDepartment: null, + })), + ); +}; diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/belongsTo/schemaInitializer.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/belongsTo/schemaInitializer.test.ts index dd3f791ac5..9f70ee7e0c 100644 --- a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/belongsTo/schemaInitializer.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/belongsTo/schemaInitializer.test.ts @@ -1,5 +1,6 @@ import { expectInitializerMenu, + mockUserRecordsWithoutDepartments, oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, test, } from '@nocobase/test/e2e'; @@ -7,7 +8,7 @@ import { test.describe('form item & create form', () => { test('configure fields', async ({ page, mockPage, mockRecords }) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - await mockRecords('users', 3); + await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); await expectInitializerMenu({ @@ -24,7 +25,7 @@ test.describe('form item & create form', () => { test.describe('form item & edit form', () => { test('configure fields', async ({ page, mockPage, mockRecords }) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - await mockRecords('users', 3); + await mockUserRecordsWithoutDepartments(mockRecords, 3); await mockRecords('general', 1); await nocoPage.goto(); diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/belongsTo/schemaSettings.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/belongsTo/schemaSettings.test.ts index 4441b392ab..d4ad95edf7 100644 --- a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/belongsTo/schemaSettings.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/belongsTo/schemaSettings.test.ts @@ -2,6 +2,7 @@ import { Page, expect, expectSettingsMenu, + mockUserRecordsWithoutDepartments, oneFilterFormBlockWithAllAssociationFields, oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, test, @@ -11,7 +12,7 @@ import { createColumnItem, showSettingsMenu, testPattern } from '../../utils'; test.describe('form item & create form', () => { test('supported options', async ({ page, mockPage, mockRecords }) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - await mockRecords('users', 3); + await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); await expectSettingsMenu({ @@ -44,7 +45,7 @@ test.describe('form item & create form', () => { test('set default value', async ({ page, mockPage, mockRecord, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -67,7 +68,7 @@ test.describe('form item & create form', () => { page, gotoPage: async () => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - records = await mockRecords('users', 3); + records = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); }, openDialog: async () => { @@ -108,7 +109,7 @@ test.describe('form item & create form', () => { test('Set the data scope', async ({ page, mockPage, mockRecords }) => { const records = await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -154,7 +155,7 @@ test.describe('form item & create form', () => { test('field component', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -180,7 +181,7 @@ test.describe('form item & create form', () => { test('quick create', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -201,7 +202,7 @@ test.describe('form item & create form', () => { test('title field', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -222,7 +223,7 @@ test.describe('form item & create form', () => { test.describe('form item & edit form', () => { test('supported options', async ({ page, mockRecords, mockPage }) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - await mockRecords('users', 3); + await mockUserRecordsWithoutDepartments(mockRecords, 3); await mockRecords('general', 1); await nocoPage.goto(); @@ -262,7 +263,7 @@ test.describe('form item & edit form', () => { record = ( await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); @@ -308,7 +309,7 @@ test.describe('form item & edit form', () => { test('Set the data scope', async ({ page, mockPage, mockRecords }) => { const { recordsOfUser } = await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); @@ -355,7 +356,7 @@ test.describe('form item & edit form', () => { test('field component', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); @@ -382,7 +383,7 @@ test.describe('form item & edit form', () => { test('quick create', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); @@ -404,7 +405,7 @@ test.describe('form item & edit form', () => { test('title field', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/hasOne/schemaSettings.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/hasOne/schemaSettings.test.ts index 3a5ecb875d..ade1022ba1 100644 --- a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/hasOne/schemaSettings.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/hasOne/schemaSettings.test.ts @@ -2,6 +2,7 @@ import { Page, expect, expectSettingsMenu, + mockUserRecordsWithoutDepartments, oneFilterFormBlockWithAllAssociationFields, oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, test, @@ -11,7 +12,7 @@ import { createColumnItem, showSettingsMenu, testPattern } from '../../utils'; test.describe('form item & create form', () => { test('supported options', async ({ page, mockPage, mockRecords }) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - await mockRecords('users', 3); + await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); await expectSettingsMenu({ @@ -42,7 +43,7 @@ test.describe('form item & create form', () => { test('set default value', async ({ page, mockPage, mockRecord, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -66,7 +67,7 @@ test.describe('form item & create form', () => { gotoPage: async () => { records = await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -112,7 +113,7 @@ test.describe('form item & create form', () => { test('Set the data scope', async ({ page, mockPage, mockRecords }) => { const records = await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -158,7 +159,7 @@ test.describe('form item & create form', () => { test('field component', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -184,7 +185,7 @@ test.describe('form item & create form', () => { test('quick create', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -205,7 +206,7 @@ test.describe('form item & create form', () => { test('title field', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -226,7 +227,7 @@ test.describe('form item & create form', () => { test.describe('form item & edit form', () => { test('supported options', async ({ page, mockRecords, mockPage }) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - await mockRecords('users', 3); + await mockUserRecordsWithoutDepartments(mockRecords, 3); await mockRecords('general', 1); await nocoPage.goto(); @@ -264,7 +265,7 @@ test.describe('form item & edit form', () => { record = ( await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); @@ -310,7 +311,7 @@ test.describe('form item & edit form', () => { test('Set the data scope', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); @@ -356,7 +357,7 @@ test.describe('form item & edit form', () => { test('field component', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); @@ -383,7 +384,7 @@ test.describe('form item & edit form', () => { test('quick create', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); @@ -405,7 +406,7 @@ test.describe('form item & edit form', () => { test('title field', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToMany/schemaSettings.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToMany/schemaSettings.test.ts deleted file mode 100644 index c3380c0bac..0000000000 --- a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToMany/schemaSettings.test.ts +++ /dev/null @@ -1,803 +0,0 @@ -import { - Page, - expect, - expectSettingsMenu, - oneFilterFormBlockWithAllAssociationFields, - oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, - test, -} from '@nocobase/test/e2e'; -import { createColumnItem, showSettingsMenu, testDefaultValue, testPattern } from '../../utils'; - -test.describe('form item & create form', () => { - test('supported options', async ({ page, mockPage, mockRecords }) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - await mockRecords('users', 3); - await nocoPage.goto(); - - await expectSettingsMenu({ - page, - showMenu: async () => { - await page.getByRole('button', { name: 'Add new' }).click(); - await page.getByLabel(`block-item-CollectionField-general-form-general.manyToMany-manyToMany`).hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.manyToMany`) - .hover(); - }, - supportedOptions: [ - 'Edit field title', - 'Display title', - 'Edit description', - 'Required', - 'Set default value', - 'Set the data scope', - 'Set default sorting rules', - 'Field component', - 'Quick create', - 'Allow multiple', - 'Pattern', - 'Title field', - 'Delete', - ], - }); - }); - - test('set default value', async ({ page, mockPage, mockRecords }) => { - let recordsOfUser; - await testDefaultValue({ - page, - gotoPage: async () => { - recordsOfUser = await (async (mockPage, mockRecords) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); - await nocoPage.goto(); - - return recordsOfUser; - })(mockPage, mockRecords); - }, - openDialog: () => - (async (page: Page) => { - await page.getByRole('button', { name: 'Add new' }).click(); - })(page), - 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, '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: 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:${recordsOfUser.map((record) => record.id).join('')}`); - }, - }); - }); - - test('pattern', async ({ page, mockPage, mockRecords }) => { - let records; - await testPattern({ - page, - gotoPage: async () => { - records = await (async (mockPage, mockRecords) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); - await nocoPage.goto(); - - return recordsOfUser; - })(mockPage, mockRecords); - }, - openDialog: () => - (async (page: Page) => { - await page.getByRole('button', { name: 'Add new' }).click(); - })(page), - 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, 'manyToMany'), - expectEditable: async () => { - await page - .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') - .getByTestId('select-object-multiple') - .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( - page - .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') - .getByTestId('select-object-multiple'), - ).toHaveClass(/ant-select-disabled/); - // 在这里等待一下,防止因闪烁导致下面的断言失败 - await page.waitForTimeout(100); - }, - expectEasyReading: async () => { - await expect( - page.getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany'), - ).toHaveText(`manyToMany:${records.map((record) => record.id).join(',')}`); - }, - }); - }); - - test('Set the data scope', async ({ page, mockPage, mockRecords }) => { - const records = await (async (mockPage, mockRecords) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); - await nocoPage.goto(); - - return recordsOfUser; - })(mockPage, mockRecords); - await (async (page: Page) => { - await page.getByRole('button', { name: 'Add new' }).click(); - })(page); - await (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, 'manyToMany'); - 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.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); - await page.getByRole('spinbutton').click(); - await page.getByRole('spinbutton').fill(String(records[0].id)); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // 再次打开弹窗,设置的值应该还在 - await (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, '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(String(records[0].id)); - await page.getByRole('button', { name: 'Cancel', exact: true }).click(); - - // 数据应该被过滤了 - await page - .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') - .getByTestId('select-object-multiple') - .click(); - await expect(page.getByRole('option', { name: String(records[0].id), exact: true })).toBeVisible(); - await expect(page.getByRole('option')).toHaveCount(1); - }); - - test('set default sorting rules', async ({ page, mockPage, mockRecords }) => { - await (async (mockPage, mockRecords) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); - await nocoPage.goto(); - - return recordsOfUser; - })(mockPage, mockRecords); - await (async (page: Page) => { - await page.getByRole('button', { name: 'Add new' }).click(); - })(page); - await (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, 'manyToMany'); - await page.getByRole('menuitem', { name: 'Set default sorting rules' }).click(); - - // 配置 - await page.getByRole('button', { name: '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(); - - // 再次打开弹窗,设置的值应该还在 - await (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, 'manyToMany'); - await page.getByRole('menuitem', { name: 'Set default sorting rules' }).click(); - await expect(page.getByRole('dialog').getByTestId('select-single')).toHaveText('ID'); - }); - - test('field component', async ({ page, mockPage, mockRecords }) => { - await (async (mockPage, mockRecords) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); - await nocoPage.goto(); - - return recordsOfUser; - })(mockPage, mockRecords); - await (async (page: Page) => { - await page.getByRole('button', { name: 'Add new' }).click(); - })(page); - await (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, 'manyToMany'); - await page.getByRole('menuitem', { name: 'Field component' }).click(); - - // 断言支持的选项 - await expect(page.getByRole('option', { name: 'Select', exact: true })).toBeVisible(); - await expect(page.getByRole('option', { name: 'Record picker', exact: true })).toBeVisible(); - await expect(page.getByRole('option', { name: 'Sub-table', exact: true })).toBeVisible(); - await expect(page.getByRole('option', { name: 'Sub-form', exact: true })).toBeVisible(); - await expect(page.getByRole('option', { name: 'Sub-form(Popover)', exact: true })).toBeVisible(); - - // 选择 Record picker - await page.getByRole('option', { name: 'Record picker', exact: true }).click(); - await expect( - page - .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') - .getByTestId('select-data-picker'), - ).toBeVisible(); - - // 选择 Sub-table - await (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, 'manyToMany'); - await page.getByRole('menuitem', { name: 'Field component' }).click(); - await page.getByRole('option', { name: 'Sub-table', exact: true }).click(); - await expect( - page - .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') - .getByLabel('schema-initializer-AssociationField.SubTable-table:configureColumns-users'), - ).toBeVisible(); - - // 选择 Sub-form - await (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, 'manyToMany'); - await page.getByRole('menuitem', { name: 'Field component' }).click(); - await page.getByRole('option', { name: 'Sub-form', exact: true }).click(); - await expect( - page - .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') - .getByLabel('schema-initializer-Grid-form:configureFields-users'), - ).toBeVisible(); - - // 选择 Sub-form(Popover) - await page.getByLabel(`block-item-CollectionField-general-form-general.manyToMany-manyToMany`).hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.manyToMany`) - .hover(); - // 加上这个延迟会使测试更稳定 - await page.waitForTimeout(100); - await page.getByRole('menuitem', { name: 'Field component' }).click(); - await page.getByRole('option', { name: 'Sub-form(Popover)', exact: true }).click(); - await page - .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') - .getByRole('img', { name: 'edit' }) - .click(); - await expect(page.getByTestId('popover-CollectionField-general')).toBeVisible(); - }); - - test('quick create', async ({ page, mockPage, mockRecords }) => { - await (async (mockPage, mockRecords) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); - await nocoPage.goto(); - - return recordsOfUser; - })(mockPage, mockRecords); - await (async (page: Page) => { - await page.getByRole('button', { name: 'Add new' }).click(); - })(page); - await (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, 'manyToMany'); - - await expect(page.getByRole('menuitem', { name: 'Quick create' })).toBeVisible(); - }); - - test('allow multiple', async ({ page, mockPage, mockRecords }) => { - await (async (mockPage, mockRecords) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); - await nocoPage.goto(); - - return recordsOfUser; - })(mockPage, mockRecords); - await (async (page: Page) => { - await page.getByRole('button', { name: 'Add new' }).click(); - })(page); - await (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, 'manyToMany'); - await expect(page.getByRole('menuitem', { name: 'Allow multiple' })).toBeVisible(); - }); - - test('title field', async ({ page, mockPage, mockRecords }) => { - await (async (mockPage, mockRecords) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); - await nocoPage.goto(); - - return recordsOfUser; - })(mockPage, mockRecords); - await (async (page: Page) => { - await page.getByRole('button', { name: 'Add new' }).click(); - })(page); - await (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, 'manyToMany'); - await expect(page.getByRole('menuitem', { name: 'Title field' })).toBeVisible(); - }); -}); - -test.describe('form item & edit form', () => { - test('supported options', async ({ page, mockRecords, mockPage }) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - await mockRecords('users', 3); - await mockRecords('general', 1); - await nocoPage.goto(); - - await expectSettingsMenu({ - page, - showMenu: async () => { - await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); - await page.getByLabel(`block-item-CollectionField-general-form-general.manyToMany-manyToMany`).hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.manyToMany`) - .hover(); - }, - supportedOptions: [ - 'Edit field title', - 'Display title', - 'Edit description', - 'Required', - 'Set the data scope', - 'Set default sorting rules', - 'Field component', - 'Quick create', - 'Allow multiple', - 'Pattern', - 'Title field', - 'Delete', - ], - unsupportedOptions: ['Set default value'], - }); - }); - - test('pattern', async ({ page, mockPage, mockRecords }) => { - let record; - await testPattern({ - page, - gotoPage: async () => { - record = ( - await (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 }; - })(mockPage, mockRecords) - ).record; - }, - openDialog: () => - (async (page: Page) => { - await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); - })(page), - 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, 'manyToMany'), - expectEditable: async () => { - await expect( - page - .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') - .getByTestId('select-object-multiple'), - ).toHaveText(`${record.manyToMany.map((item) => item.id).join('')}`); - }, - expectReadonly: async () => { - await expect( - page - .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') - .getByTestId('select-object-multiple'), - ).toHaveClass(/ant-select-disabled/); - // 在这里等待一下,防止因闪烁导致下面的断言失败 - await page.waitForTimeout(100); - }, - expectEasyReading: async () => { - await expect( - page.getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany'), - ).toHaveText(`manyToMany:${record.manyToMany.map((item) => item.id).join(',')}`); - }, - }); - }); - - test('Set the data scope', async ({ page, mockPage, mockRecords }) => { - const { recordsOfUser } = await (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 }; - })(mockPage, mockRecords); - await (async (page: Page) => { - await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); - })(page); - await (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, 'manyToMany'); - 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.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); - await page.getByRole('spinbutton').click(); - await page.getByRole('spinbutton').fill(String(recordsOfUser[0].id)); - await page.getByRole('button', { name: 'OK', exact: true }).click(); - - // 再次打开弹窗,设置的值应该还在 - await (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, '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(String(recordsOfUser[0].id)); - await page.getByRole('button', { name: 'Cancel', exact: true }).click(); - - // 数据应该被过滤了 - await page - .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') - .getByTestId('select-object-multiple') - .click(); - await expect(page.getByRole('option', { name: String(recordsOfUser[0].id), exact: true })).toBeVisible(); - }); - - test('set default sorting rules', async ({ page, mockPage, mockRecords }) => { - await (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 }; - })(mockPage, mockRecords); - await (async (page: Page) => { - await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); - })(page); - await (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, 'manyToMany'); - await page.getByRole('menuitem', { name: 'Set default sorting rules' }).click(); - - // 配置 - await page.getByRole('button', { name: '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(); - - // 再次打开弹窗,设置的值应该还在 - await (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, 'manyToMany'); - await page.getByRole('menuitem', { name: 'Set default sorting rules' }).click(); - await expect(page.getByRole('dialog').getByTestId('select-single')).toHaveText('ID'); - }); - - test('field component', async ({ page, mockPage, mockRecords }) => { - await (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 }; - })(mockPage, mockRecords); - await (async (page: Page) => { - await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); - })(page); - await (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, 'manyToMany'); - await page.getByRole('menuitem', { name: 'Field component' }).click(); - - // 断言支持的选项 - await expect(page.getByRole('option', { name: 'Select', exact: true })).toBeVisible(); - await expect(page.getByRole('option', { name: 'Record picker', exact: true })).toBeVisible(); - await expect(page.getByRole('option', { name: 'Sub-table', exact: true })).toBeVisible(); - await expect(page.getByRole('option', { name: 'Sub-form', exact: true })).toBeVisible(); - await expect(page.getByRole('option', { name: 'Sub-form(Popover)', exact: true })).toBeVisible(); - }); - - test('quick create', async ({ page, mockPage, mockRecords }) => { - await (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 }; - })(mockPage, mockRecords); - await (async (page: Page) => { - await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); - })(page); - await (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, 'manyToMany'); - - await expect(page.getByRole('menuitem', { name: 'Quick create' })).toBeVisible(); - }); - - test('allow multiple', async ({ page, mockPage, mockRecords }) => { - await (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 }; - })(mockPage, mockRecords); - await (async (page: Page) => { - await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); - })(page); - await (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, 'manyToMany'); - await expect(page.getByRole('menuitem', { name: 'Allow multiple' })).toBeVisible(); - }); - - test('title field', async ({ page, mockPage, mockRecords }) => { - await (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 }; - })(mockPage, mockRecords); - await (async (page: Page) => { - await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); - })(page); - await (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, 'manyToMany'); - await expect(page.getByRole('menuitem', { name: 'Title field' })).toBeVisible(); - }); -}); - -test.describe('form item & view form', () => { - test('supported options', async ({ page, mockPage, mockRecords }) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - await mockRecords('general', 1); - await nocoPage.goto(); - - await expectSettingsMenu({ - page, - showMenu: async () => { - await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); - await page.getByLabel(`block-item-CollectionField-general-form-general.manyToMany-manyToMany`).hover(); - await page - .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.manyToMany`) - .hover(); - }, - supportedOptions: [ - 'Edit field title', - 'Display title', - 'Edit tooltip', - 'Field component', - 'Enable link', - 'Title field', - 'Delete', - ], - unsupportedOptions: ['Set default value'], - }); - }); - - test('field component', async ({ page, mockPage, mockRecords }) => { - await (async (mockPage, mockRecords) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const record = (await mockRecords('general', 1))[0]; - await nocoPage.goto(); - - return record; - })(mockPage, mockRecords); - await (async (page: Page) => { - await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); - })(page); - await (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, 'manyToMany'); - await page.getByRole('menuitem', { name: 'Field component' }).click(); - - // 断言支持的选项 - await expect(page.getByRole('option', { name: 'Title', exact: true })).toBeVisible(); - await expect(page.getByRole('option', { name: 'Tag', exact: true })).toBeVisible(); - await expect(page.getByRole('option', { name: 'Sub-details', exact: true })).toBeVisible(); - await expect(page.getByRole('option', { name: 'Sub-table', exact: true })).toBeVisible(); - - // 切换到 Sub-details,应该显示 Initializer 按钮 - await page.getByRole('option', { name: 'Sub-details', exact: true }).click(); - await page.mouse.move(300, 0); - await expect( - page - .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') - .getByLabel('schema-initializer-Grid-form:') - .first(), - ).toBeVisible(); - }); - - test('title field', async ({ page, mockPage, mockRecords }) => { - await (async (mockPage, mockRecords) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const record = (await mockRecords('general', 1))[0]; - await nocoPage.goto(); - - return record; - })(mockPage, mockRecords); - await (async (page: Page) => { - await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); - })(page); - await (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, 'manyToMany'); - await expect(page.getByRole('menuitem', { name: 'Title field' })).toBeVisible(); - }); - - test('enable link', async ({ page, mockPage, mockRecords }) => { - // test.fail(); - const record = await (async (mockPage, mockRecords) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const record = (await mockRecords('general', 1))[0]; - await nocoPage.goto(); - - return record; - })(mockPage, mockRecords); - await (async (page: Page) => { - await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); - })(page); - - // 初始状态是一个可点击的链接 - await expect( - page - .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') - .locator('a') - .filter({ hasText: record.manyToMany[0].id }), - ).toBeVisible(); - - await (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, 'manyToMany'); - - // 默认情况下是开启状态 - await expect(page.getByRole('menuitem', { name: 'Enable link' }).getByRole('switch')).toBeChecked(); - await page.getByRole('menuitem', { name: 'Enable link' }).click(); - await expect(page.getByRole('menuitem', { name: 'Enable link' }).getByRole('switch')).not.toBeChecked(); - - // 应变为非链接状态 - await expect( - page - .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') - .locator('a') - .filter({ hasText: record.manyToMany[0].id }), - ).not.toBeVisible(); - - // 再次开启链接状态 - await page.getByRole('menuitem', { name: 'Enable link' }).click(); - await expect(page.getByRole('menuitem', { name: 'Enable link' }).getByRole('switch')).toBeChecked(); - await expect( - page - .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') - .locator('a') - .filter({ hasText: record.manyToMany[0].id }), - ).toBeVisible(); - }); -}); - -test.describe('form item & filter form', () => { - test('supported options', async ({ page, mockPage }) => { - const nocoPage = await mockPage(oneFilterFormBlockWithAllAssociationFields).waitForInit(); - await nocoPage.goto(); - - await expectSettingsMenu({ - page, - showMenu: async () => { - await page.getByLabel('block-item-CollectionField-general-filter-form-general.manyToMany-manyToMany').hover(); - await page.getByRole('button', { name: 'designer-schema-settings-CollectionField' }).hover(); - }, - supportedOptions: [ - 'Edit field title', - 'Edit description', - 'Set the data scope', - 'Field component', - 'Title field', - 'Delete', - ], - }); - }); -}); - -test.describe('table column & table', () => { - test('supported options', async ({ page, mockPage, mockRecord }) => { - const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - await mockRecord('general'); - await nocoPage.goto(); - - await expectSettingsMenu({ - page, - showMenu: async () => { - await createColumnItem(page, 'manyToMany'); - await showSettingsMenu(page, 'manyToMany'); - }, - supportedOptions: [ - 'Custom column title', - 'Column width', - 'Enable link', - 'Title field', - 'Field component', - 'Delete', - ], - }); - }); -}); diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToMany/schemaSettings1.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToMany/schemaSettings1.test.ts new file mode 100644 index 0000000000..cb40210974 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToMany/schemaSettings1.test.ts @@ -0,0 +1,349 @@ +import { + Page, + expect, + expectSettingsMenu, + mockUserRecordsWithoutDepartments, + oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, + test, +} from '@nocobase/test/e2e'; +import { testDefaultValue, testPattern } from '../../utils'; + +test.describe('form item & create form', () => { + test('supported options', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + await mockUserRecordsWithoutDepartments(mockRecords, 3); + await nocoPage.goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByRole('button', { name: 'Add new' }).click(); + await page.getByLabel(`block-item-CollectionField-general-form-general.manyToMany-manyToMany`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.manyToMany`) + .hover(); + }, + supportedOptions: [ + 'Edit field title', + 'Display title', + 'Edit description', + 'Required', + 'Set default value', + 'Set the data scope', + 'Set default sorting rules', + 'Field component', + 'Quick create', + 'Allow multiple', + 'Pattern', + 'Title field', + 'Delete', + ], + }); + }); + + test('set default value', async ({ page, mockPage, mockRecords }) => { + let recordsOfUser; + await testDefaultValue({ + page, + gotoPage: async () => { + recordsOfUser = await (async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); + await nocoPage.goto(); + + return recordsOfUser; + })(mockPage, mockRecords); + }, + openDialog: () => + (async (page: Page) => { + await page.getByRole('button', { name: 'Add new' }).click(); + })(page), + 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, '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: 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:${recordsOfUser.map((record) => record.id).join('')}`); + }, + }); + }); + + test('pattern', async ({ page, mockPage, mockRecords }) => { + let records; + await testPattern({ + page, + gotoPage: async () => { + records = await (async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); + await nocoPage.goto(); + + return recordsOfUser; + })(mockPage, mockRecords); + }, + openDialog: () => + (async (page: Page) => { + await page.getByRole('button', { name: 'Add new' }).click(); + })(page), + 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, 'manyToMany'), + expectEditable: async () => { + await page + .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') + .getByTestId('select-object-multiple') + .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( + page + .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') + .getByTestId('select-object-multiple'), + ).toHaveClass(/ant-select-disabled/); + // 在这里等待一下,防止因闪烁导致下面的断言失败 + await page.waitForTimeout(100); + }, + expectEasyReading: async () => { + await expect( + page.getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany'), + ).toHaveText(`manyToMany:${records.map((record) => record.id).join(',')}`); + }, + }); + }); + + test('Set the data scope', async ({ page, mockPage, mockRecords }) => { + const records = await (async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); + await nocoPage.goto(); + + return recordsOfUser; + })(mockPage, mockRecords); + await (async (page: Page) => { + await page.getByRole('button', { name: 'Add new' }).click(); + })(page); + await (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, 'manyToMany'); + 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.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); + await page.getByRole('spinbutton').click(); + await page.getByRole('spinbutton').fill(String(records[0].id)); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 再次打开弹窗,设置的值应该还在 + await (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, '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(String(records[0].id)); + await page.getByRole('button', { name: 'Cancel', exact: true }).click(); + + // 数据应该被过滤了 + await page + .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') + .getByTestId('select-object-multiple') + .click(); + await expect(page.getByRole('option', { name: String(records[0].id), exact: true })).toBeVisible(); + await expect(page.getByRole('option')).toHaveCount(1); + }); + + test('set default sorting rules', async ({ page, mockPage, mockRecords }) => { + await (async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); + await nocoPage.goto(); + + return recordsOfUser; + })(mockPage, mockRecords); + await (async (page: Page) => { + await page.getByRole('button', { name: 'Add new' }).click(); + })(page); + await (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, 'manyToMany'); + await page.getByRole('menuitem', { name: 'Set default sorting rules' }).click(); + + // 配置 + await page.getByRole('button', { name: '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(); + + // 再次打开弹窗,设置的值应该还在 + await (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, 'manyToMany'); + await page.getByRole('menuitem', { name: 'Set default sorting rules' }).click(); + await expect(page.getByRole('dialog').getByTestId('select-single')).toHaveText('ID'); + }); + + test('field component', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + await mockUserRecordsWithoutDepartments(mockRecords, 3); + await nocoPage.goto(); + await page.getByRole('button', { name: 'Add new' }).click(); + await page.getByLabel(`block-item-CollectionField-general-form-general.manyToMany-manyToMany`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.manyToMany`) + .hover(); + await page.getByRole('menuitem', { name: 'Field component' }).click(); + + // 断言支持的选项 + await expect(page.getByRole('option', { name: 'Select', exact: true })).toBeVisible(); + await expect(page.getByRole('option', { name: 'Record picker', exact: true })).toBeVisible(); + await expect(page.getByRole('option', { name: 'Sub-table', exact: true })).toBeVisible(); + await expect(page.getByRole('option', { name: 'Sub-form', exact: true })).toBeVisible(); + await expect(page.getByRole('option', { name: 'Sub-form(Popover)', exact: true })).toBeVisible(); + + // 选择 Record picker + await page.getByRole('option', { name: 'Record picker', exact: true }).click(); + await page.mouse.move(300, 0); + await expect( + page + .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') + .getByTestId('select-data-picker'), + ).toBeVisible(); + + // 选择 Sub-table + await page.getByLabel(`block-item-CollectionField-general-form-general.manyToMany-manyToMany`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.manyToMany`) + .hover(); + await page.getByRole('menuitem', { name: 'Field component' }).click(); + await page.getByRole('option', { name: 'Sub-table', exact: true }).click(); + await page.mouse.move(300, 0); + await expect( + page + .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') + .getByLabel('schema-initializer-AssociationField.SubTable-table:configureColumns-users'), + ).toBeVisible(); + + // 选择 Sub-form + await page.getByLabel(`block-item-CollectionField-general-form-general.manyToMany-manyToMany`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.manyToMany`) + .hover(); + await page.getByRole('menuitem', { name: 'Field component' }).click(); + await page.getByRole('option', { name: 'Sub-form', exact: true }).click(); + await page.mouse.move(300, 0); + await expect( + page + .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') + .getByLabel('schema-initializer-Grid-form:configureFields-users'), + ).toBeVisible(); + + // 选择 Sub-form(Popover) + await page.getByLabel(`block-item-CollectionField-general-form-general.manyToMany-manyToMany`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.manyToMany`) + .hover(); + // 加上这个延迟会使测试更稳定 + await page.waitForTimeout(100); + await page.getByRole('menuitem', { name: 'Field component' }).click(); + await page.getByRole('option', { name: 'Sub-form(Popover)', exact: true }).click(); + await page + .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') + .getByRole('img', { name: 'edit' }) + .click(); + await page.mouse.move(300, 0); + await expect(page.getByTestId('popover-CollectionField-general')).toBeVisible(); + }); + + test('quick create', async ({ page, mockPage, mockRecords }) => { + await (async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); + await nocoPage.goto(); + + return recordsOfUser; + })(mockPage, mockRecords); + await (async (page: Page) => { + await page.getByRole('button', { name: 'Add new' }).click(); + })(page); + await (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, 'manyToMany'); + + await expect(page.getByRole('menuitem', { name: 'Quick create' })).toBeVisible(); + }); + + test('allow multiple', async ({ page, mockPage, mockRecords }) => { + await (async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); + await nocoPage.goto(); + + return recordsOfUser; + })(mockPage, mockRecords); + await (async (page: Page) => { + await page.getByRole('button', { name: 'Add new' }).click(); + })(page); + await (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, 'manyToMany'); + await expect(page.getByRole('menuitem', { name: 'Allow multiple' })).toBeVisible(); + }); + + test('title field', async ({ page, mockPage, mockRecords }) => { + await (async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); + await nocoPage.goto(); + + return recordsOfUser; + })(mockPage, mockRecords); + await (async (page: Page) => { + await page.getByRole('button', { name: 'Add new' }).click(); + })(page); + await (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, 'manyToMany'); + await expect(page.getByRole('menuitem', { name: 'Title field' })).toBeVisible(); + }); +}); diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToMany/schemaSettings2.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToMany/schemaSettings2.test.ts new file mode 100644 index 0000000000..d104dc2bff --- /dev/null +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToMany/schemaSettings2.test.ts @@ -0,0 +1,263 @@ +import { + Page, + expect, + expectSettingsMenu, + mockUserRecordsWithoutDepartments, + oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, + test, +} from '@nocobase/test/e2e'; +import { testPattern } from '../../utils'; + +test.describe('form item & edit form', () => { + test('supported options', async ({ page, mockRecords, mockPage }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + await mockUserRecordsWithoutDepartments(mockRecords, 3); + await mockRecords('general', 1); + await nocoPage.goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); + await page.getByLabel(`block-item-CollectionField-general-form-general.manyToMany-manyToMany`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.manyToMany`) + .hover(); + }, + supportedOptions: [ + 'Edit field title', + 'Display title', + 'Edit description', + 'Required', + 'Set the data scope', + 'Set default sorting rules', + 'Field component', + 'Quick create', + 'Allow multiple', + 'Pattern', + 'Title field', + 'Delete', + ], + unsupportedOptions: ['Set default value'], + }); + }); + + test('pattern', async ({ page, mockPage, mockRecords }) => { + let record; + await testPattern({ + page, + gotoPage: async () => { + record = ( + await (async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); + const record = (await mockRecords('general', 1))[0]; + await nocoPage.goto(); + + return { record, recordsOfUser }; + })(mockPage, mockRecords) + ).record; + }, + openDialog: () => + (async (page: Page) => { + await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); + })(page), + 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, 'manyToMany'), + expectEditable: async () => { + await expect( + page + .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') + .getByTestId('select-object-multiple'), + ).toHaveText(`${record.manyToMany.map((item) => item.id).join('')}`); + }, + expectReadonly: async () => { + await expect( + page + .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') + .getByTestId('select-object-multiple'), + ).toHaveClass(/ant-select-disabled/); + // 在这里等待一下,防止因闪烁导致下面的断言失败 + await page.waitForTimeout(100); + }, + expectEasyReading: async () => { + await expect( + page.getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany'), + ).toHaveText(`manyToMany:${record.manyToMany.map((item) => item.id).join(',')}`); + }, + }); + }); + + test('Set the data scope', async ({ page, mockPage, mockRecords }) => { + const { recordsOfUser } = await (async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); + const record = (await mockRecords('general', 1))[0]; + await nocoPage.goto(); + + return { record, recordsOfUser }; + })(mockPage, mockRecords); + await (async (page: Page) => { + await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); + })(page); + await (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, 'manyToMany'); + 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.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click(); + await page.getByRole('spinbutton').click(); + await page.getByRole('spinbutton').fill(String(recordsOfUser[0].id)); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 再次打开弹窗,设置的值应该还在 + await (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, '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(String(recordsOfUser[0].id)); + await page.getByRole('button', { name: 'Cancel', exact: true }).click(); + + // 数据应该被过滤了 + await page + .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') + .getByTestId('select-object-multiple') + .click(); + await expect(page.getByRole('option', { name: String(recordsOfUser[0].id), exact: true })).toBeVisible(); + }); + + test('set default sorting rules', async ({ page, mockPage, mockRecords }) => { + await (async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); + const record = (await mockRecords('general', 1))[0]; + await nocoPage.goto(); + + return { record, recordsOfUser }; + })(mockPage, mockRecords); + await (async (page: Page) => { + await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); + })(page); + await (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, 'manyToMany'); + await page.getByRole('menuitem', { name: 'Set default sorting rules' }).click(); + + // 配置 + await page.getByRole('button', { name: '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(); + + // 再次打开弹窗,设置的值应该还在 + await (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, 'manyToMany'); + await page.getByRole('menuitem', { name: 'Set default sorting rules' }).click(); + await expect(page.getByRole('dialog').getByTestId('select-single')).toHaveText('ID'); + }); + + test('field component', async ({ page, mockPage, mockRecords }) => { + await (async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); + const record = (await mockRecords('general', 1))[0]; + await nocoPage.goto(); + + return { record, recordsOfUser }; + })(mockPage, mockRecords); + await (async (page: Page) => { + await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); + })(page); + await (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, 'manyToMany'); + await page.getByRole('menuitem', { name: 'Field component' }).click(); + + // 断言支持的选项 + await expect(page.getByRole('option', { name: 'Select', exact: true })).toBeVisible(); + await expect(page.getByRole('option', { name: 'Record picker', exact: true })).toBeVisible(); + await expect(page.getByRole('option', { name: 'Sub-table', exact: true })).toBeVisible(); + await expect(page.getByRole('option', { name: 'Sub-form', exact: true })).toBeVisible(); + await expect(page.getByRole('option', { name: 'Sub-form(Popover)', exact: true })).toBeVisible(); + }); + + test('quick create', async ({ page, mockPage, mockRecords }) => { + await (async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); + const record = (await mockRecords('general', 1))[0]; + await nocoPage.goto(); + + return { record, recordsOfUser }; + })(mockPage, mockRecords); + await (async (page: Page) => { + await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); + })(page); + await (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, 'manyToMany'); + + await expect(page.getByRole('menuitem', { name: 'Quick create' })).toBeVisible(); + }); + + test('allow multiple', async ({ page, mockPage, mockRecords }) => { + await (async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); + const record = (await mockRecords('general', 1))[0]; + await nocoPage.goto(); + + return { record, recordsOfUser }; + })(mockPage, mockRecords); + await (async (page: Page) => { + await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); + })(page); + await (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, 'manyToMany'); + await expect(page.getByRole('menuitem', { name: 'Allow multiple' })).toBeVisible(); + }); + + test('title field', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + await mockUserRecordsWithoutDepartments(mockRecords, 3); + await mockRecords('general', 1); + await nocoPage.goto(); + await page.getByLabel('action-Action.Link-Edit record-update-general-table-0').click(); + await page.getByLabel(`block-item-CollectionField-general-form-general.manyToMany-manyToMany`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.manyToMany`) + .hover(); + await expect(page.getByRole('menuitem', { name: 'Title field' })).toBeVisible(); + }); +}); diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToMany/schemaSettings3.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToMany/schemaSettings3.test.ts new file mode 100644 index 0000000000..1b600c2891 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToMany/schemaSettings3.test.ts @@ -0,0 +1,144 @@ +import { + Page, + expect, + expectSettingsMenu, + oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, + test, +} from '@nocobase/test/e2e'; + +test.describe('form item & view form', () => { + test('supported options', async ({ page, mockPage, mockRecords }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + await mockRecords('general', 1); + await nocoPage.goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); + await page.getByLabel(`block-item-CollectionField-general-form-general.manyToMany-manyToMany`).hover(); + await page + .getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.manyToMany`) + .hover(); + }, + supportedOptions: [ + 'Edit field title', + 'Display title', + 'Edit tooltip', + 'Field component', + 'Enable link', + 'Title field', + 'Delete', + ], + unsupportedOptions: ['Set default value'], + }); + }); + + test('field component', async ({ page, mockPage, mockRecords }) => { + await (async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const record = (await mockRecords('general', 1))[0]; + await nocoPage.goto(); + + return record; + })(mockPage, mockRecords); + await (async (page: Page) => { + await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); + })(page); + await (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, 'manyToMany'); + await page.getByRole('menuitem', { name: 'Field component' }).click(); + + // 断言支持的选项 + await expect(page.getByRole('option', { name: 'Title', exact: true })).toBeVisible(); + await expect(page.getByRole('option', { name: 'Tag', exact: true })).toBeVisible(); + await expect(page.getByRole('option', { name: 'Sub-details', exact: true })).toBeVisible(); + await expect(page.getByRole('option', { name: 'Sub-table', exact: true })).toBeVisible(); + + // 切换到 Sub-details,应该显示 Initializer 按钮 + await page.getByRole('option', { name: 'Sub-details', exact: true }).click(); + await page.mouse.move(300, 0); + await expect( + page + .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') + .getByLabel('schema-initializer-Grid-form:') + .first(), + ).toBeVisible(); + }); + + test('title field', async ({ page, mockPage, mockRecords }) => { + await (async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const record = (await mockRecords('general', 1))[0]; + await nocoPage.goto(); + + return record; + })(mockPage, mockRecords); + await (async (page: Page) => { + await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); + })(page); + await (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, 'manyToMany'); + await expect(page.getByRole('menuitem', { name: 'Title field' })).toBeVisible(); + }); + + test('enable link', async ({ page, mockPage, mockRecords }) => { + // test.fail(); + const record = await (async (mockPage, mockRecords) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + const record = (await mockRecords('general', 1))[0]; + await nocoPage.goto(); + + return record; + })(mockPage, mockRecords); + await (async (page: Page) => { + await page.getByLabel('action-Action.Link-View record-view-general-table-0').click(); + })(page); + + // 初始状态是一个可点击的链接 + await expect( + page + .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') + .locator('a') + .filter({ hasText: record.manyToMany[0].id }), + ).toBeVisible(); + + await (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, 'manyToMany'); + + // 默认情况下是开启状态 + await expect(page.getByRole('menuitem', { name: 'Enable link' }).getByRole('switch')).toBeChecked(); + await page.getByRole('menuitem', { name: 'Enable link' }).click(); + await expect(page.getByRole('menuitem', { name: 'Enable link' }).getByRole('switch')).not.toBeChecked(); + + // 应变为非链接状态 + await expect( + page + .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') + .locator('a') + .filter({ hasText: record.manyToMany[0].id }), + ).not.toBeVisible(); + + // 再次开启链接状态 + await page.getByRole('menuitem', { name: 'Enable link' }).click(); + await expect(page.getByRole('menuitem', { name: 'Enable link' }).getByRole('switch')).toBeChecked(); + await expect( + page + .getByLabel('block-item-CollectionField-general-form-general.manyToMany-manyToMany') + .locator('a') + .filter({ hasText: record.manyToMany[0].id }), + ).toBeVisible(); + }); +}); diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToMany/schemaSettings4.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToMany/schemaSettings4.test.ts new file mode 100644 index 0000000000..eabe0a8fac --- /dev/null +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToMany/schemaSettings4.test.ts @@ -0,0 +1,24 @@ +import { expectSettingsMenu, oneFilterFormBlockWithAllAssociationFields, test } from '@nocobase/test/e2e'; + +test.describe('form item & filter form', () => { + test('supported options', async ({ page, mockPage }) => { + const nocoPage = await mockPage(oneFilterFormBlockWithAllAssociationFields).waitForInit(); + await nocoPage.goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await page.getByLabel('block-item-CollectionField-general-filter-form-general.manyToMany-manyToMany').hover(); + await page.getByRole('button', { name: 'designer-schema-settings-CollectionField' }).hover(); + }, + supportedOptions: [ + 'Edit field title', + 'Edit description', + 'Set the data scope', + 'Field component', + 'Title field', + 'Delete', + ], + }); + }); +}); diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToMany/schemaSettings5.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToMany/schemaSettings5.test.ts new file mode 100644 index 0000000000..0bd137f5be --- /dev/null +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToMany/schemaSettings5.test.ts @@ -0,0 +1,30 @@ +import { + expectSettingsMenu, + oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, + test, +} from '@nocobase/test/e2e'; +import { createColumnItem, showSettingsMenu } from '../../utils'; + +test.describe('table column & table', () => { + test('supported options', async ({ page, mockPage, mockRecord }) => { + const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); + await mockRecord('general'); + await nocoPage.goto(); + + await expectSettingsMenu({ + page, + showMenu: async () => { + await createColumnItem(page, 'manyToMany'); + await showSettingsMenu(page, 'manyToMany'); + }, + supportedOptions: [ + 'Custom column title', + 'Column width', + 'Enable link', + 'Title field', + 'Field component', + 'Delete', + ], + }); + }); +}); diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToOne/schemaSettings.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToOne/schemaSettings.test.ts index ef428a0801..e699f01cb3 100644 --- a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToOne/schemaSettings.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/manyToOne/schemaSettings.test.ts @@ -2,6 +2,7 @@ import { Page, expect, expectSettingsMenu, + mockUserRecordsWithoutDepartments, oneFilterFormBlockWithAllAssociationFields, oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, test, @@ -12,7 +13,7 @@ import { T3377 } from './templatesOfBug'; test.describe('form item & create form', () => { test('supported options', async ({ page, mockPage, mockRecords }) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - await mockRecords('users', 3); + await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); await expectSettingsMenu({ @@ -48,7 +49,7 @@ test.describe('form item & create form', () => { gotoPage: async () => { records = await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -101,7 +102,7 @@ test.describe('form item & create form', () => { gotoPage: async () => { records = await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -145,7 +146,7 @@ test.describe('form item & create form', () => { test('Set the data scope', async ({ page, mockPage, mockRecords }) => { const records = await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -191,7 +192,7 @@ test.describe('form item & create form', () => { test('field component', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -217,7 +218,7 @@ test.describe('form item & create form', () => { test('quick create', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -238,7 +239,7 @@ test.describe('form item & create form', () => { test('title field', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -259,7 +260,7 @@ test.describe('form item & create form', () => { test.describe('form item & edit form', () => { test('supported options', async ({ page, mockRecords, mockPage }) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - await mockRecords('users', 3); + await mockUserRecordsWithoutDepartments(mockRecords, 3); await mockRecords('general', 1); await nocoPage.goto(); @@ -297,7 +298,7 @@ test.describe('form item & edit form', () => { record = ( await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); @@ -343,7 +344,7 @@ test.describe('form item & edit form', () => { test('Set the data scope', async ({ page, mockPage, mockRecords }) => { const { recordsOfUser } = await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); @@ -390,7 +391,7 @@ test.describe('form item & edit form', () => { test('field component', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); @@ -417,7 +418,7 @@ test.describe('form item & edit form', () => { test('quick create', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); @@ -439,7 +440,7 @@ test.describe('form item & edit form', () => { test('title field', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/oneToMany/schemaSettings.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/oneToMany/schemaSettings.test.ts index 72a07a5ac6..a9ba45c58f 100644 --- a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/oneToMany/schemaSettings.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/oneToMany/schemaSettings.test.ts @@ -2,6 +2,7 @@ import { Page, expect, expectSettingsMenu, + mockUserRecordsWithoutDepartments, oneFilterFormBlockWithAllAssociationFields, oneTableBlockWithAddNewAndViewAndEditAndAssociationFields, test, @@ -11,7 +12,7 @@ import { createColumnItem, showSettingsMenu, testPattern } from '../../utils'; test.describe('form item & create form', () => { test('supported options', async ({ page, mockPage, mockRecords }) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - await mockRecords('users', 3); + await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); await expectSettingsMenu({ @@ -43,7 +44,7 @@ test.describe('form item & create form', () => { test('set default value', async ({ page, mockPage, mockRecord, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -66,7 +67,7 @@ test.describe('form item & create form', () => { gotoPage: async () => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -111,7 +112,7 @@ test.describe('form item & create form', () => { test('Set the data scope', async ({ page, mockPage, mockRecords }) => { const records = await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -157,7 +158,7 @@ test.describe('form item & create form', () => { test('field component', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -184,7 +185,7 @@ test.describe('form item & create form', () => { test('quick create', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -205,7 +206,7 @@ test.describe('form item & create form', () => { test('allow multiple', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -225,7 +226,7 @@ test.describe('form item & create form', () => { test('title field', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); await nocoPage.goto(); return recordsOfUser; @@ -246,7 +247,7 @@ test.describe('form item & create form', () => { test.describe('form item & edit form', () => { test('supported options', async ({ page, mockRecords, mockPage }) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - await mockRecords('users', 3); + await mockUserRecordsWithoutDepartments(mockRecords, 3); await mockRecords('general', 1); await nocoPage.goto(); @@ -285,7 +286,7 @@ test.describe('form item & edit form', () => { record = ( await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); @@ -331,7 +332,7 @@ test.describe('form item & edit form', () => { test('Set the data scope', async ({ page, mockPage, mockRecords }) => { const { record } = await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); @@ -378,7 +379,7 @@ test.describe('form item & edit form', () => { test('field component', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); @@ -406,7 +407,7 @@ test.describe('form item & edit form', () => { test('quick create', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); @@ -428,7 +429,7 @@ test.describe('form item & edit form', () => { test('allow multiple', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); @@ -449,7 +450,7 @@ test.describe('form item & edit form', () => { test('title field', async ({ page, mockPage, mockRecords }) => { await (async (mockPage, mockRecords) => { const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndAssociationFields).waitForInit(); - const recordsOfUser = await mockRecords('users', 3); + const recordsOfUser = await mockUserRecordsWithoutDepartments(mockRecords, 3); const record = (await mockRecords('general', 1))[0]; await nocoPage.goto(); diff --git a/packages/plugins/@nocobase/plugin-kanban/src/client/__e2e__/schemaInitailizer.test.ts b/packages/plugins/@nocobase/plugin-kanban/src/client/__e2e__/schemaInitailizer.test.ts index aa79b8fd94..41d026aecd 100644 --- a/packages/plugins/@nocobase/plugin-kanban/src/client/__e2e__/schemaInitailizer.test.ts +++ b/packages/plugins/@nocobase/plugin-kanban/src/client/__e2e__/schemaInitailizer.test.ts @@ -87,21 +87,24 @@ test.describe('configure actions', () => { test('add new action in kanban', async ({ page, mockPage }) => { const nocoPage = await mockPage(oneEmptyKanbanBlock).waitForInit(); await nocoPage.goto(); - await page.getByLabel('schema-initializer-ActionBar-kanban:configureActions-general').click(); + await page.getByLabel('schema-initializer-ActionBar-kanban:configureActions-general').hover(); await page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch').click(); //按钮正常显示 await expect(page.getByLabel('action-Action-Add ')).toBeVisible(); //添加数据 await page.getByLabel('action-Action-Add new-create-general-kanban').click(); - await page.getByLabel('schema-initializer-Grid-popup:addNew:addBlock-general').click(); + await page.getByLabel('schema-initializer-Grid-popup:addNew:addBlock-general').hover(); await page.getByRole('menuitem', { name: 'form Form' }).click(); await page.mouse.move(300, 0); - await page.getByLabel('schema-initializer-Grid-form:configureFields-general').click(); + await page.getByLabel('schema-initializer-Grid-form:configureFields-general').hover(); await page.getByRole('menuitem', { name: 'Single Select' }).click(); + await page.mouse.move(300, 0); await page.getByLabel('block-item-CollectionField-').locator('.ant-select').click(); await page.getByRole('option', { name: 'option1' }).click(); + await page.mouse.move(300, 0); await page.getByLabel('schema-initializer-ActionBar-createForm:configureActions-general').hover(); await page.getByRole('menuitem', { name: 'Submit' }).click(); + await page.mouse.move(300, 0); await page.getByLabel('action-Action-Submit-submit-general-form').click(); await page.getByLabel('block-item-Kanban.Card-general-kanban').hover(); await page.getByLabel('designer-schema-initializer-Kanban.Card-Kanban.Card.Designer-general').hover(); 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 597cda6f1d..9d30d10db7 100644 --- a/packages/plugins/@nocobase/plugin-mock-collections/src/server/index.ts +++ b/packages/plugins/@nocobase/plugin-mock-collections/src/server/index.ts @@ -2,13 +2,13 @@ import Database, { Collection, Repository } from '@nocobase/database'; import { CollectionRepository } from '@nocobase/plugin-collection-manager'; import { InstallOptions, Plugin } from '@nocobase/server'; import { merge, uid } from '@nocobase/utils'; +import { promises as fs } from 'fs'; import _ from 'lodash'; +import path from 'path'; +import { Client } from 'pg'; import collectionTemplates from './collection-templates'; import * as fieldInterfaces from './field-interfaces'; import { mockAttachment } from './field-interfaces'; -import { Client } from 'pg'; -import path from 'path'; -import { promises as fs } from 'fs'; export class PluginMockCollectionsServer extends Plugin { async load() { @@ -190,7 +190,7 @@ export class PluginMockCollectionsServer extends Plugin { this.app.resourcer.registerActions({ mock: async (ctx, next) => { const { resourceName } = ctx.action; - const { values, count = 10 } = ctx.action.params; + const { values, count = 10, maxDepth = 4 } = ctx.action.params; const mockCollectionData = async (collectionName, count = 1, depth = 0, maxDepth = 4) => { const collection = ctx.db.getCollection(collectionName) as Collection; const items = await Promise.all( @@ -224,7 +224,7 @@ export class PluginMockCollectionsServer extends Plugin { if (Array.isArray(values)) { size = values.length; } - const data = await mockCollectionData(resourceName, size); + const data = await mockCollectionData(resourceName, size, 0, Number(maxDepth)); // ctx.body = { // values: (Array.isArray(data) ? data : [data]).map((item, index) => { // if (Array.isArray(values)) { diff --git a/packages/plugins/@nocobase/plugin-multi-app-share-collection/src/server/plugin.ts b/packages/plugins/@nocobase/plugin-multi-app-share-collection/src/server/plugin.ts index af5121e17a..c4ef3935fc 100644 --- a/packages/plugins/@nocobase/plugin-multi-app-share-collection/src/server/plugin.ts +++ b/packages/plugins/@nocobase/plugin-multi-app-share-collection/src/server/plugin.ts @@ -2,7 +2,6 @@ import Database from '@nocobase/database'; import PluginMultiAppManager from '@nocobase/plugin-multi-app-manager'; import { Application, AppSupervisor, Plugin } from '@nocobase/server'; import lodash from 'lodash'; -import { resolve } from 'path'; const subAppFilteredPlugins = ['multi-app-share-collection', 'multi-app-manager']; const unSyncPlugins = ['localization-management']; @@ -235,13 +234,6 @@ export class MultiAppShareCollectionPlugin extends Plugin { return; } - await this.importCollections(resolve(__dirname, 'collections')); - - // this.db.addMigrations({ - // namespace: 'multi-app-share-collection', - // directory: resolve(__dirname, './migrations'), - // }); - this.app.resourcer.registerActionHandlers({ 'applications:shareCollections': async (ctx, next) => { const { filterByTk, values } = ctx.action.params; @@ -262,9 +254,13 @@ export class MultiAppShareCollectionPlugin extends Plugin { schema: appName, }; - const plugins = [...mainApp.pm.getAliases()].filter( - (name) => name !== 'multi-app-manager' && name !== 'multi-app-share-collection', - ); + const plugins = [...mainApp.pm.getPlugins().values()] + .filter( + (plugin) => + plugin?.options?.packageName !== '@nocobase/plugin-multi-app-manager' && + plugin?.options?.packageName !== '@nocobase/plugin-multi-app-share-collection', + ) + .map((plugin) => plugin.name); return { database: lodash.merge(databaseOptions, {