fix(defaultValue): fix unparsed default value in edit form's subtable (#3289)

* chore: yarn.lock

* fix: fix unparsed default value in edit form's subtable

* test: fix test

* fix: fix T-2805

* chore: increase timeout

* chore: increase expect timeout

* test: optimize parallelism mode

* test: reduce expect timeout

* test: mack test more stable

* chore: test

* chore: test

* test: fix parallelism mode

* chore: restart
This commit is contained in:
Zeke Zhang 2024-01-01 18:44:42 +08:00 committed by GitHub
parent cc251b3222
commit e99c2f2011
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 589 additions and 79 deletions

1
.gitignore vendored
View File

@ -33,6 +33,7 @@ storage/tmp
storage/app.watch.ts
storage/logs-e2e
storage/uploads-e2e
storage/.pm2-*
tsconfig.paths.json
/playwright
/storage/playwright

View File

@ -65,5 +65,5 @@ body a:active {
/* fix https://nocobase.height.app/T-2838 */
/* antd 组件的层级有问题,有的弹窗是 1000 有的是 1200会导致弹窗被覆盖的问题。弹窗这里应该使用同一个值是比较合理的 */
.ant-modal-wrap, .ant-modal-mask {
z-index: 1000 !important;
z-index: 1150 !important;
}

View File

@ -1,10 +1,11 @@
const execa = require('execa');
const { resolve, dirname } = require('path');
const { resolve } = require('path');
const pAll = require('p-all');
const dotenv = require('dotenv');
const fs = require('fs');
const { Client } = require('pg');
const glob = require('glob');
const _ = require('lodash');
let ENV_FILE = resolve(process.cwd(), '.env.e2e');
@ -18,7 +19,10 @@ const config = {
...process.env,
};
async function runApp(index = 1, dir) {
async function runApp(dir, index = 0) {
// 一个进程需要占用两个端口? (一个是应用端口,一个是 socket 端口)
index = index * 2;
const database = `nocobase${index}`;
const client = new Client({
host: config['DB_HOST'],
@ -54,15 +58,15 @@ exports.pTest = async (options) => {
const files = glob.sync('packages/**/__e2e__/**/*.test.ts', {
root: process.cwd(),
});
const fileSet = new Set();
for (const file of files) {
fileSet.add(dirname(file));
}
const commands = [...fileSet.values()].map((v, i) => {
return () => runApp(i + 1, v);
const commands = splitArrayIntoParts(files, options.concurrency || 3).map((v, i) => {
return () => runApp(v.join(' '), i);
});
await pAll(commands, { concurrency: 3, stopOnError: false, ...options });
};
function splitArrayIntoParts(array, parts) {
let chunkSize = Math.ceil(array.length / parts);
return _.chunk(array, chunkSize);
}

View File

@ -18,5 +18,31 @@ test.describe('variables with default value', () => {
.getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText')
.getByRole('textbox'),
).toHaveValue('1');
// https://nocobase.height.app/T-2805 ----------------------------------------------------------------------
await page
.getByLabel('block-item-CollectionField-general-form-general.m2oField0-m2oField0')
.getByTestId('select-object-single')
.hover();
await page.getByLabel('icon-close-select').click();
// 等待值消失
await page.waitForTimeout(500);
await expect(
page
.getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText')
.getByRole('textbox'),
).toHaveValue('');
await page
.getByLabel('block-item-CollectionField-general-form-general.m2oField0-m2oField0')
.getByTestId('select-object-single')
.click();
await page.getByRole('option', { name: '1', exact: true }).click();
await expect(
page
.getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText')
.getByRole('textbox'),
).toHaveValue('1');
});
});

View File

@ -584,6 +584,7 @@ test.describe('creation form block schema settings', () => {
.getByRole('button', { name: 'designer-schema-settings-TableV2.Column-TableV2.Column.Designer-users' })
.hover();
await page.getByRole('menuitem', { name: 'Set default value', exact: true }).click();
await page.mouse.move(300, 0);
await page.getByLabel('Set default value').getByRole('textbox').click();
await page.getByLabel('Set default value').getByRole('textbox').fill('test default value');
await page.getByRole('button', { name: 'OK', exact: true }).click();

View File

@ -117,7 +117,7 @@ test.describe('table block schema settings', () => {
.dragTo(page.getByLabel('table-index-1').getByRole('img', { name: 'menu' }));
// 等待表格刷新
await page.waitForTimeout(2000);
await page.waitForTimeout(3000);
email1 = await page.getByText(records[0].email).boundingBox();
email2 = await page.getByText(records[1].email).boundingBox();

View File

@ -5,7 +5,7 @@ export const useStyles = genStyleHook('nb-action-drawer', (token) => {
return {
[componentCls]: {
zIndex: '1000 !important', // fix https://nocobase.height.app/T-2797
zIndex: '1150 !important', // fix https://nocobase.height.app/T-2797
overflow: 'hidden',
'&.reset': {
'&.nb-action-popup': {

View File

@ -25,7 +25,7 @@ const useParseDefaultValue = () => {
const variables = useVariables();
const localVariables = useLocalVariables();
const record = useRecord();
const { isInAssignFieldValues, isInSetDefaultValueDialog, isInFormDataTemplate } = useFlag() || {};
const { isInAssignFieldValues, isInSetDefaultValueDialog, isInFormDataTemplate, isInSubTable } = useFlag() || {};
const { getField } = useCollection();
const { isSpecialCase, setDefaultValue } = useSpecialCase();
const index = useRecordIndex();
@ -52,17 +52,21 @@ const useParseDefaultValue = () => {
isInFormDataTemplate ||
isSubMode(fieldSchema) ||
// 编辑状态下不需要设置默认值,否则会覆盖用户输入的值,只有新建状态下才需要设置默认值
(formBlockType === 'update' && isFromDatabase(record) && !isInAssignFieldValues)
(formBlockType === 'update' && !isInSubTable && isFromDatabase(record) && !isInAssignFieldValues)
) {
return;
}
const _run = async () => {
const _run = async ({ forceUpdate = false } = {}) => {
// 如果默认值是一个变量,则需要解析之后再显示出来
if (isVariable(fieldSchema.default) && variables && field) {
if (
variables &&
field &&
((isVariable(fieldSchema.default) && field.value == null) || field.value === fieldSchema.default || forceUpdate)
) {
// 一个变量字符串如果显示出来会比较奇怪
if (isVariable(field.value)) {
field.setValue(null);
await field.reset({ forceClear: true });
}
field.loading = true;
@ -79,17 +83,16 @@ const useParseDefaultValue = () => {
});
if (value == null || value === '') {
field.setValue(null);
// fix https://nocobase.height.app/T-2805
field.setInitialValue(null);
await field.reset({ forceClear: true });
} else if (isSpecialCase()) {
// 只需要设置一次就可以了
if (index === 0) {
setDefaultValue(value);
}
} else {
// eslint-disable-next-line promise/catch-or-return
Promise.resolve().then(() => {
field.setInitialValue(value);
});
field.setInitialValue(value);
}
field.loading = false;
@ -128,13 +131,7 @@ const useParseDefaultValue = () => {
return value;
},
_run,
{
equals: (oldValue, newValue) => {
field.setValue(newValue);
return oldValue === newValue;
},
},
() => run({ forceUpdate: true }),
);
return dispose;

View File

@ -2,7 +2,11 @@ import { devices, defineConfig as playwrightDefineConfig, type PlaywrightTestCon
export const defineConfig = (config?: PlaywrightTestConfig) => {
return playwrightDefineConfig({
timeout: process.env.CI ? 2 * 60 * 1000 : 30 * 1000,
timeout: process.env.CI ? 5 * 60 * 1000 : 30 * 1000,
expect: {
timeout: process.env.CI ? 1 * 60 * 1000 : 5000,
},
// Look for test files in the "tests" directory, relative to this configuration file.
testDir: 'packages',

View File

@ -5834,6 +5834,432 @@ export const oneTableBlockWithAddNewAndViewAndEditAndBasicFields: PageConfig = {
},
};
/**
* 1. Table
* 2. Add new Form sub-table
* 3. View Details sub-table
* 4. Edit Form sub-table
* 5. sub-table basic
*/
export const oneTableBlockWithAddNewAndViewAndEditAndBasicFieldsAndSubTable: PageConfig = {
collections: [
...generalWithBasic,
{
name: 'subTable',
fields: [
{
name: 'manyToMany',
interface: 'm2m',
target: 'general',
},
{
name: 'oneToMany',
interface: 'o2m',
target: 'general',
},
],
},
],
pageSchema: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Page',
properties: {
'7m533o9wcl2': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid',
'x-initializer': 'BlockInitializers',
properties: {
mbtse8e9kap: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
properties: {
ir5rfzx0z5o: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
properties: {
yr9pww7k8mq: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-decorator': 'TableBlockProvider',
'x-acl-action': 'subTable:list',
'x-decorator-props': {
collection: 'subTable',
resource: 'subTable',
action: 'list',
params: {
pageSize: 20,
},
rowKey: 'id',
showIndex: true,
dragSort: false,
disableTemplate: false,
},
'x-designer': 'TableBlockDesigner',
'x-component': 'CardItem',
'x-filter-targets': [],
properties: {
actions: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-initializer': 'TableActionInitializers',
'x-component': 'ActionBar',
'x-component-props': {
style: {
marginBottom: 'var(--nb-spacing)',
},
},
'x-uid': '0bvmtmgkrx0',
'x-async': false,
'x-index': 1,
},
'39vo8hzhsor': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'array',
'x-initializer': 'TableColumnInitializers',
'x-component': 'TableV2',
'x-component-props': {
rowKey: 'id',
rowSelection: {
type: 'checkbox',
},
useProps: '{{ useTableBlockProps }}',
},
properties: {
actions: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
title: '{{ t("Actions") }}',
'x-action-column': 'actions',
'x-decorator': 'TableV2.Column.ActionBar',
'x-component': 'TableV2.Column',
'x-designer': 'TableV2.ActionColumnDesigner',
'x-initializer': 'TableActionColumnInitializers',
properties: {
actions: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-decorator': 'DndContext',
'x-component': 'Space',
'x-component-props': {
split: '|',
},
properties: {
dghwbcfocgv: {
'x-uid': 'rhc8oxdqglj',
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
title: 'Edit record',
'x-action': 'update',
'x-designer': 'Action.Designer',
'x-component': 'Action.Link',
'x-component-props': {
openMode: 'drawer',
danger: false,
},
'x-decorator': 'ACLActionProvider',
'x-designer-props': {
linkageAction: true,
},
properties: {
drawer: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
title: '{{ t("Edit record") }}',
'x-component': 'Action.Container',
'x-component-props': {
className: 'nb-action-popup',
},
properties: {
tabs: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Tabs',
'x-component-props': {},
'x-initializer': 'TabPaneInitializers',
properties: {
tab1: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
title: '{{t("Edit")}}',
'x-component': 'Tabs.TabPane',
'x-designer': 'Tabs.Designer',
'x-component-props': {},
properties: {
grid: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid',
'x-initializer': 'RecordBlockInitializers',
properties: {
trny88kf0bk: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
properties: {
'78r8m6ecsh4': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
properties: {
lj0yhupvh3o: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-acl-action-props': {
skipScopeCheck: false,
},
'x-acl-action': 'subTable:update',
'x-decorator': 'FormBlockProvider',
'x-decorator-props': {
useSourceId: '{{ useSourceIdFromParentRecord }}',
useParams: '{{ useParamsFromRecord }}',
action: 'get',
resource: 'subTable',
collection: 'subTable',
},
'x-designer': 'FormV2.Designer',
'x-component': 'CardItem',
'x-component-props': {},
properties: {
'0ykr2ijd1qa': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'FormV2',
'x-component-props': {
useProps: '{{ useFormBlockProps }}',
},
properties: {
grid: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid',
'x-initializer': 'FormItemInitializers',
properties: {
'7mwkv9h74ki': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
properties: {
'0f4fktqpnee': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
properties: {
manyToMany: {
'x-uid': 'lclf348ur56',
_isJSONSchemaObject: true,
version: '2.0',
type: 'string',
'x-designer': 'FormItem.Designer',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-collection-field':
'subTable.manyToMany',
'x-component-props': {
mode: 'SubTable',
},
properties: {
ry6csw9ij4n: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component':
'AssociationField.SubTable',
'x-initializer':
'TableColumnInitializers',
'x-initializer-props': {
action: false,
},
'x-index': 1,
properties: {
rmz41gp1stq: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-decorator':
'TableV2.Column.Decorator',
'x-designer':
'TableV2.Column.Designer',
'x-component':
'TableV2.Column',
properties: {
singleLineText: {
'x-uid': 'tlprzxnyyqb',
_isJSONSchemaObject:
true,
version: '2.0',
'x-collection-field':
'general.singleLineText',
'x-component':
'CollectionField',
'x-component-props': {
ellipsis: true,
},
'x-decorator':
'FormItem',
'x-decorator-props': {
labelStyle: {
display: 'none',
},
},
default: null,
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'zmslu38eujy',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'vl5lkem00dr',
'x-async': false,
},
},
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'gzxknc793se',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'lr63kqkjvgo',
'x-async': false,
'x-index': 1,
},
},
'x-uid': '8iw3zvh7vxd',
'x-async': false,
'x-index': 1,
},
actions: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-initializer': 'UpdateFormActionInitializers',
'x-component': 'ActionBar',
'x-component-props': {
layout: 'one-column',
style: {
marginTop: 24,
},
},
'x-uid': '95vrlwf03yk',
'x-async': false,
'x-index': 2,
},
},
'x-uid': '17ju1kwigyw',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'by4uluzexjq',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'nzw5judm7ah',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'keraakujlcb',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'dtc6ufrnn2w',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'kgrdpc9e834',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'h60qmmbj1ez',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'f930il0aqu3',
'x-async': false,
'x-index': 1,
},
},
'x-async': false,
'x-index': 2,
},
},
'x-uid': 'gb81ougszo2',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'aa33l45v6qb',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'lm8sj8ojma9',
'x-async': false,
'x-index': 2,
},
},
'x-uid': 'z5n8ihuvx64',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'snt3mrh4ug9',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'kzi69u1gb24',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'hbmkoataojj',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'sfa1nw7kqmi',
'x-async': true,
'x-index': 1,
},
};
/**
* 1. Table
* 2. Add new Form

View File

@ -1,8 +1,8 @@
import { expect, test } from '@nocobase/test/e2e';
test('menu permission ', async ({ page, mockPage, mockRole, updateRole }) => {
const page2 = await mockPage({ name: 'page2' });
const page1 = await mockPage({ name: 'page1' });
const page2 = mockPage({ name: 'page2' });
const page1 = mockPage({ name: 'page1' });
await page1.goto();
const uid1 = await page1.getUid();
const uid2 = await page2.getUid();
@ -18,33 +18,29 @@ test('menu permission ', async ({ page, mockPage, mockRole, updateRole }) => {
window.localStorage.setItem('NOCOBASE_ROLE', roleData.name);
}, roleData);
await page.reload();
await expect(await page.getByLabel('page1')).toBeVisible();
await expect(await page.getByLabel('page2')).not.toBeVisible();
await expect(page.getByLabel('page1')).toBeVisible();
await expect(page.getByLabel('page2')).not.toBeVisible();
await page.getByTestId('plugin-settings-button').hover();
await page.getByLabel('acl').click();
await page.getByLabel(`action-Action.Link-Configure-roles-${roleData.name}`).click();
await page.getByRole('tab').getByText('Menu permissions').click();
await page.waitForSelector('.ant-table');
const page1Menu = await page.getByRole('row', { name: 'page1' }).locator('.ant-checkbox-input');
const page2Menu = await page.getByRole('row', { name: 'page2' }).locator('.ant-checkbox-input');
await expect(await page1Menu.isChecked()).toBe(true);
await expect(await page2Menu.isChecked()).toBe(false);
await expect(page.getByRole('row', { name: 'page1' }).locator('.ant-checkbox-input')).toBeChecked({ checked: true });
await expect(page.getByRole('row', { name: 'page2' }).locator('.ant-checkbox-input')).toBeChecked({ checked: false });
//修改菜单权限page1无权限,page2有权限
await updateRole({ name: roleData.name, menuUiSchemas: [uid2] });
await page.reload();
await expect(await page.getByLabel('page2')).toBeVisible();
await expect(await page.getByLabel('page1')).not.toBeVisible();
await expect(page.getByLabel('page2')).toBeVisible();
await expect(page.getByLabel('page1')).not.toBeVisible();
await page.getByTestId('plugin-settings-button').hover();
await page.getByLabel('acl').click();
await page.getByLabel(`action-Action.Link-Configure-roles-${roleData.name}`).click();
await page.getByRole('tab').getByText('Menu permissions').click();
await page.waitForSelector('.ant-table');
const page1Menu1 = await page.getByRole('row', { name: 'page1' }).locator('.ant-checkbox-input');
const page2Menu1 = await page.getByRole('row', { name: 'page2' }).locator('.ant-checkbox-input');
await expect(await page1Menu1.isChecked()).toBe(false);
await expect(await page2Menu1.isChecked()).toBe(true);
await expect(page.getByRole('row', { name: 'page1' }).locator('.ant-checkbox-input')).toBeChecked({ checked: false });
await expect(page.getByRole('row', { name: 'page2' }).locator('.ant-checkbox-input')).toBeChecked({ checked: true });
//通过路由访问无权限的菜单,跳到有权限的第一个菜单
await page.goto(`/admin/${uid1}`);
await page.waitForSelector('.nb-page-wrapper');
await expect(await page.url()).toContain(uid2);
expect(page.url()).toContain(uid2);
});

View File

@ -8,7 +8,7 @@ test.describe('TableActionInitializers & GanttActionInitializers & MapActionInit
await page.getByRole('menuitem', { name: 'Customize right' }).click();
await page.getByRole('menuitem', { name: 'Bulk edit' }).click();
await page.mouse.move(300, 0);
await expect(await page.getByLabel('Bulk edit')).toBeVisible();
await expect(page.getByLabel('Bulk edit')).toBeVisible();
});
test('bulk edit in GanttActionInitializers', async ({ page, mockPage, mockRecords }) => {
const nocoPage = await mockPage(oneEmptyGantt).waitForInit();
@ -17,6 +17,6 @@ test.describe('TableActionInitializers & GanttActionInitializers & MapActionInit
await page.getByLabel('schema-initializer-ActionBar-GanttActionInitializers-general').hover();
await page.getByRole('menuitem', { name: 'Customize right' }).click();
await page.getByRole('menuitem', { name: 'Bulk edit' }).click();
await expect(await page.getByLabel('Bulk edit')).toBeVisible();
await expect(page.getByLabel('Bulk edit')).toBeVisible();
});
});

View File

@ -14,9 +14,9 @@ test.describe('TableActionColumnInitializers & DetailsActionInitializers & ReadP
await page.getByRole('button', { name: 'Actions' }).hover();
await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-general').hover();
await page.getByRole('menuitem', { name: 'Duplicate' }).click();
await expect(await page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0')).toBeVisible();
await expect(page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0')).toBeVisible();
});
test('duplication action in DetailsActionInitializers', async ({ page, mockPage, mockCollections, mockRecords }) => {
test('duplication action in DetailsActionInitializers', async ({ page, mockPage }) => {
await mockPage(oneEmptyDetailsBlock).goto();
await page.getByLabel('schema-initializer-ActionBar-DetailsActionInitializers-general').click();
await page.getByRole('menuitem', { name: 'Duplicate' }).click();

View File

@ -2,11 +2,11 @@ import { expect, test } from '@nocobase/test/e2e';
import { oneEmptyTableBlockWithDuplicateActions } from './utils';
test.describe('direct duplicate & copy into the form and continue to fill in', () => {
test('direct duplicate', async ({ page, mockPage, mockCollections, mockRecords }) => {
test('direct duplicate', async ({ page, mockPage, mockRecords }) => {
const nocoPage = await mockPage(oneEmptyTableBlockWithDuplicateActions).waitForInit();
const data = await mockRecords('general', 3);
await nocoPage.goto();
await expect(await page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0')).toBeVisible();
await expect(page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0')).toBeVisible();
await page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0').hover();
await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }).click();
await page.getByRole('menuitem', { name: 'Duplicate mode' }).click();
@ -26,7 +26,7 @@ test.describe('direct duplicate & copy into the form and continue to fill in', (
const nocoPage = await mockPage(oneEmptyTableBlockWithDuplicateActions).waitForInit();
const data = await mockRecord('general');
await nocoPage.goto();
await expect(await page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0')).toBeVisible();
await expect(page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0')).toBeVisible();
await page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0').hover();
await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }).hover();
await page.getByRole('menuitem', { name: 'Duplicate mode' }).click();
@ -71,11 +71,8 @@ test.describe('direct duplicate & copy into the form and continue to fill in', (
await page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0').click();
await expect(
await page
.getByLabel('block-item-CollectionField-general-form-general.singleLineText')
.getByRole('textbox')
.inputValue(),
).toBe(data['singleLineText']);
page.getByLabel('block-item-CollectionField-general-form-general.singleLineText').getByRole('textbox'),
).toHaveValue(data['singleLineText']);
const [request] = await Promise.all([
page.waitForRequest((request) => request.url().includes('api/general:create')),
page.getByLabel('action-Action-Submit-submit-general-form').click(),

View File

@ -3,6 +3,7 @@ import {
expect,
expectSettingsMenu,
oneTableBlockWithAddNewAndViewAndEditAndBasicFields,
oneTableBlockWithAddNewAndViewAndEditAndBasicFieldsAndSubTable,
test,
} from '@nocobase/test/e2e';
import { createColumnItem, showSettingsMenu, testDefaultValue, testPattern, testSetValidationRules } from '../../utils';
@ -37,23 +38,20 @@ test.describe('form item & create form', () => {
test('set default value', async ({ page, mockPage }) => {
await testDefaultValue({
page,
gotoPage: () =>
(async (mockPage) => {
const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit();
await nocoPage.goto();
})(mockPage),
openDialog: () =>
(async (page: Page) => {
await page.getByRole('button', { name: 'Add new' }).click();
})(page),
gotoPage: async () => {
const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFields).waitForInit();
await nocoPage.goto();
},
openDialog: async () => {
await page.getByRole('button', { name: 'Add new' }).click();
},
closeDialog: () => page.getByLabel('drawer-Action.Container-general-Add record-mask').click(),
showMenu: () =>
(async (page: Page, fieldName: string) => {
await page.getByLabel(`block-item-CollectionField-general-form-general.${fieldName}-${fieldName}`).hover();
await page
.getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.${fieldName}`)
.hover();
})(page, 'singleLineText'),
showMenu: async () => {
await page.getByLabel(`block-item-CollectionField-general-form-general.singleLineText-singleLineText`).hover();
await page
.getByLabel(`designer-schema-settings-CollectionField-FormItem.Designer-general-general.singleLineText`)
.hover();
},
supportVariables: ['Constant', 'Current user', 'Date variables', 'Current form'],
constantValue: 'test single line text',
variableValue: ['Current user', 'Email'], // 值为 admin@nocobase.com
@ -374,3 +372,68 @@ test.describe('table column & table', () => {
await expect(page.getByRole('columnheader', { name: 'singleLineText' })).toBeHidden();
});
});
test.describe('table column & sub-table in edit form', () => {
test('supported options', async ({ page, mockPage, mockRecord }) => {
const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFieldsAndSubTable).waitForInit();
await mockRecord('subTable');
await nocoPage.goto();
await expectSettingsMenu({
page,
showMenu: async () => {
await page.getByLabel('action-Action.Link-Edit record-update-subTable-table-0').click();
await page.getByRole('button', { name: 'singleLineText', exact: true }).hover();
await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.Column.Designer-general').hover();
},
supportedOptions: ['Custom column title', 'Column width', 'Required', 'Pattern', 'Set default value', 'Delete'],
});
});
test('set default value', async ({ page, mockPage, mockRecord }) => {
let record;
await testDefaultValue({
page,
gotoPage: async () => {
const nocoPage = await mockPage(oneTableBlockWithAddNewAndViewAndEditAndBasicFieldsAndSubTable).waitForInit();
record = await mockRecord('subTable');
await nocoPage.goto();
},
openDialog: async () => {
await page.getByLabel('action-Action.Link-Edit record-update-subTable-table-0').click();
},
closeDialog: async () => {
await page.getByLabel('drawer-Action.Container-subTable-Edit record-mask').click();
},
showMenu: async () => {
await page.getByRole('button', { name: 'singleLineText', exact: true }).hover();
await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.Column.Designer-general').hover();
},
supportVariables: [
'Constant',
'Current user',
'Current role',
'Current form',
'Current object',
'Current record',
],
variableValue: ['Current user', 'Nickname'],
expectVariableValue: async () => {
await page.getByRole('button', { name: 'plus' }).click();
await expect(
page
.getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText')
.nth(0)
.getByRole('textbox'),
).toHaveValue(record.manyToMany[0].singleLineText);
await expect(
page
.getByLabel('block-item-CollectionField-general-form-general.singleLineText-singleLineText')
.nth(record.manyToMany.length) // 最后一行
.getByRole('textbox'),
).toHaveValue('Super Admin');
},
});
});
});

View File

@ -36,7 +36,7 @@ test.describe('configure setting', () => {
await page.getByRole('menuitem', { name: 'Set the data scope' }).click();
await page.getByText('Add condition', { exact: true }).click();
await page.getByTestId('select-filter-field').click();
await page.getByTitle('ID').click();
await page.getByRole('menuitemcheckbox', { name: 'ID', exact: true }).click();
await page.getByRole('spinbutton').fill('1');
const [request] = await Promise.all([
page.waitForRequest((request) => request.url().includes('api/general:list')),

View File

@ -4215,11 +4215,6 @@
dependencies:
eslint-scope "5.1.1"
"@nocobase/plugin-workflow-test@>=0.17.0-alpha.3":
version "0.17.0-alpha.7"
resolved "https://registry.yarnpkg.com/@nocobase/plugin-workflow-test/-/plugin-workflow-test-0.17.0-alpha.7.tgz#219a3a1e91e51bec08b1adbb1c4c5c9c7184ecce"
integrity sha512-krZlo1xDM66spbQG6jAYSraxazuxCuA2rD9TxptFQXjkAMTGkuDilJ+edMj6p866N3nyzvFh8lZ2/XY1HUC7Xw==
"@node-saml/node-saml@^4.0.2":
version "4.0.5"
resolved "https://registry.npmmirror.com/@node-saml/node-saml/-/node-saml-4.0.5.tgz#039e387095b54639b06df62b1b4a6d8941c6d907"