From cd09649e1ca901a9c4c96488db2a08679a9f5ca3 Mon Sep 17 00:00:00 2001 From: hongboji <116709317+hongboji@users.noreply.github.com> Date: Thu, 1 Feb 2024 17:49:07 +0800 Subject: [PATCH] test: parallel branch node e2e (#3471) * test: add parallel branch node e2e * test: parallel branch node e2e --- .../src/client/__e2e__/parallelBranch.test.ts | 1207 +++++++++++++++++ .../src/e2e/e2ePageObjectModel.ts | 28 + 2 files changed, 1235 insertions(+) create mode 100644 packages/plugins/@nocobase/plugin-workflow-parallel/src/client/__e2e__/parallelBranch.test.ts diff --git a/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/__e2e__/parallelBranch.test.ts b/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/__e2e__/parallelBranch.test.ts new file mode 100644 index 0000000000..89421bd759 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-workflow-parallel/src/client/__e2e__/parallelBranch.test.ts @@ -0,0 +1,1207 @@ +import { faker } from '@faker-js/faker'; +import { + CollectionTriggerNode, + apiCreateWorkflow, + apiDeleteWorkflow, + apiGetWorkflow, + apiUpdateWorkflowTrigger, + appendJsonCollectionName, + generalWithNoRelationalFields, + ParallelBranchNode, + ConditionYesNode, + ClculationNode, + apiGetWorkflowNodeExecutions, +} from '@nocobase/plugin-workflow-test/e2e'; +import { expect, test } from '@nocobase/test/e2e'; +import { dayjs } from '@nocobase/utils'; + +test.describe('All succeeded', () => { + test('All 3 branches were successful', async ({ page, mockCollections, mockRecords }) => { + //数据表后缀标识 + const triggerNodeAppendText = 'a' + 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 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: 'parallel', exact: true }).click(); + const parallelBranchNodeTitle = 'Parallel branch' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page + .getByLabel('Parallel branch-Parallel branch', { exact: true }) + .getByRole('textbox') + .fill(parallelBranchNodeTitle); + await page.mouse.move(300, 0, { steps: 100 }); + await page.mouse.click(300, 0); + // 添加一个分支 + const parallelBranchNode = new ParallelBranchNode(page, parallelBranchNodeTitle); + const parallelBranchNodeId = await parallelBranchNode.node.locator('.workflow-node-id').innerText(); + await parallelBranchNode.addBranchButton.click(); + // 分支1添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName); + const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName); + const oneConditionNodeId = await oneConditionNode.node.locator('.workflow-node-id').innerText(); + await oneConditionNode.nodeConfigure.click(); + await oneConditionNode.formulaRadio.click(); + await oneConditionNode.conditionExpressionEditBox.fill('1==1'); + await oneConditionNode.submitButton.click(); + // 分支2添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName); + const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName); + const twoConditionNodeId = await twoConditionNode.node.locator('.workflow-node-id').innerText(); + await twoConditionNode.nodeConfigure.click(); + await twoConditionNode.formulaRadio.click(); + await twoConditionNode.conditionExpressionEditBox.fill('1==1'); + await twoConditionNode.submitButton.click(); + // 分支3添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName); + const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName); + const threeConditionNodeId = await threeConditionNode.node.locator('.workflow-node-id').innerText(); + await threeConditionNode.nodeConfigure.click(); + await threeConditionNode.formulaRadio.click(); + await threeConditionNode.conditionExpressionEditBox.fill('1==1'); + await threeConditionNode.submitButton.click(); + // 添加后置计算节点 + await parallelBranchNode.addNodeButton.click(); + await page.getByRole('button', { name: 'calculation', exact: true }).click(); + const afterCalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page + .getByLabel('Calculation-Calculation', { exact: true }) + .getByRole('textbox') + .fill(afterCalCulationNodeName); + const afterCalCulationNode = new ClculationNode(page, afterCalCulationNodeName); + const afterCalCulationNodeId = await afterCalCulationNode.node.locator('.workflow-node-id').innerText(); + await afterCalCulationNode.nodeConfigure.click(); + await afterCalCulationNode.formulaCalculationEngine.click(); + await page.getByLabel('textbox').fill('4'); + await afterCalCulationNode.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 parallelBranchNodeJob = jobs.find((job) => job.nodeId.toString() === parallelBranchNodeId); + expect(parallelBranchNodeJob.status).toBe(1); + const oneConditionNodeJob = jobs.find((job) => job.nodeId.toString() === oneConditionNodeId); + expect(oneConditionNodeJob.status).toBe(1); + expect(oneConditionNodeJob.result).toBe(true); + const twoConditionNodeJob = jobs.find((job) => job.nodeId.toString() === twoConditionNodeId); + expect(twoConditionNodeJob.status).toBe(1); + expect(twoConditionNodeJob.result).toBe(true); + const threeConditionNodeJob = jobs.find((job) => job.nodeId.toString() === threeConditionNodeId); + expect(threeConditionNodeJob.status).toBe(1); + expect(threeConditionNodeJob.result).toBe(true); + const afterCalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === afterCalCulationNodeId); + expect(afterCalCulationNodeJob.status).toBe(1); + expect(afterCalCulationNodeJob.result).toBe(4); + // 4、后置处理:删除工作流 + await apiDeleteWorkflow(workflowId); + }); + + test('Branches 1 and 2 succeed, 3 fail', async ({ page, mockCollections, mockRecords }) => { + //数据表后缀标识 + const triggerNodeAppendText = 'a' + 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 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: 'parallel', exact: true }).click(); + const parallelBranchNodeTitle = 'Parallel branch' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page + .getByLabel('Parallel branch-Parallel branch', { exact: true }) + .getByRole('textbox') + .fill(parallelBranchNodeTitle); + await page.mouse.move(300, 0, { steps: 100 }); + await page.mouse.click(300, 0); + // 添加一个分支 + const parallelBranchNode = new ParallelBranchNode(page, parallelBranchNodeTitle); + const parallelBranchNodeId = await parallelBranchNode.node.locator('.workflow-node-id').innerText(); + await parallelBranchNode.addBranchButton.click(); + // 分支1添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName); + const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName); + const oneConditionNodeId = await oneConditionNode.node.locator('.workflow-node-id').innerText(); + await oneConditionNode.nodeConfigure.click(); + await oneConditionNode.formulaRadio.click(); + await oneConditionNode.conditionExpressionEditBox.fill('1==1'); + await oneConditionNode.submitButton.click(); + // 分支2添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName); + const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName); + const twoConditionNodeId = await twoConditionNode.node.locator('.workflow-node-id').innerText(); + await twoConditionNode.nodeConfigure.click(); + await twoConditionNode.formulaRadio.click(); + await twoConditionNode.conditionExpressionEditBox.fill('1==1'); + await twoConditionNode.submitButton.click(); + // 分支3添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName); + const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName); + const threeConditionNodeId = await threeConditionNode.node.locator('.workflow-node-id').innerText(); + await threeConditionNode.nodeConfigure.click(); + await threeConditionNode.formulaRadio.click(); + await threeConditionNode.conditionExpressionEditBox.fill('1==2'); + await threeConditionNode.submitButton.click(); + // 添加后置计算节点 + await parallelBranchNode.addNodeButton.click(); + await page.getByRole('button', { name: 'calculation', exact: true }).click(); + const afterCalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page + .getByLabel('Calculation-Calculation', { exact: true }) + .getByRole('textbox') + .fill(afterCalCulationNodeName); + const afterCalCulationNode = new ClculationNode(page, afterCalCulationNodeName); + const afterCalCulationNodeId = await afterCalCulationNode.node.locator('.workflow-node-id').innerText(); + await afterCalCulationNode.nodeConfigure.click(); + await afterCalCulationNode.formulaCalculationEngine.click(); + await page.getByLabel('textbox').fill('4'); + await afterCalCulationNode.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 parallelBranchNodeJob = jobs.find((job) => job.nodeId.toString() === parallelBranchNodeId); + expect(parallelBranchNodeJob.status).toBe(-1); + const oneConditionNodeJob = jobs.find((job) => job.nodeId.toString() === oneConditionNodeId); + expect(oneConditionNodeJob.status).toBe(1); + expect(oneConditionNodeJob.result).toBe(true); + const twoConditionNodeJob = jobs.find((job) => job.nodeId.toString() === twoConditionNodeId); + expect(twoConditionNodeJob.status).toBe(1); + expect(twoConditionNodeJob.result).toBe(true); + const threeConditionNodeJob = jobs.find((job) => job.nodeId.toString() === threeConditionNodeId); + expect(threeConditionNodeJob.status).toBe(-1); + expect(threeConditionNodeJob.result).toBe(false); + const afterCalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === afterCalCulationNodeId); + expect(afterCalCulationNodeJob).toBe(undefined); + // 4、后置处理:删除工作流 + await apiDeleteWorkflow(workflowId); + }); + + test('Branch 1 succeeds, 2 and 3 fail', async ({ page, mockCollections, mockRecords }) => { + //数据表后缀标识 + const triggerNodeAppendText = 'a' + 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 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: 'parallel', exact: true }).click(); + const parallelBranchNodeTitle = 'Parallel branch' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page + .getByLabel('Parallel branch-Parallel branch', { exact: true }) + .getByRole('textbox') + .fill(parallelBranchNodeTitle); + await page.mouse.move(300, 0, { steps: 100 }); + await page.mouse.click(300, 0); + // 添加一个分支 + const parallelBranchNode = new ParallelBranchNode(page, parallelBranchNodeTitle); + const parallelBranchNodeId = await parallelBranchNode.node.locator('.workflow-node-id').innerText(); + await parallelBranchNode.addBranchButton.click(); + // 分支1添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName); + const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName); + const oneConditionNodeId = await oneConditionNode.node.locator('.workflow-node-id').innerText(); + await oneConditionNode.nodeConfigure.click(); + await oneConditionNode.formulaRadio.click(); + await oneConditionNode.conditionExpressionEditBox.fill('1==1'); + await oneConditionNode.submitButton.click(); + // 分支2添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName); + const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName); + const twoConditionNodeId = await twoConditionNode.node.locator('.workflow-node-id').innerText(); + await twoConditionNode.nodeConfigure.click(); + await twoConditionNode.formulaRadio.click(); + await twoConditionNode.conditionExpressionEditBox.fill('1==2'); + await twoConditionNode.submitButton.click(); + // 分支3添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName); + const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName); + const threeConditionNodeId = await threeConditionNode.node.locator('.workflow-node-id').innerText(); + await threeConditionNode.nodeConfigure.click(); + await threeConditionNode.formulaRadio.click(); + await threeConditionNode.conditionExpressionEditBox.fill('1==2'); + await threeConditionNode.submitButton.click(); + // 添加后置计算节点 + await parallelBranchNode.addNodeButton.click(); + await page.getByRole('button', { name: 'calculation', exact: true }).click(); + const afterCalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page + .getByLabel('Calculation-Calculation', { exact: true }) + .getByRole('textbox') + .fill(afterCalCulationNodeName); + const afterCalCulationNode = new ClculationNode(page, afterCalCulationNodeName); + const afterCalCulationNodeId = await afterCalCulationNode.node.locator('.workflow-node-id').innerText(); + await afterCalCulationNode.nodeConfigure.click(); + await afterCalCulationNode.formulaCalculationEngine.click(); + await page.getByLabel('textbox').fill('4'); + await afterCalCulationNode.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 parallelBranchNodeJob = jobs.find((job) => job.nodeId.toString() === parallelBranchNodeId); + expect(parallelBranchNodeJob.status).toBe(-1); + const oneConditionNodeJob = jobs.find((job) => job.nodeId.toString() === oneConditionNodeId); + expect(oneConditionNodeJob.status).toBe(1); + expect(oneConditionNodeJob.result).toBe(true); + const twoConditionNodeJob = jobs.find((job) => job.nodeId.toString() === twoConditionNodeId); + expect(twoConditionNodeJob.status).toBe(-1); + expect(twoConditionNodeJob.result).toBe(false); + const threeConditionNodeJob = jobs.find((job) => job.nodeId.toString() === threeConditionNodeId); + expect(threeConditionNodeJob).toBe(undefined); + const afterCalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === afterCalCulationNodeId); + expect(afterCalCulationNodeJob).toBe(undefined); + // 4、后置处理:删除工作流 + await apiDeleteWorkflow(workflowId); + }); + + test('Branch 1 failed, 2 and 3 succeeded', async ({ page, mockCollections, mockRecords }) => { + //数据表后缀标识 + const triggerNodeAppendText = 'a' + 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 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: 'parallel', exact: true }).click(); + const parallelBranchNodeTitle = 'Parallel branch' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page + .getByLabel('Parallel branch-Parallel branch', { exact: true }) + .getByRole('textbox') + .fill(parallelBranchNodeTitle); + await page.mouse.move(300, 0, { steps: 100 }); + await page.mouse.click(300, 0); + // 添加一个分支 + const parallelBranchNode = new ParallelBranchNode(page, parallelBranchNodeTitle); + const parallelBranchNodeId = await parallelBranchNode.node.locator('.workflow-node-id').innerText(); + await parallelBranchNode.addBranchButton.click(); + // 分支1添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName); + const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName); + const oneConditionNodeId = await oneConditionNode.node.locator('.workflow-node-id').innerText(); + await oneConditionNode.nodeConfigure.click(); + await oneConditionNode.formulaRadio.click(); + await oneConditionNode.conditionExpressionEditBox.fill('1==2'); + await oneConditionNode.submitButton.click(); + // 分支2添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName); + const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName); + const twoConditionNodeId = await twoConditionNode.node.locator('.workflow-node-id').innerText(); + await twoConditionNode.nodeConfigure.click(); + await twoConditionNode.formulaRadio.click(); + await twoConditionNode.conditionExpressionEditBox.fill('1==1'); + await twoConditionNode.submitButton.click(); + // 分支3添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName); + const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName); + const threeConditionNodeId = await threeConditionNode.node.locator('.workflow-node-id').innerText(); + await threeConditionNode.nodeConfigure.click(); + await threeConditionNode.formulaRadio.click(); + await threeConditionNode.conditionExpressionEditBox.fill('1==1'); + await threeConditionNode.submitButton.click(); + // 添加后置计算节点 + await parallelBranchNode.addNodeButton.click(); + await page.getByRole('button', { name: 'calculation', exact: true }).click(); + const afterCalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page + .getByLabel('Calculation-Calculation', { exact: true }) + .getByRole('textbox') + .fill(afterCalCulationNodeName); + const afterCalCulationNode = new ClculationNode(page, afterCalCulationNodeName); + const afterCalCulationNodeId = await afterCalCulationNode.node.locator('.workflow-node-id').innerText(); + await afterCalCulationNode.nodeConfigure.click(); + await afterCalCulationNode.formulaCalculationEngine.click(); + await page.getByLabel('textbox').fill('4'); + await afterCalCulationNode.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 parallelBranchNodeJob = jobs.find((job) => job.nodeId.toString() === parallelBranchNodeId); + expect(parallelBranchNodeJob.status).toBe(-1); + const oneConditionNodeJob = jobs.find((job) => job.nodeId.toString() === oneConditionNodeId); + expect(oneConditionNodeJob.status).toBe(-1); + expect(oneConditionNodeJob.result).toBe(false); + const twoConditionNodeJob = jobs.find((job) => job.nodeId.toString() === twoConditionNodeId); + expect(twoConditionNodeJob).toBe(undefined); + const threeConditionNodeJob = jobs.find((job) => job.nodeId.toString() === threeConditionNodeId); + expect(threeConditionNodeJob).toBe(undefined); + const afterCalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === afterCalCulationNodeId); + expect(afterCalCulationNodeJob).toBe(undefined); + // 4、后置处理:删除工作流 + await apiDeleteWorkflow(workflowId); + }); +}); + +test.describe('Any succeeded', () => { + test('All 3 branches were successful', async ({ page, mockCollections, mockRecords }) => { + //数据表后缀标识 + const triggerNodeAppendText = 'a' + 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 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: 'parallel', exact: true }).click(); + const parallelBranchNodeTitle = 'Parallel branch' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page + .getByLabel('Parallel branch-Parallel branch', { exact: true }) + .getByRole('textbox') + .fill(parallelBranchNodeTitle); + await page.mouse.move(300, 0, { steps: 100 }); + await page.mouse.click(300, 0); + // 添加一个分支 + const parallelBranchNode = new ParallelBranchNode(page, parallelBranchNodeTitle); + const parallelBranchNodeId = await parallelBranchNode.node.locator('.workflow-node-id').innerText(); + await parallelBranchNode.nodeConfigure.click(); + await parallelBranchNode.anySucceededRadio.click(); + await parallelBranchNode.submitButton.click(); + await parallelBranchNode.addBranchButton.click(); + // 分支1添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName); + const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName); + const oneConditionNodeId = await oneConditionNode.node.locator('.workflow-node-id').innerText(); + await oneConditionNode.nodeConfigure.click(); + await oneConditionNode.formulaRadio.click(); + await oneConditionNode.conditionExpressionEditBox.fill('1==1'); + await oneConditionNode.submitButton.click(); + // 分支2添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName); + const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName); + const twoConditionNodeId = await twoConditionNode.node.locator('.workflow-node-id').innerText(); + await twoConditionNode.nodeConfigure.click(); + await twoConditionNode.formulaRadio.click(); + await twoConditionNode.conditionExpressionEditBox.fill('1==1'); + await twoConditionNode.submitButton.click(); + // 分支3添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName); + const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName); + const threeConditionNodeId = await threeConditionNode.node.locator('.workflow-node-id').innerText(); + await threeConditionNode.nodeConfigure.click(); + await threeConditionNode.formulaRadio.click(); + await threeConditionNode.conditionExpressionEditBox.fill('1==1'); + await threeConditionNode.submitButton.click(); + // 添加后置计算节点 + await parallelBranchNode.addNodeButton.click(); + await page.getByRole('button', { name: 'calculation', exact: true }).click(); + const afterCalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page + .getByLabel('Calculation-Calculation', { exact: true }) + .getByRole('textbox') + .fill(afterCalCulationNodeName); + const afterCalCulationNode = new ClculationNode(page, afterCalCulationNodeName); + const afterCalCulationNodeId = await afterCalCulationNode.node.locator('.workflow-node-id').innerText(); + await afterCalCulationNode.nodeConfigure.click(); + await afterCalCulationNode.formulaCalculationEngine.click(); + await page.getByLabel('textbox').fill('4'); + await afterCalCulationNode.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 parallelBranchNodeJob = jobs.find((job) => job.nodeId.toString() === parallelBranchNodeId); + expect(parallelBranchNodeJob.status).toBe(1); + const oneConditionNodeJob = jobs.find((job) => job.nodeId.toString() === oneConditionNodeId); + expect(oneConditionNodeJob.status).toBe(1); + expect(oneConditionNodeJob.result).toBe(true); + const twoConditionNodeJob = jobs.find((job) => job.nodeId.toString() === twoConditionNodeId); + expect(twoConditionNodeJob).toBe(undefined); + const threeConditionNodeJob = jobs.find((job) => job.nodeId.toString() === threeConditionNodeId); + expect(threeConditionNodeJob).toBe(undefined); + const afterCalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === afterCalCulationNodeId); + expect(afterCalCulationNodeJob.status).toBe(1); + expect(afterCalCulationNodeJob.result).toBe(4); + // 4、后置处理:删除工作流 + await apiDeleteWorkflow(workflowId); + }); + + test('Branch 1 failed, 2 and 3 succeeded', async ({ page, mockCollections, mockRecords }) => { + //数据表后缀标识 + const triggerNodeAppendText = 'a' + 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 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: 'parallel', exact: true }).click(); + const parallelBranchNodeTitle = 'Parallel branch' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page + .getByLabel('Parallel branch-Parallel branch', { exact: true }) + .getByRole('textbox') + .fill(parallelBranchNodeTitle); + await page.mouse.move(300, 0, { steps: 100 }); + await page.mouse.click(300, 0); + // 添加一个分支 + const parallelBranchNode = new ParallelBranchNode(page, parallelBranchNodeTitle); + const parallelBranchNodeId = await parallelBranchNode.node.locator('.workflow-node-id').innerText(); + await parallelBranchNode.nodeConfigure.click(); + await parallelBranchNode.anySucceededRadio.click(); + await parallelBranchNode.submitButton.click(); + await parallelBranchNode.addBranchButton.click(); + // 分支1添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName); + const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName); + const oneConditionNodeId = await oneConditionNode.node.locator('.workflow-node-id').innerText(); + await oneConditionNode.nodeConfigure.click(); + await oneConditionNode.formulaRadio.click(); + await oneConditionNode.conditionExpressionEditBox.fill('1==2'); + await oneConditionNode.submitButton.click(); + // 分支2添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName); + const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName); + const twoConditionNodeId = await twoConditionNode.node.locator('.workflow-node-id').innerText(); + await twoConditionNode.nodeConfigure.click(); + await twoConditionNode.formulaRadio.click(); + await twoConditionNode.conditionExpressionEditBox.fill('1==1'); + await twoConditionNode.submitButton.click(); + // 分支3添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName); + const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName); + const threeConditionNodeId = await threeConditionNode.node.locator('.workflow-node-id').innerText(); + await threeConditionNode.nodeConfigure.click(); + await threeConditionNode.formulaRadio.click(); + await threeConditionNode.conditionExpressionEditBox.fill('1==1'); + await threeConditionNode.submitButton.click(); + // 添加后置计算节点 + await parallelBranchNode.addNodeButton.click(); + await page.getByRole('button', { name: 'calculation', exact: true }).click(); + const afterCalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page + .getByLabel('Calculation-Calculation', { exact: true }) + .getByRole('textbox') + .fill(afterCalCulationNodeName); + const afterCalCulationNode = new ClculationNode(page, afterCalCulationNodeName); + const afterCalCulationNodeId = await afterCalCulationNode.node.locator('.workflow-node-id').innerText(); + await afterCalCulationNode.nodeConfigure.click(); + await afterCalCulationNode.formulaCalculationEngine.click(); + await page.getByLabel('textbox').fill('4'); + await afterCalCulationNode.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 parallelBranchNodeJob = jobs.find((job) => job.nodeId.toString() === parallelBranchNodeId); + expect(parallelBranchNodeJob.status).toBe(1); + const oneConditionNodeJob = jobs.find((job) => job.nodeId.toString() === oneConditionNodeId); + expect(oneConditionNodeJob.status).toBe(-1); + expect(oneConditionNodeJob.result).toBe(false); + const twoConditionNodeJob = jobs.find((job) => job.nodeId.toString() === twoConditionNodeId); + expect(twoConditionNodeJob.status).toBe(1); + expect(twoConditionNodeJob.result).toBe(true); + const threeConditionNodeJob = jobs.find((job) => job.nodeId.toString() === threeConditionNodeId); + expect(threeConditionNodeJob).toBe(undefined); + const afterCalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === afterCalCulationNodeId); + expect(afterCalCulationNodeJob.status).toBe(1); + expect(afterCalCulationNodeJob.result).toBe(4); + // 4、后置处理:删除工作流 + await apiDeleteWorkflow(workflowId); + }); + + test('Branches all failed', async ({ page, mockCollections, mockRecords }) => { + //数据表后缀标识 + const triggerNodeAppendText = 'a' + 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 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: 'parallel', exact: true }).click(); + const parallelBranchNodeTitle = 'Parallel branch' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page + .getByLabel('Parallel branch-Parallel branch', { exact: true }) + .getByRole('textbox') + .fill(parallelBranchNodeTitle); + await page.mouse.move(300, 0, { steps: 100 }); + await page.mouse.click(300, 0); + // 添加一个分支 + const parallelBranchNode = new ParallelBranchNode(page, parallelBranchNodeTitle); + const parallelBranchNodeId = await parallelBranchNode.node.locator('.workflow-node-id').innerText(); + await parallelBranchNode.nodeConfigure.click(); + await parallelBranchNode.anySucceededRadio.click(); + await parallelBranchNode.submitButton.click(); + await parallelBranchNode.addBranchButton.click(); + // 分支1添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName); + const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName); + const oneConditionNodeId = await oneConditionNode.node.locator('.workflow-node-id').innerText(); + await oneConditionNode.nodeConfigure.click(); + await oneConditionNode.formulaRadio.click(); + await oneConditionNode.conditionExpressionEditBox.fill('1==2'); + await oneConditionNode.submitButton.click(); + // 分支2添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName); + const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName); + const twoConditionNodeId = await twoConditionNode.node.locator('.workflow-node-id').innerText(); + await twoConditionNode.nodeConfigure.click(); + await twoConditionNode.formulaRadio.click(); + await twoConditionNode.conditionExpressionEditBox.fill('1==2'); + await twoConditionNode.submitButton.click(); + // 分支3添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName); + const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName); + const threeConditionNodeId = await threeConditionNode.node.locator('.workflow-node-id').innerText(); + await threeConditionNode.nodeConfigure.click(); + await threeConditionNode.formulaRadio.click(); + await threeConditionNode.conditionExpressionEditBox.fill('1==2'); + await threeConditionNode.submitButton.click(); + // 添加后置计算节点 + await parallelBranchNode.addNodeButton.click(); + await page.getByRole('button', { name: 'calculation', exact: true }).click(); + const afterCalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page + .getByLabel('Calculation-Calculation', { exact: true }) + .getByRole('textbox') + .fill(afterCalCulationNodeName); + const afterCalCulationNode = new ClculationNode(page, afterCalCulationNodeName); + const afterCalCulationNodeId = await afterCalCulationNode.node.locator('.workflow-node-id').innerText(); + await afterCalCulationNode.nodeConfigure.click(); + await afterCalCulationNode.formulaCalculationEngine.click(); + await page.getByLabel('textbox').fill('4'); + await afterCalCulationNode.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 parallelBranchNodeJob = jobs.find((job) => job.nodeId.toString() === parallelBranchNodeId); + expect(parallelBranchNodeJob.status).toBe(-1); + const oneConditionNodeJob = jobs.find((job) => job.nodeId.toString() === oneConditionNodeId); + expect(oneConditionNodeJob.status).toBe(-1); + expect(oneConditionNodeJob.result).toBe(false); + const twoConditionNodeJob = jobs.find((job) => job.nodeId.toString() === twoConditionNodeId); + expect(twoConditionNodeJob.status).toBe(-1); + expect(twoConditionNodeJob.result).toBe(false); + const threeConditionNodeJob = jobs.find((job) => job.nodeId.toString() === threeConditionNodeId); + expect(threeConditionNodeJob.status).toBe(-1); + expect(threeConditionNodeJob.result).toBe(false); + const afterCalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === afterCalCulationNodeId); + expect(afterCalCulationNodeJob).toBe(undefined); + // 4、后置处理:删除工作流 + await apiDeleteWorkflow(workflowId); + }); +}); + +test.describe('Any succeeded or failed', () => { + test('Branch 1 success', async ({ page, mockCollections, mockRecords }) => { + //数据表后缀标识 + const triggerNodeAppendText = 'a' + 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 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: 'parallel', exact: true }).click(); + const parallelBranchNodeTitle = 'Parallel branch' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page + .getByLabel('Parallel branch-Parallel branch', { exact: true }) + .getByRole('textbox') + .fill(parallelBranchNodeTitle); + await page.mouse.move(300, 0, { steps: 100 }); + await page.mouse.click(300, 0); + // 配置anySucceededOrFailedRadio + const parallelBranchNode = new ParallelBranchNode(page, parallelBranchNodeTitle); + const parallelBranchNodeId = await parallelBranchNode.node.locator('.workflow-node-id').innerText(); + await parallelBranchNode.nodeConfigure.click(); + await parallelBranchNode.anySucceededOrFailedRadio.click(); + await parallelBranchNode.submitButton.click(); + // 分支1添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName); + const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName); + const oneConditionNodeId = await oneConditionNode.node.locator('.workflow-node-id').innerText(); + await oneConditionNode.nodeConfigure.click(); + await oneConditionNode.formulaRadio.click(); + await oneConditionNode.conditionExpressionEditBox.fill('1==1'); + await oneConditionNode.submitButton.click(); + // 分支2添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName); + const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName); + const twoConditionNodeId = await twoConditionNode.node.locator('.workflow-node-id').innerText(); + await twoConditionNode.nodeConfigure.click(); + await twoConditionNode.formulaRadio.click(); + await twoConditionNode.conditionExpressionEditBox.fill('1==1'); + await twoConditionNode.submitButton.click(); + // 添加后置计算节点 + await parallelBranchNode.addNodeButton.click(); + await page.getByRole('button', { name: 'calculation', exact: true }).click(); + const afterCalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page + .getByLabel('Calculation-Calculation', { exact: true }) + .getByRole('textbox') + .fill(afterCalCulationNodeName); + const afterCalCulationNode = new ClculationNode(page, afterCalCulationNodeName); + const afterCalCulationNodeId = await afterCalCulationNode.node.locator('.workflow-node-id').innerText(); + await afterCalCulationNode.nodeConfigure.click(); + await afterCalCulationNode.formulaCalculationEngine.click(); + await page.getByLabel('textbox').fill('4'); + await afterCalCulationNode.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 parallelBranchNodeJob = jobs.find((job) => job.nodeId.toString() === parallelBranchNodeId); + expect(parallelBranchNodeJob.status).toBe(1); + const oneConditionNodeJob = jobs.find((job) => job.nodeId.toString() === oneConditionNodeId); + expect(oneConditionNodeJob.status).toBe(1); + expect(oneConditionNodeJob.result).toBe(true); + const twoConditionNodeJob = jobs.find((job) => job.nodeId.toString() === twoConditionNodeId); + expect(twoConditionNodeJob).toBe(undefined); + const afterCalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === afterCalCulationNodeId); + expect(afterCalCulationNodeJob.status).toBe(1); + expect(afterCalCulationNodeJob.result).toBe(4); + // 4、后置处理:删除工作流 + await apiDeleteWorkflow(workflowId); + }); + + test('Branch 1 failed', async ({ page, mockCollections, mockRecords }) => { + //数据表后缀标识 + const triggerNodeAppendText = 'a' + 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 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: 'parallel', exact: true }).click(); + const parallelBranchNodeTitle = 'Parallel branch' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page + .getByLabel('Parallel branch-Parallel branch', { exact: true }) + .getByRole('textbox') + .fill(parallelBranchNodeTitle); + await page.mouse.move(300, 0, { steps: 100 }); + await page.mouse.click(300, 0); + // 配置anySucceededOrFailedRadio + const parallelBranchNode = new ParallelBranchNode(page, parallelBranchNodeTitle); + const parallelBranchNodeId = await parallelBranchNode.node.locator('.workflow-node-id').innerText(); + await parallelBranchNode.nodeConfigure.click(); + await parallelBranchNode.anySucceededOrFailedRadio.click(); + await parallelBranchNode.submitButton.click(); + // 分支1添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName); + const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName); + const oneConditionNodeId = await oneConditionNode.node.locator('.workflow-node-id').innerText(); + await oneConditionNode.nodeConfigure.click(); + await oneConditionNode.formulaRadio.click(); + await oneConditionNode.conditionExpressionEditBox.fill('1==2'); + await oneConditionNode.submitButton.click(); + // 分支2添加判断节点 + await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click(); + await page.getByRole('button', { name: 'condition', exact: true }).hover(); + await page.getByLabel('rejectOnFalse').click(); + const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName); + const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName); + const twoConditionNodeId = await twoConditionNode.node.locator('.workflow-node-id').innerText(); + await twoConditionNode.nodeConfigure.click(); + await twoConditionNode.formulaRadio.click(); + await twoConditionNode.conditionExpressionEditBox.fill('1==1'); + await twoConditionNode.submitButton.click(); + // 添加后置计算节点 + await parallelBranchNode.addNodeButton.click(); + await page.getByRole('button', { name: 'calculation', exact: true }).click(); + const afterCalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString(); + await page + .getByLabel('Calculation-Calculation', { exact: true }) + .getByRole('textbox') + .fill(afterCalCulationNodeName); + const afterCalCulationNode = new ClculationNode(page, afterCalCulationNodeName); + const afterCalCulationNodeId = await afterCalCulationNode.node.locator('.workflow-node-id').innerText(); + await afterCalCulationNode.nodeConfigure.click(); + await afterCalCulationNode.formulaCalculationEngine.click(); + await page.getByLabel('textbox').fill('4'); + await afterCalCulationNode.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 parallelBranchNodeJob = jobs.find((job) => job.nodeId.toString() === parallelBranchNodeId); + expect(parallelBranchNodeJob.status).toBe(-1); + const oneConditionNodeJob = jobs.find((job) => job.nodeId.toString() === oneConditionNodeId); + expect(oneConditionNodeJob.status).toBe(-1); + expect(oneConditionNodeJob.result).toBe(false); + const twoConditionNodeJob = jobs.find((job) => job.nodeId.toString() === twoConditionNodeId); + expect(twoConditionNodeJob).toBe(undefined); + const afterCalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === afterCalCulationNodeId); + expect(afterCalCulationNodeJob).toBe(undefined); + // 4、后置处理:删除工作流 + await apiDeleteWorkflow(workflowId); + }); +}); diff --git a/packages/plugins/@nocobase/plugin-workflow-test/src/e2e/e2ePageObjectModel.ts b/packages/plugins/@nocobase/plugin-workflow-test/src/e2e/e2ePageObjectModel.ts index 0b1521ac1a..d351cda2fd 100644 --- a/packages/plugins/@nocobase/plugin-workflow-test/src/e2e/e2ePageObjectModel.ts +++ b/packages/plugins/@nocobase/plugin-workflow-test/src/e2e/e2ePageObjectModel.ts @@ -537,6 +537,33 @@ export class SQLNode { } } +export class ParallelBranchNode { + readonly page: Page; + node: Locator; + nodeTitle: Locator; + nodeConfigure: Locator; + addBranchButton: Locator; + allSucceededRadio: Locator; + anySucceededRadio: Locator; + anySucceededOrFailedRadio: Locator; + submitButton: Locator; + cancelButton: Locator; + addNodeButton: Locator; + constructor(page: Page, nodeName: string) { + this.page = page; + this.node = page.getByLabel(`Parallel branch-${nodeName}`, { exact: true }); + this.nodeTitle = page.locator('textarea').filter({ hasText: nodeName }); + this.nodeConfigure = page.getByLabel(`Parallel branch-${nodeName}`).getByRole('button', { name: 'Configure' }); + this.addBranchButton = page.getByLabel(`add-button-parallel-${nodeName}-add-branch`, { exact: true }); + this.allSucceededRadio = page.getByLabel('All succeeded', { exact: true }); + this.anySucceededRadio = page.getByLabel('Any succeeded', { exact: true }); + this.anySucceededOrFailedRadio = page.getByLabel('Any succeeded or failed', { exact: true }); + this.submitButton = page.getByLabel('action-Action-Submit-workflows'); + this.cancelButton = page.getByLabel('action-Action-Cancel-workflows'); + this.addNodeButton = page.getByLabel(`add-button-parallel-${nodeName}`, { exact: true }); + } +} + export default module.exports = { CreateWorkFlow, EditWorkFlow, @@ -557,4 +584,5 @@ export default module.exports = { ConditionYesNode, ConditionBranchNode, SQLNode, + ParallelBranchNode, };