test: Workflow manual node e2e (#3451)

* test: workflow manual node e2e

* fix: datablocks

* fix: timeout-minutes

* fix: datablocks&createRecordForm

* fix: createRecordForm
This commit is contained in:
hongboji 2024-01-29 15:59:07 +08:00 committed by GitHub
parent ad065431fb
commit 1cad202745
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 7725 additions and 5 deletions

View File

@ -74,4 +74,4 @@ jobs:
DB_USER: nocobase
DB_PASSWORD: password
DB_DATABASE: nocobase
timeout-minutes: 80
timeout-minutes: 100

View File

@ -0,0 +1,233 @@
import { faker } from '@faker-js/faker';
import {
CollectionTriggerNode,
apiCreateWorkflow,
apiDeleteWorkflow,
apiGetWorkflow,
apiUpdateWorkflowTrigger,
appendJsonCollectionName,
generalWithNoRelationalFields,
ManualNode,
} from '@nocobase/plugin-workflow-test/e2e';
import { expect, test } from '@nocobase/test/e2e';
import { dayjs } from '@nocobase/utils';
test('filter task node', async ({ page, mockPage, mockCollections, mockRecords }) => {
//数据表后缀标识
const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
const manualNodeAppendText = 'b' + dayjs().format('HHmmss').toString();
// 创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
// 创建Manual节点数据表
const manualNodeCollectionDisplayName = `自动>组织[普通表]${manualNodeAppendText}`;
const manualNodeCollectionName = `tt_amt_org${manualNodeAppendText}`;
const manualNodeFieldName = 'orgname';
const manualNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), manualNodeAppendText)
.collections,
);
//添加工作流
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'collection',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
//配置工作流触发器
const triggerNodeData = {
config: { appends: [], collection: triggerNodeCollectionName, changed: [], condition: { $and: [] }, mode: 1 },
};
const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
//配置Manual节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'manual', exact: true }).click();
const manualNodeName = 'Manual' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Manual-Manual', { exact: true }).getByRole('textbox').fill(manualNodeName);
const manualNode = new ManualNode(page, manualNodeName);
const manualNodeId = await manualNode.node.locator('.workflow-node-id').innerText();
await manualNode.nodeConfigure.click();
await manualNode.assigneesDropDown.click();
await page.getByRole('option', { name: 'Super Admin' }).click();
await manualNode.configureUserInterfaceButton.click();
await manualNode.addBlockButton.hover();
await manualNode.createRecordFormMenu.hover();
await page.getByRole('menuitem', { name: manualNodeCollectionDisplayName }).click();
await page.mouse.move(300, 0, { steps: 100 });
await page
.locator(`button[aria-label^="schema-initializer-Grid-FormItemInitializers-${manualNodeCollectionName}"]`)
.hover();
await page.getByLabel(`designer-schema-settings-CardItem-CreateFormDesigner-${manualNodeCollectionName}`).hover();
await page.getByRole('menuitem', { name: 'Edit block title' }).click();
const blockTitle = 'Create record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Edit block title').getByRole('textbox').fill(blockTitle);
await page.getByRole('button', { name: 'OK', exact: true }).click();
await page
.locator(`button[aria-label^="schema-initializer-Grid-FormItemInitializers-${manualNodeCollectionName}"]`)
.hover();
await page.getByRole('menuitem', { name: manualNodeFieldDisplayName }).getByRole('switch').click();
await page.mouse.move(300, 0, { steps: 100 });
await page.mouse.click(300, 0);
await manualNode.submitButton.click();
await page.waitForLoadState('networkidle');
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,待办弹窗表单中显示数据
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const newPage = mockPage();
await newPage.goto();
await page.waitForLoadState('networkidle');
await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover();
await page.getByRole('menuitem', { name: 'check-square Workflow todos' }).click();
await page.mouse.move(300, 0, { steps: 100 });
await page.waitForTimeout(300);
await page.getByLabel('action-Filter.Action-Filter-filter-users_jobs-workflow-todo').click();
await page.getByText('Add condition', { exact: true }).click();
await page.getByTestId('select-filter-field').click();
await page.getByRole('menuitemcheckbox', { name: 'Task right' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Title' }).click();
await page.getByRole('textbox').fill(manualNodeName);
await page.getByRole('button', { name: 'Submit' }).click();
// 3、预期结果列表中出现筛选的工作流
await expect(page.getByText(manualNodeName)).toBeAttached();
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('filter workflow name', async ({ page, mockPage, mockCollections, mockRecords }) => {
//数据表后缀标识
const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
const manualNodeAppendText = 'b' + dayjs().format('HHmmss').toString();
// 创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
// 创建Manual节点数据表
const manualNodeCollectionDisplayName = `自动>组织[普通表]${manualNodeAppendText}`;
const manualNodeCollectionName = `tt_amt_org${manualNodeAppendText}`;
const manualNodeFieldName = 'orgname';
const manualNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), manualNodeAppendText)
.collections,
);
//添加工作流
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'collection',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
//配置工作流触发器
const triggerNodeData = {
config: { appends: [], collection: triggerNodeCollectionName, changed: [], condition: { $and: [] }, mode: 1 },
};
const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
//配置Manual节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.addNodeButton.click();
await page.getByRole('button', { name: 'manual', exact: true }).click();
const manualNodeName = 'Manual' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Manual-Manual', { exact: true }).getByRole('textbox').fill(manualNodeName);
const manualNode = new ManualNode(page, manualNodeName);
const manualNodeId = await manualNode.node.locator('.workflow-node-id').innerText();
await manualNode.nodeConfigure.click();
await manualNode.assigneesDropDown.click();
await page.getByRole('option', { name: 'Super Admin' }).click();
await manualNode.configureUserInterfaceButton.click();
await manualNode.addBlockButton.hover();
await manualNode.createRecordFormMenu.hover();
await page.getByRole('menuitem', { name: manualNodeCollectionDisplayName }).click();
await page.mouse.move(300, 0, { steps: 100 });
await page
.locator(`button[aria-label^="schema-initializer-Grid-FormItemInitializers-${manualNodeCollectionName}"]`)
.hover();
await page.getByLabel(`designer-schema-settings-CardItem-CreateFormDesigner-${manualNodeCollectionName}`).hover();
await page.getByRole('menuitem', { name: 'Edit block title' }).click();
const blockTitle = 'Create record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Edit block title').getByRole('textbox').fill(blockTitle);
await page.getByRole('button', { name: 'OK', exact: true }).click();
await page
.locator(`button[aria-label^="schema-initializer-Grid-FormItemInitializers-${manualNodeCollectionName}"]`)
.hover();
await page.getByRole('menuitem', { name: manualNodeFieldDisplayName }).getByRole('switch').click();
await page.mouse.move(300, 0, { steps: 100 });
await page.mouse.click(300, 0);
await manualNode.submitButton.click();
await page.waitForLoadState('networkidle');
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,待办弹窗表单中显示数据
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const newPage = mockPage();
await newPage.goto();
await page.waitForLoadState('networkidle');
await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover();
await page.getByRole('menuitem', { name: 'check-square Workflow todos' }).click();
await page.mouse.move(300, 0, { steps: 100 });
await page.waitForTimeout(300);
await page.getByLabel('action-Filter.Action-Filter-filter-users_jobs-workflow-todo').click();
await page.getByText('Add condition', { exact: true }).click();
await page.getByTestId('select-filter-field').click();
await page.getByRole('menuitemcheckbox', { name: 'Workflow right' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Name' }).click();
await page.getByRole('textbox').fill(workFlowName);
await page.getByRole('button', { name: 'Submit' }).click();
// 3、预期结果列表中出现筛选的工作流
await expect(page.getByText(manualNodeName)).toBeAttached();
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});

