@nocobase/plugin-workflow-parallel 0.19.0-alpha.4 → 0.19.0-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,8 +2,11 @@ module.exports = {
2
2
  "react": "18.2.0",
3
3
  "antd": "5.12.8",
4
4
  "@ant-design/icons": "5.2.6",
5
- "@nocobase/client": "0.19.0-alpha.4",
6
- "@nocobase/plugin-workflow": "0.19.0-alpha.4",
5
+ "@nocobase/client": "0.19.0-alpha.6",
6
+ "@nocobase/plugin-workflow": "0.19.0-alpha.6",
7
7
  "react-i18next": "11.18.6",
8
- "@nocobase/server": "0.19.0-alpha.4"
8
+ "@nocobase/server": "0.19.0-alpha.6",
9
+ "@nocobase/plugin-workflow-test": "0.19.0-alpha.6",
10
+ "@nocobase/test": "0.19.0-alpha.6",
11
+ "@nocobase/utils": "0.19.0-alpha.6"
9
12
  };
package/package.json CHANGED
@@ -4,9 +4,11 @@
4
4
  "displayName.zh-CN": "工作流:并行分支节点",
5
5
  "description": "Could be used for parallel execution of branch processes in the workflow.",
6
6
  "description.zh-CN": "用于在工作流中需要并行执行的分支流程。",
7
- "version": "0.19.0-alpha.4",
7
+ "version": "0.19.0-alpha.6",
8
8
  "license": "AGPL-3.0",
9
9
  "main": "./dist/server/index.js",
10
+ "homepage": "https://docs.nocobase.com/plugins/workflow-parallel",
11
+ "homepage.zh-CN": "https://docs-cn.nocobase.com/plugins/workflow-parallel",
10
12
  "devDependencies": {
11
13
  "@ant-design/icons": "5.x",
12
14
  "antd": "5.x",
@@ -20,5 +22,8 @@
20
22
  "@nocobase/server": "0.x",
21
23
  "@nocobase/test": "0.x"
22
24
  },
23
- "gitHead": "9583023f7bea828da5192384a5c002782c341b65"
25
+ "gitHead": "2eb524db98c7f4136fe1a9a1b1259cd72cf6635f",
26
+ "keywords": [
27
+ "Workflow"
28
+ ]
24
29
  }
