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, {