View File

@ -435,11 +435,11 @@ export class ManualNode {
this.assigneesDropDown = page.getByTestId('select-single');
this.configureUserInterfaceButton = page.getByRole('button', { name: 'Configure user interface' });
this.addBlockButton = page.getByLabel('schema-initializer-Grid-AddBlockButton-workflows');
this.triggerDataMenu = page.getByLabel('Data blocks-triggerData');
this.nodeDataMenu = page.getByLabel('nodes', { exact: true });
this.triggerDataMenu = page.getByRole('menuitem', { name: 'Trigger data' });
this.nodeDataMenu = page.getByRole('menuitem', { name: 'Node result right' });
this.customFormMenu = page.getByRole('menuitem', { name: 'Custom form' });
this.createRecordFormMenu = page.getByRole('menuitem', { name: 'Create record form' });
this.updateRecordFormMenu = page.getByRole('menuitem', { name: 'Update record form' });
this.createRecordFormMenu = page.getByRole('menuitem', { name: 'Create record form right' });
this.updateRecordFormMenu = page.getByRole('menuitem', { name: 'Update record form right' });
this.submitButton = page.getByLabel('action-Action-Submit-workflows');
this.cancelButton = page.getByLabel('action-Action-Cancel-workflows');
this.addNodeButton = page.getByLabel(`add-button-manual-${nodeName}`, { exact: true });

View File

@ -605,6 +605,44 @@ export const apiGetList = async (collectionName: string) => {
return await result.json();
};
// 查询业务表list
export const apiFilterList = async (collectionName: string, filter: string) => {
const api = await request.newContext({
storageState: process.env.PLAYWRIGHT_AUTH_FILE,
});
const state = await api.storageState();
const headers = getHeaders(state);
const result = await api.get(`/api/${collectionName}:list?${filter}`, {
headers,
});
if (!result.ok()) {
throw new Error(await result.text());
}
/*
{
"data": [
{
"id": 1,
"createdAt": "2023-12-12T02:43:53.793Z",
"updatedAt": "2023-12-12T05:41:33.300Z",
"key": "fzk3j2oj4el",
"title": "a11",
"enabled": true,
"description": null
}
],
"meta": {
"count": 1,
"page": 1,
"pageSize": 20,
"totalPage": 1
}
}
*/
return await result.json();
};
// 添加业务表单条数据触发工作流表单事件,triggerWorkflows=key1!field,key2,key3!field.subfield
export const apiCreateRecordTriggerFormEvent = async (collectionName: string, triggerWorkflows: string, data: any) => {
const api = await request.newContext({
@ -744,4 +782,5 @@ export default module.exports = {
apiGetList,
apiCreateRecordTriggerFormEvent,
apiSubmitRecordTriggerFormEvent,
apiFilterList,
};