@@ -0,0 +1,1207 @@
1
+ import { faker } from '@faker-js/faker';
2
+ import {
3
+ CollectionTriggerNode,
4
+ apiCreateWorkflow,
5
+ apiDeleteWorkflow,
6
+ apiGetWorkflow,
7
+ apiUpdateWorkflowTrigger,
8
+ appendJsonCollectionName,
9
+ generalWithNoRelationalFields,
10
+ ParallelBranchNode,
11
+ ConditionYesNode,
12
+ ClculationNode,
13
+ apiGetWorkflowNodeExecutions,
14
+ } from '@nocobase/plugin-workflow-test/e2e';
15
+ import { expect, test } from '@nocobase/test/e2e';
16
+ import { dayjs } from '@nocobase/utils';
17
+
18
+ test.describe('All succeeded', () => {
19
+ test('All 3 branches were successful', async ({ page, mockCollections, mockRecords }) => {
20
+ //数据表后缀标识
21
+ const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
22
+
23
+ // 创建触发器节点数据表
24
+ const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
25
+ const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
26
+ const triggerNodeFieldName = 'orgname';
27
+ const triggerNodeFieldDisplayName = '公司名称(单行文本)';
28
+ await mockCollections(
29
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
30
+ .collections,
31
+ );
32
+ //添加工作流
33
+ const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
34
+ const workflowData = {
35
+ current: true,
36
+ options: { deleteExecutionOnStatus: [] },
37
+ title: workFlowName,
38
+ type: 'collection',
39
+ enabled: true,
40
+ };
41
+ const workflow = await apiCreateWorkflow(workflowData);
42
+ const workflowObj = JSON.parse(JSON.stringify(workflow));
43
+ const workflowId = workflowObj.id;
44
+ //配置工作流触发器
45
+ const triggerNodeData = {
46
+ config: { appends: [], collection: triggerNodeCollectionName, changed: [], condition: { $and: [] }, mode: 1 },
47
+ };
48
+ const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
49
+ const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
50
+ //配置分支节点
51
+ await page.goto(`admin/workflow/workflows/${workflowId}`);
52
+ await page.waitForLoadState('networkidle');
53
+ const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
54
+ await collectionTriggerNode.addNodeButton.click();
55
+ await page.getByRole('button', { name: 'parallel', exact: true }).click();
56
+ const parallelBranchNodeTitle = 'Parallel branch' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
57
+ await page
58
+ .getByLabel('Parallel branch-Parallel branch', { exact: true })
59
+ .getByRole('textbox')
60
+ .fill(parallelBranchNodeTitle);
61
+ await page.mouse.move(300, 0, { steps: 100 });
62
+ await page.mouse.click(300, 0);
63
+ // 添加一个分支
64
+ const parallelBranchNode = new ParallelBranchNode(page, parallelBranchNodeTitle);
65
+ const parallelBranchNodeId = await parallelBranchNode.node.locator('.workflow-node-id').innerText();
66
+ await parallelBranchNode.addBranchButton.click();
67
+ // 分支1添加判断节点
68
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click();
69
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
70
+ await page.getByLabel('rejectOnFalse').click();
71
+ const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
72
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName);
73
+ const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName);
74
+ const oneConditionNodeId = await oneConditionNode.node.locator('.workflow-node-id').innerText();
75
+ await oneConditionNode.nodeConfigure.click();
76
+ await oneConditionNode.formulaRadio.click();
77
+ await oneConditionNode.conditionExpressionEditBox.fill('1==1');
78
+ await oneConditionNode.submitButton.click();
79
+ // 分支2添加判断节点
80
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click();
81
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
82
+ await page.getByLabel('rejectOnFalse').click();
83
+ const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
84
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName);
85
+ const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName);
86
+ const twoConditionNodeId = await twoConditionNode.node.locator('.workflow-node-id').innerText();
87
+ await twoConditionNode.nodeConfigure.click();
88
+ await twoConditionNode.formulaRadio.click();
89
+ await twoConditionNode.conditionExpressionEditBox.fill('1==1');
90
+ await twoConditionNode.submitButton.click();
91
+ // 分支3添加判断节点
92
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click();
93
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
94
+ await page.getByLabel('rejectOnFalse').click();
95
+ const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
96
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName);
97
+ const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName);
98
+ const threeConditionNodeId = await threeConditionNode.node.locator('.workflow-node-id').innerText();
99
+ await threeConditionNode.nodeConfigure.click();
100
+ await threeConditionNode.formulaRadio.click();
101
+ await threeConditionNode.conditionExpressionEditBox.fill('1==1');
102
+ await threeConditionNode.submitButton.click();
103
+ // 添加后置计算节点
104
+ await parallelBranchNode.addNodeButton.click();
105
+ await page.getByRole('button', { name: 'calculation', exact: true }).click();
106
+ const afterCalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
107
+ await page
108
+ .getByLabel('Calculation-Calculation', { exact: true })
109
+ .getByRole('textbox')
110
+ .fill(afterCalCulationNodeName);
111
+ const afterCalCulationNode = new ClculationNode(page, afterCalCulationNodeName);
112
+ const afterCalCulationNodeId = await afterCalCulationNode.node.locator('.workflow-node-id').innerText();
113
+ await afterCalCulationNode.nodeConfigure.click();
114
+ await afterCalCulationNode.formulaCalculationEngine.click();
115
+ await page.getByLabel('textbox').fill('4');
116
+ await afterCalCulationNode.submitButton.click();
117
+ // 2、测试步骤:添加数据触发工作流
118
+ const triggerNodeCollectionRecordOne =
119
+ triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
120
+ const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
121
+ { orgname: triggerNodeCollectionRecordOne },
122
+ ]);
123
+ await page.waitForTimeout(1000);
124
+ // 3、预期结果:工作流成功触发,判断节点全部通过,后置计算节点执行成功
125
+ const getWorkflow = await apiGetWorkflow(workflowId);
126
+ const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
127
+ const getWorkflowExecuted = getWorkflowObj.executed;
128
+ expect(getWorkflowExecuted).toBe(1);
129
+
130
+ const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
131
+ const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
132
+ getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
133
+ return b.id - a.id;
134
+ });
135
+ const jobs = getWorkflowNodeExecutionsObj[0].jobs;
136
+ const parallelBranchNodeJob = jobs.find((job) => job.nodeId.toString() === parallelBranchNodeId);
137
+ expect(parallelBranchNodeJob.status).toBe(1);
138
+ const oneConditionNodeJob = jobs.find((job) => job.nodeId.toString() === oneConditionNodeId);
139
+ expect(oneConditionNodeJob.status).toBe(1);
140
+ expect(oneConditionNodeJob.result).toBe(true);
141
+ const twoConditionNodeJob = jobs.find((job) => job.nodeId.toString() === twoConditionNodeId);
142
+ expect(twoConditionNodeJob.status).toBe(1);
143
+ expect(twoConditionNodeJob.result).toBe(true);
144
+ const threeConditionNodeJob = jobs.find((job) => job.nodeId.toString() === threeConditionNodeId);
145
+ expect(threeConditionNodeJob.status).toBe(1);
146
+ expect(threeConditionNodeJob.result).toBe(true);
147
+ const afterCalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === afterCalCulationNodeId);
148
+ expect(afterCalCulationNodeJob.status).toBe(1);
149
+ expect(afterCalCulationNodeJob.result).toBe(4);
150
+ // 4、后置处理:删除工作流
151
+ await apiDeleteWorkflow(workflowId);
152
+ });
153
+
154
+ test('Branches 1 and 2 succeed, 3 fail', async ({ page, mockCollections, mockRecords }) => {
155
+ //数据表后缀标识
156
+ const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
157
+
158
+ // 创建触发器节点数据表
159
+ const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
160
+ const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
161
+ const triggerNodeFieldName = 'orgname';
162
+ const triggerNodeFieldDisplayName = '公司名称(单行文本)';
163
+ await mockCollections(
164
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
165
+ .collections,
166
+ );
167
+ //添加工作流
168
+ const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
169
+ const workflowData = {
170
+ current: true,
171
+ options: { deleteExecutionOnStatus: [] },
172
+ title: workFlowName,
173
+ type: 'collection',
174
+ enabled: true,
175
+ };
176
+ const workflow = await apiCreateWorkflow(workflowData);
177
+ const workflowObj = JSON.parse(JSON.stringify(workflow));
178
+ const workflowId = workflowObj.id;
179
+ //配置工作流触发器
180
+ const triggerNodeData = {
181
+ config: { appends: [], collection: triggerNodeCollectionName, changed: [], condition: { $and: [] }, mode: 1 },
182
+ };
183
+ const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
184
+ const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
185
+ //配置分支节点
186
+ await page.goto(`admin/workflow/workflows/${workflowId}`);
187
+ await page.waitForLoadState('networkidle');
188
+ const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
189
+ await collectionTriggerNode.addNodeButton.click();
190
+ await page.getByRole('button', { name: 'parallel', exact: true }).click();
191
+ const parallelBranchNodeTitle = 'Parallel branch' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
192
+ await page
193
+ .getByLabel('Parallel branch-Parallel branch', { exact: true })
194
+ .getByRole('textbox')
195
+ .fill(parallelBranchNodeTitle);
196
+ await page.mouse.move(300, 0, { steps: 100 });
197
+ await page.mouse.click(300, 0);
198
+ // 添加一个分支
199
+ const parallelBranchNode = new ParallelBranchNode(page, parallelBranchNodeTitle);
200
+ const parallelBranchNodeId = await parallelBranchNode.node.locator('.workflow-node-id').innerText();
201
+ await parallelBranchNode.addBranchButton.click();
202
+ // 分支1添加判断节点
203
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click();
204
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
205
+ await page.getByLabel('rejectOnFalse').click();
206
+ const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
207
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName);
208
+ const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName);
209
+ const oneConditionNodeId = await oneConditionNode.node.locator('.workflow-node-id').innerText();
210
+ await oneConditionNode.nodeConfigure.click();
211
+ await oneConditionNode.formulaRadio.click();
212
+ await oneConditionNode.conditionExpressionEditBox.fill('1==1');
213
+ await oneConditionNode.submitButton.click();
214
+ // 分支2添加判断节点
215
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click();
216
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
217
+ await page.getByLabel('rejectOnFalse').click();
218
+ const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
219
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName);
220
+ const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName);
221
+ const twoConditionNodeId = await twoConditionNode.node.locator('.workflow-node-id').innerText();
222
+ await twoConditionNode.nodeConfigure.click();
223
+ await twoConditionNode.formulaRadio.click();
224
+ await twoConditionNode.conditionExpressionEditBox.fill('1==1');
225
+ await twoConditionNode.submitButton.click();
226
+ // 分支3添加判断节点
227
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click();
228
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
229
+ await page.getByLabel('rejectOnFalse').click();
230
+ const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
231
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName);
232
+ const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName);
233
+ const threeConditionNodeId = await threeConditionNode.node.locator('.workflow-node-id').innerText();
234
+ await threeConditionNode.nodeConfigure.click();
235
+ await threeConditionNode.formulaRadio.click();
236
+ await threeConditionNode.conditionExpressionEditBox.fill('1==2');
237
+ await threeConditionNode.submitButton.click();
238
+ // 添加后置计算节点
239
+ await parallelBranchNode.addNodeButton.click();
240
+ await page.getByRole('button', { name: 'calculation', exact: true }).click();
241
+ const afterCalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
242
+ await page
243
+ .getByLabel('Calculation-Calculation', { exact: true })
244
+ .getByRole('textbox')
245
+ .fill(afterCalCulationNodeName);
246
+ const afterCalCulationNode = new ClculationNode(page, afterCalCulationNodeName);
247
+ const afterCalCulationNodeId = await afterCalCulationNode.node.locator('.workflow-node-id').innerText();
248
+ await afterCalCulationNode.nodeConfigure.click();
249
+ await afterCalCulationNode.formulaCalculationEngine.click();
250
+ await page.getByLabel('textbox').fill('4');
251
+ await afterCalCulationNode.submitButton.click();
252
+ // 2、测试步骤:添加数据触发工作流
253
+ const triggerNodeCollectionRecordOne =
254
+ triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
255
+ const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
256
+ { orgname: triggerNodeCollectionRecordOne },
257
+ ]);
258
+ await page.waitForTimeout(1000);
259
+ // 3、预期结果:工作流成功触发,判断节点全部通过,后置计算节点执行成功
260
+ const getWorkflow = await apiGetWorkflow(workflowId);
261
+ const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
262
+ const getWorkflowExecuted = getWorkflowObj.executed;
263
+ expect(getWorkflowExecuted).toBe(1);
264
+
265
+ const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
266
+ const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
267
+ getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
268
+ return b.id - a.id;
269
+ });
270
+ const jobs = getWorkflowNodeExecutionsObj[0].jobs;
271
+ const parallelBranchNodeJob = jobs.find((job) => job.nodeId.toString() === parallelBranchNodeId);
272
+ expect(parallelBranchNodeJob.status).toBe(-1);
273
+ const oneConditionNodeJob = jobs.find((job) => job.nodeId.toString() === oneConditionNodeId);
274
+ expect(oneConditionNodeJob.status).toBe(1);
275
+ expect(oneConditionNodeJob.result).toBe(true);
276
+ const twoConditionNodeJob = jobs.find((job) => job.nodeId.toString() === twoConditionNodeId);
277
+ expect(twoConditionNodeJob.status).toBe(1);
278
+ expect(twoConditionNodeJob.result).toBe(true);
279
+ const threeConditionNodeJob = jobs.find((job) => job.nodeId.toString() === threeConditionNodeId);
280
+ expect(threeConditionNodeJob.status).toBe(-1);
281
+ expect(threeConditionNodeJob.result).toBe(false);
282
+ const afterCalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === afterCalCulationNodeId);
283
+ expect(afterCalCulationNodeJob).toBe(undefined);
284
+ // 4、后置处理:删除工作流
285
+ await apiDeleteWorkflow(workflowId);
286
+ });
287
+
288
+ test('Branch 1 succeeds, 2 and 3 fail', async ({ page, mockCollections, mockRecords }) => {
289
+ //数据表后缀标识
290
+ const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
291
+
292
+ // 创建触发器节点数据表
293
+ const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
294
+ const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
295
+ const triggerNodeFieldName = 'orgname';
296
+ const triggerNodeFieldDisplayName = '公司名称(单行文本)';
297
+ await mockCollections(
298
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
299
+ .collections,
300
+ );
301
+ //添加工作流
302
+ const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
303
+ const workflowData = {
304
+ current: true,
305
+ options: { deleteExecutionOnStatus: [] },
306
+ title: workFlowName,
307
+ type: 'collection',
308
+ enabled: true,
309
+ };
310
+ const workflow = await apiCreateWorkflow(workflowData);
311
+ const workflowObj = JSON.parse(JSON.stringify(workflow));
312
+ const workflowId = workflowObj.id;
313
+ //配置工作流触发器
314
+ const triggerNodeData = {
315
+ config: { appends: [], collection: triggerNodeCollectionName, changed: [], condition: { $and: [] }, mode: 1 },
316
+ };
317
+ const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
318
+ const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
319
+ //配置分支节点
320
+ await page.goto(`admin/workflow/workflows/${workflowId}`);
321
+ await page.waitForLoadState('networkidle');
322
+ const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
323
+ await collectionTriggerNode.addNodeButton.click();
324
+ await page.getByRole('button', { name: 'parallel', exact: true }).click();
325
+ const parallelBranchNodeTitle = 'Parallel branch' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
326
+ await page
327
+ .getByLabel('Parallel branch-Parallel branch', { exact: true })
328
+ .getByRole('textbox')
329
+ .fill(parallelBranchNodeTitle);
330
+ await page.mouse.move(300, 0, { steps: 100 });
331
+ await page.mouse.click(300, 0);
332
+ // 添加一个分支
333
+ const parallelBranchNode = new ParallelBranchNode(page, parallelBranchNodeTitle);
334
+ const parallelBranchNodeId = await parallelBranchNode.node.locator('.workflow-node-id').innerText();
335
+ await parallelBranchNode.addBranchButton.click();
336
+ // 分支1添加判断节点
337
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click();
338
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
339
+ await page.getByLabel('rejectOnFalse').click();
340
+ const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
341
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName);
342
+ const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName);
343
+ const oneConditionNodeId = await oneConditionNode.node.locator('.workflow-node-id').innerText();
344
+ await oneConditionNode.nodeConfigure.click();
345
+ await oneConditionNode.formulaRadio.click();
346
+ await oneConditionNode.conditionExpressionEditBox.fill('1==1');
347
+ await oneConditionNode.submitButton.click();
348
+ // 分支2添加判断节点
349
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click();
350
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
351
+ await page.getByLabel('rejectOnFalse').click();
352
+ const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
353
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName);
354
+ const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName);
355
+ const twoConditionNodeId = await twoConditionNode.node.locator('.workflow-node-id').innerText();
356
+ await twoConditionNode.nodeConfigure.click();
357
+ await twoConditionNode.formulaRadio.click();
358
+ await twoConditionNode.conditionExpressionEditBox.fill('1==2');
359
+ await twoConditionNode.submitButton.click();
360
+ // 分支3添加判断节点
361
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click();
362
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
363
+ await page.getByLabel('rejectOnFalse').click();
364
+ const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
365
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName);
366
+ const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName);
367
+ const threeConditionNodeId = await threeConditionNode.node.locator('.workflow-node-id').innerText();
368
+ await threeConditionNode.nodeConfigure.click();
369
+ await threeConditionNode.formulaRadio.click();
370
+ await threeConditionNode.conditionExpressionEditBox.fill('1==2');
371
+ await threeConditionNode.submitButton.click();
372
+ // 添加后置计算节点
373
+ await parallelBranchNode.addNodeButton.click();
374
+ await page.getByRole('button', { name: 'calculation', exact: true }).click();
375
+ const afterCalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
376
+ await page
377
+ .getByLabel('Calculation-Calculation', { exact: true })
378
+ .getByRole('textbox')
379
+ .fill(afterCalCulationNodeName);
380
+ const afterCalCulationNode = new ClculationNode(page, afterCalCulationNodeName);
381
+ const afterCalCulationNodeId = await afterCalCulationNode.node.locator('.workflow-node-id').innerText();
382
+ await afterCalCulationNode.nodeConfigure.click();
383
+ await afterCalCulationNode.formulaCalculationEngine.click();
384
+ await page.getByLabel('textbox').fill('4');
385
+ await afterCalCulationNode.submitButton.click();
386
+ // 2、测试步骤:添加数据触发工作流
387
+ const triggerNodeCollectionRecordOne =
388
+ triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
389
+ const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
390
+ { orgname: triggerNodeCollectionRecordOne },
391
+ ]);
392
+ await page.waitForTimeout(1000);
393
+ // 3、预期结果:工作流成功触发,判断节点全部通过,后置计算节点执行成功
394
+ const getWorkflow = await apiGetWorkflow(workflowId);
395
+ const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
396
+ const getWorkflowExecuted = getWorkflowObj.executed;
397
+ expect(getWorkflowExecuted).toBe(1);
398
+
399
+ const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
400
+ const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
401
+ getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
402
+ return b.id - a.id;
403
+ });
404
+ const jobs = getWorkflowNodeExecutionsObj[0].jobs;
405
+ const parallelBranchNodeJob = jobs.find((job) => job.nodeId.toString() === parallelBranchNodeId);
406
+ expect(parallelBranchNodeJob.status).toBe(-1);
407
+ const oneConditionNodeJob = jobs.find((job) => job.nodeId.toString() === oneConditionNodeId);
408
+ expect(oneConditionNodeJob.status).toBe(1);
409
+ expect(oneConditionNodeJob.result).toBe(true);
410
+ const twoConditionNodeJob = jobs.find((job) => job.nodeId.toString() === twoConditionNodeId);
411
+ expect(twoConditionNodeJob.status).toBe(-1);
412
+ expect(twoConditionNodeJob.result).toBe(false);
413
+ const threeConditionNodeJob = jobs.find((job) => job.nodeId.toString() === threeConditionNodeId);
414
+ expect(threeConditionNodeJob).toBe(undefined);
415
+ const afterCalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === afterCalCulationNodeId);
416
+ expect(afterCalCulationNodeJob).toBe(undefined);
417
+ // 4、后置处理:删除工作流
418
+ await apiDeleteWorkflow(workflowId);
419
+ });
420
+
421
+ test('Branch 1 failed, 2 and 3 succeeded', async ({ page, mockCollections, mockRecords }) => {
422
+ //数据表后缀标识
423
+ const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
424
+
425
+ // 创建触发器节点数据表
426
+ const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
427
+ const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
428
+ const triggerNodeFieldName = 'orgname';
429
+ const triggerNodeFieldDisplayName = '公司名称(单行文本)';
430
+ await mockCollections(
431
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
432
+ .collections,
433
+ );
434
+ //添加工作流
435
+ const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
436
+ const workflowData = {
437
+ current: true,
438
+ options: { deleteExecutionOnStatus: [] },
439
+ title: workFlowName,
440
+ type: 'collection',
441
+ enabled: true,
442
+ };
443
+ const workflow = await apiCreateWorkflow(workflowData);
444
+ const workflowObj = JSON.parse(JSON.stringify(workflow));
445
+ const workflowId = workflowObj.id;
446
+ //配置工作流触发器
447
+ const triggerNodeData = {
448
+ config: { appends: [], collection: triggerNodeCollectionName, changed: [], condition: { $and: [] }, mode: 1 },
449
+ };
450
+ const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
451
+ const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
452
+ //配置分支节点
453
+ await page.goto(`admin/workflow/workflows/${workflowId}`);
454
+ await page.waitForLoadState('networkidle');
455
+ const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
456
+ await collectionTriggerNode.addNodeButton.click();
457
+ await page.getByRole('button', { name: 'parallel', exact: true }).click();
458
+ const parallelBranchNodeTitle = 'Parallel branch' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
459
+ await page
460
+ .getByLabel('Parallel branch-Parallel branch', { exact: true })
461
+ .getByRole('textbox')
462
+ .fill(parallelBranchNodeTitle);
463
+ await page.mouse.move(300, 0, { steps: 100 });
464
+ await page.mouse.click(300, 0);
465
+ // 添加一个分支
466
+ const parallelBranchNode = new ParallelBranchNode(page, parallelBranchNodeTitle);
467
+ const parallelBranchNodeId = await parallelBranchNode.node.locator('.workflow-node-id').innerText();
468
+ await parallelBranchNode.addBranchButton.click();
469
+ // 分支1添加判断节点
470
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click();
471
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
472
+ await page.getByLabel('rejectOnFalse').click();
473
+ const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
474
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName);
475
+ const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName);
476
+ const oneConditionNodeId = await oneConditionNode.node.locator('.workflow-node-id').innerText();
477
+ await oneConditionNode.nodeConfigure.click();
478
+ await oneConditionNode.formulaRadio.click();
479
+ await oneConditionNode.conditionExpressionEditBox.fill('1==2');
480
+ await oneConditionNode.submitButton.click();
481
+ // 分支2添加判断节点
482
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click();
483
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
484
+ await page.getByLabel('rejectOnFalse').click();
485
+ const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
486
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName);
487
+ const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName);
488
+ const twoConditionNodeId = await twoConditionNode.node.locator('.workflow-node-id').innerText();
489
+ await twoConditionNode.nodeConfigure.click();
490
+ await twoConditionNode.formulaRadio.click();
491
+ await twoConditionNode.conditionExpressionEditBox.fill('1==1');
492
+ await twoConditionNode.submitButton.click();
493
+ // 分支3添加判断节点
494
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click();
495
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
496
+ await page.getByLabel('rejectOnFalse').click();
497
+ const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
498
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName);
499
+ const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName);
500
+ const threeConditionNodeId = await threeConditionNode.node.locator('.workflow-node-id').innerText();
501
+ await threeConditionNode.nodeConfigure.click();
502
+ await threeConditionNode.formulaRadio.click();
503
+ await threeConditionNode.conditionExpressionEditBox.fill('1==1');
504
+ await threeConditionNode.submitButton.click();
505
+ // 添加后置计算节点
506
+ await parallelBranchNode.addNodeButton.click();
507
+ await page.getByRole('button', { name: 'calculation', exact: true }).click();
508
+ const afterCalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
509
+ await page
510
+ .getByLabel('Calculation-Calculation', { exact: true })
511
+ .getByRole('textbox')
512
+ .fill(afterCalCulationNodeName);
513
+ const afterCalCulationNode = new ClculationNode(page, afterCalCulationNodeName);
514
+ const afterCalCulationNodeId = await afterCalCulationNode.node.locator('.workflow-node-id').innerText();
515
+ await afterCalCulationNode.nodeConfigure.click();
516
+ await afterCalCulationNode.formulaCalculationEngine.click();
517
+ await page.getByLabel('textbox').fill('4');
518
+ await afterCalCulationNode.submitButton.click();
519
+ // 2、测试步骤:添加数据触发工作流
520
+ const triggerNodeCollectionRecordOne =
521
+ triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
522
+ const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
523
+ { orgname: triggerNodeCollectionRecordOne },
524
+ ]);
525
+ await page.waitForTimeout(1000);
526
+ // 3、预期结果:工作流成功触发,判断节点全部通过,后置计算节点执行成功
527
+ const getWorkflow = await apiGetWorkflow(workflowId);
528
+ const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
529
+ const getWorkflowExecuted = getWorkflowObj.executed;
530
+ expect(getWorkflowExecuted).toBe(1);
531
+
532
+ const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
533
+ const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
534
+ getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
535
+ return b.id - a.id;
536
+ });
537
+ const jobs = getWorkflowNodeExecutionsObj[0].jobs;
538
+ const parallelBranchNodeJob = jobs.find((job) => job.nodeId.toString() === parallelBranchNodeId);
539
+ expect(parallelBranchNodeJob.status).toBe(-1);
540
+ const oneConditionNodeJob = jobs.find((job) => job.nodeId.toString() === oneConditionNodeId);
541
+ expect(oneConditionNodeJob.status).toBe(-1);
542
+ expect(oneConditionNodeJob.result).toBe(false);
543
+ const twoConditionNodeJob = jobs.find((job) => job.nodeId.toString() === twoConditionNodeId);
544
+ expect(twoConditionNodeJob).toBe(undefined);
545
+ const threeConditionNodeJob = jobs.find((job) => job.nodeId.toString() === threeConditionNodeId);
546
+ expect(threeConditionNodeJob).toBe(undefined);
547
+ const afterCalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === afterCalCulationNodeId);
548
+ expect(afterCalCulationNodeJob).toBe(undefined);
549
+ // 4、后置处理:删除工作流
550
+ await apiDeleteWorkflow(workflowId);
551
+ });
552
+ });
553
+
554
+ test.describe('Any succeeded', () => {
555
+ test('All 3 branches were successful', async ({ page, mockCollections, mockRecords }) => {
556
+ //数据表后缀标识
557
+ const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
558
+
559
+ // 创建触发器节点数据表
560
+ const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
561
+ const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
562
+ const triggerNodeFieldName = 'orgname';
563
+ const triggerNodeFieldDisplayName = '公司名称(单行文本)';
564
+ await mockCollections(
565
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
566
+ .collections,
567
+ );
568
+ //添加工作流
569
+ const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
570
+ const workflowData = {
571
+ current: true,
572
+ options: { deleteExecutionOnStatus: [] },
573
+ title: workFlowName,
574
+ type: 'collection',
575
+ enabled: true,
576
+ };
577
+ const workflow = await apiCreateWorkflow(workflowData);
578
+ const workflowObj = JSON.parse(JSON.stringify(workflow));
579
+ const workflowId = workflowObj.id;
580
+ //配置工作流触发器
581
+ const triggerNodeData = {
582
+ config: { appends: [], collection: triggerNodeCollectionName, changed: [], condition: { $and: [] }, mode: 1 },
583
+ };
584
+ const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
585
+ const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
586
+ //配置分支节点
587
+ await page.goto(`admin/workflow/workflows/${workflowId}`);
588
+ await page.waitForLoadState('networkidle');
589
+ const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
590
+ await collectionTriggerNode.addNodeButton.click();
591
+ await page.getByRole('button', { name: 'parallel', exact: true }).click();
592
+ const parallelBranchNodeTitle = 'Parallel branch' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
593
+ await page
594
+ .getByLabel('Parallel branch-Parallel branch', { exact: true })
595
+ .getByRole('textbox')
596
+ .fill(parallelBranchNodeTitle);
597
+ await page.mouse.move(300, 0, { steps: 100 });
598
+ await page.mouse.click(300, 0);
599
+ // 添加一个分支
600
+ const parallelBranchNode = new ParallelBranchNode(page, parallelBranchNodeTitle);
601
+ const parallelBranchNodeId = await parallelBranchNode.node.locator('.workflow-node-id').innerText();
602
+ await parallelBranchNode.nodeConfigure.click();
603
+ await parallelBranchNode.anySucceededRadio.click();
604
+ await parallelBranchNode.submitButton.click();
605
+ await parallelBranchNode.addBranchButton.click();
606
+ // 分支1添加判断节点
607
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click();
608
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
609
+ await page.getByLabel('rejectOnFalse').click();
610
+ const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
611
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName);
612
+ const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName);
613
+ const oneConditionNodeId = await oneConditionNode.node.locator('.workflow-node-id').innerText();
614
+ await oneConditionNode.nodeConfigure.click();
615
+ await oneConditionNode.formulaRadio.click();
616
+ await oneConditionNode.conditionExpressionEditBox.fill('1==1');
617
+ await oneConditionNode.submitButton.click();
618
+ // 分支2添加判断节点
619
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click();
620
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
621
+ await page.getByLabel('rejectOnFalse').click();
622
+ const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
623
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName);
624
+ const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName);
625
+ const twoConditionNodeId = await twoConditionNode.node.locator('.workflow-node-id').innerText();
626
+ await twoConditionNode.nodeConfigure.click();
627
+ await twoConditionNode.formulaRadio.click();
628
+ await twoConditionNode.conditionExpressionEditBox.fill('1==1');
629
+ await twoConditionNode.submitButton.click();
630
+ // 分支3添加判断节点
631
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click();
632
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
633
+ await page.getByLabel('rejectOnFalse').click();
634
+ const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
635
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName);
636
+ const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName);
637
+ const threeConditionNodeId = await threeConditionNode.node.locator('.workflow-node-id').innerText();
638
+ await threeConditionNode.nodeConfigure.click();
639
+ await threeConditionNode.formulaRadio.click();
640
+ await threeConditionNode.conditionExpressionEditBox.fill('1==1');
641
+ await threeConditionNode.submitButton.click();
642
+ // 添加后置计算节点
643
+ await parallelBranchNode.addNodeButton.click();
644
+ await page.getByRole('button', { name: 'calculation', exact: true }).click();
645
+ const afterCalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
646
+ await page
647
+ .getByLabel('Calculation-Calculation', { exact: true })
648
+ .getByRole('textbox')
649
+ .fill(afterCalCulationNodeName);
650
+ const afterCalCulationNode = new ClculationNode(page, afterCalCulationNodeName);
651
+ const afterCalCulationNodeId = await afterCalCulationNode.node.locator('.workflow-node-id').innerText();
652
+ await afterCalCulationNode.nodeConfigure.click();
653
+ await afterCalCulationNode.formulaCalculationEngine.click();
654
+ await page.getByLabel('textbox').fill('4');
655
+ await afterCalCulationNode.submitButton.click();
656
+ // 2、测试步骤:添加数据触发工作流
657
+ const triggerNodeCollectionRecordOne =
658
+ triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
659
+ const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
660
+ { orgname: triggerNodeCollectionRecordOne },
661
+ ]);
662
+ await page.waitForTimeout(1000);
663
+ // 3、预期结果:工作流成功触发,判断节点全部通过,后置计算节点执行成功
664
+ const getWorkflow = await apiGetWorkflow(workflowId);
665
+ const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
666
+ const getWorkflowExecuted = getWorkflowObj.executed;
667
+ expect(getWorkflowExecuted).toBe(1);
668
+
669
+ const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
670
+ const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
671
+ getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
672
+ return b.id - a.id;
673
+ });
674
+ const jobs = getWorkflowNodeExecutionsObj[0].jobs;
675
+ const parallelBranchNodeJob = jobs.find((job) => job.nodeId.toString() === parallelBranchNodeId);
676
+ expect(parallelBranchNodeJob.status).toBe(1);
677
+ const oneConditionNodeJob = jobs.find((job) => job.nodeId.toString() === oneConditionNodeId);
678
+ expect(oneConditionNodeJob.status).toBe(1);
679
+ expect(oneConditionNodeJob.result).toBe(true);
680
+ const twoConditionNodeJob = jobs.find((job) => job.nodeId.toString() === twoConditionNodeId);
681
+ expect(twoConditionNodeJob).toBe(undefined);
682
+ const threeConditionNodeJob = jobs.find((job) => job.nodeId.toString() === threeConditionNodeId);
683
+ expect(threeConditionNodeJob).toBe(undefined);
684
+ const afterCalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === afterCalCulationNodeId);
685
+ expect(afterCalCulationNodeJob.status).toBe(1);
686
+ expect(afterCalCulationNodeJob.result).toBe(4);
687
+ // 4、后置处理:删除工作流
688
+ await apiDeleteWorkflow(workflowId);
689
+ });
690
+
691
+ test('Branch 1 failed, 2 and 3 succeeded', async ({ page, mockCollections, mockRecords }) => {
692
+ //数据表后缀标识
693
+ const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
694
+
695
+ // 创建触发器节点数据表
696
+ const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
697
+ const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
698
+ const triggerNodeFieldName = 'orgname';
699
+ const triggerNodeFieldDisplayName = '公司名称(单行文本)';
700
+ await mockCollections(
701
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
702
+ .collections,
703
+ );
704
+ //添加工作流
705
+ const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
706
+ const workflowData = {
707
+ current: true,
708
+ options: { deleteExecutionOnStatus: [] },
709
+ title: workFlowName,
710
+ type: 'collection',
711
+ enabled: true,
712
+ };
713
+ const workflow = await apiCreateWorkflow(workflowData);
714
+ const workflowObj = JSON.parse(JSON.stringify(workflow));
715
+ const workflowId = workflowObj.id;
716
+ //配置工作流触发器
717
+ const triggerNodeData = {
718
+ config: { appends: [], collection: triggerNodeCollectionName, changed: [], condition: { $and: [] }, mode: 1 },
719
+ };
720
+ const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
721
+ const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
722
+ //配置分支节点
723
+ await page.goto(`admin/workflow/workflows/${workflowId}`);
724
+ await page.waitForLoadState('networkidle');
725
+ const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
726
+ await collectionTriggerNode.addNodeButton.click();
727
+ await page.getByRole('button', { name: 'parallel', exact: true }).click();
728
+ const parallelBranchNodeTitle = 'Parallel branch' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
729
+ await page
730
+ .getByLabel('Parallel branch-Parallel branch', { exact: true })
731
+ .getByRole('textbox')
732
+ .fill(parallelBranchNodeTitle);
733
+ await page.mouse.move(300, 0, { steps: 100 });
734
+ await page.mouse.click(300, 0);
735
+ // 添加一个分支
736
+ const parallelBranchNode = new ParallelBranchNode(page, parallelBranchNodeTitle);
737
+ const parallelBranchNodeId = await parallelBranchNode.node.locator('.workflow-node-id').innerText();
738
+ await parallelBranchNode.nodeConfigure.click();
739
+ await parallelBranchNode.anySucceededRadio.click();
740
+ await parallelBranchNode.submitButton.click();
741
+ await parallelBranchNode.addBranchButton.click();
742
+ // 分支1添加判断节点
743
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click();
744
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
745
+ await page.getByLabel('rejectOnFalse').click();
746
+ const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
747
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName);
748
+ const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName);
749
+ const oneConditionNodeId = await oneConditionNode.node.locator('.workflow-node-id').innerText();
750
+ await oneConditionNode.nodeConfigure.click();
751
+ await oneConditionNode.formulaRadio.click();
752
+ await oneConditionNode.conditionExpressionEditBox.fill('1==2');
753
+ await oneConditionNode.submitButton.click();
754
+ // 分支2添加判断节点
755
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click();
756
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
757
+ await page.getByLabel('rejectOnFalse').click();
758
+ const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
759
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName);
760
+ const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName);
761
+ const twoConditionNodeId = await twoConditionNode.node.locator('.workflow-node-id').innerText();
762
+ await twoConditionNode.nodeConfigure.click();
763
+ await twoConditionNode.formulaRadio.click();
764
+ await twoConditionNode.conditionExpressionEditBox.fill('1==1');
765
+ await twoConditionNode.submitButton.click();
766
+ // 分支3添加判断节点
767
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click();
768
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
769
+ await page.getByLabel('rejectOnFalse').click();
770
+ const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
771
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName);
772
+ const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName);
773
+ const threeConditionNodeId = await threeConditionNode.node.locator('.workflow-node-id').innerText();
774
+ await threeConditionNode.nodeConfigure.click();
775
+ await threeConditionNode.formulaRadio.click();
776
+ await threeConditionNode.conditionExpressionEditBox.fill('1==1');
777
+ await threeConditionNode.submitButton.click();
778
+ // 添加后置计算节点
779
+ await parallelBranchNode.addNodeButton.click();
780
+ await page.getByRole('button', { name: 'calculation', exact: true }).click();
781
+ const afterCalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
782
+ await page
783
+ .getByLabel('Calculation-Calculation', { exact: true })
784
+ .getByRole('textbox')
785
+ .fill(afterCalCulationNodeName);
786
+ const afterCalCulationNode = new ClculationNode(page, afterCalCulationNodeName);
787
+ const afterCalCulationNodeId = await afterCalCulationNode.node.locator('.workflow-node-id').innerText();
788
+ await afterCalCulationNode.nodeConfigure.click();
789
+ await afterCalCulationNode.formulaCalculationEngine.click();
790
+ await page.getByLabel('textbox').fill('4');
791
+ await afterCalCulationNode.submitButton.click();
792
+ // 2、测试步骤:添加数据触发工作流
793
+ const triggerNodeCollectionRecordOne =
794
+ triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
795
+ const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
796
+ { orgname: triggerNodeCollectionRecordOne },
797
+ ]);
798
+ await page.waitForTimeout(1000);
799
+ // 3、预期结果:工作流成功触发,判断节点全部通过,后置计算节点执行成功
800
+ const getWorkflow = await apiGetWorkflow(workflowId);
801
+ const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
802
+ const getWorkflowExecuted = getWorkflowObj.executed;
803
+ expect(getWorkflowExecuted).toBe(1);
804
+
805
+ const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
806
+ const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
807
+ getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
808
+ return b.id - a.id;
809
+ });
810
+ const jobs = getWorkflowNodeExecutionsObj[0].jobs;
811
+ const parallelBranchNodeJob = jobs.find((job) => job.nodeId.toString() === parallelBranchNodeId);
812
+ expect(parallelBranchNodeJob.status).toBe(1);
813
+ const oneConditionNodeJob = jobs.find((job) => job.nodeId.toString() === oneConditionNodeId);
814
+ expect(oneConditionNodeJob.status).toBe(-1);
815
+ expect(oneConditionNodeJob.result).toBe(false);
816
+ const twoConditionNodeJob = jobs.find((job) => job.nodeId.toString() === twoConditionNodeId);
817
+ expect(twoConditionNodeJob.status).toBe(1);
818
+ expect(twoConditionNodeJob.result).toBe(true);
819
+ const threeConditionNodeJob = jobs.find((job) => job.nodeId.toString() === threeConditionNodeId);
820
+ expect(threeConditionNodeJob).toBe(undefined);
821
+ const afterCalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === afterCalCulationNodeId);
822
+ expect(afterCalCulationNodeJob.status).toBe(1);
823
+ expect(afterCalCulationNodeJob.result).toBe(4);
824
+ // 4、后置处理:删除工作流
825
+ await apiDeleteWorkflow(workflowId);
826
+ });
827
+
828
+ test('Branches all failed', async ({ page, mockCollections, mockRecords }) => {
829
+ //数据表后缀标识
830
+ const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
831
+
832
+ // 创建触发器节点数据表
833
+ const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
834
+ const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
835
+ const triggerNodeFieldName = 'orgname';
836
+ const triggerNodeFieldDisplayName = '公司名称(单行文本)';
837
+ await mockCollections(
838
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
839
+ .collections,
840
+ );
841
+ //添加工作流
842
+ const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
843
+ const workflowData = {
844
+ current: true,
845
+ options: { deleteExecutionOnStatus: [] },
846
+ title: workFlowName,
847
+ type: 'collection',
848
+ enabled: true,
849
+ };
850
+ const workflow = await apiCreateWorkflow(workflowData);
851
+ const workflowObj = JSON.parse(JSON.stringify(workflow));
852
+ const workflowId = workflowObj.id;
853
+ //配置工作流触发器
854
+ const triggerNodeData = {
855
+ config: { appends: [], collection: triggerNodeCollectionName, changed: [], condition: { $and: [] }, mode: 1 },
856
+ };
857
+ const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
858
+ const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
859
+ //配置分支节点
860
+ await page.goto(`admin/workflow/workflows/${workflowId}`);
861
+ await page.waitForLoadState('networkidle');
862
+ const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
863
+ await collectionTriggerNode.addNodeButton.click();
864
+ await page.getByRole('button', { name: 'parallel', exact: true }).click();
865
+ const parallelBranchNodeTitle = 'Parallel branch' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
866
+ await page
867
+ .getByLabel('Parallel branch-Parallel branch', { exact: true })
868
+ .getByRole('textbox')
869
+ .fill(parallelBranchNodeTitle);
870
+ await page.mouse.move(300, 0, { steps: 100 });
871
+ await page.mouse.click(300, 0);
872
+ // 添加一个分支
873
+ const parallelBranchNode = new ParallelBranchNode(page, parallelBranchNodeTitle);
874
+ const parallelBranchNodeId = await parallelBranchNode.node.locator('.workflow-node-id').innerText();
875
+ await parallelBranchNode.nodeConfigure.click();
876
+ await parallelBranchNode.anySucceededRadio.click();
877
+ await parallelBranchNode.submitButton.click();
878
+ await parallelBranchNode.addBranchButton.click();
879
+ // 分支1添加判断节点
880
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click();
881
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
882
+ await page.getByLabel('rejectOnFalse').click();
883
+ const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
884
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName);
885
+ const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName);
886
+ const oneConditionNodeId = await oneConditionNode.node.locator('.workflow-node-id').innerText();
887
+ await oneConditionNode.nodeConfigure.click();
888
+ await oneConditionNode.formulaRadio.click();
889
+ await oneConditionNode.conditionExpressionEditBox.fill('1==2');
890
+ await oneConditionNode.submitButton.click();
891
+ // 分支2添加判断节点
892
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click();
893
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
894
+ await page.getByLabel('rejectOnFalse').click();
895
+ const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
896
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName);
897
+ const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName);
898
+ const twoConditionNodeId = await twoConditionNode.node.locator('.workflow-node-id').innerText();
899
+ await twoConditionNode.nodeConfigure.click();
900
+ await twoConditionNode.formulaRadio.click();
901
+ await twoConditionNode.conditionExpressionEditBox.fill('1==2');
902
+ await twoConditionNode.submitButton.click();
903
+ // 分支3添加判断节点
904
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-3`).click();
905
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
906
+ await page.getByLabel('rejectOnFalse').click();
907
+ const threeConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
908
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(threeConditionNodeName);
909
+ const threeConditionNode = new ConditionYesNode(page, threeConditionNodeName);
910
+ const threeConditionNodeId = await threeConditionNode.node.locator('.workflow-node-id').innerText();
911
+ await threeConditionNode.nodeConfigure.click();
912
+ await threeConditionNode.formulaRadio.click();
913
+ await threeConditionNode.conditionExpressionEditBox.fill('1==2');
914
+ await threeConditionNode.submitButton.click();
915
+ // 添加后置计算节点
916
+ await parallelBranchNode.addNodeButton.click();
917
+ await page.getByRole('button', { name: 'calculation', exact: true }).click();
918
+ const afterCalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
919
+ await page
920
+ .getByLabel('Calculation-Calculation', { exact: true })
921
+ .getByRole('textbox')
922
+ .fill(afterCalCulationNodeName);
923
+ const afterCalCulationNode = new ClculationNode(page, afterCalCulationNodeName);
924
+ const afterCalCulationNodeId = await afterCalCulationNode.node.locator('.workflow-node-id').innerText();
925
+ await afterCalCulationNode.nodeConfigure.click();
926
+ await afterCalCulationNode.formulaCalculationEngine.click();
927
+ await page.getByLabel('textbox').fill('4');
928
+ await afterCalCulationNode.submitButton.click();
929
+ // 2、测试步骤:添加数据触发工作流
930
+ const triggerNodeCollectionRecordOne =
931
+ triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
932
+ const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
933
+ { orgname: triggerNodeCollectionRecordOne },
934
+ ]);
935
+ await page.waitForTimeout(1000);
936
+ // 3、预期结果:工作流成功触发,判断节点全部通过,后置计算节点执行成功
937
+ const getWorkflow = await apiGetWorkflow(workflowId);
938
+ const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
939
+ const getWorkflowExecuted = getWorkflowObj.executed;
940
+ expect(getWorkflowExecuted).toBe(1);
941
+
942
+ const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
943
+ const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
944
+ getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
945
+ return b.id - a.id;
946
+ });
947
+ const jobs = getWorkflowNodeExecutionsObj[0].jobs;
948
+ const parallelBranchNodeJob = jobs.find((job) => job.nodeId.toString() === parallelBranchNodeId);
949
+ expect(parallelBranchNodeJob.status).toBe(-1);
950
+ const oneConditionNodeJob = jobs.find((job) => job.nodeId.toString() === oneConditionNodeId);
951
+ expect(oneConditionNodeJob.status).toBe(-1);
952
+ expect(oneConditionNodeJob.result).toBe(false);
953
+ const twoConditionNodeJob = jobs.find((job) => job.nodeId.toString() === twoConditionNodeId);
954
+ expect(twoConditionNodeJob.status).toBe(-1);
955
+ expect(twoConditionNodeJob.result).toBe(false);
956
+ const threeConditionNodeJob = jobs.find((job) => job.nodeId.toString() === threeConditionNodeId);
957
+ expect(threeConditionNodeJob.status).toBe(-1);
958
+ expect(threeConditionNodeJob.result).toBe(false);
959
+ const afterCalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === afterCalCulationNodeId);
960
+ expect(afterCalCulationNodeJob).toBe(undefined);
961
+ // 4、后置处理:删除工作流
962
+ await apiDeleteWorkflow(workflowId);
963
+ });
964
+ });
965
+
966
+ test.describe('Any succeeded or failed', () => {
967
+ test('Branch 1 success', async ({ page, mockCollections, mockRecords }) => {
968
+ //数据表后缀标识
969
+ const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
970
+
971
+ // 创建触发器节点数据表
972
+ const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
973
+ const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
974
+ const triggerNodeFieldName = 'orgname';
975
+ const triggerNodeFieldDisplayName = '公司名称(单行文本)';
976
+ await mockCollections(
977
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
978
+ .collections,
979
+ );
980
+ //添加工作流
981
+ const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
982
+ const workflowData = {
983
+ current: true,
984
+ options: { deleteExecutionOnStatus: [] },
985
+ title: workFlowName,
986
+ type: 'collection',
987
+ enabled: true,
988
+ };
989
+ const workflow = await apiCreateWorkflow(workflowData);
990
+ const workflowObj = JSON.parse(JSON.stringify(workflow));
991
+ const workflowId = workflowObj.id;
992
+ //配置工作流触发器
993
+ const triggerNodeData = {
994
+ config: { appends: [], collection: triggerNodeCollectionName, changed: [], condition: { $and: [] }, mode: 1 },
995
+ };
996
+ const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
997
+ const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
998
+ //配置分支节点
999
+ await page.goto(`admin/workflow/workflows/${workflowId}`);
1000
+ await page.waitForLoadState('networkidle');
1001
+ const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
1002
+ await collectionTriggerNode.addNodeButton.click();
1003
+ await page.getByRole('button', { name: 'parallel', exact: true }).click();
1004
+ const parallelBranchNodeTitle = 'Parallel branch' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
1005
+ await page
1006
+ .getByLabel('Parallel branch-Parallel branch', { exact: true })
1007
+ .getByRole('textbox')
1008
+ .fill(parallelBranchNodeTitle);
1009
+ await page.mouse.move(300, 0, { steps: 100 });
1010
+ await page.mouse.click(300, 0);
1011
+ // 配置anySucceededOrFailedRadio
1012
+ const parallelBranchNode = new ParallelBranchNode(page, parallelBranchNodeTitle);
1013
+ const parallelBranchNodeId = await parallelBranchNode.node.locator('.workflow-node-id').innerText();
1014
+ await parallelBranchNode.nodeConfigure.click();
1015
+ await parallelBranchNode.anySucceededOrFailedRadio.click();
1016
+ await parallelBranchNode.submitButton.click();
1017
+ // 分支1添加判断节点
1018
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click();
1019
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
1020
+ await page.getByLabel('rejectOnFalse').click();
1021
+ const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
1022
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName);
1023
+ const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName);
1024
+ const oneConditionNodeId = await oneConditionNode.node.locator('.workflow-node-id').innerText();
1025
+ await oneConditionNode.nodeConfigure.click();
1026
+ await oneConditionNode.formulaRadio.click();
1027
+ await oneConditionNode.conditionExpressionEditBox.fill('1==1');
1028
+ await oneConditionNode.submitButton.click();
1029
+ // 分支2添加判断节点
1030
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click();
1031
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
1032
+ await page.getByLabel('rejectOnFalse').click();
1033
+ const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
1034
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName);
1035
+ const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName);
1036
+ const twoConditionNodeId = await twoConditionNode.node.locator('.workflow-node-id').innerText();
1037
+ await twoConditionNode.nodeConfigure.click();
1038
+ await twoConditionNode.formulaRadio.click();
1039
+ await twoConditionNode.conditionExpressionEditBox.fill('1==1');
1040
+ await twoConditionNode.submitButton.click();
1041
+ // 添加后置计算节点
1042
+ await parallelBranchNode.addNodeButton.click();
1043
+ await page.getByRole('button', { name: 'calculation', exact: true }).click();
1044
+ const afterCalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
1045
+ await page
1046
+ .getByLabel('Calculation-Calculation', { exact: true })
1047
+ .getByRole('textbox')
1048
+ .fill(afterCalCulationNodeName);
1049
+ const afterCalCulationNode = new ClculationNode(page, afterCalCulationNodeName);
1050
+ const afterCalCulationNodeId = await afterCalCulationNode.node.locator('.workflow-node-id').innerText();
1051
+ await afterCalCulationNode.nodeConfigure.click();
1052
+ await afterCalCulationNode.formulaCalculationEngine.click();
1053
+ await page.getByLabel('textbox').fill('4');
1054
+ await afterCalCulationNode.submitButton.click();
1055
+ // 2、测试步骤:添加数据触发工作流
1056
+ const triggerNodeCollectionRecordOne =
1057
+ triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
1058
+ const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
1059
+ { orgname: triggerNodeCollectionRecordOne },
1060
+ ]);
1061
+ await page.waitForTimeout(1000);
1062
+ // 3、预期结果:工作流成功触发,判断节点全部通过,后置计算节点执行成功
1063
+ const getWorkflow = await apiGetWorkflow(workflowId);
1064
+ const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
1065
+ const getWorkflowExecuted = getWorkflowObj.executed;
1066
+ expect(getWorkflowExecuted).toBe(1);
1067
+
1068
+ const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
1069
+ const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
1070
+ getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
1071
+ return b.id - a.id;
1072
+ });
1073
+ const jobs = getWorkflowNodeExecutionsObj[0].jobs;
1074
+ const parallelBranchNodeJob = jobs.find((job) => job.nodeId.toString() === parallelBranchNodeId);
1075
+ expect(parallelBranchNodeJob.status).toBe(1);
1076
+ const oneConditionNodeJob = jobs.find((job) => job.nodeId.toString() === oneConditionNodeId);
1077
+ expect(oneConditionNodeJob.status).toBe(1);
1078
+ expect(oneConditionNodeJob.result).toBe(true);
1079
+ const twoConditionNodeJob = jobs.find((job) => job.nodeId.toString() === twoConditionNodeId);
1080
+ expect(twoConditionNodeJob).toBe(undefined);
1081
+ const afterCalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === afterCalCulationNodeId);
1082
+ expect(afterCalCulationNodeJob.status).toBe(1);
1083
+ expect(afterCalCulationNodeJob.result).toBe(4);
1084
+ // 4、后置处理:删除工作流
1085
+ await apiDeleteWorkflow(workflowId);
1086
+ });
1087
+
1088
+ test('Branch 1 failed', async ({ page, mockCollections, mockRecords }) => {
1089
+ //数据表后缀标识
1090
+ const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
1091
+
1092
+ // 创建触发器节点数据表
1093
+ const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
1094
+ const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
1095
+ const triggerNodeFieldName = 'orgname';
1096
+ const triggerNodeFieldDisplayName = '公司名称(单行文本)';
1097
+ await mockCollections(
1098
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
1099
+ .collections,
1100
+ );
1101
+ //添加工作流
1102
+ const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
1103
+ const workflowData = {
1104
+ current: true,
1105
+ options: { deleteExecutionOnStatus: [] },
1106
+ title: workFlowName,
1107
+ type: 'collection',
1108
+ enabled: true,
1109
+ };
1110
+ const workflow = await apiCreateWorkflow(workflowData);
1111
+ const workflowObj = JSON.parse(JSON.stringify(workflow));
1112
+ const workflowId = workflowObj.id;
1113
+ //配置工作流触发器
1114
+ const triggerNodeData = {
1115
+ config: { appends: [], collection: triggerNodeCollectionName, changed: [], condition: { $and: [] }, mode: 1 },
1116
+ };
1117
+ const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
1118
+ const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
1119
+ //配置分支节点
1120
+ await page.goto(`admin/workflow/workflows/${workflowId}`);
1121
+ await page.waitForLoadState('networkidle');
1122
+ const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
1123
+ await collectionTriggerNode.addNodeButton.click();
1124
+ await page.getByRole('button', { name: 'parallel', exact: true }).click();
1125
+ const parallelBranchNodeTitle = 'Parallel branch' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
1126
+ await page
1127
+ .getByLabel('Parallel branch-Parallel branch', { exact: true })
1128
+ .getByRole('textbox')
1129
+ .fill(parallelBranchNodeTitle);
1130
+ await page.mouse.move(300, 0, { steps: 100 });
1131
+ await page.mouse.click(300, 0);
1132
+ // 配置anySucceededOrFailedRadio
1133
+ const parallelBranchNode = new ParallelBranchNode(page, parallelBranchNodeTitle);
1134
+ const parallelBranchNodeId = await parallelBranchNode.node.locator('.workflow-node-id').innerText();
1135
+ await parallelBranchNode.nodeConfigure.click();
1136
+ await parallelBranchNode.anySucceededOrFailedRadio.click();
1137
+ await parallelBranchNode.submitButton.click();
1138
+ // 分支1添加判断节点
1139
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-1`).click();
1140
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
1141
+ await page.getByLabel('rejectOnFalse').click();
1142
+ const oneConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
1143
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(oneConditionNodeName);
1144
+ const oneConditionNode = new ConditionYesNode(page, oneConditionNodeName);
1145
+ const oneConditionNodeId = await oneConditionNode.node.locator('.workflow-node-id').innerText();
1146
+ await oneConditionNode.nodeConfigure.click();
1147
+ await oneConditionNode.formulaRadio.click();
1148
+ await oneConditionNode.conditionExpressionEditBox.fill('1==2');
1149
+ await oneConditionNode.submitButton.click();
1150
+ // 分支2添加判断节点
1151
+ await page.getByLabel(`add-button-parallel-${parallelBranchNodeTitle}-2`).click();
1152
+ await page.getByRole('button', { name: 'condition', exact: true }).hover();
1153
+ await page.getByLabel('rejectOnFalse').click();
1154
+ const twoConditionNodeName = 'condition' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
1155
+ await page.getByLabel('Condition-Condition', { exact: true }).getByRole('textbox').fill(twoConditionNodeName);
1156
+ const twoConditionNode = new ConditionYesNode(page, twoConditionNodeName);
1157
+ const twoConditionNodeId = await twoConditionNode.node.locator('.workflow-node-id').innerText();
1158
+ await twoConditionNode.nodeConfigure.click();
1159
+ await twoConditionNode.formulaRadio.click();
1160
+ await twoConditionNode.conditionExpressionEditBox.fill('1==1');
1161
+ await twoConditionNode.submitButton.click();
1162
+ // 添加后置计算节点
1163
+ await parallelBranchNode.addNodeButton.click();
1164
+ await page.getByRole('button', { name: 'calculation', exact: true }).click();
1165
+ const afterCalCulationNodeName = 'calculation' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
1166
+ await page
1167
+ .getByLabel('Calculation-Calculation', { exact: true })
1168
+ .getByRole('textbox')
1169
+ .fill(afterCalCulationNodeName);
1170
+ const afterCalCulationNode = new ClculationNode(page, afterCalCulationNodeName);
1171
+ const afterCalCulationNodeId = await afterCalCulationNode.node.locator('.workflow-node-id').innerText();
1172
+ await afterCalCulationNode.nodeConfigure.click();
1173
+ await afterCalCulationNode.formulaCalculationEngine.click();
1174
+ await page.getByLabel('textbox').fill('4');
1175
+ await afterCalCulationNode.submitButton.click();
1176
+ // 2、测试步骤:添加数据触发工作流
1177
+ const triggerNodeCollectionRecordOne =
1178
+ triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
1179
+ const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
1180
+ { orgname: triggerNodeCollectionRecordOne },
1181
+ ]);
1182
+ await page.waitForTimeout(1000);
1183
+ // 3、预期结果:工作流成功触发,判断节点全部通过,后置计算节点执行成功
1184
+ const getWorkflow = await apiGetWorkflow(workflowId);
1185
+ const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
1186
+ const getWorkflowExecuted = getWorkflowObj.executed;
1187
+ expect(getWorkflowExecuted).toBe(1);
1188
+
1189
+ const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
1190
+ const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
1191
+ getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
1192
+ return b.id - a.id;
1193
+ });
1194
+ const jobs = getWorkflowNodeExecutionsObj[0].jobs;
1195
+ const parallelBranchNodeJob = jobs.find((job) => job.nodeId.toString() === parallelBranchNodeId);
1196
+ expect(parallelBranchNodeJob.status).toBe(-1);
1197
+ const oneConditionNodeJob = jobs.find((job) => job.nodeId.toString() === oneConditionNodeId);
1198
+ expect(oneConditionNodeJob.status).toBe(-1);
1199
+ expect(oneConditionNodeJob.result).toBe(false);
1200
+ const twoConditionNodeJob = jobs.find((job) => job.nodeId.toString() === twoConditionNodeId);
1201
+ expect(twoConditionNodeJob).toBe(undefined);
1202
+ const afterCalCulationNodeJob = jobs.find((job) => job.nodeId.toString() === afterCalCulationNodeId);
1203
+ expect(afterCalCulationNodeJob).toBe(undefined);
1204
+ // 4、后置处理:删除工作流
1205
+ await apiDeleteWorkflow(workflowId);
1206
+ });
1207
+ });