test: workflow e2e (#3261)

* test: workflow e2e

* test: workflow e2e

* fix: merge main, fix incompatibility

* test: remove unneeded test cases

* fix: process.env.PLAYWRIGHT_AUTH_FILE

* fix: workflow e2e

* test: increase e2e timeout-minutes to 180

* fix: error

* fix: workflow aggregate e2e test

* fix: cancel useTransaction

* fix: updateRecord

* fix: queryRecord

* fix: queryRecord

* fix: queryRecord

* fix: formEvent

* fix: format files

* fix: test

* fix: error

* fix: error

* fix: split files

* fix: ci

* fix: error

* fix: error

* fix: client end

* fix: test

* fix: test

* feat: concurrency=10

* fix: concurrency=3

* test: increase timeout

* test: p-test

---------

Co-authored-by: chenos <chenlinxh@gmail.com>
Co-authored-by: Zeke Zhang <958414905@qq.com>
This commit is contained in:
hongboji 2023-12-29 09:13:00 +08:00 committed by GitHub
parent 0c60780b50
commit e7c2c9ff83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 21228 additions and 1982 deletions

View File

@ -27,4 +27,6 @@ packages/core/cli/templates/plugin/src/client/*.tpl
packages/app/client/src/.plugins
docker
storage
benchmark
benchmark
packages/core/cli/src
t.js

View File

@ -63,11 +63,9 @@ jobs:
__E2E__: true
- run: npx playwright install chromium --with-deps
- name: Test with postgres
run: yarn e2e test -x --skip-reporter
run: yarn e2e p-test --stop-on-error
env:
__E2E__: true
APP_BASE_URL: http://127.0.0.1:13000
APP_PORT: 13000
APP_ENV: production
LOGGER_LEVEL: error
DB_DIALECT: postgres
@ -76,4 +74,4 @@ jobs:
DB_USER: nocobase
DB_PASSWORD: password
DB_DATABASE: nocobase
timeout-minutes: 90
timeout-minutes: 180

View File

@ -19,6 +19,7 @@
"fs-extra": "^11.1.1",
"pm2": "^5.2.0",
"portfinder": "^1.0.28",
"p-all": "3.0.0",
"serve": "^13.0.2",
"tsx": "^4.6.2"
},

View File

@ -2,6 +2,7 @@ const { Command } = require('commander');
const { run, isPortReachable } = require('../util');
const { execSync } = require('node:child_process');
const axios = require('axios');
const { pTest } = require('./p-test');
/**
* 检查服务是否启动成功
@ -200,4 +201,12 @@ module.exports = (cli) => {
e2e.command('install-deps').action(async () => {
await run('npx', ['playwright', 'install', '--with-deps']);
});
e2e
.command('p-test')
.option('--stop-on-error')
.option('--concurrency [concurrency]', '', 3)
.action(async (opts) => {
await pTest(opts);
});
};

View File

@ -0,0 +1,68 @@
const execa = require('execa');
const { resolve, dirname } = require('path');
const pAll = require('p-all');
const dotenv = require('dotenv');
const fs = require('fs');
const { Client } = require('pg');
const glob = require('glob');
let ENV_FILE = resolve(process.cwd(), '.env.e2e');
if (!fs.existsSync(ENV_FILE)) {
ENV_FILE = resolve(process.cwd(), '.env.e2e.example');
}
const data = fs.readFileSync(ENV_FILE, 'utf-8');
const config = {
...dotenv.parse(data),
...process.env,
};
async function runApp(index = 1, dir) {
const database = `nocobase${index}`;
const client = new Client({
host: config['DB_HOST'],
port: Number(config['DB_PORT']),
user: config['DB_USER'],
password: config['DB_PASSWORD'],
database: 'postgres',
});
await client.connect();
await client.query(`DROP DATABASE IF EXISTS "${database}"`);
await client.query(`CREATE DATABASE "${database}";`);
await client.end();
return execa('yarn', ['nocobase', 'e2e', 'test', dir, '-x', '--skip-reporter'], {
shell: true,
stdio: 'inherit',
env: {
...config,
CI: true,
__E2E__: true,
APP_BASE_URL: undefined,
LOGGER_LEVEL: 'error',
APP_ENV: 'production',
APP_PORT: 20000 + index,
DB_DATABASE: `nocobase${index}`,
SOCKET_PATH: `storage/gateway-e2e-${index}.sock`,
PM2_HOME: resolve(process.cwd(), `storage/.pm2-${index}`),
PLAYWRIGHT_AUTH_FILE: resolve(process.cwd(), `storage/playwright/.auth/admin-${index}.json`),
},
});
}
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);
});
await pAll(commands, { concurrency: 3, stopOnError: false, ...options });
};

View File

@ -217,6 +217,9 @@ exports.genTsConfigPaths = function genTsConfigPaths() {
paths[`${packageJsonName}/server`] = [`${relativePath}/src/server`];
paths[`${packageJsonName}/e2e`] = [`${relativePath}/src/e2e`];
}
if (packageJsonName === '@nocobase/plugin-workflow-test') {
paths[`${packageJsonName}/e2e`] = [`${relativePath}/src/e2e`];
}
});
const tsConfigJsonPath = join(cwd, './tsconfig.paths.json');
@ -272,7 +275,7 @@ exports.initEnv = function initEnv() {
}
}
if (process.argv[2] === 'e2e') {
if (!process.env.APP_ENV_PATH && process.argv[2] === 'e2e') {
// 用于存放 playwright 自动生成的相关的文件
generatePlaywrightPath();
if (!fs.existsSync('.env.e2e') && fs.existsSync('.env.e2e.example')) {

View File

@ -1,6 +1,8 @@
import { expect, oneFormBlockBasedOnUsers, test } from '@nocobase/test/e2e';
test('fields', async ({ page, mockPage }) => {
// 在 CI 中多进程跑的时候,可能需要等待更长的时间
test.slow();
await mockPage(oneFormBlockBasedOnUsers).goto();
await page.getByLabel('schema-initializer-Grid-FormItemInitializers-users').click();
await page.getByRole('menuitem', { name: 'Nickname' }).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(1000);
await page.waitForTimeout(2000);
email1 = await page.getByText(records[0].email).boundingBox();
email2 = await page.getByText(records[1].email).boundingBox();

View File

@ -253,7 +253,7 @@ export class NocoPage {
const _test = base.extend<ExtendUtils>({
mockPage: async ({ page }, use) => {
// 保证每个测试运行时 faker 的随机值都是一样的
faker.seed(1);
// faker.seed(1);
const nocoPages: NocoPage[] = [];
const mockPage = (config?: PageConfig) => {
@ -284,27 +284,27 @@ const _test = base.extend<ExtendUtils>({
collectionSettings = omitSomeFields(
Array.isArray(collectionSettings) ? collectionSettings : [collectionSettings],
);
collectionsName = collectionSettings.map((item) => item.name);
collectionsName = [...collectionsName, ...collectionSettings.map((item) => item.name)];
await createCollections(collectionSettings);
};
await use(_createCollections);
if (collectionsName.length) {
await deleteCollections(collectionsName);
await deleteCollections(_.uniq(collectionsName));
}
},
mockCollections: async ({ page }, use) => {
let collectionsName = [];
const destroy = async () => {
if (collectionsName.length) {
await deleteCollections(collectionsName);
await deleteCollections(_.uniq(collectionsName));
}
};
const mockCollections = async (collectionSettings: CollectionSetting[]) => {
collectionSettings = omitSomeFields(collectionSettings);
collectionsName = collectionSettings.map((item) => item.name);
collectionsName = [...collectionsName, ...collectionSettings.map((item) => item.name)];
return createCollections(collectionSettings);
};
@ -315,13 +315,13 @@ const _test = base.extend<ExtendUtils>({
let collectionsName = [];
const destroy = async () => {
if (collectionsName.length) {
await deleteCollections(collectionsName);
await deleteCollections(_.uniq(collectionsName));
}
};
const mockCollection = async (collectionSetting: CollectionSetting, options?: { manualDestroy: boolean }) => {
const collectionSettings = omitSomeFields([collectionSetting]);
collectionsName = collectionSettings.map((item) => item.name);
collectionsName = [...collectionsName, ...collectionSettings.map((item) => item.name)];
return createCollections(collectionSettings);
};

View File

@ -0,0 +1,519 @@
import { faker } from '@faker-js/faker';
import {
AggregateNode,
CollectionTriggerNode,
apiCreateWorkflow,
apiDeleteWorkflow,
apiGetWorkflow,
apiGetWorkflowNodeExecutions,
apiUpdateWorkflowTrigger,
appendJsonCollectionName,
generalWithNoRelationalFields,
} from '@nocobase/plugin-workflow-test/e2e';
import { expect, test } from '@nocobase/test/e2e';
import { dayjs } from '@nocobase/utils';
test('Collection event add data trigger, aggregated data table, no filtering, normal table integer fields not de-emphasised COUNT', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
const aggregateNodeAppendText = 'b' + faker.string.alphanumeric(4);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
// 创建聚合节点数据表
const aggregateNodeCollectionDisplayName = `自动>组织[普通表]${aggregateNodeAppendText}`;
const aggregateNodeCollectionName = `tt_amt_org${aggregateNodeAppendText}`;
const aggregateNodeFieldName = 'staffnum';
const aggregateNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), aggregateNodeAppendText)
.collections,
);
const aggregateNodeCollectionData = [
{ staffnum: 3, regcapital: 3.12 },
{ staffnum: 3, regcapital: 3.6 },
{ staffnum: 4, regcapital: 4.6 },
{ staffnum: 4, regcapital: 4.6 },
{ staffnum: 5, regcapital: 5.6 },
];
const aggregateNodeCollectionRecords = await mockRecords(aggregateNodeCollectionName, aggregateNodeCollectionData);
//添加工作流
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));
//配置聚合数据节点
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: 'aggregate', exact: true }).click();
const aggregateRecordNodeName = 'Aggregate' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Aggregate-Aggregate', { exact: true }).getByRole('textbox').fill(aggregateRecordNodeName);
const aggregateRecordNode = new AggregateNode(page, aggregateRecordNodeName);
const aggregateRecordNodeId = await aggregateRecordNode.node.locator('.workflow-node-id').innerText();
await aggregateRecordNode.nodeConfigure.click();
await aggregateRecordNode.collectionDropDown.click();
await page.getByText(aggregateNodeCollectionDisplayName).click();
await aggregateRecordNode.aggregatedFieldDropDown.click();
await page.getByRole('option', { name: aggregateNodeFieldDisplayName }).click();
await aggregateRecordNode.submitButton.click();
// 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 getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === aggregateRecordNodeId);
const queryRecordNodeJobResult = queryRecordNodeJob.result;
expect(queryRecordNodeJobResult).toBe(aggregateNodeCollectionData.length);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, aggregated data table, no filtering, normal table integer fields not de-emphasised SUM', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
const aggregateNodeAppendText = 'b' + faker.string.alphanumeric(4);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
// 创建聚合节点数据表
const aggregateNodeCollectionDisplayName = `自动>组织[普通表]${aggregateNodeAppendText}`;
const aggregateNodeCollectionName = `tt_amt_org${aggregateNodeAppendText}`;
const aggregateNodeFieldName = 'staffnum';
const aggregateNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), aggregateNodeAppendText)
.collections,
);
const aggregateNodeCollectionData = [
{ staffnum: 3, regcapital: 3.12 },
{ staffnum: 3, regcapital: 3.6 },
{ staffnum: 4, regcapital: 4.6 },
{ staffnum: 4, regcapital: 4.6 },
{ staffnum: 5, regcapital: 5.6 },
];
const aggregateNodeCollectionRecords = await mockRecords(aggregateNodeCollectionName, aggregateNodeCollectionData);
//添加工作流
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));
//配置聚合数据节点
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: 'aggregate', exact: true }).click();
const aggregateRecordNodeName = 'Aggregate' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Aggregate-Aggregate', { exact: true }).getByRole('textbox').fill(aggregateRecordNodeName);
const aggregateRecordNode = new AggregateNode(page, aggregateRecordNodeName);
const aggregateRecordNodeId = await aggregateRecordNode.node.locator('.workflow-node-id').innerText();
await aggregateRecordNode.nodeConfigure.click();
await aggregateRecordNode.sumRadio.click();
await aggregateRecordNode.collectionDropDown.click();
await page.getByText(aggregateNodeCollectionDisplayName).click();
await aggregateRecordNode.aggregatedFieldDropDown.click();
await page.getByRole('option', { name: aggregateNodeFieldDisplayName }).click();
await aggregateRecordNode.submitButton.click();
// 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 getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === aggregateRecordNodeId);
const queryRecordNodeJobResult = queryRecordNodeJob.result;
// aggregateNodeCollectionData中staffnum字段值总和
const aggregateNodeCollectionDataSum = aggregateNodeCollectionData.reduce((total, currentValue) => {
return total + currentValue.staffnum;
}, 0);
expect(queryRecordNodeJobResult).toBe(aggregateNodeCollectionDataSum);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, aggregated data table, no filtering, normal table integer fields not de-emphasised AVG', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
const aggregateNodeAppendText = 'b' + faker.string.alphanumeric(4);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
// 创建聚合节点数据表
const aggregateNodeCollectionDisplayName = `自动>组织[普通表]${aggregateNodeAppendText}`;
const aggregateNodeCollectionName = `tt_amt_org${aggregateNodeAppendText}`;
const aggregateNodeFieldName = 'staffnum';
const aggregateNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), aggregateNodeAppendText)
.collections,
);
const aggregateNodeCollectionData = [
{ staffnum: 3, regcapital: 3.12 },
{ staffnum: 3, regcapital: 3.6 },
{ staffnum: 4, regcapital: 4.6 },
{ staffnum: 4, regcapital: 4.6 },
{ staffnum: 5, regcapital: 5.6 },
];
const aggregateNodeCollectionRecords = await mockRecords(aggregateNodeCollectionName, aggregateNodeCollectionData);
//添加工作流
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));
//配置聚合数据节点
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: 'aggregate', exact: true }).click();
const aggregateRecordNodeName = 'Aggregate' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Aggregate-Aggregate', { exact: true }).getByRole('textbox').fill(aggregateRecordNodeName);
const aggregateRecordNode = new AggregateNode(page, aggregateRecordNodeName);
const aggregateRecordNodeId = await aggregateRecordNode.node.locator('.workflow-node-id').innerText();
await aggregateRecordNode.nodeConfigure.click();
await aggregateRecordNode.avgRadio.click();
await aggregateRecordNode.collectionDropDown.click();
await page.getByText(aggregateNodeCollectionDisplayName).click();
await aggregateRecordNode.aggregatedFieldDropDown.click();
await page.getByRole('option', { name: aggregateNodeFieldDisplayName }).click();
await aggregateRecordNode.submitButton.click();
// 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 getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === aggregateRecordNodeId);
const queryRecordNodeJobResult = queryRecordNodeJob.result;
// aggregateNodeCollectionData中staffnum字段值平均值
const aggregateNodeCollectionDataAvg =
aggregateNodeCollectionData.reduce((total, currentValue) => {
return total + currentValue.staffnum;
}, 0) / aggregateNodeCollectionData.length;
expect(queryRecordNodeJobResult).toBe(aggregateNodeCollectionDataAvg);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, aggregated data table, no filtering, normal table integer fields not de-emphasised MIN', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
const aggregateNodeAppendText = 'b' + faker.string.alphanumeric(4);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
// 创建聚合节点数据表
const aggregateNodeCollectionDisplayName = `自动>组织[普通表]${aggregateNodeAppendText}`;
const aggregateNodeCollectionName = `tt_amt_org${aggregateNodeAppendText}`;
const aggregateNodeFieldName = 'staffnum';
const aggregateNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), aggregateNodeAppendText)
.collections,
);
const aggregateNodeCollectionData = [
{ staffnum: 3, regcapital: 3.12 },
{ staffnum: 3, regcapital: 3.6 },
{ staffnum: 4, regcapital: 4.6 },
{ staffnum: 4, regcapital: 4.6 },
{ staffnum: 5, regcapital: 5.6 },
];
const aggregateNodeCollectionRecords = await mockRecords(aggregateNodeCollectionName, aggregateNodeCollectionData);
//添加工作流
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));
//配置聚合数据节点
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: 'aggregate', exact: true }).click();
const aggregateRecordNodeName = 'Aggregate' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Aggregate-Aggregate', { exact: true }).getByRole('textbox').fill(aggregateRecordNodeName);
const aggregateRecordNode = new AggregateNode(page, aggregateRecordNodeName);
const aggregateRecordNodeId = await aggregateRecordNode.node.locator('.workflow-node-id').innerText();
await aggregateRecordNode.nodeConfigure.click();
await aggregateRecordNode.minRadio.click();
await aggregateRecordNode.collectionDropDown.click();
await page.getByText(aggregateNodeCollectionDisplayName).click();
await aggregateRecordNode.aggregatedFieldDropDown.click();
await page.getByRole('option', { name: aggregateNodeFieldDisplayName }).click();
await aggregateRecordNode.submitButton.click();
// 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 getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === aggregateRecordNodeId);
const queryRecordNodeJobResult = queryRecordNodeJob.result;
// aggregateNodeCollectionData中staffnum字段值最小值
const aggregateNodeCollectionDataMin = aggregateNodeCollectionData.reduce((min, currentValue) => {
return currentValue.staffnum < min ? currentValue.staffnum : min;
}, aggregateNodeCollectionData[0].staffnum);
expect(queryRecordNodeJobResult).toBe(aggregateNodeCollectionDataMin);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, aggregated data table, no filtering, normal table integer fields not de-emphasised MAX', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
const aggregateNodeAppendText = 'b' + faker.string.alphanumeric(4);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
// 创建聚合节点数据表
const aggregateNodeCollectionDisplayName = `自动>组织[普通表]${aggregateNodeAppendText}`;
const aggregateNodeCollectionName = `tt_amt_org${aggregateNodeAppendText}`;
const aggregateNodeFieldName = 'staffnum';
const aggregateNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), aggregateNodeAppendText)
.collections,
);
const aggregateNodeCollectionData = [
{ staffnum: 3, regcapital: 3.12 },
{ staffnum: 3, regcapital: 3.6 },
{ staffnum: 4, regcapital: 4.6 },
{ staffnum: 4, regcapital: 4.6 },
{ staffnum: 5, regcapital: 5.6 },
];
const aggregateNodeCollectionRecords = await mockRecords(aggregateNodeCollectionName, aggregateNodeCollectionData);
//添加工作流
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));
//配置聚合数据节点
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: 'aggregate', exact: true }).click();
const aggregateRecordNodeName = 'Aggregate' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Aggregate-Aggregate', { exact: true }).getByRole('textbox').fill(aggregateRecordNodeName);
const aggregateRecordNode = new AggregateNode(page, aggregateRecordNodeName);
const aggregateRecordNodeId = await aggregateRecordNode.node.locator('.workflow-node-id').innerText();
await aggregateRecordNode.nodeConfigure.click();
await aggregateRecordNode.maxRadio.click();
await aggregateRecordNode.collectionDropDown.click();
await page.getByText(aggregateNodeCollectionDisplayName).click();
await aggregateRecordNode.aggregatedFieldDropDown.click();
await page.getByRole('option', { name: aggregateNodeFieldDisplayName }).click();
await aggregateRecordNode.submitButton.click();
// 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 getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === aggregateRecordNodeId);
const queryRecordNodeJobResult = queryRecordNodeJob.result;
// aggregateNodeCollectionData中staffnum字段值最大值
const aggregateNodeCollectionDataMax = aggregateNodeCollectionData.reduce((max, currentValue) => {
return currentValue.staffnum > max ? currentValue.staffnum : max;
}, aggregateNodeCollectionData[0].staffnum);
expect(queryRecordNodeJobResult).toBe(aggregateNodeCollectionDataMax);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});

View File

@ -0,0 +1,659 @@
import { faker } from '@faker-js/faker';
import {
CreateWorkFlow,
EditWorkFlow,
FormEventTriggerNode,
WorkflowListRecords,
apiCreateRecordTriggerFormEvent,
apiCreateWorkflow,
apiDeleteWorkflow,
apiGetWorkflow,
apiUpdateWorkflowTrigger,
appendJsonCollectionName,
generalWithNoRelationalFields,
} from '@nocobase/plugin-workflow-test/e2e';
import { expect, test } from '@nocobase/test/e2e';
import { dayjs } from '@nocobase/utils';
test.describe('Configuration page to configure the Trigger node', () => {
test('Form Submit Button Binding Workflow Add Data Trigger', async ({
page,
mockPage,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
//添加工作流
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'form',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
//配置工作流触发器
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const formEventTriggerNode = new FormEventTriggerNode(page, workFlowName, triggerNodeCollectionName);
await formEventTriggerNode.nodeConfigure.click();
await formEventTriggerNode.collectionDropDown.click();
await page.getByRole('option', { name: triggerNodeCollectionDisplayName }).click();
await formEventTriggerNode.submitButton.click();
//配置录入数据区块
const newPage = mockPage();
await newPage.goto();
await page.waitForLoadState('networkidle');
await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover();
await page.getByRole('menuitem', { name: 'table Table' }).hover();
await page.getByRole('menuitem', { name: `${triggerNodeCollectionDisplayName}` }).click();
// 移开鼠标,关闭菜单
await page.mouse.move(300, 0);
await page.getByText('Configure columns').hover();
await page.getByText(triggerNodeFieldDisplayName).click();
await page.getByText('Configure actions').hover();
await page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch').click();
await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).toBeEnabled();
await page.getByLabel(`action-Action-Add new-create-${triggerNodeCollectionName}-table`).click();
await page.getByLabel(`schema-initializer-Grid-CreateFormBlockInitializers-${triggerNodeCollectionName}`).hover();
await page.getByRole('menuitem', { name: 'form Form' }).click();
// 移开鼠标,关闭菜单
await page.mouse.move(300, 0);
await page
.getByLabel(`schema-initializer-ActionBar-CreateFormActionInitializers-${triggerNodeCollectionName}`)
.hover();
await page.getByRole('menuitem', { name: 'Submit' }).click();
// 绑定工作流
await page.getByLabel(`schema-initializer-Grid-FormItemInitializers-${triggerNodeCollectionName}`).hover();
await page.getByRole('menuitem', { name: `${triggerNodeFieldDisplayName}` }).click();
await page.mouse.move(300, 0);
await page.getByLabel(`action-Action-Submit-submit-${triggerNodeCollectionName}-form`).hover();
await page
.getByRole('button', { name: `designer-schema-settings-Action-Action.Designer-${triggerNodeCollectionName}` })
.hover();
await page.getByRole('menuitem', { name: 'Bind workflows' }).click();
await page.getByRole('button', { name: 'plus Add workflow' }).click();
await page.getByRole('button', { name: 'Select workflow' }).click();
await page.getByRole('option', { name: workFlowName }).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
// 2、测试步骤进入“数据区块”-“添加”按钮,填写表单,点击“确定”按钮
const fieldData = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByRole('textbox').fill(fieldData);
await page.getByLabel(`action-Action-Submit-submit-${triggerNodeCollectionName}-form`, { exact: true }).click();
await page.waitForLoadState('networkidle');
await page.waitForTimeout(1000);
// 3、预期结果触发次数为1
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Form Submit to Workflow Button Add Data Trigger', async ({ page, mockPage, mockCollections, mockRecords }) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
//添加工作流
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'form',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
//配置工作流触发器
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const formEventTriggerNode = new FormEventTriggerNode(page, workFlowName, triggerNodeCollectionName);
await formEventTriggerNode.nodeConfigure.click();
await formEventTriggerNode.collectionDropDown.click();
await page.getByRole('option', { name: triggerNodeCollectionDisplayName }).click();
await formEventTriggerNode.submitButton.click();
//配置录入数据区块
const newPage = mockPage();
await newPage.goto();
await page.waitForLoadState('networkidle');
await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover();
await page.getByRole('menuitem', { name: 'table Table' }).hover();
await page.getByRole('menuitem', { name: `${triggerNodeCollectionDisplayName}` }).click();
// 移开鼠标,关闭菜单
await page.mouse.move(300, 0);
await page.getByText('Configure columns').hover();
await page.getByText(triggerNodeFieldDisplayName).click();
await page.getByText('Configure actions').hover();
await page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch').click();
await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).toBeEnabled();
await page.getByLabel(`action-Action-Add new-create-${triggerNodeCollectionName}-table`).click();
await page.getByLabel(`schema-initializer-Grid-CreateFormBlockInitializers-${triggerNodeCollectionName}`).hover();
await page.getByRole('menuitem', { name: 'form Form' }).click();
// 移开鼠标,关闭菜单
await page.mouse.move(300, 0);
// 绑定工作流
await page
.getByLabel(`schema-initializer-ActionBar-CreateFormActionInitializers-${triggerNodeCollectionName}`)
.hover();
await page.getByRole('menuitem', { name: 'Customize' }).hover();
await page.getByRole('menuitem', { name: 'Submit to workflow' }).click();
await page.getByLabel(`schema-initializer-Grid-FormItemInitializers-${triggerNodeCollectionName}`).hover();
await page.getByRole('menuitem', { name: `${triggerNodeFieldDisplayName}` }).click();
await page.mouse.move(300, 0);
await page.getByRole('button', { name: 'Submit to workflow' }).hover();
await page
.getByRole('button', { name: `designer-schema-settings-Action-Action.Designer-${triggerNodeCollectionName}` })
.hover();
await page.getByRole('menuitem', { name: 'Bind workflows' }).click();
await page.getByRole('button', { name: 'plus Add workflow' }).click();
await page.getByRole('button', { name: 'Select workflow' }).click();
await page.getByRole('option', { name: workFlowName }).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
// 2、测试步骤进入“数据区块”-“添加”按钮,填写表单,点击“确定”按钮
const fieldData = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByRole('textbox').fill(fieldData);
await page
.getByLabel(`action-Action-Submit to workflow-customize:triggerWorkflows-${triggerNodeCollectionName}-form`)
.click();
await page.waitForLoadState('networkidle');
await page.waitForTimeout(1000);
// 3、预期结果触发次数为1
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Configuration Page Path Jump Workflow Management Page', () => {
test('Form event Workflow Configuration Page Path Jump Workflow Management Page', async ({
page,
mockPage,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
// const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
// const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
// const triggerNodeFieldName = 'orgname';
// const triggerNodeFieldDisplayName = '公司名称(单行文本)';
// await mockCollections(appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText).collections);
//添加工作流
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'form',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
//配置工作流触发器
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
// 2、测试步骤跳转到工作流管理页面
await page.getByRole('link', { name: 'Workflow' }).click();
// 3、预期结果跳转路径正确
await page.waitForLoadState('networkidle');
expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Form event Workflow History Version Configuration Page Path Jump Workflow Management Page', async ({
page,
mockPage,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
//添加工作流
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'form',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
const WorkflowKey = workflowObj.key;
//配置工作流触发器
const triggerNodeData = { config: { collection: triggerNodeCollectionName, appends: [] } };
const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne =
triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const triggerWorkflows = WorkflowKey;
const triggerNodeCollectionRecords = await apiCreateRecordTriggerFormEvent(
triggerNodeCollectionName,
triggerWorkflows,
{ orgname: triggerNodeCollectionRecordOne },
);
await page.waitForTimeout(1000);
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
await page.getByLabel('more').click();
await page.getByLabel('revision').click();
await page.waitForLoadState('networkidle');
//元素重复
await page.getByLabel('version', { exact: true }).click();
await page.getByLabel('version-1').click();
await page.getByRole('link', { name: 'Workflow' }).click();
// 3、预期结果跳转路径正确
await page.waitForLoadState('networkidle');
expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Form event Workflow Execution Log Page Path Jump Workflow Management Page', async ({
page,
mockPage,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
//添加工作流
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'form',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
const WorkflowKey = workflowObj.key;
//配置工作流触发器
const triggerNodeData = { config: { collection: triggerNodeCollectionName, appends: [] } };
const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne =
triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const triggerWorkflows = WorkflowKey;
const triggerNodeCollectionRecords = await apiCreateRecordTriggerFormEvent(
triggerNodeCollectionName,
triggerWorkflows,
{ orgname: triggerNodeCollectionRecordOne },
);
await page.waitForTimeout(1000);
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
const workflowListRecords = new WorkflowListRecords(page, workFlowName);
await workflowListRecords.executionCountPopup.click();
await page.getByText('View').click();
await page.waitForLoadState('networkidle');
await page.getByRole('link', { name: 'Workflow', exact: true }).click();
// 3、预期结果跳转路径正确
await page.waitForLoadState('networkidle');
expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test.skip('Form event Workflow Execution Log Page Path Jump Execution Log Screen', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
//添加工作流
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'form',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
const WorkflowKey = workflowObj.key;
//配置工作流触发器
const triggerNodeData = { config: { collection: triggerNodeCollectionName, appends: [] } };
const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne =
triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const triggerWorkflows = WorkflowKey;
const triggerNodeCollectionRecords = await apiCreateRecordTriggerFormEvent(
triggerNodeCollectionName,
triggerWorkflows,
{ orgname: triggerNodeCollectionRecordOne },
);
await page.waitForTimeout(1000);
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
const workflowListRecords = new WorkflowListRecords(page, workFlowName);
await workflowListRecords.executionCountPopup.click();
await page.getByText('View').click();
await page.waitForLoadState('networkidle');
//跳转其他执行日志界面,元素无法定位
// 3、预期结果跳转路径正确
await page.waitForLoadState('networkidle');
// expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Configuration page version switching', () => {});
test.describe('Configuration page disable enable', () => {
test('Form event Workflow Add Data Trigger Disable Do Not Trigger', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
//添加工作流
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'form',
enabled: false,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
const WorkflowKey = workflowObj.key;
//配置工作流触发器
const triggerNodeData = { config: { collection: triggerNodeCollectionName, appends: [] } };
const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne =
triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const triggerWorkflows = WorkflowKey;
const triggerNodeCollectionRecords = await apiCreateRecordTriggerFormEvent(
triggerNodeCollectionName,
triggerWorkflows,
{ orgname: triggerNodeCollectionRecordOne },
);
await page.waitForTimeout(1000);
// 3、预期结果触发次数为1
let getWorkflow = await apiGetWorkflow(workflowId);
let getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
let getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(0);
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
await page.getByRole('switch', { name: 'On Off' }).click();
await apiCreateRecordTriggerFormEvent(triggerNodeCollectionName, triggerWorkflows, {
orgname: triggerNodeCollectionRecordOne + '1',
});
await page.waitForTimeout(1000);
getWorkflow = await apiGetWorkflow(workflowId);
getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Form event Workflow Add Data Trigger Disable Enable Post Trigger', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
//添加工作流
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'form',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
const WorkflowKey = workflowObj.key;
//配置工作流触发器
const triggerNodeData = { config: { collection: triggerNodeCollectionName, appends: [] } };
const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne =
triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const triggerWorkflows = WorkflowKey;
const triggerNodeCollectionRecords = await apiCreateRecordTriggerFormEvent(
triggerNodeCollectionName,
triggerWorkflows,
{ orgname: triggerNodeCollectionRecordOne },
);
await page.waitForTimeout(1000);
// 3、预期结果触发次数为1
let getWorkflow = await apiGetWorkflow(workflowId);
let getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
let getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
await page.getByRole('switch', { name: 'On Off' }).click();
await apiCreateRecordTriggerFormEvent(triggerNodeCollectionName, triggerWorkflows, {
orgname: triggerNodeCollectionRecordOne + '1',
});
await page.waitForTimeout(1000);
getWorkflow = await apiGetWorkflow(workflowId);
getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Configuration page execution history', () => {});
test.describe('Configuration page copy to new version', () => {
test('Copy the Form event of the Configuration Trigger node', async ({ page, mockCollections, mockRecords }) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
//添加工作流
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'form',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
const WorkflowKey = workflowObj.key;
//配置工作流触发器
const triggerNodeData = { config: { collection: triggerNodeCollectionName, appends: [] } };
const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne =
triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const triggerWorkflows = WorkflowKey;
const triggerNodeCollectionRecords = await apiCreateRecordTriggerFormEvent(
triggerNodeCollectionName,
triggerWorkflows,
{ orgname: triggerNodeCollectionRecordOne },
);
await page.waitForTimeout(1000);
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
await page.getByLabel('more').click();
await page.getByLabel('revision').click();
await page.waitForLoadState('networkidle');
// 3、预期结果新版本工作流配置内容同旧版本一样
const formEventTriggerNode = new FormEventTriggerNode(page, workFlowName, triggerNodeCollectionName);
await formEventTriggerNode.nodeConfigure.click();
await expect(page.getByRole('button', { name: triggerNodeCollectionDisplayName })).toBeVisible();
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Configuration page delete version', () => {});
test.describe('Node Add Modify Delete', () => {});

View File

@ -0,0 +1,175 @@
import { faker } from '@faker-js/faker';
import {
CreateWorkFlow,
EditWorkFlow,
FormEventTriggerNode,
WorkflowListRecords,
apiCreateRecordTriggerFormEvent,
apiCreateWorkflow,
apiDeleteWorkflow,
apiGetWorkflow,
apiUpdateWorkflowTrigger,
appendJsonCollectionName,
generalWithNoRelationalFields,
} from '@nocobase/plugin-workflow-test/e2e';
import { expect, test } from '@nocobase/test/e2e';
import { dayjs } from '@nocobase/utils';
test.describe('Filter', () => {
test('filter workflow name', async ({ page }) => {
//添加工作流
const triggerNodeAppendText = faker.string.alphanumeric(5);
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'form',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
// 2、筛选工作流
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
await page.getByRole('textbox').fill(workFlowName);
await page.getByRole('button', { name: 'Submit' }).click();
// 3、预期结果列表中出现筛选的工作流
await expect(page.getByText(workFlowName)).toBeAttached();
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Add new', () => {
test('add new Form event', async ({ page }) => {
// 添加工作流
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
await page.getByLabel('action-Action-Add new-workflows').click();
const createWorkFlow = new CreateWorkFlow(page);
const workFlowName = faker.string.alphanumeric(5);
await createWorkFlow.name.fill(workFlowName);
await createWorkFlow.triggerType.click();
await page.getByRole('option', { name: 'Form event' }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
// 3、预期结果列表中出现新建的工作流
await expect(page.getByText(workFlowName)).toBeVisible();
// 4、后置处理删除工作流
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
await page.getByRole('textbox').fill(workFlowName);
await page.getByRole('button', { name: 'Submit' }).click();
await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName}`).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
await expect(page.getByText(workFlowName)).toBeHidden();
});
});
test.describe('Sync', () => {});
test.describe('Delete', () => {
test('delete Form event', async ({ page }) => {
//添加工作流
const triggerNodeAppendText = faker.string.alphanumeric(5);
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'form',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
// 删除工作流
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
await page.getByRole('textbox').fill(workFlowName);
await page.getByRole('button', { name: 'Submit' }).click();
await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName}`).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
// 3、预期结果列表中出现筛选的工作流
await expect(page.getByText(workFlowName)).toBeHidden();
// 4、后置处理删除工作流
});
});
test.describe('Edit', () => {
test('edit Form event name', async ({ page }) => {
//添加工作流
const triggerNodeAppendText = faker.string.alphanumeric(5);
let workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'form',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
// 编辑工作流
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
await page.getByLabel(`action-Action.Link-Edit-workflows-${workFlowName}`).click();
const editWorkFlow = new EditWorkFlow(page, workFlowName);
workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
await editWorkFlow.name.fill(workFlowName);
await page.getByLabel('action-Action-Submit-workflows').click();
await page.waitForLoadState('networkidle');
// 3、预期结果编辑成功列表中出现编辑后的工作流
await expect(page.getByText(workFlowName)).toBeAttached();
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Duplicate', () => {
test('Duplicate Form event triggers with only unconfigured trigger nodes', async ({ page }) => {
//添加工作流
const triggerNodeAppendText = faker.string.alphanumeric(5);
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'form',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
// 2、复制工作流
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
await page.getByLabel(`action-Action.Link-Duplicate-workflows-${workFlowName}`).click();
await page.getByLabel(`action-Action-Submit-workflows-${workFlowName}`).click();
await page.waitForLoadState('networkidle');
// 3、预期结果列表中出现筛选的工作流
await expect(page.getByText(`${workFlowName} copy`)).toBeAttached();
// 4、后置处理删除工作流
await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName} copy`).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
await expect(page.getByText(`${workFlowName} copy`)).toBeHidden();
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Executed', () => {});

View File

@ -0,0 +1,2 @@
export * from './dist/client';
export { default } from './dist/client';

View File

@ -0,0 +1 @@
module.exports = require('./dist/client/index.js');

View File

@ -0,0 +1,2 @@
export * from './dist/e2e';
export { default } from './dist/e2e';

View File

@ -0,0 +1 @@
module.exports = require('./dist/e2e/index.js');

View File

@ -0,0 +1,3 @@
import { Plugin } from '@nocobase/client';
export default class extends Plugin {}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,528 @@
import { Locator, Page } from '@nocobase/test/e2e';
export class CreateWorkFlow {
readonly page: Page;
name: Locator;
triggerType: Locator;
description: Locator;
autoDeleteHistory: Locator;
submitButton: Locator;
cancelButton: Locator;
constructor(page: Page) {
this.page = page;
this.name = page.getByLabel('block-item-CollectionField-workflows-Name').getByRole('textbox');
this.triggerType = page.getByTestId('select-single');
this.description = page.getByTestId('description-item').getByRole('textbox');
this.autoDeleteHistory = page.getByTestId('select-multiple');
this.submitButton = page.getByLabel('action-Action-Submit-workflows');
this.cancelButton = page.getByLabel('action-Action-Cancel-workflows');
}
}
export class EditWorkFlow {
readonly page: Page;
name: Locator;
statusIsOn: Locator;
statusIisOff: Locator;
description: Locator;
autoDeleteHistory: Locator;
submitButton: Locator;
cancelButton: Locator;
constructor(page: Page, workFlowName: string) {
this.page = page;
this.name = page.getByLabel('block-item-CollectionField-workflows-Name').getByRole('textbox');
this.statusIsOn = page.getByLabel('On', { exact: true });
this.statusIisOff = page.getByLabel('Off');
this.description = page.getByTestId('description-item').getByRole('textbox');
this.autoDeleteHistory = page
.getByTestId('deleteExecutionOnStatus-item')
.getByTestId('antd-select')
.locator('div')
.nth(1);
this.submitButton = page.getByLabel(`action-Action-Submit-workflows-${workFlowName}`);
this.cancelButton = page.getByLabel(`action-Action-Cancel-workflows-${workFlowName}`);
}
}
export class WorkflowManagement {
readonly page: Page;
addNewButton: Locator;
deleteButton: Locator;
filterButton: Locator;
constructor(page: Page) {
this.page = page;
this.addNewButton = page.getByLabel('action-Action-Add new-workflows');
this.deleteButton = page.getByLabel('action-Action-Delete-workflows');
this.filterButton = page.getByLabel('action-Filter.Action-Filter-filter-workflows');
}
}
export class WorkflowListRecords {
readonly page: Page;
executionCountPopup: Locator;
configureAction: Locator;
editAction: Locator;
duplicateAction: Locator;
deleteAction: Locator;
constructor(page: Page, workFlowName: string) {
this.page = page;
this.executionCountPopup = page.getByLabel(`executed-${workFlowName}`);
this.configureAction = page.getByLabel(`action-WorkflowLink-Configure-workflows-${workFlowName}`);
this.editAction = page.getByLabel(`action-Action.Link-Edit-workflows-${workFlowName}`);
this.duplicateAction = page.getByLabel(`action-Action.Link-Duplicate-workflows-${workFlowName}`);
this.deleteAction = page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName}`);
}
}
export class ApprovalTriggerNode {
readonly page: Page;
node: Locator;
nodeTitle: Locator;
nodeConfigure: Locator;
collectionDropDown: Locator;
checkWthdrawable: Locator;
configureUserInterfaceButton: Locator;
addBlockButton: Locator;
addApplyFormMenu: Locator;
configureFieldsButton: Locator;
configureActionsButton: Locator;
saveDraftSwitch: Locator;
addNodeButton: Locator;
constructor(page: Page, triggerName: string, collectionName: string) {
this.page = page;
this.node = page.getByText('TriggeraConfigure');
this.nodeTitle = page.locator('textarea').filter({ hasText: triggerName });
this.nodeConfigure = page.getByRole('button', { name: 'Configure' });
this.collectionDropDown = page.getByRole('button', { name: 'Select collection' });
this.checkWthdrawable = page.getByLabel('Withdrawable');
this.configureUserInterfaceButton = page.getByRole('button', { name: 'Configure user interface' });
this.addBlockButton = page.getByRole('button', { name: 'Add block' });
this.addApplyFormMenu = page.getByRole('menuitem', { name: 'Apply form' });
this.configureFieldsButton = page.getByTestId('configure-fields-button-of-form-item-' + collectionName);
this.configureActionsButton = page.getByTestId(
'approval-trigger-configure-form-actions-add-action-button-' + collectionName,
);
this.saveDraftSwitch = page.getByRole('menuitem', { name: 'Save draft' }).getByRole('switch');
this.addNodeButton = page.getByLabel('add-button', { exact: true });
}
}
export class ApprovalNode {
readonly page: Page;
node: Locator;
nodeTitle: Locator;
nodeConfigure: Locator;
assigneesDropDown: Locator;
checkReturnable: Locator;
configureUserInterfaceButton: Locator;
addBlockButton: Locator;
addApplyFormMenu: Locator;
configureFieldsButton: Locator;
configureActionsButton: Locator;
saveDraftSwitch: Locator;
addNodeButton: Locator;
constructor(page: Page, nodeName: string, collectionName: string) {
this.page = page;
this.node = page.getByText('TriggeraConfigure');
this.nodeTitle = page.locator('textarea').filter({ hasText: nodeName });
this.nodeConfigure = page.getByRole('button', { name: 'Configure' });
this.assigneesDropDown = page.getByLabel('Search');
this.checkReturnable = page.getByLabel('Returnable');
this.configureUserInterfaceButton = page.getByRole('button', { name: 'Configure user interface' });
this.addBlockButton = page.getByTestId('add-block-button-in-workflow-workflows');
this.addApplyFormMenu = page.getByRole('menuitem', { name: 'Apply form' });
this.configureFieldsButton = page.getByTestId('configure-fields-button-of-form-item-' + collectionName);
this.configureActionsButton = page.getByTestId(
'approval-trigger-configure-form-actions-add-action-button-' + collectionName,
);
this.saveDraftSwitch = page.getByRole('menuitem', { name: 'Save draft' }).getByRole('switch');
this.addNodeButton = page.getByLabel(`add-button-calculation-${nodeName}`, { exact: true });
}
}
export class ScheduleTriggerNode {
readonly page: Page;
node: Locator;
nodeTitle: Locator;
nodeConfigure: Locator;
customTimeTriggerOptions: Locator;
startTimeEntryBox: Locator;
RrpeatModeDropdown: Locator;
dataTableTimeFieldOptions: Locator;
collectionDropDown: Locator;
startTimeDropdown: Locator;
submitButton: Locator;
cancelButton: Locator;
addNodeButton: Locator;
constructor(page: Page, triggerName: string, collectionName: string) {
this.page = page;
this.node = page.getByText('TriggeraConfigure');
this.nodeTitle = page.locator('textarea').filter({ hasText: triggerName });
this.nodeConfigure = page.getByRole('button', { name: 'Configure' });
this.customTimeTriggerOptions = page.getByLabel('Based on certain date');
this.startTimeEntryBox = page.getByPlaceholder('Select date');
this.RrpeatModeDropdown = page.getByLabel('block-item-RepeatField-workflows-Repeat mode');
this.dataTableTimeFieldOptions = page.getByLabel('Based on date field of collection');
this.collectionDropDown = page.getByRole('button', { name: 'Select collection' });
this.startTimeDropdown = page.getByLabel('block-item-OnField-workflows-Starts on');
this.submitButton = page.getByLabel('action-Action-Submit-workflows');
this.cancelButton = page.getByLabel('action-Action-Cancel-workflows');
this.addNodeButton = page.getByLabel('add-button', { exact: true });
}
}
export class CollectionTriggerNode {
readonly page: Page;
node: Locator;
nodeTitle: Locator;
nodeConfigure: Locator;
collectionDropDown: Locator;
triggerOnDropdown: Locator;
submitButton: Locator;
cancelButton: Locator;
addNodeButton: Locator;
constructor(page: Page, triggerName: string, collectionName: string) {
this.page = page;
this.node = page.getByLabel(`Trigger-${triggerName}`);
this.nodeTitle = page.getByLabel(`Trigger-${triggerName}`).getByRole('textbox');
this.nodeConfigure = page.getByLabel(`Trigger-${triggerName}`).getByRole('button', { name: 'Configure' });
this.collectionDropDown = page.getByRole('button', { name: 'Select collection' });
this.triggerOnDropdown = page
.getByLabel('block-item-Select-workflows-Trigger on')
.getByRole('button', { name: 'Trigger on' });
this.submitButton = page.getByLabel('action-Action-Submit-workflows');
this.cancelButton = page.getByLabel('action-Action-Cancel-workflows');
this.addNodeButton = page.getByLabel('add-button', { exact: true });
}
}
export class FormEventTriggerNode {
readonly page: Page;
node: Locator;
nodeTitle: Locator;
nodeConfigure: Locator;
collectionDropDown: Locator;
relationalDataDropdown: Locator;
submitButton: Locator;
cancelButton: Locator;
addNodeButton: Locator;
constructor(page: Page, triggerName: string, collectionName: string) {
this.page = page;
this.node = page.getByLabel(`Trigger-${triggerName}`);
this.nodeTitle = page.getByLabel(`Trigger-${triggerName}`).getByRole('textbox');
this.nodeConfigure = page.getByLabel(`Trigger-${triggerName}`).getByRole('button', { name: 'Configure' });
this.collectionDropDown = page.getByRole('button', { name: 'Select collection' });
this.relationalDataDropdown = page.getByTestId('select-field-Preload associations');
this.submitButton = page.getByLabel('action-Action-Submit-workflows');
this.cancelButton = page.getByLabel('action-Action-Cancel-workflows');
this.addNodeButton = page.getByLabel('add-button', { exact: true });
}
}
export class ClculationNode {
readonly page: Page;
node: Locator;
nodeTitle: Locator;
nodeConfigure: Locator;
mathCalculationEngine: Locator;
formulaCalculationEngine: Locator;
calculationExpression: Locator;
submitButton: Locator;
cancelButton: Locator;
addNodeButton: Locator;
constructor(page: Page, nodeName: string) {
this.page = page;
this.node = page.getByLabel(`Calculation-${nodeName}`, { exact: true });
this.nodeTitle = page.getByLabel(`Calculation-${nodeName}`, { exact: true }).getByRole('textbox');
this.nodeConfigure = page
.getByLabel(`Calculation-${nodeName}`, { exact: true })
.getByRole('button', { name: 'Configure' });
this.mathCalculationEngine = page.getByLabel('Math.js');
this.formulaCalculationEngine = page.getByLabel('Formula.js');
this.calculationExpression = page.getByLabel('textbox');
this.submitButton = page.getByLabel('action-Action-Submit-workflows');
this.cancelButton = page.getByLabel('action-Action-Cancel-workflows');
this.addNodeButton = page.getByLabel(`add-button-calculation-${nodeName}`, { exact: true });
}
}
export class QueryRecordNode {
readonly page: Page;
node: Locator;
nodeTitle: Locator;
nodeConfigure: Locator;
collectionDropDown: Locator;
allowMultipleDataBoxesForResults: Locator;
addSortFieldsButton: Locator;
pageNumberEditBox: Locator;
pageNumberVariableButton: Locator;
pageSizeEditBox: Locator;
exitProcessOptionsBoxWithEmptyResult: Locator;
submitButton: Locator;
cancelButton: Locator;
addNodeButton: Locator;
constructor(page: Page, nodeName: string) {
this.page = page;
this.node = page.getByLabel(`Query record-${nodeName}`, { exact: true });
this.nodeTitle = page.getByLabel(`Query record-${nodeName}`, { exact: true }).getByRole('textbox');
this.nodeConfigure = page
.getByLabel(`Query record-${nodeName}`, { exact: true })
.getByRole('button', { name: 'Configure' });
this.collectionDropDown = page.getByRole('button', { name: 'Select collection' });
this.allowMultipleDataBoxesForResults = page.getByLabel('Allow multiple records as');
this.addSortFieldsButton = page.getByRole('button', { name: 'plus Add sort field' });
this.pageNumberEditBox = page.getByLabel('variable-constant');
this.pageNumberVariableButton = page.getByLabel('variable-button');
this.pageSizeEditBox = page.getByLabel('block-item-InputNumber-workflows-Page size').getByRole('spinbutton');
this.exitProcessOptionsBoxWithEmptyResult = page.getByLabel('Exit when query result is null');
this.submitButton = page.getByLabel('action-Action-Submit-workflows');
this.cancelButton = page.getByLabel('action-Action-Cancel-workflows');
this.addNodeButton = page.getByLabel(`add-button-query-${nodeName}`, { exact: true });
}
}
export class CreateRecordNode {
readonly page: Page;
node: Locator;
nodeTitle: Locator;
nodeConfigure: Locator;
collectionDropDown: Locator;
addFieldsButton: Locator;
submitButton: Locator;
cancelButton: Locator;
addNodeButton: Locator;
constructor(page: Page, nodeName: string) {
this.page = page;
this.node = page.getByLabel(`Create record-${nodeName}`, { exact: true });
this.nodeTitle = page.getByLabel(`Create record-${nodeName}`, { exact: true }).getByRole('textbox');
this.nodeConfigure = page
.getByLabel(`Create record-${nodeName}`, { exact: true })
.getByRole('button', { name: 'Configure' });
this.collectionDropDown = page.getByRole('button', { name: 'Select collection' });
this.addFieldsButton = page.getByRole('button', { name: 'plus Add field' });
this.submitButton = page.getByLabel('action-Action-Submit-workflows');
this.cancelButton = page.getByLabel('action-Action-Cancel-workflows');
this.addNodeButton = page.getByLabel(`add-button-create-${nodeName}`, { exact: true });
}
}
export class UpdateRecordNode {
readonly page: Page;
node: Locator;
nodeTitle: Locator;
nodeConfigure: Locator;
collectionDropDown: Locator;
batchUpdateModeRadio: Locator;
articleByArticleUpdateModeRadio: Locator;
addFieldsButton: Locator;
submitButton: Locator;
cancelButton: Locator;
addNodeButton: Locator;
constructor(page: Page, nodeName: string) {
this.page = page;
this.node = page.getByLabel(`Update record-${nodeName}`, { exact: true });
this.nodeTitle = page.getByLabel(`Update record-${nodeName}`, { exact: true }).getByRole('textbox');
this.nodeConfigure = page
.getByLabel(`Update record-${nodeName}`, { exact: true })
.getByRole('button', { name: 'Configure' });
this.collectionDropDown = page.getByRole('button', { name: 'Select collection' });
this.batchUpdateModeRadio = page
.getByLabel('block-item-IndividualHooksRadioWithTooltip-workflows-Update mode')
.getByLabel('Update in a batch');
this.articleByArticleUpdateModeRadio = page
.getByLabel('block-item-IndividualHooksRadioWithTooltip-workflows-Update mode')
.getByLabel('Update one by one');
this.addFieldsButton = page.getByRole('button', { name: 'plus Add field' });
this.submitButton = page.getByLabel('action-Action-Submit-workflows');
this.cancelButton = page.getByLabel('action-Action-Cancel-workflows');
this.addNodeButton = page.getByLabel(`add-button-update-${nodeName}`, { exact: true });
}
}
export class DeleteRecordNode {
readonly page: Page;
node: Locator;
nodeTitle: Locator;
nodeConfigure: Locator;
collectionDropDown: Locator;
submitButton: Locator;
cancelButton: Locator;
addNodeButton: Locator;
constructor(page: Page, nodeName: string) {
this.page = page;
this.node = page.getByLabel(`Delete record-${nodeName}`, { exact: true });
this.nodeTitle = page.getByLabel(`Delete record-${nodeName}`, { exact: true }).getByRole('textbox');
this.nodeConfigure = page
.getByLabel(`Delete record-${nodeName}`, { exact: true })
.getByRole('button', { name: 'Configure' });
this.collectionDropDown = page.getByRole('button', { name: 'Select collection' });
this.submitButton = page.getByLabel('action-Action-Submit-workflows');
this.cancelButton = page.getByLabel('action-Action-Cancel-workflows');
this.addNodeButton = page.getByLabel(`add-button-delete-${nodeName}`, { exact: true });
}
}
export class AggregateNode {
readonly page: Page;
node: Locator;
nodeTitle: Locator;
nodeConfigure: Locator;
countRadio: Locator;
sumRadio: Locator;
avgRadio: Locator;
maxRadio: Locator;
minRadio: Locator;
dataTableDataRadio: Locator;
linkedDataTableDataRadio: Locator;
collectionDropDown: Locator;
aggregatedFieldDropDown: Locator;
submitButton: Locator;
cancelButton: Locator;
addNodeButton: Locator;
constructor(page: Page, nodeName: string) {
this.page = page;
this.node = page.getByLabel(`Aggregate-${nodeName}`, { exact: true });
this.nodeTitle = page.getByLabel(`Aggregate-${nodeName}`, { exact: true }).getByRole('textbox');
this.nodeConfigure = page
.getByLabel(`Aggregate-${nodeName}`, { exact: true })
.getByRole('button', { name: 'Configure' });
this.countRadio = page.getByLabel('COUNT');
this.sumRadio = page.getByLabel('SUM', { exact: true });
this.avgRadio = page.getByLabel('AVG', { exact: true });
this.maxRadio = page.getByLabel('MAX', { exact: true });
this.minRadio = page.getByLabel('MIN', { exact: true });
this.dataTableDataRadio = page.getByLabel('Data of collection');
this.linkedDataTableDataRadio = page.getByLabel('Data of associated collection');
this.collectionDropDown = page.getByRole('button', { name: 'Select collection' });
// this.aggregatedFieldDropDown = page.getByLabel('block-item-FieldsSelect-workflows-Field to aggregate').getByRole('textbox').getByRole('combobox');
this.aggregatedFieldDropDown = page.locator(
'input.ant-select-selection-search-input[role="combobox"][aria-haspopup="listbox"]',
);
this.submitButton = page.getByLabel('action-Action-Submit-workflows');
this.cancelButton = page.getByLabel('action-Action-Cancel-workflows');
this.addNodeButton = page.getByLabel(`add-button-aggregate-${nodeName}`, { exact: true });
}
}
export class ManualNode {
readonly page: Page;
node: Locator;
nodeTitle: Locator;
nodeConfigure: Locator;
assigneesDropDown: Locator;
configureUserInterfaceButton: Locator;
addBlockButton: Locator;
triggerDataMenu: Locator;
nodeDataMenu: Locator;
customFormMenu: Locator;
createRecordFormMenu: Locator;
updateRecordFormMenu: Locator;
submitButton: Locator;
cancelButton: Locator;
addNodeButton: Locator;
constructor(page: Page, nodeName: string) {
this.page = page;
this.node = page.getByLabel(`Manual-${nodeName}`, { exact: true });
this.nodeTitle = page.getByLabel(`Manual-${nodeName}`, { exact: true }).getByRole('textbox');
this.nodeConfigure = page
.getByLabel(`Manual-${nodeName}`, { exact: true })
.getByRole('button', { name: 'Configure' });
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.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.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 });
}
}
export class ConditionYesNode {
readonly page: Page;
node: Locator;
nodeTitle: Locator;
nodeConfigure: Locator;
basicRadio: Locator;
mathRadio: Locator;
formulaRadio: Locator;
submitButton: Locator;
cancelButton: Locator;
addNodeButton: Locator;
constructor(page: Page, nodeName: string) {
this.page = page;
this.node = page.getByLabel(`Condition-${nodeName}`, { exact: true });
this.nodeTitle = page.getByLabel(`Condition-${nodeName}`, { exact: true }).getByRole('textbox');
this.nodeConfigure = page
.getByLabel(`Condition-${nodeName}`, { exact: true })
.getByRole('button', { name: 'Configure' });
// await page.getByLabel('variable-constant').first().click();
// await page.getByLabel('variable-button').first().click();
// await page.getByLabel('select-operator-calc').first().click();
// await page.getByRole('option', { name: '=' }).click();
// await page.getByLabel('variable-constant').nth(1).click();
// await page.getByLabel('variable-button').nth(1).click();
this.basicRadio = page.getByLabel('Basic');
this.mathRadio = page.getByLabel('Math.js');
this.formulaRadio = page.getByLabel('Formula.js');
this.submitButton = page.getByLabel('action-Action-Submit-workflows');
this.cancelButton = page.getByLabel('action-Action-Cancel-workflows');
this.addNodeButton = page.getByLabel(`add-button-condition-${nodeName}`, { exact: true });
}
}
export class ConditionBranchNode {
readonly page: Page;
node: Locator;
nodeTitle: Locator;
nodeConfigure: Locator;
basicRadio: Locator;
mathRadio: Locator;
formulaRadio: Locator;
submitButton: Locator;
cancelButton: Locator;
addNoBranchNode: Locator;
addYesBranchNode: Locator;
addNodeButton: Locator;
constructor(page: Page, nodeName: string) {
this.page = page;
this.node = page.getByLabel(`Condition-${nodeName}`, { exact: true });
this.nodeTitle = page.getByLabel(`Condition-${nodeName}`, { exact: true }).getByRole('textbox');
this.nodeConfigure = page
.getByLabel(`Condition-${nodeName}`, { exact: true })
.getByRole('button', { name: 'Configure' });
this.submitButton = page.getByLabel('action-Action-Submit-workflows');
this.cancelButton = page.getByLabel('action-Action-Cancel-workflows');
this.addNodeButton = page.getByLabel(`add-button-condition-${nodeName}`, { exact: true });
this.basicRadio = page.getByLabel('Basic');
this.mathRadio = page.getByLabel('Math.js');
this.formulaRadio = page.getByLabel('Formula.js');
this.addNoBranchNode = page.getByLabel(`add-button-condition-${nodeName}-0`);
this.addYesBranchNode = page.getByLabel(`add-button-condition-${nodeName}-1`);
}
}
export default module.exports = {
CreateWorkFlow,
EditWorkFlow,
WorkflowManagement,
WorkflowListRecords,
ApprovalTriggerNode,
ApprovalNode,
ScheduleTriggerNode,
CollectionTriggerNode,
FormEventTriggerNode,
ClculationNode,
QueryRecordNode,
CreateRecordNode,
UpdateRecordNode,
DeleteRecordNode,
AggregateNode,
ManualNode,
ConditionYesNode,
ConditionBranchNode,
};

View File

@ -0,0 +1,747 @@
import { request } from '@nocobase/test/e2e';
const PORT = process.env.APP_PORT || 20000;
const APP_BASE_URL = process.env.APP_BASE_URL || `http://localhost:${PORT}`;
// 创建工作流
export const apiCreateWorkflow = async (data: any) => {
const api = await request.newContext({
storageState: process.env.PLAYWRIGHT_AUTH_FILE,
});
const state = await api.storageState();
const headers = getHeaders(state);
/*
{
"current": true,
"options": {
"deleteExecutionOnStatus": []
},
"title": "t3",
"type": "collection"
}
*/
const result = await api.post(`/api/workflows:create`, {
headers,
data,
});
if (!result.ok()) {
throw new Error(await result.text());
}
/*
{
"data": {
"id": 74,
"key": "il2nu3ovj53",
"updatedAt": "2023-12-12T06:53:21.232Z",
"createdAt": "2023-12-12T06:53:21.232Z",
"title": "t3",
"type": "collection",
"enabled": false,
"description": null,
"executed": 0,
"allExecuted": 0,
"config": {},
"current": true,
"options": {
"deleteExecutionOnStatus": []
},
"useTransaction": true
}
}
*/
return (await result.json()).data;
};
// 更新工作流
export const apiUpdateWorkflow = async (id: number, data: any) => {
const api = await request.newContext({
storageState: process.env.PLAYWRIGHT_AUTH_FILE,
});
const state = await api.storageState();
const headers = getHeaders(state);
/*
{
"id": 74,
"key": "il2nu3ovj53",
"updatedAt": "2023-12-12T06:53:21.232Z",
"createdAt": "2023-12-12T06:53:21.232Z",
"title": "t3",
"type": "collection",
"enabled": false,
"description": null,
"executed": 0,
"allExecuted": 0,
"current": true,
"options": {
"deleteExecutionOnStatus": []
},
"useTransaction": true
}
*/
const result = await api.post(`/api/workflows:update?filterByTk=${id}`, {
headers,
data,
});
if (!result.ok()) {
throw new Error(await result.text());
}
/*{
"data": [
{
"id": 72,
"createdAt": "2023-12-12T02:43:53.793Z",
"updatedAt": "2023-12-12T05:41:33.300Z",
"key": "fzk3j2oj4el",
"title": "a11",
"enabled": true,
"description": null,
"type": "collection",
"config": {},
"useTransaction": true,
"executed": 0,
"allExecuted": 0,
"current": true,
"options": {
"deleteExecutionOnStatus": []
}
}
]
}*/
return (await result.json()).data;
};
// 删除工作流
export const apiDeleteWorkflow = async (id: number) => {
const api = await request.newContext({
storageState: process.env.PLAYWRIGHT_AUTH_FILE,
});
const state = await api.storageState();
const headers = getHeaders(state);
const result = await api.post(`/api/workflows:destroy?filterByTk=${id}`, {
headers,
});
if (!result.ok()) {
throw new Error(await result.text());
}
// {"data":1}
return (await result.json()).data;
};
// 查询工作流
export const apiGetWorkflow = async (id: number) => {
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/workflows:get?filterByTk=${id}`, {
headers,
});
if (!result.ok()) {
throw new Error(await result.text());
}
/*
{
"data": {
"id": 73,
"createdAt": "2023-12-12T05:59:52.741Z",
"updatedAt": "2023-12-12T05:59:52.741Z",
"key": "1iuin0qchrh",
"title": "t2",
"enabled": false,
"description": null,
"type": "collection",
"config": { },
"useTransaction": true,
"executed": 0,
"allExecuted": 0,
"current": true,
"options": { }
}
}
*/
return (await result.json()).data;
};
// 更新工作流触发器节点
export const apiUpdateWorkflowTrigger = async (id: number, data: any) => {
const api = await request.newContext({
storageState: process.env.PLAYWRIGHT_AUTH_FILE,
});
const state = await api.storageState();
const headers = getHeaders(state);
/*
{
"config": {
"appends": [
"dept"
],
"collection": "tt_mnt_org",
"changed": [],
"condition": {
"$and": [
{
"id": {
"$eq": 1
}
}
]
},
"mode": 1
}
}
*/
const result = await api.post(`/api/workflows:update?filterByTk=${id}`, {
headers,
data,
});
if (!result.ok()) {
throw new Error(await result.text());
}
/*
{
"data": [
{
"id": 73,
"createdAt": "2023-12-12T05:59:52.741Z",
"updatedAt": "2023-12-12T06:13:36.068Z",
"key": "1iuin0qchrh",
"title": "t2",
"enabled": false,
"description": null,
"type": "collection",
"config": {
"appends": [
"dept"
],
"collection": "tt_mnt_org",
"changed": [],
"condition": {
"$and": [
{
"id": {
"$eq": 1
}
}
]
},
"mode": 1
},
"useTransaction": true,
"executed": 0,
"allExecuted": 0,
"current": true,
"options": {}
}
]
}
*/
return (await result.json()).data;
};
// 添加工作流节点
export const apiCreateWorkflowNode = async (workflowId: number, data: any) => {
const api = await request.newContext({
storageState: process.env.PLAYWRIGHT_AUTH_FILE,
});
const state = await api.storageState();
const headers = getHeaders(state);
/*upstreamIdid ,null
{
"type": "calculation",
"upstreamId": 263,
"branchIndex": null,
"title": "运算",
"config": {}
}
*/
const result = await api.post(`/api/workflows/${workflowId}/nodes:create`, {
headers,
data,
});
if (!result.ok()) {
throw new Error(await result.text());
}
/*
{
"data": {
"id": 265,
"type": "calculation",
"upstreamId": null,
"branchIndex": null,
"title": "运算",
"config": {},
"workflowId": 76,
"updatedAt": "2023-12-16T10:56:39.288Z",
"createdAt": "2023-12-16T10:56:39.281Z",
"key": "20jz2urt5w7",
"downstreamId": 263
}
}
*/
return (await result.json()).data;
};
// 查询工作流节点
export const apiGetWorkflowNode = async (id: number) => {
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/flow_nodes:get?filterByTk=${id}`, {
headers,
});
if (!result.ok()) {
throw new Error(await result.text());
}
/*
{
"data": {
"id": 267,
"createdAt": "2023-12-17T06:56:10.147Z",
"updatedAt": "2023-12-17T08:53:38.117Z",
"key": "idr5wibhyqn",
"title": "查询数据",
"upstreamId": 269,
"branchIndex": null,
"downstreamId": 270,
"type": "query",
"config": {
"collection": "users",
"params": {
"filter": {
"$and": [
{
"id": {
"$eq": "{{$context.data.id}}"
}
}
]
},
"sort": [],
"page": 1,
"pageSize": 20,
"appends": []
}
},
"workflowId": 76
}
}
*/
return (await result.json()).data;
};
// 更新工作流节点配置
export const apiUpdateWorkflowNode = async (id: number, data: any) => {
const api = await request.newContext({
storageState: process.env.PLAYWRIGHT_AUTH_FILE,
});
const state = await api.storageState();
const headers = getHeaders(state);
/*
{
"config": {
"engine": "math.js",
"expression": "1"
}
}
*/
const result = await api.post(`/api/flow_nodes:update?filterByTk=${id}`, {
headers,
data,
});
if (!result.ok()) {
throw new Error(await result.text());
}
/*
{
"data": [
{
"id": 266,
"createdAt": "2023-12-16T10:56:58.586Z",
"updatedAt": "2023-12-16T11:16:32.796Z",
"key": "atbyvcs5mwc",
"title": "运算",
"upstreamId": 263,
"branchIndex": null,
"downstreamId": null,
"type": "calculation",
"config": {
"engine": "math.js",
"expression": "1"
},
"workflowId": 76
}
]
}
*/
return (await result.json()).data;
};
// 查询节点执行历史
export const apiGetWorkflowNodeExecutions = async (id: number) => {
const api = await request.newContext({
storageState: process.env.PLAYWRIGHT_AUTH_FILE,
});
const state = await api.storageState();
const headers = getHeaders(state);
const url = `/api/executions:list?appends[]=jobs&filter[workflowId]=${id}&fields=id,createdAt,updatedAt,key,status,workflowId,jobs`;
const result = await api.get(url, {
headers,
});
if (!result.ok()) {
throw new Error(await result.text());
}
/*
{
"data": [
{
"id": 15,
"createdAt": "2023-12-13T02:13:13.737Z",
"updatedAt": "2023-12-13T02:13:13.799Z",
"key": "yibkv8h2uq6",
"useTransaction": false,
"status": 1,
"workflowId": 16,
"jobs": [
{
"id": 16,
"createdAt": "2023-12-13T02:13:13.783Z",
"updatedAt": "2023-12-13T02:13:13.783Z",
"executionId": 15,
"nodeId": 16,
"upstreamId": null,
"status": 1,
"result": false
},
{
"id": 17,
"createdAt": "2023-12-13T02:13:13.788Z",
"updatedAt": "2023-12-13T02:13:13.788Z",
"executionId": 15,
"nodeId": 17,
"upstreamId": 16,
"status": 1,
"result": true
}
]
},
{
"id": 14,
"createdAt": "2023-12-13T02:09:00.529Z",
"updatedAt": "2023-12-13T02:09:00.590Z",
"key": "yibkv8h2uq6",
"useTransaction": false,
"status": 1,
"workflowId": 16,
"jobs": [
{
"id": 14,
"createdAt": "2023-12-13T02:09:00.575Z",
"updatedAt": "2023-12-13T02:09:00.575Z",
"executionId": 14,
"nodeId": 16,
"upstreamId": null,
"status": 1,
"result": false
},
{
"id": 15,
"createdAt": "2023-12-13T02:09:00.583Z",
"updatedAt": "2023-12-13T02:09:00.583Z",
"executionId": 14,
"nodeId": 17,
"upstreamId": 14,
"status": 1,
"result": true
}
]
}
],
"meta": {
"count": 2,
"page": 1,
"pageSize": 20,
"totalPage": 1
}
}
*/
return (await result.json()).data;
};
// 更新业务表单条数据
export const apiUpdateRecord = async (collectionName: string, id: number, data: any) => {
const api = await request.newContext({
storageState: process.env.PLAYWRIGHT_AUTH_FILE,
});
const state = await api.storageState();
const headers = getHeaders(state);
const result = await api.post(`/api/${collectionName}:update?filterByTk=${id}`, {
headers,
data,
});
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
}
]
}
*/
return (await result.json()).data;
};
// 查询业务表单条数据
export const apiGetRecord = async (collectionName: string, id: number) => {
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}:get?filterByTk=${id}`, {
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": {
"allowedActions": {
"view": [
1
],
"update": [
1
],
"destroy": [
1
]
}
}
}
*/
return (await result.json()).data;
};
// 查询业务表list
export const apiGetList = async (collectionName: 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`, {
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({
storageState: process.env.PLAYWRIGHT_AUTH_FILE,
});
const state = await api.storageState();
const headers = getHeaders(state);
/*
{
"title": "a11",
"enabled": true,
"description": null
}
*/
const result = await api.post(`/api/${collectionName}:create?triggerWorkflows=${triggerWorkflows}`, {
headers,
data,
});
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": {
"allowedActions": {
"view": [
1
],
"update": [
1
],
"destroy": [
1
]
}
}
}
*/
return (await result.json()).data;
};
// 提交至工作流触发工作流表单事件
export const apiSubmitRecordTriggerFormEvent = async (triggerWorkflows: string, data: any) => {
const api = await request.newContext({
storageState: process.env.PLAYWRIGHT_AUTH_FILE,
});
const state = await api.storageState();
const headers = getHeaders(state);
/*
{
"title": "a11",
"enabled": true,
"description": null
}
*/
const result = await api.post(`/api/workflows:trigger?triggerWorkflows=${triggerWorkflows}`, {
headers,
data,
});
if (!result.ok()) {
throw new Error(await result.text());
}
/*
{}
*/
return await result.json();
};
const getStorageItem = (key: string, storageState: any) => {
return storageState.origins
.find((item) => item.origin === APP_BASE_URL)
?.localStorage.find((item) => item.name === key)?.value;
};
function getHeaders(storageState: any) {
const headers: any = {};
const token = getStorageItem('NOCOBASE_TOKEN', storageState);
const auth = getStorageItem('NOCOBASE_AUTH', storageState);
const subAppName = new URL(APP_BASE_URL).pathname.match(/^\/apps\/([^/]*)\/*/)?.[1];
const hostName = new URL(APP_BASE_URL).host;
const locale = getStorageItem('NOCOBASE_LOCALE', storageState);
const timezone = '+08:00';
const withAclMeta = 'true';
const role = getStorageItem('NOCOBASE_ROLE', storageState);
if (token) {
headers.Authorization = `Bearer ${token}`;
}
if (auth) {
headers['X-Authenticator'] = auth;
}
if (subAppName) {
headers['X-App'] = subAppName;
}
if (hostName) {
headers['X-Hostname'] = hostName;
}
if (locale) {
headers['X-Locale'] = locale;
}
if (timezone) {
headers['X-Timezone'] = timezone;
}
if (withAclMeta) {
headers['X-With-Acl-Meta'] = withAclMeta;
}
if (role) {
headers['X-Role'] = role;
}
return headers;
}
export default module.exports = {
apiCreateWorkflow,
apiUpdateWorkflow,
apiDeleteWorkflow,
apiGetWorkflow,
apiUpdateWorkflowTrigger,
apiGetWorkflowNodeExecutions,
apiCreateWorkflowNode,
apiUpdateWorkflowNode,
apiGetWorkflowNode,
apiUpdateRecord,
apiGetRecord,
apiGetList,
apiCreateRecordTriggerFormEvent,
apiSubmitRecordTriggerFormEvent,
};

View File

@ -0,0 +1,4 @@
export * from './e2eCollectionModel';
export * from './e2ePageObjectModel';
export { default } from './e2ePageObjectModel';
export * from './e2eUtils';

View File

@ -0,0 +1,360 @@
import { faker } from '@faker-js/faker';
import {
CreateWorkFlow,
EditWorkFlow,
ScheduleTriggerNode,
WorkflowListRecords,
apiCreateWorkflow,
apiDeleteWorkflow,
apiGetWorkflow,
apiUpdateWorkflowTrigger,
appendJsonCollectionName,
generalWithNoRelationalFields,
} from '@nocobase/plugin-workflow-test/e2e';
import { expect, test } from '@nocobase/test/e2e';
import { dayjs } from '@nocobase/utils';
test.describe('Configuration page to configure the Trigger node', () => {
test('Triggered one minute after the current time of the customized time', async ({
page,
mockCollections,
mockRecords,
}) => {
test.setTimeout(120000);
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
//添加工作流
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'schedule',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
//配置工作流触发器
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const scheduleTriggerNode = new ScheduleTriggerNode(page, workFlowName, triggerNodeCollectionName);
await scheduleTriggerNode.nodeConfigure.click();
await scheduleTriggerNode.startTimeEntryBox.click();
await scheduleTriggerNode.startTimeEntryBox.fill(dayjs().add(60, 'second').format('YYYY-MM-DD HH:mm:ss'));
await page.getByRole('button', { name: 'OK', exact: true }).click();
await scheduleTriggerNode.submitButton.click();
// 2、测试步骤等待60秒
await page.waitForTimeout(60000);
// 3、预期结果工作流成功触发
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Configuration Page Path Jump Workflow Management Page', () => {
test('Schedule event Workflow Configuration Page Path Jump Workflow Management Page', async ({ page }) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
// const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
// const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
// const triggerNodeFieldName = 'orgname';
// const triggerNodeFieldDisplayName = '公司名称(单行文本)';
// await mockCollections(appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText).collections);
//添加工作流
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'schedule',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
//配置工作流触发器
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
// 2、测试步骤跳转到工作流管理页面
await page.getByRole('link', { name: 'Workflow' }).click();
// 3、预期结果跳转路径正确
await page.waitForLoadState('networkidle');
expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Schedule event Workflow History Version Configuration Page Path Jump Workflow Management Page', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
//添加工作流
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'schedule',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
//配置工作流触发器
const now = new Date();
now.setMinutes(now.getMinutes() + 1);
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
const timeWithTimeZone = now.toLocaleString('en-US', { timeZone: timeZone });
const triggerNodeData = { config: { mode: 0, startsOn: timeWithTimeZone } };
const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
// 2、测试步骤等待60秒
await page.waitForTimeout(60000);
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
await page.getByLabel('more').click();
await page.getByLabel('revision').click();
await page.waitForLoadState('networkidle');
//元素重复
await page.getByLabel('version', { exact: true }).click();
await page.getByLabel('version-1').click();
await page.getByRole('link', { name: 'Workflow' }).click();
// 3、预期结果跳转路径正确
await page.waitForLoadState('networkidle');
expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Schedule event Workflow Execution Log Page Path Jump Workflow Management Page', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
//添加工作流
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'schedule',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
//配置工作流触发器
const now = new Date();
now.setMinutes(now.getMinutes() + 1);
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
const timeWithTimeZone = now.toLocaleString('en-US', { timeZone: timeZone });
const triggerNodeData = { config: { mode: 0, startsOn: timeWithTimeZone } };
const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
// 2、测试步骤等待60秒
await page.waitForTimeout(60000);
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
const workflowListRecords = new WorkflowListRecords(page, workFlowName);
await workflowListRecords.executionCountPopup.click();
await page.getByText('View').click();
await page.waitForLoadState('networkidle');
await page.getByRole('link', { name: 'Workflow', exact: true }).click();
// 3、预期结果跳转路径正确
await page.waitForLoadState('networkidle');
expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test.skip('Schedule event Workflow Execution Log Page Path Jump Execution Log Screen', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
//添加工作流
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'schedule',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
//配置工作流触发器
const now = new Date();
now.setMinutes(now.getMinutes() + 1);
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
const timeWithTimeZone = now.toLocaleString('en-US', { timeZone: timeZone });
const triggerNodeData = { config: { mode: 0, startsOn: timeWithTimeZone } };
const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
// 2、测试步骤等待60秒
await page.waitForTimeout(60000);
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
const workflowListRecords = new WorkflowListRecords(page, workFlowName);
await workflowListRecords.executionCountPopup.click();
await page.getByText('View').click();
await page.waitForLoadState('networkidle');
//跳转其他执行日志界面,元素无法定位
// 3、预期结果跳转路径正确
await page.waitForLoadState('networkidle');
// expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Configuration page version switching', () => {});
test.describe('Configuration page disable enable', () => {});
test.describe('Configuration page execution history', () => {});
test.describe('Configuration page copy to new version', () => {
test('Copy the Schedule event of the Configuration Trigger node', async ({ page, mockCollections, mockRecords }) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
//添加工作流
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'schedule',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
//配置工作流触发器
const now = new Date();
now.setMinutes(now.getMinutes() + 1);
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
const timeWithTimeZone = now.toLocaleString('en-US', { timeZone: timeZone });
const triggerNodeData = { config: { mode: 0, startsOn: timeWithTimeZone } };
const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
// 2、测试步骤等待60秒
await page.waitForTimeout(60000);
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
const workflowListRecords = new WorkflowListRecords(page, workFlowName);
await workflowListRecords.configureAction.click();
await page.getByLabel('more').click();
await page.getByLabel('revision').click();
await page.waitForLoadState('networkidle');
const scheduleTriggerNode = new ScheduleTriggerNode(page, workFlowName, triggerNodeCollectionName);
await scheduleTriggerNode.nodeConfigure.click();
// 3、预期结果startTime时间为60秒后的时间
const timeWithoutTimeZonea = now.toLocaleString('en-US', { timeZone: timeZone, hour12: false });
// 将 MM/DD/YYYY, HH:mm:ss 格式的字符串转换为 YYYY-MM-DD HH:mm:ss 格式
const parts = timeWithoutTimeZonea.split(/[\s,/:]+/);
const formattedTimeWithTimeZone = `${parts[2]}-${parts[0].padStart(2, '0')}-${parts[1].padStart(2, '0')} ${
parts[3]
}:${parts[4]}:${parts[5]}`;
await expect(scheduleTriggerNode.startTimeEntryBox).toHaveValue(formattedTimeWithTimeZone);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Configuration page delete version', () => {});
test.describe('Node Add Modify Delete', () => {});

View File

@ -0,0 +1,174 @@
import { faker } from '@faker-js/faker';
import {
CreateWorkFlow,
EditWorkFlow,
ScheduleTriggerNode,
WorkflowListRecords,
apiCreateWorkflow,
apiDeleteWorkflow,
apiGetWorkflow,
apiUpdateWorkflowTrigger,
appendJsonCollectionName,
generalWithNoRelationalFields,
} from '@nocobase/plugin-workflow-test/e2e';
import { expect, test } from '@nocobase/test/e2e';
import { dayjs } from '@nocobase/utils';
test.describe('Filter', () => {
test('filter workflow name', async ({ page }) => {
//添加工作流
const triggerNodeAppendText = faker.string.alphanumeric(5);
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'schedule',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
// 2、筛选工作流
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
await page.getByRole('textbox').fill(workFlowName);
await page.getByRole('button', { name: 'Submit', exact: true }).click();
// 3、预期结果列表中出现筛选的工作流
await expect(page.getByText(workFlowName)).toBeAttached();
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Add new', () => {
test('add new Schedule event', async ({ page }) => {
// 添加工作流
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
await page.getByLabel('action-Action-Add new-workflows').click();
const createWorkFlow = new CreateWorkFlow(page);
const workFlowName = faker.string.alphanumeric(5);
await createWorkFlow.name.fill(workFlowName);
await createWorkFlow.triggerType.click();
await page.getByRole('option', { name: 'Schedule event' }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
// 3、预期结果列表中出现新建的工作流
await expect(page.getByText(workFlowName)).toBeVisible();
// 4、后置处理删除工作流
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
await page.getByRole('textbox').fill(workFlowName);
await page.getByRole('button', { name: 'Submit', exact: true }).click();
await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName}`).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
await expect(page.getByText(workFlowName)).toBeHidden();
});
});
test.describe('Sync', () => {});
test.describe('Delete', () => {
test('delete Schedule event', async ({ page }) => {
//添加工作流
const triggerNodeAppendText = faker.string.alphanumeric(5);
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'schedule',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
// 删除工作流
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
await page.getByRole('textbox').fill(workFlowName);
await page.getByRole('button', { name: 'Submit', exact: true }).click();
await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName}`).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
// 3、预期结果列表中出现筛选的工作流
await expect(page.getByText(workFlowName)).toBeHidden();
// 4、后置处理删除工作流
});
});
test.describe('Edit', () => {
test('edit Schedule event name', async ({ page }) => {
//添加工作流
const triggerNodeAppendText = faker.string.alphanumeric(5);
let workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'schedule',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
// 编辑工作流
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
await page.getByLabel(`action-Action.Link-Edit-workflows-${workFlowName}`).click();
const editWorkFlow = new EditWorkFlow(page, workFlowName);
workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
await editWorkFlow.name.fill(workFlowName);
await page.getByLabel('action-Action-Submit-workflows').click();
await page.waitForLoadState('networkidle');
// 3、预期结果编辑成功列表中出现编辑后的工作流
await expect(page.getByText(workFlowName)).toBeAttached();
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Duplicate', () => {
test('Duplicate Schedule event triggers with only unconfigured trigger nodes', async ({ page }) => {
//添加工作流
const triggerNodeAppendText = faker.string.alphanumeric(5);
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'schedule',
enabled: true,
};
const workflow = await apiCreateWorkflow(workflowData);
const workflowObj = JSON.parse(JSON.stringify(workflow));
const workflowId = workflowObj.id;
// 2、复制工作流
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
await page.getByLabel(`action-Action.Link-Duplicate-workflows-${workFlowName}`).click();
await page.getByLabel(`action-Action-Submit-workflows-${workFlowName}`).click();
// 3、预期结果列表中出现筛选的工作流
await expect(page.getByText(`${workFlowName} copy`)).toBeAttached();
// 4、后置处理删除工作流
await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName} copy`).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
await expect(page.getByText(`${workFlowName} copy`)).toBeHidden();
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Executed', () => {});

View File

@ -0,0 +1,761 @@
import { faker } from '@faker-js/faker';
import {
AggregateNode,
ClculationNode,
CollectionTriggerNode,
CreateRecordNode,
QueryRecordNode,
apiCreateWorkflow,
apiCreateWorkflowNode,
apiDeleteWorkflow,
apiGetWorkflow,
apiGetWorkflowNode,
apiGetWorkflowNodeExecutions,
apiUpdateWorkflowNode,
apiUpdateWorkflowTrigger,
appendJsonCollectionName,
generalWithNoRelationalFields,
} from '@nocobase/plugin-workflow-test/e2e';
import { expect, test } from '@nocobase/test/e2e';
import { dayjs } from '@nocobase/utils';
test('Collection event add data trigger, get trigger node single line text variable', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置计算节点
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: 'calculation', exact: true }).click();
const calculationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Calculation-Calculation', { exact: true }).getByRole('textbox').fill(calculationNodeName);
const calculationNode = new ClculationNode(page, calculationNodeName);
await calculationNode.nodeConfigure.click();
await calculationNode.formulaCalculationEngine.click();
await page.getByLabel('variable-button').click();
await page.getByText('Trigger variables').click();
await page.getByText('Trigger data').click();
await page.getByText('公司名称(单行文本)').click();
await expect(page.getByLabel('textbox')).toHaveText('Trigger variables / Trigger data / 公司名称(单行文本)');
await calculationNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const getWorkflowNodeExecutionsObjResult = getWorkflowNodeExecutionsObj[0].jobs[0].result;
expect(getWorkflowNodeExecutionsObjResult).toBe(triggerNodeCollectionRecordOne);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data triggers, get predecessor Formula engine arithmetic node data', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置前置计算节点
const preCalculationNodeTitle = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preCalculationNodeData = {
type: 'calculation',
upstreamId: null,
branchIndex: null,
title: preCalculationNodeTitle,
config: { engine: 'formula.js', expression: '{{$context.data.orgname}}' },
};
const preCalculationNode = await apiCreateWorkflowNode(workflowId, preCalculationNodeData);
const preCalculationNodeObj = JSON.parse(JSON.stringify(preCalculationNode));
const preCalculationNodeId = preCalculationNodeObj.id;
const getPreCalculationNode = await apiGetWorkflowNode(preCalculationNodeId);
const preCalculationNodeKey = getPreCalculationNode.key;
//配置计算节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const preCalculationNodePom = new ClculationNode(page, preCalculationNodeTitle);
await preCalculationNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'calculation', exact: true }).click();
const calculationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Calculation-Calculation', { exact: true }).getByRole('textbox').fill(calculationNodeName);
const calculationNode = new ClculationNode(page, calculationNodeName);
const conditionNodeId = await calculationNode.node.locator('.workflow-node-id').innerText();
await calculationNode.nodeConfigure.click();
await calculationNode.formulaCalculationEngine.click();
await page.getByLabel('variable-button').click();
await page.getByText('Node result').click();
await page.getByRole('menuitemcheckbox', { name: preCalculationNodeTitle }).click();
await expect(page.getByLabel('textbox')).toHaveText(`Node result / ${preCalculationNodeTitle}`);
await calculationNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const job = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(job.result).toBe(triggerNodeCollectionRecordOne);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection events add data triggers, get single line of text data for front query data nodes', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置前置查询节点
const preQueryRecordNodeTitle = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preQueryRecordNodeData = {
type: 'query',
upstreamId: null,
branchIndex: null,
title: preQueryRecordNodeTitle,
config: {
collection: triggerNodeCollectionName,
params: {
filter: { $and: [{ id: { $eq: '{{$context.data.id}}' } }] },
sort: [],
page: 1,
pageSize: 20,
appends: [],
},
},
};
const preQueryRecordNode = await apiCreateWorkflowNode(workflowId, preQueryRecordNodeData);
const preQueryRecordNodeObj = JSON.parse(JSON.stringify(preQueryRecordNode));
const preQueryRecordNodeId = preQueryRecordNodeObj.id;
const getPreQueryRecordNode = await apiGetWorkflowNode(preQueryRecordNodeId);
const preQueryRecordNodeKey = getPreQueryRecordNode.key;
//配置计算节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'calculation', exact: true }).click();
const calculationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Calculation-Calculation', { exact: true }).getByRole('textbox').fill(calculationNodeName);
const calculationNode = new ClculationNode(page, calculationNodeName);
const conditionNodeId = await calculationNode.node.locator('.workflow-node-id').innerText();
await calculationNode.nodeConfigure.click();
await calculationNode.formulaCalculationEngine.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Node result' }).click();
await page.getByRole('menuitemcheckbox', { name: preQueryRecordNodeTitle }).click();
await page.getByRole('menuitemcheckbox', { name: '公司名称(单行文本)' }).click();
await expect(page.getByLabel('textbox')).toHaveText(`Node result / ${preQueryRecordNodeTitle} / 公司名称(单行文本)`);
await calculationNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const job = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(job.result).toBe(triggerNodeCollectionRecordOne);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, get front added data node single line text data', async ({
page,
mockCollections,
mockRecords,
}) => {
//创建触发器节点数据表
const triggerNodeAppendText = faker.string.alphanumeric(5);
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
// 创建新增数据节点数据表
const createRecordNodeAppendText = faker.string.alphanumeric(6);
const createRecordNodeCollectionDisplayName = `自动>组织[普通表]${createRecordNodeAppendText}`;
const createRecordNodeCollectionName = `tt_amt_org${createRecordNodeAppendText}`;
const createRecordNodeFieldName = 'orgname';
const createRecordNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), createRecordNodeAppendText)
.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));
//配置前置添加数据节点
const preCreateRecordNodeTitle = 'Create record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preCreateRecordNodeData = {
type: 'create',
upstreamId: null,
branchIndex: null,
title: preCreateRecordNodeTitle,
config: {
params: { values: { orgname: '{{$context.data.orgname}}' }, appends: [] },
collection: createRecordNodeCollectionName,
},
};
const preCreateRecordNode = await apiCreateWorkflowNode(workflowId, preCreateRecordNodeData);
const preCreateRecordNodeObj = JSON.parse(JSON.stringify(preCreateRecordNode));
const preCreateRecordNodeId = preCreateRecordNodeObj.id;
const getPreCreateRecordNode = await apiGetWorkflowNode(preCreateRecordNodeId);
const preCreateRecordNodeKey = getPreCreateRecordNode.key;
//配置计算节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const preCreateRecordNodePom = new CreateRecordNode(page, preCreateRecordNodeTitle);
await preCreateRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'calculation', exact: true }).click();
const calculationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Calculation-Calculation', { exact: true }).getByRole('textbox').fill(calculationNodeName);
const calculationNode = new ClculationNode(page, calculationNodeName);
const conditionNodeId = await calculationNode.node.locator('.workflow-node-id').innerText();
await calculationNode.nodeConfigure.click();
await calculationNode.formulaCalculationEngine.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Node result' }).click();
await page.getByRole('menuitemcheckbox', { name: preCreateRecordNodeTitle }).click();
await page.getByRole('menuitemcheckbox', { name: '公司名称(单行文本)' }).click();
await expect(page.getByLabel('textbox')).toHaveText(`Node result / ${preCreateRecordNodeTitle} / 公司名称(单行文本)`);
await calculationNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const job = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(job.result).toBe(triggerNodeCollectionRecordOne);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event adds data triggers, fetches data from front-end aggregation query nodes', async ({
page,
mockCollections,
mockRecords,
}) => {
//创建触发器节点数据表
const triggerNodeAppendText = faker.string.alphanumeric(5);
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置前置聚合查询节点
const preAggregateNodeTitle = 'Aggregate' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preAggregateNodeData = {
type: 'aggregate',
upstreamId: null,
branchIndex: null,
title: preAggregateNodeTitle,
config: {
aggregator: 'count',
associated: false,
params: { field: 'id', filter: { $and: [] } },
collection: triggerNodeCollectionName,
},
};
const preAggregateNode = await apiCreateWorkflowNode(workflowId, preAggregateNodeData);
const preAggregateNodeObj = JSON.parse(JSON.stringify(preAggregateNode));
const preAggregateNodeId = preAggregateNodeObj.id;
const getPreAggregateNode = await apiGetWorkflowNode(preAggregateNodeId);
const preAggregateNodeKey = getPreAggregateNode.key;
//配置计算节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const preAggregateNodePom = new AggregateNode(page, preAggregateNodeTitle);
await preAggregateNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'calculation', exact: true }).click();
const calculationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Calculation-Calculation', { exact: true }).getByRole('textbox').fill(calculationNodeName);
const calculationNode = new ClculationNode(page, calculationNodeName);
const conditionNodeId = await calculationNode.node.locator('.workflow-node-id').innerText();
await calculationNode.nodeConfigure.click();
await calculationNode.formulaCalculationEngine.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Node result' }).click();
await page.getByRole('menuitemcheckbox', { name: preAggregateNodeTitle }).click();
await expect(page.getByLabel('textbox')).toHaveText(`Node result / ${preAggregateNodeTitle}`);
await calculationNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const job = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(job.result).toBe(1);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test.skip('Collection event add data trigger, get front manual node add form single line text data', async ({
page,
mockCollections,
mockRecords,
}) => {
// 创建触发器节点数据表
const triggerNodeAppendText = faker.string.alphanumeric(5);
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
// 创建人工节点数据表
const manualNodeAppendText = faker.string.alphanumeric(5);
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));
//配置前置人工节点新增数据表单
const preManualNodeNodeTitle = 'Manual' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preManualNodeNodeCustomFormTitle = 'Custom form' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preManualNodeNodeData = { type: 'manual', upstreamId: null, branchIndex: null, title: 'Manual', config: {} };
const preManualNodeNode = await apiCreateWorkflowNode(workflowId, preManualNodeNodeData);
const preManualNodeNodeObj = JSON.parse(JSON.stringify(preManualNodeNode));
const preManualNodeNodeId = preManualNodeNodeObj.id;
const getPreManualNodeNode = await apiGetWorkflowNode(preManualNodeNodeId);
const preAggregateNodeKey = getPreManualNodeNode.key;
const preManualNodeNodeConfig = {
config: {
assignees: [1],
schema: {
tab1: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
title: '{{t("Manual", { ns: "workflow-manual" })}}',
'x-component': 'Tabs.TabPane',
'x-designer': 'Tabs.Designer',
properties: {
grid: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid',
'x-initializer': 'AddBlockButton',
name: 'grid',
properties: {
'59t231zx5vx': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
properties: {
'13do6fj5t73': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
properties: {
krb1bo0p486: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-decorator': 'FormBlockProvider',
'x-decorator-props': {
formType: 'create',
resource: 'tt_mnt_org',
collection: 'tt_mnt_org',
},
'x-designer': 'CreateFormDesigner',
'x-component': 'CardItem',
'x-component-props': {
title: 'Create record4567',
},
properties: {
kzqri0ib7ji: {
_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',
name: 'grid',
properties: {
yt2rbpepdsl: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
properties: {
eptw1hy20lm: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
properties: {
orgname: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'string',
name: 'orgname',
'x-designer': 'FormItem.Designer',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-collection-field': `${manualNodeCollectionName}.${manualNodeFieldName}`,
'x-component-props': {},
},
},
name: 'eptw1hy20lm',
},
},
name: 'yt2rbpepdsl',
},
},
},
actions: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-initializer': 'AddActionButton',
'x-component': 'ActionBar',
'x-component-props': {
layout: 'one-column',
style: {
marginTop: '1.5em',
flexWrap: 'wrap',
},
},
properties: {
resolve: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
title: '{{t("Continue the process", { ns: "workflow-manual" })}}',
'x-decorator': 'ManualActionStatusProvider',
'x-decorator-props': {
value: 1,
},
'x-component': 'Action',
'x-component-props': {
type: 'primary',
useAction: '{{ useSubmit }}',
},
'x-designer': 'ManualActionDesigner',
'x-designer-props': {},
name: 'resolve',
},
},
'x-decorator': 'ActionBarProvider',
name: 'actions',
},
},
name: 'kzqri0ib7ji',
},
},
name: 'krb1bo0p486',
},
},
name: '13do6fj5t73',
},
},
name: '59t231zx5vx',
},
},
},
},
name: 'tab1',
},
},
forms: {
kzqri0ib7ji: {
type: 'create',
title: preManualNodeNodeCustomFormTitle,
actions: [
{
status: 1,
key: 'resolve',
},
],
collection: manualNodeCollectionName,
},
},
},
};
await apiUpdateWorkflowNode(preManualNodeNodeId, preManualNodeNodeConfig);
//配置计算节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const preManualNodeNodePom = new AggregateNode(page, preManualNodeNodeTitle);
await preManualNodeNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'calculation', exact: true }).click();
const calculationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Calculation-Calculation', { exact: true }).getByRole('textbox').fill(calculationNodeName);
const calculationNode = new ClculationNode(page, calculationNodeName);
const conditionNodeId = await calculationNode.node.locator('.workflow-node-id').innerText();
await calculationNode.nodeConfigure.click();
await calculationNode.formulaCalculationEngine.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Node result' }).click();
await page.getByRole('menuitemcheckbox', { name: preManualNodeNodeTitle }).click();
await page.getByRole('menuitemcheckbox', { name: preManualNodeNodeCustomFormTitle }).click();
await page.getByRole('menuitemcheckbox', { name: '公司名称(单行文本)' }).click();
await expect(page.getByLabel('textbox')).toHaveText(
`Node result / ${preManualNodeNodeTitle} / ${preManualNodeNodeCustomFormTitle} / 公司名称(单行文本)`,
);
await calculationNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// api请求办理人工节点
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const job = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(job.result).toBe(triggerNodeCollectionRecordOne);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});

View File

@ -0,0 +1,755 @@
import { faker } from '@faker-js/faker';
import {
AggregateNode,
ClculationNode,
CollectionTriggerNode,
CreateRecordNode,
QueryRecordNode,
apiCreateWorkflow,
apiCreateWorkflowNode,
apiDeleteWorkflow,
apiGetWorkflow,
apiGetWorkflowNode,
apiGetWorkflowNodeExecutions,
apiUpdateWorkflowNode,
apiUpdateWorkflowTrigger,
appendJsonCollectionName,
generalWithNoRelationalFields,
} from '@nocobase/plugin-workflow-test/e2e';
import { expect, test } from '@nocobase/test/e2e';
import { dayjs } from '@nocobase/utils';
test('Collection event add data trigger, get trigger node single line text variable', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置计算节点
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: 'calculation', exact: true }).click();
const calculationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Calculation-Calculation', { exact: true }).getByRole('textbox').fill(calculationNodeName);
const calculationNode = new ClculationNode(page, calculationNodeName);
await calculationNode.nodeConfigure.click();
await page.getByLabel('variable-button').click();
await page.getByText('Trigger variables').click();
await page.getByText('Trigger data').click();
await page.getByText('公司名称(单行文本)').click();
await expect(page.getByLabel('textbox')).toHaveText('Trigger variables / Trigger data / 公司名称(单行文本)');
await calculationNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const getWorkflowNodeExecutionsObjResult = getWorkflowNodeExecutionsObj[0].jobs[0].result;
expect(getWorkflowNodeExecutionsObjResult).toBe(triggerNodeCollectionRecordOne);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data triggers, get predecessor Math engine arithmetic node data', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置前置计算节点
const preCalculationNodeTitle = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preCalculationNodeData = {
type: 'calculation',
upstreamId: null,
branchIndex: null,
title: preCalculationNodeTitle,
config: { engine: 'math.js', expression: '{{$context.data.orgname}}' },
};
const preCalculationNode = await apiCreateWorkflowNode(workflowId, preCalculationNodeData);
const preCalculationNodeObj = JSON.parse(JSON.stringify(preCalculationNode));
const preCalculationNodeId = preCalculationNodeObj.id;
const getPreCalculationNode = await apiGetWorkflowNode(preCalculationNodeId);
const preCalculationNodeKey = getPreCalculationNode.key;
//配置计算节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const preCalculationNodePom = new ClculationNode(page, preCalculationNodeTitle);
await preCalculationNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'calculation', exact: true }).click();
const calculationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Calculation-Calculation', { exact: true }).getByRole('textbox').fill(calculationNodeName);
const calculationNode = new ClculationNode(page, calculationNodeName);
const conditionNodeId = await calculationNode.node.locator('.workflow-node-id').innerText();
await calculationNode.nodeConfigure.click();
await page.getByLabel('variable-button').click();
await page.getByText('Node result').click();
await page.getByRole('menuitemcheckbox', { name: preCalculationNodeTitle }).click();
await expect(page.getByLabel('textbox')).toHaveText(`Node result / ${preCalculationNodeTitle}`);
await calculationNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const job = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(job.result).toBe(triggerNodeCollectionRecordOne);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection events add data triggers, get single line of text data for front query data nodes', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置前置查询节点
const preQueryRecordNodeTitle = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preQueryRecordNodeData = {
type: 'query',
upstreamId: null,
branchIndex: null,
title: preQueryRecordNodeTitle,
config: {
collection: triggerNodeCollectionName,
params: {
filter: { $and: [{ id: { $eq: '{{$context.data.id}}' } }] },
sort: [],
page: 1,
pageSize: 20,
appends: [],
},
},
};
const preQueryRecordNode = await apiCreateWorkflowNode(workflowId, preQueryRecordNodeData);
const preQueryRecordNodeObj = JSON.parse(JSON.stringify(preQueryRecordNode));
const preQueryRecordNodeId = preQueryRecordNodeObj.id;
const getPreQueryRecordNode = await apiGetWorkflowNode(preQueryRecordNodeId);
const preQueryRecordNodeKey = getPreQueryRecordNode.key;
//配置计算节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'calculation', exact: true }).click();
const calculationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Calculation-Calculation', { exact: true }).getByRole('textbox').fill(calculationNodeName);
const calculationNode = new ClculationNode(page, calculationNodeName);
const conditionNodeId = await calculationNode.node.locator('.workflow-node-id').innerText();
await calculationNode.nodeConfigure.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Node result' }).click();
await page.getByRole('menuitemcheckbox', { name: preQueryRecordNodeTitle }).click();
await page.getByRole('menuitemcheckbox', { name: '公司名称(单行文本)' }).click();
await expect(page.getByLabel('textbox')).toHaveText(`Node result / ${preQueryRecordNodeTitle} / 公司名称(单行文本)`);
await calculationNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const job = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(job.result).toBe(triggerNodeCollectionRecordOne);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, get front added data node single line text data', async ({
page,
mockCollections,
mockRecords,
}) => {
//创建触发器节点数据表
const triggerNodeAppendText = faker.string.alphanumeric(5);
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
// 创建新增数据节点数据表
const createRecordNodeAppendText = faker.string.alphanumeric(6);
const createRecordNodeCollectionDisplayName = `自动>组织[普通表]${createRecordNodeAppendText}`;
const createRecordNodeCollectionName = `tt_amt_org${createRecordNodeAppendText}`;
const createRecordNodeFieldName = 'orgname';
const createRecordNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), createRecordNodeAppendText)
.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));
//配置前置添加数据节点
const preCreateRecordNodeTitle = 'Create record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preCreateRecordNodeData = {
type: 'create',
upstreamId: null,
branchIndex: null,
title: preCreateRecordNodeTitle,
config: {
params: { values: { orgname: '{{$context.data.orgname}}' }, appends: [] },
collection: createRecordNodeCollectionName,
},
};
const preCreateRecordNode = await apiCreateWorkflowNode(workflowId, preCreateRecordNodeData);
const preCreateRecordNodeObj = JSON.parse(JSON.stringify(preCreateRecordNode));
const preCreateRecordNodeId = preCreateRecordNodeObj.id;
const getPreCreateRecordNode = await apiGetWorkflowNode(preCreateRecordNodeId);
const preCreateRecordNodeKey = getPreCreateRecordNode.key;
//配置计算节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const preCreateRecordNodePom = new CreateRecordNode(page, preCreateRecordNodeTitle);
await preCreateRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'calculation', exact: true }).click();
const calculationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Calculation-Calculation', { exact: true }).getByRole('textbox').fill(calculationNodeName);
const calculationNode = new ClculationNode(page, calculationNodeName);
const conditionNodeId = await calculationNode.node.locator('.workflow-node-id').innerText();
await calculationNode.nodeConfigure.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Node result' }).click();
await page.getByRole('menuitemcheckbox', { name: preCreateRecordNodeTitle }).click();
await page.getByRole('menuitemcheckbox', { name: '公司名称(单行文本)' }).click();
await expect(page.getByLabel('textbox')).toHaveText(`Node result / ${preCreateRecordNodeTitle} / 公司名称(单行文本)`);
await calculationNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const job = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(job.result).toBe(triggerNodeCollectionRecordOne);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event adds data triggers, fetches data from front-end aggregation query nodes', async ({
page,
mockCollections,
mockRecords,
}) => {
//创建触发器节点数据表
const triggerNodeAppendText = faker.string.alphanumeric(5);
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置前置聚合查询节点
const preAggregateNodeTitle = 'Aggregate' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preAggregateNodeData = {
type: 'aggregate',
upstreamId: null,
branchIndex: null,
title: preAggregateNodeTitle,
config: {
aggregator: 'count',
associated: false,
params: { field: 'id', filter: { $and: [] } },
collection: triggerNodeCollectionName,
},
};
const preAggregateNode = await apiCreateWorkflowNode(workflowId, preAggregateNodeData);
const preAggregateNodeObj = JSON.parse(JSON.stringify(preAggregateNode));
const preAggregateNodeId = preAggregateNodeObj.id;
const getPreAggregateNode = await apiGetWorkflowNode(preAggregateNodeId);
const preAggregateNodeKey = getPreAggregateNode.key;
//配置计算节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const preAggregateNodePom = new AggregateNode(page, preAggregateNodeTitle);
await preAggregateNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'calculation', exact: true }).click();
const calculationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Calculation-Calculation', { exact: true }).getByRole('textbox').fill(calculationNodeName);
const calculationNode = new ClculationNode(page, calculationNodeName);
const conditionNodeId = await calculationNode.node.locator('.workflow-node-id').innerText();
await calculationNode.nodeConfigure.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Node result' }).click();
await page.getByRole('menuitemcheckbox', { name: preAggregateNodeTitle }).click();
await expect(page.getByLabel('textbox')).toHaveText(`Node result / ${preAggregateNodeTitle}`);
await calculationNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const job = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(job.result).toBe(1);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test.skip('Collection event add data trigger, get front manual node add form single line text data', async ({
page,
mockCollections,
mockRecords,
}) => {
// 创建触发器节点数据表
const triggerNodeAppendText = faker.string.alphanumeric(5);
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
// 创建人工节点数据表
const manualNodeAppendText = faker.string.alphanumeric(5);
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));
//配置前置人工节点新增数据表单
const preManualNodeNodeTitle = 'Manual' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preManualNodeNodeCustomFormTitle = 'Custom form' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preManualNodeNodeData = { type: 'manual', upstreamId: null, branchIndex: null, title: 'Manual', config: {} };
const preManualNodeNode = await apiCreateWorkflowNode(workflowId, preManualNodeNodeData);
const preManualNodeNodeObj = JSON.parse(JSON.stringify(preManualNodeNode));
const preManualNodeNodeId = preManualNodeNodeObj.id;
const getPreManualNodeNode = await apiGetWorkflowNode(preManualNodeNodeId);
const preAggregateNodeKey = getPreManualNodeNode.key;
const preManualNodeNodeConfig = {
config: {
assignees: [1],
schema: {
tab1: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
title: '{{t("Manual", { ns: "workflow-manual" })}}',
'x-component': 'Tabs.TabPane',
'x-designer': 'Tabs.Designer',
properties: {
grid: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid',
'x-initializer': 'AddBlockButton',
name: 'grid',
properties: {
'59t231zx5vx': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
properties: {
'13do6fj5t73': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
properties: {
krb1bo0p486: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-decorator': 'FormBlockProvider',
'x-decorator-props': {
formType: 'create',
resource: 'tt_mnt_org',
collection: 'tt_mnt_org',
},
'x-designer': 'CreateFormDesigner',
'x-component': 'CardItem',
'x-component-props': {
title: 'Create record4567',
},
properties: {
kzqri0ib7ji: {
_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',
name: 'grid',
properties: {
yt2rbpepdsl: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
properties: {
eptw1hy20lm: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
properties: {
orgname: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'string',
name: 'orgname',
'x-designer': 'FormItem.Designer',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-collection-field': `${manualNodeCollectionName}.${manualNodeFieldName}`,
'x-component-props': {},
},
},
name: 'eptw1hy20lm',
},
},
name: 'yt2rbpepdsl',
},
},
},
actions: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-initializer': 'AddActionButton',
'x-component': 'ActionBar',
'x-component-props': {
layout: 'one-column',
style: {
marginTop: '1.5em',
flexWrap: 'wrap',
},
},
properties: {
resolve: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
title: '{{t("Continue the process", { ns: "workflow-manual" })}}',
'x-decorator': 'ManualActionStatusProvider',
'x-decorator-props': {
value: 1,
},
'x-component': 'Action',
'x-component-props': {
type: 'primary',
useAction: '{{ useSubmit }}',
},
'x-designer': 'ManualActionDesigner',
'x-designer-props': {},
name: 'resolve',
},
},
'x-decorator': 'ActionBarProvider',
name: 'actions',
},
},
name: 'kzqri0ib7ji',
},
},
name: 'krb1bo0p486',
},
},
name: '13do6fj5t73',
},
},
name: '59t231zx5vx',
},
},
},
},
name: 'tab1',
},
},
forms: {
kzqri0ib7ji: {
type: 'create',
title: preManualNodeNodeCustomFormTitle,
actions: [
{
status: 1,
key: 'resolve',
},
],
collection: manualNodeCollectionName,
},
},
},
};
await apiUpdateWorkflowNode(preManualNodeNodeId, preManualNodeNodeConfig);
//配置计算节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const preManualNodeNodePom = new AggregateNode(page, preManualNodeNodeTitle);
await preManualNodeNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'calculation', exact: true }).click();
const calculationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Calculation-Calculation', { exact: true }).getByRole('textbox').fill(calculationNodeName);
const calculationNode = new ClculationNode(page, calculationNodeName);
const conditionNodeId = await calculationNode.node.locator('.workflow-node-id').innerText();
await calculationNode.nodeConfigure.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Node result' }).click();
await page.getByRole('menuitemcheckbox', { name: preManualNodeNodeTitle }).click();
await page.getByRole('menuitemcheckbox', { name: preManualNodeNodeCustomFormTitle }).click();
await page.getByRole('menuitemcheckbox', { name: '公司名称(单行文本)' }).click();
await expect(page.getByLabel('textbox')).toHaveText(
`Node result / ${preManualNodeNodeTitle} / ${preManualNodeNodeCustomFormTitle} / 公司名称(单行文本)`,
);
await calculationNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// api请求办理人工节点
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const job = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(job.result).toBe(triggerNodeCollectionRecordOne);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});

View File

@ -0,0 +1,735 @@
import { faker } from '@faker-js/faker';
import {
CollectionTriggerNode,
CreateWorkFlow,
EditWorkFlow,
WorkflowListRecords,
apiCreateWorkflow,
apiDeleteWorkflow,
apiGetWorkflow,
apiUpdateRecord,
apiUpdateWorkflowTrigger,
appendJsonCollectionName,
generalWithNoRelationalFields,
} from '@nocobase/plugin-workflow-test/e2e';
import { expect, test } from '@nocobase/test/e2e';
test.describe('Configuration page to configure the Trigger node', () => {
test('Add Data Trigger with No Filter', async ({ page, mockCollections, mockRecords }) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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;
//配置工作流触发器
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.nodeConfigure.click();
await collectionTriggerNode.collectionDropDown.click();
await page.getByRole('option', { name: triggerNodeCollectionDisplayName }).click();
await collectionTriggerNode.triggerOnDropdown.click();
await page.getByText('After record added', { exact: true }).click();
await collectionTriggerNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Modify Data Without Filter Trigger', async ({ page, mockCollections, mockRecords }) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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;
//配置工作流触发器
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.nodeConfigure.click();
await collectionTriggerNode.collectionDropDown.click();
await page.getByRole('option', { name: triggerNodeCollectionDisplayName }).click();
await collectionTriggerNode.triggerOnDropdown.click();
await page.getByText('After record updated', { exact: true }).click();
await collectionTriggerNode.submitButton.click();
// 2、测试步骤添加数据,编辑数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
const recordId = triggerNodeCollectionRecords[0].id;
await apiUpdateRecord(triggerNodeCollectionName, recordId, { orgname: triggerNodeCollectionRecordOne + '1' });
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);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('No-filter new or modified data triggers', async ({ page, mockCollections, mockRecords }) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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;
//配置工作流触发器
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.nodeConfigure.click();
await collectionTriggerNode.collectionDropDown.click();
await page.getByRole('option', { name: triggerNodeCollectionDisplayName }).click();
await collectionTriggerNode.triggerOnDropdown.click();
await page.getByText('After record added or updated', { exact: true }).click();
await collectionTriggerNode.submitButton.click();
// 2、测试步骤添加数据,编辑数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
const recordId = triggerNodeCollectionRecords[0].id;
await apiUpdateRecord(triggerNodeCollectionName, recordId, { orgname: triggerNodeCollectionRecordOne + '1' });
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(2);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Filter radio fields equal to a specific value new data trigger', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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;
//配置工作流触发器
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.nodeConfigure.click();
await collectionTriggerNode.collectionDropDown.click();
await page.getByRole('option', { name: triggerNodeCollectionDisplayName }).click();
await collectionTriggerNode.triggerOnDropdown.click();
await page.getByText('After record added or updated', { exact: true }).click();
// 设置触发器过滤条件
await page.getByText('Add condition', { exact: true }).click();
await page
.getByLabel('block-item-Filter-workflows-Only triggers when match conditions')
.getByRole('button', { name: 'Select field' })
.click();
await page.getByText('公司状态(下拉单选)').click();
await page
.getByLabel('block-item-Filter-workflows-Only triggers when match conditions')
.getByTestId('select-single')
.click();
await page.getByRole('option', { name: '存续' }).click();
await collectionTriggerNode.submitButton.click();
// 2、测试步骤添加数据,编辑数据触发工作流
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [{ status_singleselect: '1' }]);
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);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Filter radio fields equal to a specific value Edit Data Trigger', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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;
//配置工作流触发器
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.nodeConfigure.click();
await collectionTriggerNode.collectionDropDown.click();
await page.getByRole('option', { name: triggerNodeCollectionDisplayName }).click();
await collectionTriggerNode.triggerOnDropdown.click();
await page.getByText('After record updated', { exact: true }).click();
// 设置触发器过滤条件
await page.getByText('Add condition', { exact: true }).click();
await page
.getByLabel('block-item-Filter-workflows-Only triggers when match conditions')
.getByRole('button', { name: 'Select field' })
.click();
await page.getByText('公司状态(下拉单选)').click();
await page
.getByLabel('block-item-Filter-workflows-Only triggers when match conditions')
.getByTestId('select-single')
.click();
await page.getByRole('option', { name: '存续' }).click();
await collectionTriggerNode.submitButton.click();
// 2、测试步骤添加数据,编辑数据触发工作流
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [{ status_singleselect: '1' }]);
await page.waitForTimeout(1000);
const recordId = triggerNodeCollectionRecords[0].id;
await apiUpdateRecord(triggerNodeCollectionName, recordId, { orgname: '1' });
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);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Configuration Page Path Jump Workflow Management Page', () => {
test('Collection event Workflow Configuration Page Path Jump Workflow Management Page', async ({
page,
mockCollections,
mockRecords,
}) => {
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
// const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
// const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
// const triggerNodeFieldName = 'orgname';
// const triggerNodeFieldDisplayName = '公司名称(单行文本)';
// await mockCollections(appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText).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;
//配置工作流触发器
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
// 2、测试步骤跳转到工作流管理页面
await page.getByRole('link', { name: 'Workflow' }).click();
// 3、预期结果跳转路径正确
await page.waitForLoadState('networkidle');
expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event Workflow History Version Configuration Page Path Jump Workflow Management Page', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
await page.getByLabel('more').click();
await page.getByLabel('revision').click();
await page.waitForLoadState('networkidle');
//元素重复
await page.getByLabel('version', { exact: true }).click();
await page.getByLabel('version-1').click();
await page.getByRole('link', { name: 'Workflow' }).click();
// 3、预期结果跳转路径正确
await page.waitForLoadState('networkidle');
expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event Workflow Execution Log Page Path Jump Workflow Management Page', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
const workflowListRecords = new WorkflowListRecords(page, workFlowName);
await workflowListRecords.executionCountPopup.click();
await page.getByText('View').click();
await page.waitForLoadState('networkidle');
await page.getByRole('link', { name: 'Workflow', exact: true }).click();
// 3、预期结果跳转路径正确
await page.waitForLoadState('networkidle');
expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test.skip('Collection event Workflow Execution Log Page Path Jump Execution Log Screen', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
const workflowListRecords = new WorkflowListRecords(page, workFlowName);
await expect(workflowListRecords.executionCountPopup).toHaveText('1');
await workflowListRecords.executionCountPopup.click();
await page.getByText('View').click();
await page.waitForLoadState('networkidle');
//跳转其他执行日志界面,元素无法定位
// 3、预期结果跳转路径正确
await page.waitForLoadState('networkidle');
// expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Configuration page version switching', () => {});
test.describe('Configuration page disable enable', () => {
test('Collection Event Workflow Add Data Trigger Disable Do Not Trigger', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果触发次数为1
let getWorkflow = await apiGetWorkflow(workflowId);
let getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
let getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
await page.getByRole('switch', { name: 'On Off' }).click();
await mockRecords(triggerNodeCollectionName, [{ orgname: triggerNodeCollectionRecordOne + '1' }]);
await page.waitForTimeout(1000);
getWorkflow = await apiGetWorkflow(workflowId);
getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection Event Workflow Add Data Trigger Disable Enable Post Trigger', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
//添加工作流
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
const workflowData = {
current: true,
options: { deleteExecutionOnStatus: [] },
title: workFlowName,
type: 'collection',
enabled: false,
};
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));
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果触发次数为1
let getWorkflow = await apiGetWorkflow(workflowId);
let getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
let getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(0);
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
await page.getByRole('switch', { name: 'On Off' }).click();
await mockRecords(triggerNodeCollectionName, [{ orgname: triggerNodeCollectionRecordOne + '1' }]);
await page.waitForTimeout(1000);
getWorkflow = await apiGetWorkflow(workflowId);
getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Configuration page execution history', () => {});
test.describe('Configuration page copy to new version', () => {
test('Copy the Collection event of the Configuration Trigger node', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
await page.locator('.workflow-toolbar').getByLabel('more').hover();
await page.getByLabel('revision').click();
await page.waitForLoadState('networkidle');
// 3、预期结果新版本工作流配置内容同旧版本一样
const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
await collectionTriggerNode.nodeConfigure.click();
await expect(page.getByRole('button', { name: triggerNodeCollectionDisplayName })).toBeVisible();
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Configuration page delete version', () => {});
test.describe('Node Add Modify Delete', () => {});

View File

@ -0,0 +1,174 @@
import { faker } from '@faker-js/faker';
import {
CollectionTriggerNode,
CreateWorkFlow,
EditWorkFlow,
WorkflowListRecords,
apiCreateWorkflow,
apiDeleteWorkflow,
apiGetWorkflow,
apiUpdateRecord,
apiUpdateWorkflowTrigger,
appendJsonCollectionName,
generalWithNoRelationalFields,
} from '@nocobase/plugin-workflow-test/e2e';
import { expect, test } from '@nocobase/test/e2e';
test.describe('Filter', () => {
test('filter workflow name', async ({ page }) => {
//添加工作流
const triggerNodeAppendText = faker.string.alphanumeric(5);
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;
// 2、筛选工作流
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
await page.getByRole('textbox').fill(workFlowName);
await page.getByRole('button', { name: 'Submit' }).click();
// 3、预期结果列表中出现筛选的工作流
await expect(page.getByText(workFlowName)).toBeAttached();
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Add new', () => {
test('add new Collection event', async ({ page }) => {
// 添加工作流
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
await page.getByLabel('action-Action-Add new-workflows').click();
const createWorkFlow = new CreateWorkFlow(page);
const workFlowName = faker.string.alphanumeric(5);
await createWorkFlow.name.fill(workFlowName);
await createWorkFlow.triggerType.click();
await page.getByRole('option', { name: 'Collection event' }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
// 3、预期结果列表中出现新建的工作流
await expect(page.getByText(workFlowName)).toBeVisible();
// 4、后置处理删除工作流
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
await page.getByRole('textbox').fill(workFlowName);
await page.getByRole('button', { name: 'Submit' }).click();
await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName}`).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
await expect(page.getByText(workFlowName)).toBeHidden();
});
});
test.describe('Sync', () => {});
test.describe('Delete', () => {
test('delete Collection event', async ({ page }) => {
//添加工作流
const triggerNodeAppendText = faker.string.alphanumeric(5);
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;
// 删除工作流
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
await page.getByRole('textbox').fill(workFlowName);
await page.getByRole('button', { name: 'Submit' }).click();
await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName}`).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
// 3、预期结果列表中出现筛选的工作流
await expect(page.getByText(workFlowName)).toBeHidden();
// 4、后置处理删除工作流
});
});
test.describe('Edit', () => {
test('edit Collection event name', async ({ page }) => {
//添加工作流
const triggerNodeAppendText = faker.string.alphanumeric(5);
let 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;
// 编辑工作流
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
await page.getByLabel(`action-Action.Link-Edit-workflows-${workFlowName}`).click();
const editWorkFlow = new EditWorkFlow(page, workFlowName);
workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
await editWorkFlow.name.fill(workFlowName);
await page.getByLabel('action-Action-Submit-workflows').click();
await page.waitForLoadState('networkidle');
// 3、预期结果编辑成功列表中出现编辑后的工作流
await expect(page.getByText(workFlowName)).toBeAttached();
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Duplicate', () => {
test('Duplicate Collection event triggers with only unconfigured trigger nodes', async ({ page }) => {
//添加工作流
const triggerNodeAppendText = faker.string.alphanumeric(5);
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;
// 2、复制工作流
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
await page.getByLabel(`action-Action.Link-Duplicate-workflows-${workFlowName}`).click();
await page.getByLabel(`action-Action-Submit-workflows-${workFlowName}`).click();
// 3、预期结果列表中出现筛选的工作流
await expect(page.getByText(`${workFlowName} copy`)).toBeAttached();
// 4、后置处理删除工作流
await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName} copy`).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
await expect(page.getByText(`${workFlowName} copy`)).toBeHidden();
await apiDeleteWorkflow(workflowId);
});
});
test.describe('Executed', () => {});

View File

@ -0,0 +1,481 @@
import { faker } from '@faker-js/faker';
import {
ClculationNode,
CollectionTriggerNode,
ConditionBranchNode,
ConditionYesNode,
QueryRecordNode,
apiCreateWorkflow,
apiCreateWorkflowNode,
apiDeleteWorkflow,
apiGetWorkflow,
apiGetWorkflowNode,
apiGetWorkflowNodeExecutions,
apiUpdateWorkflowTrigger,
appendJsonCollectionName,
generalWithNoRelationalFields,
} from '@nocobase/plugin-workflow-test/e2e';
import { expect, test } from '@nocobase/test/e2e';
import { dayjs } from '@nocobase/utils';
test('Collection event add data trigger, determine trigger node integer field variable is equal to an equal constant, pass.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'staffnum';
const triggerNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置判断节点
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: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
const conditionNodeId = await conditionNode.node.locator('.workflow-node-id').innerText();
await conditionNode.nodeConfigure.click();
await conditionNode.mathRadio.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await page.getByLabel('textbox').focus();
const conditionalRightConstant = faker.number.int();
await page.keyboard.type(`==${conditionalRightConstant}`);
await expect(page.getByLabel('textbox')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}==${conditionalRightConstant}`,
);
await conditionNode.submitButton.click();
//添加No分支计算节点
await conditionNode.addNoBranchNode.click();
await page.getByRole('button', { name: 'calculation', exact: true }).click();
const noBranchcalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page
.getByLabel('Calculation-Calculation', { exact: true })
.getByRole('textbox')
.fill(noBranchcalCulationNodeName);
const noBranchcalCulationNode = new ClculationNode(page, noBranchcalCulationNodeName);
const noBranchcalCulationNodeId = await noBranchcalCulationNode.node.locator('.workflow-node-id').innerText();
await noBranchcalCulationNode.nodeConfigure.click();
await page.getByLabel('textbox').fill('0');
await noBranchcalCulationNode.submitButton.click();
//添加Yes分支计算节点
await conditionNode.addYesBranchNode.click();
await page.getByRole('button', { name: 'calculation', exact: true }).click();
const yesBranchcalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page
.getByLabel('Calculation-Calculation', { exact: true })
.getByRole('textbox')
.fill(yesBranchcalCulationNodeName);
const yesBranchcalCulationNode = new ClculationNode(page, yesBranchcalCulationNodeName);
const yesBranchcalCulationNodeId = await yesBranchcalCulationNode.node.locator('.workflow-node-id').innerText();
await yesBranchcalCulationNode.nodeConfigure.click();
await page.getByLabel('textbox').fill('1');
await yesBranchcalCulationNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = conditionalRightConstant;
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ staffnum: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const conditionNodeJob = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(conditionNodeJob.result).toBe(true);
const noBranchcalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === noBranchcalCulationNodeId);
expect(noBranchcalCulationNodeJob).toBe(undefined);
const yesBranchcalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === yesBranchcalCulationNodeId);
expect(yesBranchcalCulationNodeJob.result).toBe(1);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event Add Data Trigger, determines that the trigger node integer field variable is equal to an unequal constant, fails.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'staffnum';
const triggerNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置判断节点
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: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
const conditionNodeId = await conditionNode.node.locator('.workflow-node-id').innerText();
await conditionNode.nodeConfigure.click();
await conditionNode.mathRadio.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await page.getByLabel('textbox').focus();
const conditionalRightConstant = faker.number.int();
await page.keyboard.type(`==${conditionalRightConstant}`);
await expect(page.getByLabel('textbox')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}==${conditionalRightConstant}`,
);
await conditionNode.submitButton.click();
//添加No分支计算节点
await conditionNode.addNoBranchNode.click();
await page.getByRole('button', { name: 'calculation', exact: true }).click();
const noBranchcalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page
.getByLabel('Calculation-Calculation', { exact: true })
.getByRole('textbox')
.fill(noBranchcalCulationNodeName);
const noBranchcalCulationNode = new ClculationNode(page, noBranchcalCulationNodeName);
const noBranchcalCulationNodeId = await noBranchcalCulationNode.node.locator('.workflow-node-id').innerText();
await noBranchcalCulationNode.nodeConfigure.click();
await page.getByLabel('textbox').fill('0');
await noBranchcalCulationNode.submitButton.click();
//添加Yes分支计算节点
await conditionNode.addYesBranchNode.click();
await page.getByRole('button', { name: 'calculation', exact: true }).click();
const yesBranchcalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page
.getByLabel('Calculation-Calculation', { exact: true })
.getByRole('textbox')
.fill(yesBranchcalCulationNodeName);
const yesBranchcalCulationNode = new ClculationNode(page, yesBranchcalCulationNodeName);
const yesBranchcalCulationNodeId = await yesBranchcalCulationNode.node.locator('.workflow-node-id').innerText();
await yesBranchcalCulationNode.nodeConfigure.click();
await page.getByLabel('textbox').fill('1');
await yesBranchcalCulationNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordTwo = faker.number.int();
await mockRecords(triggerNodeCollectionName, [{ staffnum: triggerNodeCollectionRecordTwo }]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点false
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const conditionNodeJob = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(conditionNodeJob.result).toBe(false);
const noBranchcalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === noBranchcalCulationNodeId);
expect(noBranchcalCulationNodeJob.result).toBe(0);
const yesBranchcalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === yesBranchcalCulationNodeId);
expect(yesBranchcalCulationNodeJob).toBe(undefined);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event Add Data Trigger, determines that the trigger node integer field variable is not equal to an equal constant, fails.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'staffnum';
const triggerNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置判断节点
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: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
const conditionNodeId = await conditionNode.node.locator('.workflow-node-id').innerText();
await conditionNode.nodeConfigure.click();
await conditionNode.mathRadio.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await page.getByLabel('textbox').focus();
const conditionalRightConstant = faker.number.int();
await page.keyboard.type(`!=${conditionalRightConstant}`);
await expect(page.getByLabel('textbox')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}!=${conditionalRightConstant}`,
);
await conditionNode.submitButton.click();
//添加No分支计算节点
await conditionNode.addNoBranchNode.click();
await page.getByRole('button', { name: 'calculation', exact: true }).click();
const noBranchcalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page
.getByLabel('Calculation-Calculation', { exact: true })
.getByRole('textbox')
.fill(noBranchcalCulationNodeName);
const noBranchcalCulationNode = new ClculationNode(page, noBranchcalCulationNodeName);
const noBranchcalCulationNodeId = await noBranchcalCulationNode.node.locator('.workflow-node-id').innerText();
await noBranchcalCulationNode.nodeConfigure.click();
await page.getByLabel('textbox').fill('0');
await noBranchcalCulationNode.submitButton.click();
//添加Yes分支计算节点
await conditionNode.addYesBranchNode.click();
await page.getByRole('button', { name: 'calculation', exact: true }).click();
const yesBranchcalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page
.getByLabel('Calculation-Calculation', { exact: true })
.getByRole('textbox')
.fill(yesBranchcalCulationNodeName);
const yesBranchcalCulationNode = new ClculationNode(page, yesBranchcalCulationNodeName);
const yesBranchcalCulationNodeId = await yesBranchcalCulationNode.node.locator('.workflow-node-id').innerText();
await yesBranchcalCulationNode.nodeConfigure.click();
await page.getByLabel('textbox').fill('1');
await yesBranchcalCulationNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordTwo = conditionalRightConstant;
await mockRecords(triggerNodeCollectionName, [{ staffnum: triggerNodeCollectionRecordTwo }]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点false
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const conditionNodeJob = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(conditionNodeJob.result).toBe(false);
const noBranchcalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === noBranchcalCulationNodeId);
expect(noBranchcalCulationNodeJob.result).toBe(0);
const yesBranchcalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === yesBranchcalCulationNodeId);
expect(yesBranchcalCulationNodeJob).toBe(undefined);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, determines that the trigger node integer field variable is not equal to an unequal constant, passes.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'staffnum';
const triggerNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置判断节点
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: 'condition', exact: true }).hover();
await page.getByLabel('branch').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionBranchNode(page, conditionNodeName);
const conditionNodeId = await conditionNode.node.locator('.workflow-node-id').innerText();
await conditionNode.nodeConfigure.click();
await conditionNode.mathRadio.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await page.getByLabel('textbox').focus();
const conditionalRightConstant = faker.number.int();
await page.keyboard.type(`!=${conditionalRightConstant}`);
await expect(page.getByLabel('textbox')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}!=${conditionalRightConstant}`,
);
await conditionNode.submitButton.click();
//添加No分支计算节点
await conditionNode.addNoBranchNode.click();
await page.getByRole('button', { name: 'calculation', exact: true }).click();
const noBranchcalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page
.getByLabel('Calculation-Calculation', { exact: true })
.getByRole('textbox')
.fill(noBranchcalCulationNodeName);
const noBranchcalCulationNode = new ClculationNode(page, noBranchcalCulationNodeName);
const noBranchcalCulationNodeId = await noBranchcalCulationNode.node.locator('.workflow-node-id').innerText();
await noBranchcalCulationNode.nodeConfigure.click();
await page.getByLabel('textbox').fill('0');
await noBranchcalCulationNode.submitButton.click();
//添加Yes分支计算节点
await conditionNode.addYesBranchNode.click();
await page.getByRole('button', { name: 'calculation', exact: true }).click();
const yesBranchcalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page
.getByLabel('Calculation-Calculation', { exact: true })
.getByRole('textbox')
.fill(yesBranchcalCulationNodeName);
const yesBranchcalCulationNode = new ClculationNode(page, yesBranchcalCulationNodeName);
const yesBranchcalCulationNodeId = await yesBranchcalCulationNode.node.locator('.workflow-node-id').innerText();
await yesBranchcalCulationNode.nodeConfigure.click();
await page.getByLabel('textbox').fill('1');
await yesBranchcalCulationNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.number.int();
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ staffnum: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const conditionNodeJob = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(conditionNodeJob.result).toBe(true);
const noBranchcalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === noBranchcalCulationNodeId);
expect(noBranchcalCulationNodeJob).toBe(undefined);
const yesBranchcalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === yesBranchcalCulationNodeId);
expect(yesBranchcalCulationNodeJob.result).toBe(1);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});

View File

@ -0,0 +1,812 @@
import { faker } from '@faker-js/faker';
import {
ClculationNode,
CollectionTriggerNode,
ConditionBranchNode,
ConditionYesNode,
QueryRecordNode,
apiCreateWorkflow,
apiCreateWorkflowNode,
apiDeleteWorkflow,
apiGetWorkflow,
apiGetWorkflowNode,
apiGetWorkflowNodeExecutions,
apiUpdateWorkflowTrigger,
appendJsonCollectionName,
generalWithNoRelationalFields,
} from '@nocobase/plugin-workflow-test/e2e';
import { expect, test } from '@nocobase/test/e2e';
import { dayjs } from '@nocobase/utils';
test('Collection event add data trigger, determines that the trigger node single line text field variable is equal to an equal constant, passes.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置判断节点
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: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
const conditionNodeId = await conditionNode.node.locator('.workflow-node-id').innerText();
await conditionNode.nodeConfigure.click();
await page.getByText('Add condition', { exact: true }).click();
await page.getByLabel('variable-button').first().click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByText(triggerNodeFieldDisplayName).click();
await expect(page.getByLabel('variable-tag')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}`,
);
const conditionalRightConstant = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('variable-constant').fill(conditionalRightConstant);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = conditionalRightConstant;
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const getWorkflowNodeExecutionsObjResult = getWorkflowNodeExecutionsObj[0].jobs[0].result;
expect(getWorkflowNodeExecutionsObjResult).toBe(true);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, determines that the trigger node single line text field variable is equal to an unequal constant, fails.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置判断节点
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: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
const conditionNodeId = await conditionNode.node.locator('.workflow-node-id').innerText();
await conditionNode.nodeConfigure.click();
await page.getByText('Add condition', { exact: true }).click();
await page.getByLabel('variable-button').first().click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByText(triggerNodeFieldDisplayName).click();
await expect(page.getByLabel('variable-tag')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}`,
);
const conditionalRightConstant = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('variable-constant').fill(conditionalRightConstant);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const getWorkflowNodeExecutionsObjResult = getWorkflowNodeExecutionsObj[0].jobs[0].result;
expect(getWorkflowNodeExecutionsObjResult).toBe(false);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event Add Data Trigger, determines that the trigger node single line text field variable is not equal to an equal constant, fails.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置判断节点
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: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
const conditionNodeId = await conditionNode.node.locator('.workflow-node-id').innerText();
await conditionNode.nodeConfigure.click();
await page.getByText('Add condition', { exact: true }).click();
await page.getByLabel('variable-button').first().click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByText(triggerNodeFieldDisplayName).click();
await expect(page.getByLabel('variable-tag')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}`,
);
await page.getByLabel('select-operator-calc').first().click();
await page.getByRole('option', { name: '≠' }).click();
const conditionalRightConstant = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('variable-constant').fill(conditionalRightConstant);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = conditionalRightConstant;
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const getWorkflowNodeExecutionsObjResult = getWorkflowNodeExecutionsObj[0].jobs[0].result;
expect(getWorkflowNodeExecutionsObjResult).toBe(false);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, determines that the trigger node single line text field variable is not equal to an unequal constant, passes.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置判断节点
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: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
const conditionNodeId = await conditionNode.node.locator('.workflow-node-id').innerText();
await conditionNode.nodeConfigure.click();
await page.getByText('Add condition', { exact: true }).click();
await page.getByLabel('variable-button').first().click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByText(triggerNodeFieldDisplayName).click();
await expect(page.getByLabel('variable-tag')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}`,
);
await page.getByLabel('select-operator-calc').first().click();
await page.getByRole('option', { name: '≠' }).click();
const conditionalRightConstant = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('variable-constant').fill(conditionalRightConstant);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = conditionalRightConstant + '1';
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const getWorkflowNodeExecutionsObjResult = getWorkflowNodeExecutionsObj[0].jobs[0].result;
expect(getWorkflowNodeExecutionsObjResult).toBe(true);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, determine trigger node integer variable equal to query node equal integer variable, pass.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'staffnum';
const triggerNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置前置查询节点
const preQueryRecordNodeTitle = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preQueryRecordNodeData = {
type: 'query',
upstreamId: null,
branchIndex: null,
title: preQueryRecordNodeTitle,
config: {
collection: triggerNodeCollectionName,
params: {
filter: { $and: [{ id: { $eq: '{{$context.data.id}}' } }] },
sort: [],
page: 1,
pageSize: 20,
appends: [],
},
},
};
const preQueryRecordNode = await apiCreateWorkflowNode(workflowId, preQueryRecordNodeData);
const preQueryRecordNodeObj = JSON.parse(JSON.stringify(preQueryRecordNode));
const preQueryRecordNodeId = preQueryRecordNodeObj.id;
const getPreQueryRecordNode = await apiGetWorkflowNode(preQueryRecordNodeId);
const preQueryRecordNodeKey = getPreQueryRecordNode.key;
//配置判断节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
const conditionNodeId = await conditionNode.node.locator('.workflow-node-id').innerText();
await conditionNode.nodeConfigure.click();
await page.getByText('Add condition', { exact: true }).click();
await page.getByLabel('variable-button').first().click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await expect(page.getByLabel('variable-tag')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}`,
);
await page.getByLabel('variable-button').nth(1).click();
await page.getByRole('menuitemcheckbox', { name: 'Node result' }).click();
await page.getByRole('menuitemcheckbox', { name: preQueryRecordNodeTitle }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await expect(page.getByLabel('variable-tag').nth(1)).toHaveText(
`Node result / ${preQueryRecordNodeTitle} / ${triggerNodeFieldDisplayName}`,
);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.number.int();
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ staffnum: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const job = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(job.result).toBe(true);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, determine trigger node integer variable is equal to query node not equal integer variable, not pass.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'staffnum';
const triggerNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
const triggerNodeCollectionRecordOne = faker.number.int();
await mockRecords(triggerNodeCollectionName, [{ staffnum: triggerNodeCollectionRecordOne }]);
//添加工作流
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));
//配置前置查询节点
const preQueryRecordNodeTitle = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preQueryRecordNodeData = {
type: 'query',
upstreamId: null,
branchIndex: null,
title: preQueryRecordNodeTitle,
config: {
collection: triggerNodeCollectionName,
params: {
filter: { $and: [{ id: { $ne: '{{$context.data.id}}' } }] },
sort: [],
page: 1,
pageSize: 20,
appends: [],
},
},
};
const preQueryRecordNode = await apiCreateWorkflowNode(workflowId, preQueryRecordNodeData);
const preQueryRecordNodeObj = JSON.parse(JSON.stringify(preQueryRecordNode));
const preQueryRecordNodeId = preQueryRecordNodeObj.id;
const getPreQueryRecordNode = await apiGetWorkflowNode(preQueryRecordNodeId);
const preQueryRecordNodeKey = getPreQueryRecordNode.key;
//配置判断节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
const conditionNodeId = await conditionNode.node.locator('.workflow-node-id').innerText();
await conditionNode.nodeConfigure.click();
await page.getByText('Add condition', { exact: true }).click();
await page.getByLabel('variable-button').first().click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await expect(page.getByLabel('variable-tag')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}`,
);
await page.getByLabel('variable-button').nth(1).click();
await page.getByRole('menuitemcheckbox', { name: 'Node result' }).click();
await page.getByRole('menuitemcheckbox', { name: preQueryRecordNodeTitle }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await expect(page.getByLabel('variable-tag').nth(1)).toHaveText(
`Node result / ${preQueryRecordNodeTitle} / ${triggerNodeFieldDisplayName}`,
);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordTwo = faker.number.int();
await mockRecords(triggerNodeCollectionName, [{ staffnum: triggerNodeCollectionRecordTwo }]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const job = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(job.result).toBe(false);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, determine trigger node integer variable is not equal to query node equal integer variable, not pass.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'staffnum';
const triggerNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置前置查询节点
const preQueryRecordNodeTitle = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preQueryRecordNodeData = {
type: 'query',
upstreamId: null,
branchIndex: null,
title: preQueryRecordNodeTitle,
config: {
collection: triggerNodeCollectionName,
params: {
filter: { $and: [{ id: { $eq: '{{$context.data.id}}' } }] },
sort: [],
page: 1,
pageSize: 20,
appends: [],
},
},
};
const preQueryRecordNode = await apiCreateWorkflowNode(workflowId, preQueryRecordNodeData);
const preQueryRecordNodeObj = JSON.parse(JSON.stringify(preQueryRecordNode));
const preQueryRecordNodeId = preQueryRecordNodeObj.id;
const getPreQueryRecordNode = await apiGetWorkflowNode(preQueryRecordNodeId);
const preQueryRecordNodeKey = getPreQueryRecordNode.key;
//配置判断节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
const conditionNodeId = await conditionNode.node.locator('.workflow-node-id').innerText();
await conditionNode.nodeConfigure.click();
await page.getByText('Add condition', { exact: true }).click();
await page.getByLabel('variable-button').first().click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await expect(page.getByLabel('variable-tag')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}`,
);
await page.getByLabel('select-operator-calc').first().click();
await page.getByRole('option', { name: '≠' }).click();
await page.getByLabel('variable-button').nth(1).click();
await page.getByRole('menuitemcheckbox', { name: 'Node result' }).click();
await page.getByRole('menuitemcheckbox', { name: preQueryRecordNodeTitle }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await expect(page.getByLabel('variable-tag').nth(1)).toHaveText(
`Node result / ${preQueryRecordNodeTitle} / ${triggerNodeFieldDisplayName}`,
);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.number.int();
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ staffnum: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const job = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(job.result).toBe(false);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, determine trigger node integer variable is not equal to query node not equal integer variable, pass.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'staffnum';
const triggerNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
const triggerNodeCollectionRecordOne = faker.number.int();
await mockRecords(triggerNodeCollectionName, [{ staffnum: triggerNodeCollectionRecordOne }]);
//添加工作流
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));
//配置前置查询节点
const preQueryRecordNodeTitle = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preQueryRecordNodeData = {
type: 'query',
upstreamId: null,
branchIndex: null,
title: preQueryRecordNodeTitle,
config: {
collection: triggerNodeCollectionName,
params: {
filter: { $and: [{ id: { $ne: '{{$context.data.id}}' } }] },
sort: [],
page: 1,
pageSize: 20,
appends: [],
},
},
};
const preQueryRecordNode = await apiCreateWorkflowNode(workflowId, preQueryRecordNodeData);
const preQueryRecordNodeObj = JSON.parse(JSON.stringify(preQueryRecordNode));
const preQueryRecordNodeId = preQueryRecordNodeObj.id;
const getPreQueryRecordNode = await apiGetWorkflowNode(preQueryRecordNodeId);
const preQueryRecordNodeKey = getPreQueryRecordNode.key;
//配置判断节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
const conditionNodeId = await conditionNode.node.locator('.workflow-node-id').innerText();
await conditionNode.nodeConfigure.click();
await page.getByText('Add condition', { exact: true }).click();
await page.getByLabel('variable-button').first().click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await expect(page.getByLabel('variable-tag')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}`,
);
await page.getByLabel('select-operator-calc').first().click();
await page.getByRole('option', { name: '≠' }).click();
await page.getByLabel('variable-button').nth(1).click();
await page.getByRole('menuitemcheckbox', { name: 'Node result' }).click();
await page.getByRole('menuitemcheckbox', { name: preQueryRecordNodeTitle }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await expect(page.getByLabel('variable-tag').nth(1)).toHaveText(
`Node result / ${preQueryRecordNodeTitle} / ${triggerNodeFieldDisplayName}`,
);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordTwo = faker.number.int();
await mockRecords(triggerNodeCollectionName, [{ staffnum: triggerNodeCollectionRecordTwo }]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const job = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(job.result).toBe(true);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});

View File

@ -0,0 +1,790 @@
import { faker } from '@faker-js/faker';
import {
ClculationNode,
CollectionTriggerNode,
ConditionBranchNode,
ConditionYesNode,
QueryRecordNode,
apiCreateWorkflow,
apiCreateWorkflowNode,
apiDeleteWorkflow,
apiGetWorkflow,
apiGetWorkflowNode,
apiGetWorkflowNodeExecutions,
apiUpdateWorkflowTrigger,
appendJsonCollectionName,
generalWithNoRelationalFields,
} from '@nocobase/plugin-workflow-test/e2e';
import { expect, test } from '@nocobase/test/e2e';
import { dayjs } from '@nocobase/utils';
test('Collection event Add Data Trigger, Formula engine, determines that the trigger node single line text field variable is equal to an equal constant, passes.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置判断节点
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: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
await conditionNode.nodeConfigure.click();
await conditionNode.formulaRadio.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await page.getByLabel('textbox').focus();
const conditionalRightConstant = faker.string.alphanumeric(10);
await page.keyboard.type(`=='${conditionalRightConstant}'`);
await expect(page.getByLabel('textbox')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}=='${conditionalRightConstant}'`,
);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = conditionalRightConstant;
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const getWorkflowNodeExecutionsObjResult = getWorkflowNodeExecutionsObj[0].jobs[0].result;
expect(getWorkflowNodeExecutionsObjResult).toBe(true);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event Add Data Trigger, Formula engine, determines that the trigger node single line text field variable is equal to an unequal constant, fails.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置判断节点
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: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
await conditionNode.nodeConfigure.click();
await conditionNode.formulaRadio.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await page.getByLabel('textbox').focus();
const conditionalRightConstant = faker.string.alphanumeric(10);
await page.keyboard.type(`=='${conditionalRightConstant}'`);
await expect(page.getByLabel('textbox')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}=='${conditionalRightConstant}'`,
);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const getWorkflowNodeExecutionsObjResult = getWorkflowNodeExecutionsObj[0].jobs[0].result;
expect(getWorkflowNodeExecutionsObjResult).toBe(false);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event Add Data Trigger, Formula engine, determines that the trigger node single line text field variable is not equal to an equal constant, fails.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置判断节点
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: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
await conditionNode.nodeConfigure.click();
await conditionNode.formulaRadio.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await page.getByLabel('textbox').focus();
const conditionalRightConstant = faker.string.alphanumeric(10);
await page.keyboard.type(`!='${conditionalRightConstant}'`);
await expect(page.getByLabel('textbox')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}!='${conditionalRightConstant}'`,
);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = conditionalRightConstant;
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const getWorkflowNodeExecutionsObjResult = getWorkflowNodeExecutionsObj[0].jobs[0].result;
expect(getWorkflowNodeExecutionsObjResult).toBe(false);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event Add Data Trigger, Formula engine, determines that the trigger node single line text field variable is not equal to an unequal constant, passes.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置判断节点
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: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
await conditionNode.nodeConfigure.click();
await conditionNode.formulaRadio.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await page.getByLabel('textbox').focus();
const conditionalRightConstant = faker.string.alphanumeric(10);
await page.keyboard.type(`!='${conditionalRightConstant}'`);
await expect(page.getByLabel('textbox')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}!='${conditionalRightConstant}'`,
);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.string.alphanumeric(9);
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const getWorkflowNodeExecutionsObjResult = getWorkflowNodeExecutionsObj[0].jobs[0].result;
expect(getWorkflowNodeExecutionsObjResult).toBe(true);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, Formula engine, determine the trigger node integer variable is equal to the query node equal integer variable, pass.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'staffnum';
const triggerNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
const triggerNodeCollectionRecordOne = faker.number.int();
await mockRecords(triggerNodeCollectionName, [{ staffnum: triggerNodeCollectionRecordOne }]);
//添加工作流
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));
//配置前置查询节点
const preQueryRecordNodeTitle = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preQueryRecordNodeData = {
type: 'query',
upstreamId: null,
branchIndex: null,
title: preQueryRecordNodeTitle,
config: {
collection: triggerNodeCollectionName,
params: {
filter: { $and: [{ id: { $eq: '{{$context.data.id}}' } }] },
sort: [],
page: 1,
pageSize: 20,
appends: [],
},
},
};
const preQueryRecordNode = await apiCreateWorkflowNode(workflowId, preQueryRecordNodeData);
const preQueryRecordNodeObj = JSON.parse(JSON.stringify(preQueryRecordNode));
const preQueryRecordNodeId = preQueryRecordNodeObj.id;
const getPreQueryRecordNode = await apiGetWorkflowNode(preQueryRecordNodeId);
const preQueryRecordNodeKey = getPreQueryRecordNode.key;
//配置判断节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
const conditionNodeId = await conditionNode.node.locator('.workflow-node-id').innerText();
await conditionNode.nodeConfigure.click();
await conditionNode.formulaRadio.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await page.getByLabel('textbox').focus();
await page.keyboard.type('==');
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Node result' }).click();
await page.getByRole('menuitemcheckbox', { name: preQueryRecordNodeTitle }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await expect(page.getByLabel('textbox')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}==Node result / ${preQueryRecordNodeTitle} / ${triggerNodeFieldDisplayName}`,
);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordTwo = faker.number.int();
await mockRecords(triggerNodeCollectionName, [{ staffnum: triggerNodeCollectionRecordTwo }]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const job = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(job.result).toBe(true);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, Formula engine, determine trigger node integer variable is equal to query node not equal integer variable, not pass.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'staffnum';
const triggerNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
const triggerNodeCollectionRecordOne = faker.number.int();
await mockRecords(triggerNodeCollectionName, [{ staffnum: triggerNodeCollectionRecordOne }]);
//添加工作流
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));
//配置前置查询节点
const preQueryRecordNodeTitle = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preQueryRecordNodeData = {
type: 'query',
upstreamId: null,
branchIndex: null,
title: preQueryRecordNodeTitle,
config: {
collection: triggerNodeCollectionName,
params: {
filter: { $and: [{ id: { $ne: '{{$context.data.id}}' } }] },
sort: [],
page: 1,
pageSize: 20,
appends: [],
},
},
};
const preQueryRecordNode = await apiCreateWorkflowNode(workflowId, preQueryRecordNodeData);
const preQueryRecordNodeObj = JSON.parse(JSON.stringify(preQueryRecordNode));
const preQueryRecordNodeId = preQueryRecordNodeObj.id;
const getPreQueryRecordNode = await apiGetWorkflowNode(preQueryRecordNodeId);
const preQueryRecordNodeKey = getPreQueryRecordNode.key;
//配置判断节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
const conditionNodeId = await conditionNode.node.locator('.workflow-node-id').innerText();
await conditionNode.nodeConfigure.click();
await conditionNode.formulaRadio.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await page.getByLabel('textbox').focus();
await page.keyboard.type('==');
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Node result' }).click();
await page.getByRole('menuitemcheckbox', { name: preQueryRecordNodeTitle }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await expect(page.getByLabel('textbox')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}==Node result / ${preQueryRecordNodeTitle} / ${triggerNodeFieldDisplayName}`,
);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordTwo = faker.number.int();
await mockRecords(triggerNodeCollectionName, [{ staffnum: triggerNodeCollectionRecordTwo }]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const job = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(job.result).toBe(false);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, Formula engine, determine trigger node integer variable is not equal to query node equal integer variable, not pass.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'staffnum';
const triggerNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置前置查询节点
const preQueryRecordNodeTitle = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preQueryRecordNodeData = {
type: 'query',
upstreamId: null,
branchIndex: null,
title: preQueryRecordNodeTitle,
config: {
collection: triggerNodeCollectionName,
params: {
filter: { $and: [{ id: { $eq: '{{$context.data.id}}' } }] },
sort: [],
page: 1,
pageSize: 20,
appends: [],
},
},
};
const preQueryRecordNode = await apiCreateWorkflowNode(workflowId, preQueryRecordNodeData);
const preQueryRecordNodeObj = JSON.parse(JSON.stringify(preQueryRecordNode));
const preQueryRecordNodeId = preQueryRecordNodeObj.id;
const getPreQueryRecordNode = await apiGetWorkflowNode(preQueryRecordNodeId);
const preQueryRecordNodeKey = getPreQueryRecordNode.key;
//配置判断节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
const conditionNodeId = await conditionNode.node.locator('.workflow-node-id').innerText();
await conditionNode.nodeConfigure.click();
await conditionNode.formulaRadio.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await page.getByLabel('textbox').focus();
await page.keyboard.type('!=');
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Node result' }).click();
await page.getByRole('menuitemcheckbox', { name: preQueryRecordNodeTitle }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await expect(page.getByLabel('textbox')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}!=Node result / ${preQueryRecordNodeTitle} / ${triggerNodeFieldDisplayName}`,
);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordTwo = faker.number.int();
await mockRecords(triggerNodeCollectionName, [{ staffnum: triggerNodeCollectionRecordTwo }]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const job = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(job.result).toBe(false);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, Formula engine, determine the trigger node integer variable is not equal to the query node not equal integer variable, pass.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'staffnum';
const triggerNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
const triggerNodeCollectionRecordOne = faker.number.int();
await mockRecords(triggerNodeCollectionName, [{ staffnum: triggerNodeCollectionRecordOne }]);
//添加工作流
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));
//配置前置查询节点
const preQueryRecordNodeTitle = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const preQueryRecordNodeData = {
type: 'query',
upstreamId: null,
branchIndex: null,
title: preQueryRecordNodeTitle,
config: {
collection: triggerNodeCollectionName,
params: {
filter: { $and: [{ id: { $ne: '{{$context.data.id}}' } }] },
sort: [],
page: 1,
pageSize: 20,
appends: [],
},
},
};
const preQueryRecordNode = await apiCreateWorkflowNode(workflowId, preQueryRecordNodeData);
const preQueryRecordNodeObj = JSON.parse(JSON.stringify(preQueryRecordNode));
const preQueryRecordNodeId = preQueryRecordNodeObj.id;
const getPreQueryRecordNode = await apiGetWorkflowNode(preQueryRecordNodeId);
const preQueryRecordNodeKey = getPreQueryRecordNode.key;
//配置判断节点
await page.goto(`admin/workflow/workflows/${workflowId}`);
await page.waitForLoadState('networkidle');
const preQueryRecordNodePom = new QueryRecordNode(page, preQueryRecordNodeTitle);
await preQueryRecordNodePom.addNodeButton.click();
await page.getByRole('button', { name: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
const conditionNodeId = await conditionNode.node.locator('.workflow-node-id').innerText();
await conditionNode.nodeConfigure.click();
await conditionNode.formulaRadio.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await page.getByLabel('textbox').focus();
await page.keyboard.type('!=');
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Node result' }).click();
await page.getByRole('menuitemcheckbox', { name: preQueryRecordNodeTitle }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await expect(page.getByLabel('textbox')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}!=Node result / ${preQueryRecordNodeTitle} / ${triggerNodeFieldDisplayName}`,
);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordTwo = faker.number.int();
await mockRecords(triggerNodeCollectionName, [{ staffnum: triggerNodeCollectionRecordTwo }]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const job = jobs.find((job) => job.nodeId.toString() === conditionNodeId);
expect(job.result).toBe(true);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});

View File

@ -0,0 +1,354 @@
import { faker } from '@faker-js/faker';
import {
ClculationNode,
CollectionTriggerNode,
ConditionBranchNode,
ConditionYesNode,
QueryRecordNode,
apiCreateWorkflow,
apiCreateWorkflowNode,
apiDeleteWorkflow,
apiGetWorkflow,
apiGetWorkflowNode,
apiGetWorkflowNodeExecutions,
apiUpdateWorkflowTrigger,
appendJsonCollectionName,
generalWithNoRelationalFields,
} from '@nocobase/plugin-workflow-test/e2e';
import { expect, test } from '@nocobase/test/e2e';
import { dayjs } from '@nocobase/utils';
test('Collection event add data trigger, Math engine, determine trigger node integer field variable is equal to an equal constant, pass.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'staffnum';
const triggerNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置判断节点
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: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
const conditionNodeId = await conditionNode.node.locator('.workflow-node-id').innerText();
await conditionNode.nodeConfigure.click();
await conditionNode.mathRadio.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await page.getByLabel('textbox').focus();
const conditionalRightConstant = faker.number.int();
await page.keyboard.type(`==${conditionalRightConstant}`);
await expect(page.getByLabel('textbox')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}==${conditionalRightConstant}`,
);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = conditionalRightConstant;
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ staffnum: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const getWorkflowNodeExecutionsObjResult = getWorkflowNodeExecutionsObj[0].jobs[0].result;
expect(getWorkflowNodeExecutionsObjResult).toBe(true);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event Add Data Trigger, Math engine, determines that the trigger node integer field variable is equal to an unequal constant, fails.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'staffnum';
const triggerNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置判断节点
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: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
const conditionNodeId = await conditionNode.node.locator('.workflow-node-id').innerText();
await conditionNode.nodeConfigure.click();
await conditionNode.mathRadio.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await page.getByLabel('textbox').focus();
const conditionalRightConstant = faker.number.int();
await page.keyboard.type(`==${conditionalRightConstant}`);
await expect(page.getByLabel('textbox')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}==${conditionalRightConstant}`,
);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.number.int();
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ staffnum: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const getWorkflowNodeExecutionsObjResult = getWorkflowNodeExecutionsObj[0].jobs[0].result;
expect(getWorkflowNodeExecutionsObjResult).toBe(false);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event Add Data Trigger, Math engine, determines that the trigger node integer field variable is not equal to an equal constant, fails.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'staffnum';
const triggerNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置判断节点
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: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
await conditionNode.nodeConfigure.click();
await conditionNode.mathRadio.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await page.getByLabel('textbox').focus();
const conditionalRightConstant = faker.number.int();
await page.keyboard.type(`!=${conditionalRightConstant}`);
await expect(page.getByLabel('textbox')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}!=${conditionalRightConstant}`,
);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = conditionalRightConstant;
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ staffnum: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const getWorkflowNodeExecutionsObjResult = getWorkflowNodeExecutionsObj[0].jobs[0].result;
expect(getWorkflowNodeExecutionsObjResult).toBe(false);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, Math engine, determines that the trigger node integer field variable is not equal to an unequal constant, passes.', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'staffnum';
const triggerNodeFieldDisplayName = '员工人数(整数)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置判断节点
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: 'condition', exact: true }).hover();
await page.getByLabel('rejectOnFalse').click();
const conditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(conditionNodeName);
const conditionNode = new ConditionYesNode(page, conditionNodeName);
await conditionNode.nodeConfigure.click();
await conditionNode.mathRadio.click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await page.getByLabel('textbox').focus();
const conditionalRightConstant = faker.number.int();
await page.keyboard.type(`!=${conditionalRightConstant}`);
await expect(page.getByLabel('textbox')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}!=${conditionalRightConstant}`,
);
await conditionNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = faker.number.int();
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ staffnum: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,判断节点true通过
const getWorkflow = await apiGetWorkflow(workflowId);
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
const getWorkflowExecuted = getWorkflowObj.executed;
expect(getWorkflowExecuted).toBe(1);
const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const getWorkflowNodeExecutionsObjResult = getWorkflowNodeExecutionsObj[0].jobs[0].result;
expect(getWorkflowNodeExecutionsObjResult).toBe(true);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});

View File

@ -0,0 +1,207 @@
import { faker } from '@faker-js/faker';
import {
CollectionTriggerNode,
DeleteRecordNode,
apiCreateWorkflow,
apiDeleteWorkflow,
apiGetList,
apiUpdateWorkflowTrigger,
appendJsonCollectionName,
generalWithNoRelationalFields,
} from '@nocobase/plugin-workflow-test/e2e';
import { expect, test } from '@nocobase/test/e2e';
import { dayjs } from '@nocobase/utils';
test('Collection event add data trigger, filter single line text field not null, delete common table data', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
const deleteNodeAppendText = 'b' + faker.string.alphanumeric(4);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
// 创建删除数据节点数据表
const deleteNodeCollectionDisplayName = `自动>组织[普通表]${deleteNodeAppendText}`;
const deleteNodeCollectionName = `tt_amt_org${deleteNodeAppendText}`;
const deleteNodeFieldName = 'orgname';
const deleteNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), deleteNodeAppendText)
.collections,
);
const deleteNodeCollectionRecordOne = 'a' + faker.string.alphanumeric(4);
const deleteNodeCollectionRecordTwo = 'b' + faker.string.alphanumeric(4);
const deleteNodeCollectionRecordThree = 'c' + faker.string.alphanumeric(4);
const deleteNodeCollectionRecords = await mockRecords(deleteNodeCollectionName, [
{ orgname: deleteNodeCollectionRecordOne },
{ orgname: deleteNodeCollectionRecordTwo },
{ orgname: deleteNodeCollectionRecordThree },
]);
//添加工作流
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));
//配置删除数据节点
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: 'destroy', exact: true }).click();
const deleteRecordNodeName = 'Delete record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Delete record-Delete record', { exact: true }).getByRole('textbox').fill(deleteRecordNodeName);
const deleteRecordNode = new DeleteRecordNode(page, deleteRecordNodeName);
await deleteRecordNode.nodeConfigure.click();
await deleteRecordNode.collectionDropDown.click();
await page.getByText(deleteNodeCollectionDisplayName).click();
// 设置过滤条件
await page.getByText('Add condition', { exact: true }).click();
await page.getByLabel('block-item-Filter-workflows-Filter').getByRole('button', { name: 'Select field' }).click();
await page.getByRole('menuitemcheckbox', { name: deleteNodeFieldDisplayName.toString() }).click();
await page.getByTestId('select-filter-operator').click();
await page.getByRole('option', { name: 'is not empty' }).click();
await deleteRecordNode.submitButton.click();
// 查看删除前数据
let deleteNodeCollectionData = await apiGetList(deleteNodeCollectionName);
let deleteNodeCollectionDataObj = JSON.parse(JSON.stringify(deleteNodeCollectionData));
expect(deleteNodeCollectionDataObj.meta.count).toBe(3);
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,数据删除成功
deleteNodeCollectionData = await apiGetList(deleteNodeCollectionName);
deleteNodeCollectionDataObj = JSON.parse(JSON.stringify(deleteNodeCollectionData));
expect(deleteNodeCollectionDataObj.meta.count).toBe(0);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, filter single line text field is trigger node single line text field variable , delete common table data', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
const deleteNodeAppendText = 'b' + faker.string.alphanumeric(4);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
// 创建删除数据节点数据表
const deleteNodeCollectionDisplayName = `自动>组织[普通表]${deleteNodeAppendText}`;
const deleteNodeCollectionName = `tt_amt_org${deleteNodeAppendText}`;
const deleteNodeFieldName = 'orgname';
const deleteNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), deleteNodeAppendText)
.collections,
);
const deleteNodeCollectionRecordOne = 'a' + faker.string.alphanumeric(4);
const deleteNodeCollectionRecordTwo = 'b' + faker.string.alphanumeric(4);
const deleteNodeCollectionRecordThree = 'c' + faker.string.alphanumeric(4);
const deleteNodeCollectionRecords = await mockRecords(deleteNodeCollectionName, [
{ orgname: deleteNodeCollectionRecordOne },
{ orgname: deleteNodeCollectionRecordTwo },
{ orgname: deleteNodeCollectionRecordThree },
]);
//添加工作流
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));
//配置删除数据节点
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: 'destroy', exact: true }).click();
const deleteRecordNodeName = 'Delete record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Delete record-Delete record', { exact: true }).getByRole('textbox').fill(deleteRecordNodeName);
const deleteRecordNode = new DeleteRecordNode(page, deleteRecordNodeName);
await deleteRecordNode.nodeConfigure.click();
await deleteRecordNode.collectionDropDown.click();
await page.getByText(deleteNodeCollectionDisplayName).click();
// 设置过滤条件
await page.getByText('Add condition', { exact: true }).click();
await page.getByLabel('block-item-Filter-workflows-Filter').getByRole('button', { name: 'Select field' }).click();
await page.getByRole('menuitemcheckbox', { name: deleteNodeFieldDisplayName.toString() }).click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger variables' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Trigger data' }).click();
await page.getByRole('menuitemcheckbox', { name: triggerNodeFieldDisplayName }).click();
await expect(page.getByLabel('block-item-Filter-workflows-Filter').getByLabel('variable-tag')).toHaveText(
`Trigger variables / Trigger data / ${triggerNodeFieldDisplayName}`,
);
await deleteRecordNode.submitButton.click();
// 查看删除前数据
let deleteNodeCollectionData = await apiGetList(deleteNodeCollectionName);
let deleteNodeCollectionDataObj = JSON.parse(JSON.stringify(deleteNodeCollectionData));
expect(deleteNodeCollectionDataObj.meta.count).toBe(3);
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = deleteNodeCollectionRecordOne;
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
{ orgname: triggerNodeCollectionRecordOne },
]);
await page.waitForTimeout(1000);
// 3、预期结果工作流成功触发,数据删除成功
deleteNodeCollectionData = await apiGetList(deleteNodeCollectionName);
deleteNodeCollectionDataObj = JSON.parse(JSON.stringify(deleteNodeCollectionData));
expect(deleteNodeCollectionDataObj.meta.count).toBe(2);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});

View File

@ -0,0 +1,928 @@
import { faker } from '@faker-js/faker';
import {
CollectionTriggerNode,
QueryRecordNode,
apiCreateWorkflow,
apiDeleteWorkflow,
apiGetWorkflow,
apiGetWorkflowNodeExecutions,
apiUpdateWorkflowTrigger,
appendJsonCollectionName,
generalWithNoRelationalFields,
} from '@nocobase/plugin-workflow-test/e2e';
import { expect, test } from '@nocobase/test/e2e';
import { dayjs } from '@nocobase/utils';
test('Collection event add data trigger, no filter no sort query common table 1 record', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.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));
//配置查询节点
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: 'query', exact: true }).click();
const queryRecordNodeName = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Query record-Query record', { exact: true }).getByRole('textbox').fill(queryRecordNodeName);
const queryRecordNode = new QueryRecordNode(page, queryRecordNodeName);
const queryRecordNodeId = await queryRecordNode.node.locator('.workflow-node-id').innerText();
await queryRecordNode.nodeConfigure.click();
await queryRecordNode.collectionDropDown.click();
await page.getByRole('option', { name: triggerNodeCollectionDisplayName }).click();
await queryRecordNode.submitButton.click();
// 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 getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === queryRecordNodeId);
const queryRecordNodeJobResult = queryRecordNodeJob.result;
expect(queryRecordNodeJobResult.orgname).toBe(triggerNodeCollectionRecordOne);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, no filtering and no sorting, query common table multiple records, set page 1 20 per page', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
const triggerNodeCollectionRecordNumber = faker.number.int({ min: 0, max: 19 });
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, triggerNodeCollectionRecordNumber);
//添加工作流
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));
//配置查询节点
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: 'query', exact: true }).click();
const queryRecordNodeName = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Query record-Query record', { exact: true }).getByRole('textbox').fill(queryRecordNodeName);
const queryRecordNode = new QueryRecordNode(page, queryRecordNodeName);
const queryRecordNodeId = await queryRecordNode.node.locator('.workflow-node-id').innerText();
await queryRecordNode.nodeConfigure.click();
await queryRecordNode.collectionDropDown.click();
await page.getByRole('option', { name: triggerNodeCollectionDisplayName }).click();
await queryRecordNode.allowMultipleDataBoxesForResults.check();
await expect(queryRecordNode.pageNumberEditBox).toHaveValue('1');
await expect(queryRecordNode.pageSizeEditBox).toHaveValue('20');
await queryRecordNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
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 getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === queryRecordNodeId);
const queryRecordNodeJobResult = queryRecordNodeJob.result;
expect(queryRecordNodeJobResult.length).toBe(triggerNodeCollectionRecordNumber + 1);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, no filter ID ascending, query common table with multiple records, set page X to Y per page', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
const triggerNodeCollectionRecordNumber = faker.number.int({ min: 0, max: 19 });
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, triggerNodeCollectionRecordNumber);
//添加工作流
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));
//配置查询节点
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: 'query', exact: true }).click();
const queryRecordNodeName = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Query record-Query record', { exact: true }).getByRole('textbox').fill(queryRecordNodeName);
const queryRecordNode = new QueryRecordNode(page, queryRecordNodeName);
const queryRecordNodeId = await queryRecordNode.node.locator('.workflow-node-id').innerText();
await queryRecordNode.nodeConfigure.click();
await queryRecordNode.collectionDropDown.click();
await page.getByRole('option', { name: triggerNodeCollectionDisplayName }).click();
await queryRecordNode.allowMultipleDataBoxesForResults.check();
// 设置排序条件
await queryRecordNode.addSortFieldsButton.click();
await page.getByTestId('select-single').click();
await page.getByRole('option', { name: 'ID', exact: true }).click();
await page.getByLabel('block-item-Radio.Group-workflows').getByText('ASC').click();
await expect(queryRecordNode.pageNumberEditBox).toHaveValue('1');
await expect(queryRecordNode.pageSizeEditBox).toHaveValue('20');
const pageNumber = faker.number.int({ min: 1, max: 5 });
const pageSize = faker.number.int({ min: 1, max: 4 });
await queryRecordNode.pageNumberEditBox.fill(pageNumber.toString());
await queryRecordNode.pageSizeEditBox.fill(pageSize.toString());
await queryRecordNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
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 getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === queryRecordNodeId);
const queryRecordNodeJobResult = queryRecordNodeJob.result;
let nodeResultRecords = 0;
const recordCount = triggerNodeCollectionRecordNumber + 1;
if (pageNumber > Math.ceil(recordCount / pageSize)) {
nodeResultRecords = 0;
expect(queryRecordNodeJobResult).toEqual([]);
} else if (pageNumber * pageSize > recordCount) {
nodeResultRecords = recordCount - (pageNumber - 1) * pageSize;
expect(queryRecordNodeJobResult.length).toBe(nodeResultRecords);
// 获取数组中对象下ID的值
const nodeResultRecordsIDArray = queryRecordNodeJobResult.map((obj) => obj.id);
// 断言数组的最小值等于(页码-1*每页记录数+1
expect(Math.min(...nodeResultRecordsIDArray)).toBe((pageNumber - 1) * pageSize + 1);
// 断言数组的最大值等于总记录数
expect(Math.max(...nodeResultRecordsIDArray)).toBe(recordCount);
} else {
nodeResultRecords = pageSize;
expect(queryRecordNodeJobResult.length).toBe(nodeResultRecords);
const nodeResultRecordsIDArray = queryRecordNodeJobResult.map((obj) => obj.id);
// 断言数组的最小值等于(页码-1*每页记录数+1
expect(Math.min(...nodeResultRecordsIDArray)).toBe((pageNumber - 1) * pageSize + 1);
// 断言数组的最大值等于pageNumber * pageSize
expect(Math.max(...nodeResultRecordsIDArray)).toBe(pageNumber * pageSize);
}
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, no filter ID descending, query common table with multiple records, set page X to Y per page', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
const triggerNodeCollectionRecordNumber = faker.number.int({ min: 0, max: 19 });
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, triggerNodeCollectionRecordNumber);
//添加工作流
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));
//配置查询节点
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: 'query', exact: true }).click();
const queryRecordNodeName = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Query record-Query record', { exact: true }).getByRole('textbox').fill(queryRecordNodeName);
const queryRecordNode = new QueryRecordNode(page, queryRecordNodeName);
const queryRecordNodeId = await queryRecordNode.node.locator('.workflow-node-id').innerText();
await queryRecordNode.nodeConfigure.click();
await queryRecordNode.collectionDropDown.click();
await page.getByRole('option', { name: triggerNodeCollectionDisplayName }).click();
await queryRecordNode.allowMultipleDataBoxesForResults.check();
// 设置排序条件
await queryRecordNode.addSortFieldsButton.click();
await page.getByTestId('select-single').click();
await page.getByRole('option', { name: 'ID', exact: true }).click();
await page.getByLabel('block-item-Radio.Group-workflows').getByText('DESC').click();
await expect(queryRecordNode.pageNumberEditBox).toHaveValue('1');
await expect(queryRecordNode.pageSizeEditBox).toHaveValue('20');
const pageNumber = faker.number.int({ min: 1, max: 5 });
const pageSize = faker.number.int({ min: 1, max: 4 });
await queryRecordNode.pageNumberEditBox.fill(pageNumber.toString());
await queryRecordNode.pageSizeEditBox.fill(pageSize.toString());
await queryRecordNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
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 getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === queryRecordNodeId);
const queryRecordNodeJobResult = queryRecordNodeJob.result;
let nodeResultRecords = 0;
const recordCount = triggerNodeCollectionRecordNumber + 1;
if (pageNumber > Math.ceil(recordCount / pageSize)) {
nodeResultRecords = 0;
expect(queryRecordNodeJobResult).toEqual([]);
} else if (pageNumber * pageSize > recordCount) {
nodeResultRecords = recordCount - (pageNumber - 1) * pageSize;
expect(queryRecordNodeJobResult.length).toBe(nodeResultRecords);
// 获取数组中对象下ID的值
const nodeResultRecordsIDArray = queryRecordNodeJobResult.map((obj) => obj.id);
// 断言数组的最小值等于1
expect(Math.min(...nodeResultRecordsIDArray)).toBe(1);
// 断言数组的最大值等于总记录数
expect(Math.max(...nodeResultRecordsIDArray)).toBe(nodeResultRecords);
} else {
nodeResultRecords = pageSize;
expect(queryRecordNodeJobResult.length).toBe(nodeResultRecords);
const nodeResultRecordsIDArray = queryRecordNodeJobResult.map((obj) => obj.id);
// 断言数组的最小值等于(页码-1*每页记录数+1
expect(Math.min(...nodeResultRecordsIDArray)).toBe(recordCount - pageNumber * pageSize + 1);
// 断言数组的最大值等于pageNumber * pageSize
expect(Math.max(...nodeResultRecordsIDArray)).toBe(recordCount - (pageNumber - 1) * pageSize);
}
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, no filtering and no sorting, query multiple records of a common table, set page X to Y per page', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
const triggerNodeCollectionRecordNumber = faker.number.int({ min: 0, max: 19 });
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, triggerNodeCollectionRecordNumber);
//添加工作流
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));
//配置查询节点
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: 'query', exact: true }).click();
const queryRecordNodeName = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Query record-Query record', { exact: true }).getByRole('textbox').fill(queryRecordNodeName);
const queryRecordNode = new QueryRecordNode(page, queryRecordNodeName);
const queryRecordNodeId = await queryRecordNode.node.locator('.workflow-node-id').innerText();
await queryRecordNode.nodeConfigure.click();
await queryRecordNode.collectionDropDown.click();
await page.getByRole('option', { name: triggerNodeCollectionDisplayName }).click();
await queryRecordNode.allowMultipleDataBoxesForResults.check();
await expect(queryRecordNode.pageNumberEditBox).toHaveValue('1');
await expect(queryRecordNode.pageSizeEditBox).toHaveValue('20');
const pageNumber = faker.number.int({ min: 1, max: 5 });
const pageSize = faker.number.int({ min: 1, max: 4 });
await queryRecordNode.pageNumberEditBox.fill(pageNumber.toString());
await queryRecordNode.pageSizeEditBox.fill(pageSize.toString());
await queryRecordNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
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 getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === queryRecordNodeId);
const queryRecordNodeJobResult = queryRecordNodeJob.result;
let nodeResultRecords = 0;
const recordCount = triggerNodeCollectionRecordNumber + 1;
if (pageNumber > Math.ceil(recordCount / pageSize)) {
nodeResultRecords = 0;
expect(queryRecordNodeJobResult).toEqual([]);
} else if (pageNumber * pageSize > recordCount) {
nodeResultRecords = recordCount - (pageNumber - 1) * pageSize;
expect(queryRecordNodeJobResult.length).toBe(nodeResultRecords);
// 获取数组中对象下ID的值
const nodeResultRecordsIDArray = queryRecordNodeJobResult.map((obj) => obj.id);
// 断言数组的最小值等于(页码-1*每页记录数+1
expect(Math.min(...nodeResultRecordsIDArray)).toBe((pageNumber - 1) * pageSize + 1);
// 断言数组的最大值等于总记录数
expect(Math.max(...nodeResultRecordsIDArray)).toBe(recordCount);
} else {
nodeResultRecords = pageSize;
expect(queryRecordNodeJobResult.length).toBe(nodeResultRecords);
const nodeResultRecordsIDArray = queryRecordNodeJobResult.map((obj) => obj.id);
// 断言数组的最小值等于(页码-1*每页记录数+1
expect(Math.min(...nodeResultRecordsIDArray)).toBe((pageNumber - 1) * pageSize + 1);
// 断言数组的最大值等于pageNumber * pageSize
expect(Math.max(...nodeResultRecordsIDArray)).toBe(pageNumber * pageSize);
}
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, no filtering and no sorting, query the ordinary table 1 record, set the X page Y per page, query the results of the empty, exit the process', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
const triggerNodeCollectionRecordNumber = faker.number.int({ min: 0, max: 19 });
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, triggerNodeCollectionRecordNumber);
//添加工作流
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));
//配置查询节点
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: 'query', exact: true }).click();
const queryRecordNodeName = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Query record-Query record', { exact: true }).getByRole('textbox').fill(queryRecordNodeName);
const queryRecordNode = new QueryRecordNode(page, queryRecordNodeName);
const queryRecordNodeId = await queryRecordNode.node.locator('.workflow-node-id').innerText();
await queryRecordNode.nodeConfigure.click();
await queryRecordNode.collectionDropDown.click();
await page.getByRole('option', { name: triggerNodeCollectionDisplayName }).click();
// await queryRecordNode.allowMultipleDataBoxesForResults.check();
await expect(queryRecordNode.pageNumberEditBox).toHaveValue('1');
await expect(queryRecordNode.pageSizeEditBox).toHaveValue('20');
const pageNumber = faker.number.int({ min: 5, max: 5 });
const pageSize = faker.number.int({ min: 5, max: 5 });
await queryRecordNode.pageNumberEditBox.fill(pageNumber.toString());
await queryRecordNode.pageSizeEditBox.fill(pageSize.toString());
await queryRecordNode.exitProcessOptionsBoxWithEmptyResult.check();
await expect(queryRecordNode.exitProcessOptionsBoxWithEmptyResult).toBeChecked();
await queryRecordNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
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 getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === queryRecordNodeId);
const queryRecordNodeJobResult = queryRecordNodeJob.result;
let nodeResultRecords = 0;
const recordCount = triggerNodeCollectionRecordNumber + 1;
if (pageNumber > Math.ceil(recordCount / pageSize)) {
nodeResultRecords = 0;
// expect(queryRecordNodeJobResult).toEqual([]);
expect(queryRecordNodeJobResult).toBeNull();
} else if (pageNumber * pageSize > recordCount) {
nodeResultRecords = recordCount - (pageNumber - 1) * pageSize;
expect(queryRecordNodeJobResult.length).toBe(nodeResultRecords);
// 获取数组中对象下ID的值
const nodeResultRecordsIDArray = queryRecordNodeJobResult.map((obj) => obj.id);
// 断言数组的最小值等于(页码-1*每页记录数+1
expect(Math.min(...nodeResultRecordsIDArray)).toBe((pageNumber - 1) * pageSize + 1);
// 断言数组的最大值等于总记录数
expect(Math.max(...nodeResultRecordsIDArray)).toBe(recordCount);
} else {
nodeResultRecords = pageSize;
expect(queryRecordNodeJobResult.length).toBe(nodeResultRecords);
const nodeResultRecordsIDArray = queryRecordNodeJobResult.map((obj) => obj.id);
// 断言数组的最小值等于(页码-1*每页记录数+1
expect(Math.min(...nodeResultRecordsIDArray)).toBe((pageNumber - 1) * pageSize + 1);
// 断言数组的最大值等于pageNumber * pageSize
expect(Math.max(...nodeResultRecordsIDArray)).toBe(pageNumber * pageSize);
}
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, no filtering and no sorting, query the common table multiple records, set the X page Y per page, query results are empty, exit the process', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = faker.string.alphanumeric(5);
//创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
const triggerNodeCollectionRecordNumber = faker.number.int({ min: 0, max: 19 });
const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, triggerNodeCollectionRecordNumber);
//添加工作流
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));
//配置查询节点
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: 'query', exact: true }).click();
const queryRecordNodeName = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Query record-Query record', { exact: true }).getByRole('textbox').fill(queryRecordNodeName);
const queryRecordNode = new QueryRecordNode(page, queryRecordNodeName);
const queryRecordNodeId = await queryRecordNode.node.locator('.workflow-node-id').innerText();
await queryRecordNode.nodeConfigure.click();
await queryRecordNode.collectionDropDown.click();
await page.getByRole('option', { name: triggerNodeCollectionDisplayName }).click();
await queryRecordNode.allowMultipleDataBoxesForResults.check();
await expect(queryRecordNode.pageNumberEditBox).toHaveValue('1');
await expect(queryRecordNode.pageSizeEditBox).toHaveValue('20');
const pageNumber = faker.number.int({ min: 5, max: 5 });
const pageSize = faker.number.int({ min: 5, max: 5 });
await queryRecordNode.pageNumberEditBox.fill(pageNumber.toString());
await queryRecordNode.pageSizeEditBox.fill(pageSize.toString());
await queryRecordNode.exitProcessOptionsBoxWithEmptyResult.check();
await expect(queryRecordNode.exitProcessOptionsBoxWithEmptyResult).toBeChecked();
await queryRecordNode.submitButton.click();
// 2、测试步骤添加数据触发工作流
const triggerNodeCollectionRecordOne = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
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 getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === queryRecordNodeId);
const queryRecordNodeJobResult = queryRecordNodeJob.result;
let nodeResultRecords = 0;
const recordCount = triggerNodeCollectionRecordNumber + 1;
if (pageNumber > Math.ceil(recordCount / pageSize)) {
nodeResultRecords = 0;
expect(queryRecordNodeJobResult).toEqual([]);
} else if (pageNumber * pageSize > recordCount) {
nodeResultRecords = recordCount - (pageNumber - 1) * pageSize;
expect(queryRecordNodeJobResult.length).toBe(nodeResultRecords);
// 获取数组中对象下ID的值
const nodeResultRecordsIDArray = queryRecordNodeJobResult.map((obj) => obj.id);
// 断言数组的最小值等于(页码-1*每页记录数+1
expect(Math.min(...nodeResultRecordsIDArray)).toBe((pageNumber - 1) * pageSize + 1);
// 断言数组的最大值等于总记录数
expect(Math.max(...nodeResultRecordsIDArray)).toBe(recordCount);
} else {
nodeResultRecords = pageSize;
expect(queryRecordNodeJobResult.length).toBe(nodeResultRecords);
const nodeResultRecordsIDArray = queryRecordNodeJobResult.map((obj) => obj.id);
// 断言数组的最小值等于(页码-1*每页记录数+1
expect(Math.min(...nodeResultRecordsIDArray)).toBe((pageNumber - 1) * pageSize + 1);
// 断言数组的最大值等于pageNumber * pageSize
expect(Math.max(...nodeResultRecordsIDArray)).toBe(pageNumber * pageSize);
}
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, filter to meet all conditions (status_singleselect=1 and staffnum>20) unsorted, query normal table 1 record', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
const queryNodeAppendText = 'b' + faker.string.alphanumeric(4);
// 创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
// 创建查询节点数据表
const queryNodeCollectionDisplayName = `自动>组织[普通表]${queryNodeAppendText}`;
const queryNodeCollectionName = `tt_amt_org${queryNodeAppendText}`;
const queryNodeFieldName = 'orgname';
const queryNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), queryNodeAppendText)
.collections,
);
const queryNodeCollectioRecordOne = [{ status_singleselect: '1', staffnum: 10 }];
const queryNodeCollectioRecordTwo = [{ status_singleselect: '1', staffnum: 20 }];
const queryNodeCollectioRecordThree = [{ status_singleselect: '1', staffnum: 30 }];
const queryNodeCollectioRecordFour = [{ status_singleselect: '1', staffnum: 40 }];
const queryNodeCollectioRecordFive = [{ status_singleselect: '2', staffnum: 10 }];
const queryNodeCollectioRecordSix = [{ status_singleselect: '2', staffnum: 20 }];
const queryNodeCollectioRecordSeven = [{ status_singleselect: '2', staffnum: 30 }];
const queryNodeCollectioRecordEight = [{ status_singleselect: '2', staffnum: 40 }];
await mockRecords(queryNodeCollectionName, queryNodeCollectioRecordOne);
await mockRecords(queryNodeCollectionName, queryNodeCollectioRecordTwo);
await mockRecords(queryNodeCollectionName, queryNodeCollectioRecordThree);
await mockRecords(queryNodeCollectionName, queryNodeCollectioRecordFour);
await mockRecords(queryNodeCollectionName, queryNodeCollectioRecordFive);
await mockRecords(queryNodeCollectionName, queryNodeCollectioRecordSix);
await mockRecords(queryNodeCollectionName, queryNodeCollectioRecordSeven);
await mockRecords(queryNodeCollectionName, queryNodeCollectioRecordEight);
//添加工作流
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));
//配置查询节点
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: 'query', exact: true }).click();
const queryRecordNodeName = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Query record-Query record', { exact: true }).getByRole('textbox').fill(queryRecordNodeName);
const queryRecordNode = new QueryRecordNode(page, queryRecordNodeName);
const queryRecordNodeId = await queryRecordNode.node.locator('.workflow-node-id').innerText();
await queryRecordNode.nodeConfigure.click();
await queryRecordNode.collectionDropDown.click();
await page.getByText(queryNodeCollectionDisplayName).click();
// await queryRecordNode.allowMultipleDataBoxesForResults.check();
// 设置过滤条件
await page.getByText('Add condition', { exact: true }).click();
await page.getByLabel('block-item-Filter-workflows-Filter').getByRole('button', { name: 'Select field' }).click();
await page.getByRole('menuitemcheckbox', { name: '公司状态(下拉单选)' }).click();
await page.getByTestId('select-single').click();
await page.getByRole('option', { name: '存续' }).click();
await page.getByText('Add condition', { exact: true }).click();
await page.getByLabel('block-item-Filter-workflows-Filter').getByRole('button', { name: 'Select field' }).click();
await page.getByRole('menuitemcheckbox', { name: '员工人数(整数)' }).click();
await page.getByRole('button', { name: '=' }).click();
await page.getByRole('option', { name: '>' }).click();
await page.getByLabel('block-item-Filter-workflows-Filter').getByRole('spinbutton').fill('20');
await queryRecordNode.submitButton.click();
// 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 getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === queryRecordNodeId);
const queryRecordNodeJobResult = queryRecordNodeJob.result;
const nodeResultRecordID = queryRecordNodeJobResult.id;
const expectRecordIDArray = [3, 4];
// 断言nodeResultRecordID的值在expectRecordIDArray数组中
expect(expectRecordIDArray).toContain(nodeResultRecordID);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});
test('Collection event add data trigger, filter to satisfy any condition (status_singleselect=1 or staffnum>20) unsorted, query common table for multiple rows, set page X to Y per page', async ({
page,
mockCollections,
mockRecords,
}) => {
//数据表后缀标识
const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
const queryNodeAppendText = 'b' + faker.string.alphanumeric(4);
// 创建触发器节点数据表
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
const triggerNodeFieldName = 'orgname';
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
.collections,
);
// 创建查询节点数据表
const queryNodeCollectionDisplayName = `自动>组织[普通表]${queryNodeAppendText}`;
const queryNodeCollectionName = `tt_amt_org${queryNodeAppendText}`;
const queryNodeFieldName = 'orgname';
const queryNodeFieldDisplayName = '公司名称(单行文本)';
await mockCollections(
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), queryNodeAppendText)
.collections,
);
const queryNodeCollectioRecordOne = [{ status_singleselect: '1', staffnum: 10 }];
const queryNodeCollectioRecordTwo = [{ status_singleselect: '1', staffnum: 20 }];
const queryNodeCollectioRecordThree = [{ status_singleselect: '1', staffnum: 30 }];
const queryNodeCollectioRecordFour = [{ status_singleselect: '1', staffnum: 40 }];
const queryNodeCollectioRecordFive = [{ status_singleselect: '2', staffnum: 10 }];
const queryNodeCollectioRecordSix = [{ status_singleselect: '2', staffnum: 20 }];
const queryNodeCollectioRecordSeven = [{ status_singleselect: '2', staffnum: 30 }];
const queryNodeCollectioRecordEight = [{ status_singleselect: '2', staffnum: 40 }];
await mockRecords(queryNodeCollectionName, queryNodeCollectioRecordOne);
await mockRecords(queryNodeCollectionName, queryNodeCollectioRecordTwo);
await mockRecords(queryNodeCollectionName, queryNodeCollectioRecordThree);
await mockRecords(queryNodeCollectionName, queryNodeCollectioRecordFour);
await mockRecords(queryNodeCollectionName, queryNodeCollectioRecordFive);
await mockRecords(queryNodeCollectionName, queryNodeCollectioRecordSix);
await mockRecords(queryNodeCollectionName, queryNodeCollectioRecordSeven);
await mockRecords(queryNodeCollectionName, queryNodeCollectioRecordEight);
//添加工作流
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));
//配置查询节点
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: 'query', exact: true }).click();
const queryRecordNodeName = 'Query record' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByLabel('Query record-Query record', { exact: true }).getByRole('textbox').fill(queryRecordNodeName);
const queryRecordNode = new QueryRecordNode(page, queryRecordNodeName);
const queryRecordNodeId = await queryRecordNode.node.locator('.workflow-node-id').innerText();
await queryRecordNode.nodeConfigure.click();
await queryRecordNode.collectionDropDown.click();
await page.getByText(queryNodeCollectionDisplayName).click();
await queryRecordNode.allowMultipleDataBoxesForResults.check();
// 设置过滤条件
await page.getByTestId('filter-select-all-or-any').click();
await page.getByRole('option', { name: 'Any' }).click();
await page.getByText('Add condition', { exact: true }).click();
await page.getByLabel('block-item-Filter-workflows-Filter').getByRole('button', { name: 'Select field' }).click();
await page.getByRole('menuitemcheckbox', { name: '公司状态(下拉单选)' }).click();
await page.getByTestId('select-single').click();
await page.getByRole('option', { name: '存续' }).click();
await page.getByText('Add condition', { exact: true }).click();
await page.getByLabel('block-item-Filter-workflows-Filter').getByRole('button', { name: 'Select field' }).click();
await page.getByRole('menuitemcheckbox', { name: '员工人数(整数)' }).click();
await page.getByRole('button', { name: '=' }).click();
await page.getByRole('option', { name: '>' }).click();
await page.getByLabel('block-item-Filter-workflows-Filter').getByRole('spinbutton').fill('20');
await queryRecordNode.submitButton.click();
// 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 getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
return b.id - a.id;
});
const jobs = getWorkflowNodeExecutionsObj[0].jobs;
const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === queryRecordNodeId);
const queryRecordNodeJobResult = queryRecordNodeJob.result;
expect(queryRecordNodeJobResult.length).toBe(6);
// 4、后置处理删除工作流
await apiDeleteWorkflow(workflowId);
});

View File

@ -1,36 +0,0 @@
import { expect, test } from '@nocobase/test/e2e';
import { dayjs } from '@nocobase/utils';
import { CreateWorkFlow } from './pageobject/workFlow';
test.describe('workflow manage', () => {
test('add new from event', async ({ page }) => {
//用例编号
const caseNum = 'WF02AA';
//用例标题
const caseTitle = 'add new from event';
// 1、前置条件已登录
// 2、测试步骤进入“工作流管理”-“新建”按钮,填写表单,点击“确定”按钮
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
await page.getByLabel('action-Action-Add new-workflows').click();
const createWorkFlow = new CreateWorkFlow(page);
const workFlowName = caseTitle + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await createWorkFlow.name.fill(workFlowName);
await createWorkFlow.triggerType.click();
await page.getByRole('option', { name: 'Form event' }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
// 3、预期结果新建成功列表中出现新建的工作流
await expect(page.getByText(workFlowName)).toBeVisible();
// 4、后置处理删除新建的工作流
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
await page.getByRole('textbox').fill(workFlowName);
await page.getByRole('button', { name: 'Submit' }).click();
await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName}`).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
await expect(page.getByText(workFlowName)).toBeHidden();
});
});

View File

@ -1,43 +0,0 @@
import { expect, test } from '@nocobase/test/e2e';
import { dayjs } from '@nocobase/utils';
import { CreateWorkFlow, EditWorkFlow } from './pageobject/workFlow';
test.describe('workflow manage', () => {
test('edit from event name', async ({ page }) => {
//用例编号
const caseNum = 'WF05AA';
//用例标题
const caseTitle = 'edit from event name';
// 1、前置条件1.1、已登录,1.2、存在一个工作流
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
await page.getByLabel('action-Action-Add new-workflows').click();
const createWorkFlow = new CreateWorkFlow(page);
let workFlowName = caseTitle + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await createWorkFlow.name.fill(workFlowName);
await createWorkFlow.triggerType.click();
await page.getByRole('option', { name: 'Form event' }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
await expect(page.getByText(workFlowName)).toBeAttached();
// 2、测试步骤进入“工作流管理”-“编辑”按钮,编辑名称,点击“确定”按钮
await page.getByLabel(`action-Action.Link-Edit-workflows-${workFlowName}`).click();
const editWorkFlow = new EditWorkFlow(page);
workFlowName = caseTitle + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await createWorkFlow.name.fill(workFlowName);
await page.getByLabel('action-Action-Submit-workflows').click();
// 3、预期结果编辑成功列表中出现编辑后的工作流
await expect(page.getByText(workFlowName)).toBeAttached();
// 4、后置处理删除工作流
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
await page.getByRole('textbox').fill(workFlowName);
await page.getByRole('button', { name: 'Submit' }).click();
await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName}`).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
await expect(page.getByText(workFlowName)).toBeHidden();
});
});

View File

@ -1,39 +0,0 @@
import type { Locator, Page } from '@nocobase/test/e2e';
export class CreateWorkFlow {
readonly page: Page;
name: Locator;
triggerType: Locator;
description: Locator;
autoDeleteHistory: Locator;
constructor(page: Page) {
this.page = page;
this.name = page.getByLabel('block-item-CollectionField-workflows-Name').getByRole('textbox');
this.triggerType = page.getByTestId('select-single');
this.description = page.getByTestId('description-item').getByRole('textbox');
this.autoDeleteHistory = page.getByTestId('select-multiple');
}
}
export class EditWorkFlow {
readonly page: Page;
name: Locator;
statusIsOn: Locator;
statusIisOff: Locator;
description: Locator;
autoDeleteHistory: Locator;
constructor(page: Page) {
this.page = page;
this.name = page.getByTestId('title-item').getByRole('textbox');
this.statusIsOn = page.getByTestId('enabled-item').getByLabel('On');
this.statusIisOff = page.getByLabel('Off');
this.description = page.getByTestId('description-item').getByRole('textbox');
this.autoDeleteHistory = page
.getByTestId('deleteExecutionOnStatus-item')
.getByTestId('antd-select')
.locator('div')
.nth(1);
}
}

View File

@ -1,99 +0,0 @@
import { expect, test } from '@nocobase/test/e2e';
import { dayjs } from '@nocobase/utils';
import { appendJsonCollectionName, e2e_GeneralFormsTable, generateRandomLetters } from './pageobject/e2eTemplateJson';
import { CreateWorkFlow } from './pageobject/workFlow';
test.describe('trigger collection events', () => {
test('add data to trigger collection events', async ({ page, mockPage }) => {
//用例编号
const caseNum = 'WF20AA';
//后缀标识用于不同用例调用e2eTemplateJson.ts中相同模板JSON生成不同的数据表标识、名称
const appendText = caseNum.toLowerCase() + generateRandomLetters().toString();
//用例标题
const caseTitle = 'add data to trigger collection events';
// 1、前置条件1.1、已登录;1.2、存在一个配置好数据表的表单事件工作流1.3、存在一个添加数据的区块
//创建数据表
const e2eJsonCollectionDisplayName = '自动>组织[普通表]';
const e2eJsonCollectionName = 'tt_amt_org';
const collectionDisplayName = e2eJsonCollectionDisplayName + appendText;
const collectionName = e2eJsonCollectionName + appendText;
const fieldName = 'orgname';
const fieldDisplayName = '公司名称(单行文本)';
const newPage = mockPage(appendJsonCollectionName(e2e_GeneralFormsTable, appendText));
//配置工作流
await page.goto('/admin/settings/workflow');
await page.waitForLoadState('networkidle');
await page.getByLabel('action-Action-Add new-workflows').click();
const createWorkFlow = new CreateWorkFlow(page);
const workFlowName = caseTitle + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await createWorkFlow.name.fill(workFlowName);
await createWorkFlow.triggerType.click();
await page.getByTitle('Collection event').getByText('Collection event').click();
await page.getByLabel('action-Action-Submit-workflows').click();
await expect(page.getByText(workFlowName)).toBeVisible();
//配置工作流触发器
await page.getByLabel(`action-WorkflowLink-Configure-workflows-${workFlowName}`).click();
await page.getByRole('button', { name: 'Configure' }).click();
await page.getByTestId('select-collection').click();
await page.getByText(collectionDisplayName).click();
await page.getByTestId('select-single').click();
await page.getByText('After record added', { exact: true }).click();
await page.getByLabel('action-Action-Submit-workflows').click();
await page.getByRole('link', { name: 'Workflow' }).click();
await page.getByLabel(`action-Action.Link-Edit-workflows-${workFlowName}`).click();
await page.getByLabel('On', { exact: true }).check();
await page.getByLabel('action-Action-Submit-workflows').click();
//配置录入数据区块
await newPage.goto();
await page.getByLabel('schema-initializer-Grid-BlockInitializers').hover();
await page.getByRole('menuitem', { name: 'table Table' }).hover();
await page.getByRole('menuitem', { name: collectionDisplayName }).click();
// 移开鼠标,关闭菜单
await page.mouse.move(300, 0);
await page.getByText('Configure columns').hover();
await page.getByText(fieldDisplayName).click();
await page.getByText('Configure actions').hover();
await page.getByRole('menuitem', { name: 'Add new' }).click();
await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).toBeEnabled();
await page.getByLabel(`action-Action-Add new-create-tt_amt_org${appendText}-table`).click();
await page.getByLabel(`schema-initializer-Grid-CreateFormBlockInitializers-tt_amt_org${appendText}`).hover();
await page.getByRole('menuitem', { name: 'form Form' }).click();
// 移开鼠标,关闭菜单
await page.mouse.move(300, 0);
await page.getByLabel(`schema-initializer-ActionBar-CreateFormActionInitializers-tt_amt_org${appendText}`).hover();
await page.getByRole('menuitem', { name: 'Submit' }).click();
await page.getByLabel(`schema-initializer-Grid-FormItemInitializers-tt_amt_org${appendText}`).hover();
await page.getByRole('menuitem', { name: fieldDisplayName }).click();
await page.mouse.move(300, 0);
// 2、测试步骤进入“数据区块”-“添加”按钮,填写表单,点击“确定”按钮
const fieldData = fieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
await page.getByRole('textbox').fill(fieldData);
await page.getByLabel(`action-Action-Submit-submit-${collectionName}-form`, { exact: true }).click();
await expect(page.getByText(fieldData)).toBeVisible();
// 3、预期结果数据添加成功工作流成功触发
await expect(page.getByText(fieldData)).toBeVisible();
await page.goto('/admin/settings/workflow');
await expect(page.getByRole('table').locator('a').filter({ hasText: '1' })).toBeVisible();
// 4、后置处理删除工作流
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
await page.getByRole('textbox').fill(workFlowName);
await page.getByRole('button', { name: 'Submit' }).click();
await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName}`).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
await expect(page.getByText(workFlowName)).toBeHidden();
});
});

View File

@ -19128,6 +19128,13 @@ osx-release@^1.0.0:
dependencies:
minimist "^1.1.0"
p-all@3.0.0:
version "3.0.0"
resolved "https://registry.npmmirror.com/p-all/-/p-all-3.0.0.tgz#077c023c37e75e760193badab2bad3ccd5782bfb"
integrity sha512-qUZbvbBFVXm6uJ7U/WDiO0fv6waBMbjlCm4E66oZdRR+egswICarIdHyVSZZHudH8T5SF8x/JG0q0duFzPnlBw==
dependencies:
p-map "^4.0.0"
p-cancelable@^1.0.0:
version "1.1.0"
resolved "https://registry.npmmirror.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc"