@nocobase/plugin-workflow-test 0.18.0-alpha.9 → 0.19.0-alpha.10

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.
@@ -189,6 +189,7 @@ export declare class AggregateNode {
189
189
  linkedDataTableDataRadio: Locator;
190
190
  collectionDropDown: Locator;
191
191
  aggregatedFieldDropDown: Locator;
192
+ distinctCheckBox: Locator;
192
193
  submitButton: Locator;
193
194
  cancelButton: Locator;
194
195
  addNodeButton: Locator;
@@ -220,6 +221,7 @@ export declare class ConditionYesNode {
220
221
  basicRadio: Locator;
221
222
  mathRadio: Locator;
222
223
  formulaRadio: Locator;
224
+ conditionExpressionEditBox: Locator;
223
225
  submitButton: Locator;
224
226
  cancelButton: Locator;
225
227
  addNodeButton: Locator;
@@ -233,6 +235,7 @@ export declare class ConditionBranchNode {
233
235
  basicRadio: Locator;
234
236
  mathRadio: Locator;
235
237
  formulaRadio: Locator;
238
+ conditionExpressionEditBox: Locator;
236
239
  submitButton: Locator;
237
240
  cancelButton: Locator;
238
241
  addNoBranchNode: Locator;
@@ -240,6 +243,31 @@ export declare class ConditionBranchNode {
240
243
  addNodeButton: Locator;
241
244
  constructor(page: Page, nodeName: string);
242
245
  }
246
+ export declare class SQLNode {
247
+ readonly page: Page;
248
+ node: Locator;
249
+ nodeTitle: Locator;
250
+ nodeConfigure: Locator;
251
+ sqlEditBox: Locator;
252
+ submitButton: Locator;
253
+ cancelButton: Locator;
254
+ addNodeButton: Locator;
255
+ constructor(page: Page, nodeName: string);
256
+ }
257
+ export declare class ParallelBranchNode {
258
+ readonly page: Page;
259
+ node: Locator;
260
+ nodeTitle: Locator;
261
+ nodeConfigure: Locator;
262
+ addBranchButton: Locator;
263
+ allSucceededRadio: Locator;
264
+ anySucceededRadio: Locator;
265
+ anySucceededOrFailedRadio: Locator;
266
+ submitButton: Locator;
267
+ cancelButton: Locator;
268
+ addNodeButton: Locator;
269
+ constructor(page: Page, nodeName: string);
270
+ }
243
271
  declare const _default: {
244
272
  CreateWorkFlow: typeof CreateWorkFlow;
245
273
  EditWorkFlow: typeof EditWorkFlow;
@@ -259,5 +287,7 @@ declare const _default: {
259
287
  ManualNode: typeof ManualNode;
260
288
  ConditionYesNode: typeof ConditionYesNode;
261
289
  ConditionBranchNode: typeof ConditionBranchNode;
290
+ SQLNode: typeof SQLNode;
291
+ ParallelBranchNode: typeof ParallelBranchNode;
262
292
  };
263
293
  export default _default;
@@ -30,7 +30,9 @@ __export(e2ePageObjectModel_exports, {
30
30
  EditWorkFlow: () => EditWorkFlow,
31
31
  FormEventTriggerNode: () => FormEventTriggerNode,
32
32
  ManualNode: () => ManualNode,
33
+ ParallelBranchNode: () => ParallelBranchNode,
33
34
  QueryRecordNode: () => QueryRecordNode,
35
+ SQLNode: () => SQLNode,
34
36
  ScheduleTriggerNode: () => ScheduleTriggerNode,
35
37
  UpdateRecordNode: () => UpdateRecordNode,
36
38
  WorkflowListRecords: () => WorkflowListRecords,
@@ -380,6 +382,7 @@ class AggregateNode {
380
382
  linkedDataTableDataRadio;
381
383
  collectionDropDown;
382
384
  aggregatedFieldDropDown;
385
+ distinctCheckBox;
383
386
  submitButton;
384
387
  cancelButton;
385
388
  addNodeButton;
@@ -399,6 +402,7 @@ class AggregateNode {
399
402
  this.aggregatedFieldDropDown = page.locator(
400
403
  'input.ant-select-selection-search-input[role="combobox"][aria-haspopup="listbox"]'
401
404
  );
405
+ this.distinctCheckBox = page.getByLabel("block-item-Checkbox-workflows-Distinct").locator('input.ant-checkbox-input[type="checkbox"]');
402
406
  this.submitButton = page.getByLabel("action-Action-Submit-workflows");
403
407
  this.cancelButton = page.getByLabel("action-Action-Cancel-workflows");
404
408
  this.addNodeButton = page.getByLabel(`add-button-aggregate-${nodeName}`, { exact: true });
@@ -428,11 +432,11 @@ class ManualNode {
428
432
  this.assigneesDropDown = page.getByTestId("select-single");
429
433
  this.configureUserInterfaceButton = page.getByRole("button", { name: "Configure user interface" });
430
434
  this.addBlockButton = page.getByLabel("schema-initializer-Grid-AddBlockButton-workflows");
431
- this.triggerDataMenu = page.getByLabel("Data blocks-triggerData");
432
- this.nodeDataMenu = page.getByLabel("nodes", { exact: true });
435
+ this.triggerDataMenu = page.getByRole("menuitem", { name: "Trigger data" });
436
+ this.nodeDataMenu = page.getByRole("menuitem", { name: "Node result right" });
433
437
  this.customFormMenu = page.getByRole("menuitem", { name: "Custom form" });
434
- this.createRecordFormMenu = page.getByRole("menuitem", { name: "Create record form" });
435
- this.updateRecordFormMenu = page.getByRole("menuitem", { name: "Update record form" });
438
+ this.createRecordFormMenu = page.getByRole("menuitem", { name: "Create record form right" });
439
+ this.updateRecordFormMenu = page.getByRole("menuitem", { name: "Update record form right" });
436
440
  this.submitButton = page.getByLabel("action-Action-Submit-workflows");
437
441
  this.cancelButton = page.getByLabel("action-Action-Cancel-workflows");
438
442
  this.addNodeButton = page.getByLabel(`add-button-manual-${nodeName}`, { exact: true });
@@ -446,6 +450,7 @@ class ConditionYesNode {
446
450
  basicRadio;
447
451
  mathRadio;
448
452
  formulaRadio;
453
+ conditionExpressionEditBox;
449
454
  submitButton;
450
455
  cancelButton;
451
456
  addNodeButton;
@@ -454,6 +459,7 @@ class ConditionYesNode {
454
459
  this.node = page.getByLabel(`Condition-${nodeName}`, { exact: true });
455
460
  this.nodeTitle = page.getByLabel(`Condition-${nodeName}`, { exact: true }).getByRole("textbox");
456
461
  this.nodeConfigure = page.getByLabel(`Condition-${nodeName}`, { exact: true }).getByRole("button", { name: "Configure" });
462
+ this.conditionExpressionEditBox = page.getByLabel("textbox");
457
463
  this.basicRadio = page.getByLabel("Basic");
458
464
  this.mathRadio = page.getByLabel("Math.js");
459
465
  this.formulaRadio = page.getByLabel("Formula.js");
@@ -470,6 +476,7 @@ class ConditionBranchNode {
470
476
  basicRadio;
471
477
  mathRadio;
472
478
  formulaRadio;
479
+ conditionExpressionEditBox;
473
480
  submitButton;
474
481
  cancelButton;
475
482
  addNoBranchNode;
@@ -480,6 +487,7 @@ class ConditionBranchNode {
480
487
  this.node = page.getByLabel(`Condition-${nodeName}`, { exact: true });
481
488
  this.nodeTitle = page.getByLabel(`Condition-${nodeName}`, { exact: true }).getByRole("textbox");
482
489
  this.nodeConfigure = page.getByLabel(`Condition-${nodeName}`, { exact: true }).getByRole("button", { name: "Configure" });
490
+ this.conditionExpressionEditBox = page.getByLabel("textbox");
483
491
  this.submitButton = page.getByLabel("action-Action-Submit-workflows");
484
492
  this.cancelButton = page.getByLabel("action-Action-Cancel-workflows");
485
493
  this.addNodeButton = page.getByLabel(`add-button-condition-${nodeName}`, { exact: true });
@@ -490,6 +498,52 @@ class ConditionBranchNode {
490
498
  this.addYesBranchNode = page.getByLabel(`add-button-condition-${nodeName}-1`);
491
499
  }
492
500
  }
501
+ class SQLNode {
502
+ page;
503
+ node;
504
+ nodeTitle;
505
+ nodeConfigure;
506
+ sqlEditBox;
507
+ submitButton;
508
+ cancelButton;
509
+ addNodeButton;
510
+ constructor(page, nodeName) {
511
+ this.page = page;
512
+ this.node = page.getByLabel(`SQL action-${nodeName}`, { exact: true });
513
+ this.nodeTitle = page.getByLabel(`SQL action-${nodeName}`, { exact: true }).getByRole("textbox");
514
+ this.nodeConfigure = page.getByLabel(`SQL action-${nodeName}`, { exact: true }).getByRole("button", { name: "Configure" });
515
+ this.sqlEditBox = page.getByLabel("block-item-WorkflowVariableRawTextArea-workflows-SQL").getByRole("textbox");
516
+ this.submitButton = page.getByLabel("action-Action-Submit-workflows");
517
+ this.cancelButton = page.getByLabel("action-Action-Cancel-workflows");
518
+ this.addNodeButton = page.getByLabel(`add-button-sql-${nodeName}`, { exact: true });
519
+ }
520
+ }
521
+ class ParallelBranchNode {
522
+ page;
523
+ node;
524
+ nodeTitle;
525
+ nodeConfigure;
526
+ addBranchButton;
527
+ allSucceededRadio;
528
+ anySucceededRadio;
529
+ anySucceededOrFailedRadio;
530
+ submitButton;
531
+ cancelButton;
532
+ addNodeButton;
533
+ constructor(page, nodeName) {
534
+ this.page = page;
535
+ this.node = page.getByLabel(`Parallel branch-${nodeName}`, { exact: true });
536
+ this.nodeTitle = page.locator("textarea").filter({ hasText: nodeName });
537
+ this.nodeConfigure = page.getByLabel(`Parallel branch-${nodeName}`).getByRole("button", { name: "Configure" });
538
+ this.addBranchButton = page.getByLabel(`add-button-parallel-${nodeName}-add-branch`, { exact: true });
539
+ this.allSucceededRadio = page.getByLabel("All succeeded", { exact: true });
540
+ this.anySucceededRadio = page.getByLabel("Any succeeded", { exact: true });
541
+ this.anySucceededOrFailedRadio = page.getByLabel("Any succeeded or failed", { exact: true });
542
+ this.submitButton = page.getByLabel("action-Action-Submit-workflows");
543
+ this.cancelButton = page.getByLabel("action-Action-Cancel-workflows");
544
+ this.addNodeButton = page.getByLabel(`add-button-parallel-${nodeName}`, { exact: true });
545
+ }
546
+ }
493
547
  var e2ePageObjectModel_default = module.exports = {
494
548
  CreateWorkFlow,
495
549
  EditWorkFlow,
@@ -508,7 +562,9 @@ var e2ePageObjectModel_default = module.exports = {
508
562
  AggregateNode,
509
563
  ManualNode,
510
564
  ConditionYesNode,
511
- ConditionBranchNode
565
+ ConditionBranchNode,
566
+ SQLNode,
567
+ ParallelBranchNode
512
568
  };
513
569
  // Annotate the CommonJS export names for ESM import in node:
514
570
  0 && (module.exports = {
@@ -525,7 +581,9 @@ var e2ePageObjectModel_default = module.exports = {
525
581
  EditWorkFlow,
526
582
  FormEventTriggerNode,
527
583
  ManualNode,
584
+ ParallelBranchNode,
528
585
  QueryRecordNode,
586
+ SQLNode,
529
587
  ScheduleTriggerNode,
530
588
  UpdateRecordNode,
531
589
  WorkflowListRecords,
@@ -10,6 +10,7 @@ export declare const apiGetWorkflowNodeExecutions: (id: number) => Promise<any>;
10
10
  export declare const apiUpdateRecord: (collectionName: string, id: number, data: any) => Promise<any>;
11
11
  export declare const apiGetRecord: (collectionName: string, id: number) => Promise<any>;
12
12
  export declare const apiGetList: (collectionName: string) => Promise<any>;
13
+ export declare const apiFilterList: (collectionName: string, filter: string) => Promise<any>;
13
14
  export declare const apiCreateRecordTriggerFormEvent: (collectionName: string, triggerWorkflows: string, data: any) => Promise<any>;
14
15
  export declare const apiSubmitRecordTriggerFormEvent: (triggerWorkflows: string, data: any) => Promise<any>;
15
16
  declare const _default: {
@@ -27,5 +28,6 @@ declare const _default: {
27
28
  apiGetList: (collectionName: string) => Promise<any>;
28
29
  apiCreateRecordTriggerFormEvent: (collectionName: string, triggerWorkflows: string, data: any) => Promise<any>;
29
30
  apiSubmitRecordTriggerFormEvent: (triggerWorkflows: string, data: any) => Promise<any>;
31
+ apiFilterList: (collectionName: string, filter: string) => Promise<any>;
30
32
  };
31
33
  export default _default;
@@ -21,6 +21,7 @@ __export(e2eUtils_exports, {
21
21
  apiCreateWorkflow: () => apiCreateWorkflow,
22
22
  apiCreateWorkflowNode: () => apiCreateWorkflowNode,
23
23
  apiDeleteWorkflow: () => apiDeleteWorkflow,
24
+ apiFilterList: () => apiFilterList,
24
25
  apiGetList: () => apiGetList,
25
26
  apiGetRecord: () => apiGetRecord,
26
27
  apiGetWorkflow: () => apiGetWorkflow,
@@ -212,6 +213,20 @@ const apiGetList = async (collectionName) => {
212
213
  }
213
214
  return await result.json();
214
215
  };
216
+ const apiFilterList = async (collectionName, filter) => {
217
+ const api = await import_e2e.request.newContext({
218
+ storageState: process.env.PLAYWRIGHT_AUTH_FILE
219
+ });
220
+ const state = await api.storageState();
221
+ const headers = getHeaders(state);
222
+ const result = await api.get(`/api/${collectionName}:list?${filter}`, {
223
+ headers
224
+ });
225
+ if (!result.ok()) {
226
+ throw new Error(await result.text());
227
+ }
228
+ return await result.json();
229
+ };
215
230
  const apiCreateRecordTriggerFormEvent = async (collectionName, triggerWorkflows, data) => {
216
231
  const api = await import_e2e.request.newContext({
217
232
  storageState: process.env.PLAYWRIGHT_AUTH_FILE
@@ -297,7 +312,8 @@ var e2eUtils_default = module.exports = {
297
312
  apiGetRecord,
298
313
  apiGetList,
299
314
  apiCreateRecordTriggerFormEvent,
300
- apiSubmitRecordTriggerFormEvent
315
+ apiSubmitRecordTriggerFormEvent,
316
+ apiFilterList
301
317
  };
302
318
  // Annotate the CommonJS export names for ESM import in node:
303
319
  0 && (module.exports = {
@@ -305,6 +321,7 @@ var e2eUtils_default = module.exports = {
305
321
  apiCreateWorkflow,
306
322
  apiCreateWorkflowNode,
307
323
  apiDeleteWorkflow,
324
+ apiFilterList,
308
325
  apiGetList,
309
326
  apiGetRecord,
310
327
  apiGetWorkflow,
@@ -1,8 +1,8 @@
1
1
  module.exports = {
2
- "@nocobase/client": "0.18.0-alpha.9",
3
- "@nocobase/utils": "0.18.0-alpha.9",
2
+ "@nocobase/client": "0.19.0-alpha.10",
3
+ "@nocobase/utils": "0.19.0-alpha.10",
4
4
  "lodash": "4.17.21",
5
- "@nocobase/test": "0.18.0-alpha.9",
6
- "@nocobase/server": "0.18.0-alpha.9",
7
- "@nocobase/database": "0.18.0-alpha.9"
5
+ "@nocobase/test": "0.19.0-alpha.10",
6
+ "@nocobase/server": "0.19.0-alpha.10",
7
+ "@nocobase/database": "0.19.0-alpha.10"
8
8
  };
@@ -1,13 +1,10 @@
1
- import { Plugin, ApplicationOptions } from '@nocobase/server';
1
+ import { ApplicationOptions, Plugin } from '@nocobase/server';
2
2
  import { MockServer } from '@nocobase/test';
3
- interface MockServerOptions extends ApplicationOptions {
4
- autoStart?: boolean;
3
+ export interface MockServerOptions extends ApplicationOptions {
5
4
  collectionsPath?: string;
6
- cleanDb?: boolean;
7
5
  }
8
6
  export declare function sleep(ms: number): Promise<unknown>;
9
- export declare function getApp({ autoStart, cleanDb, plugins, ...options }?: MockServerOptions): Promise<MockServer>;
7
+ export declare function getApp(options?: MockServerOptions): Promise<MockServer>;
10
8
  export default class WorkflowTestPlugin extends Plugin {
11
9
  load(): Promise<void>;
12
10
  }
13
- export {};
@@ -35,60 +35,43 @@ module.exports = __toCommonJS(server_exports);
35
35
  var import_path = __toESM(require("path"));
36
36
  var import_server = require("@nocobase/server");
37
37
  var import_test = require("@nocobase/test");
38
- var import_instructions = __toESM(require("./instructions"));
39
38
  var import_functions = __toESM(require("./functions"));
40
- async function createMockServer({ autoStart, collectionsPath, cleanDb, ...options }) {
41
- const app = (0, import_test.mockServer)(options);
42
- if (cleanDb) {
43
- await app.cleanDb();
44
- }
45
- await app.load();
46
- if (collectionsPath) {
47
- await app.db.import({ directory: collectionsPath });
48
- }
49
- try {
50
- await app.db.sync();
51
- } catch (error) {
52
- console.error(error);
53
- }
54
- if (autoStart) {
55
- await app.start();
56
- }
57
- return app;
58
- }
39
+ var import_triggers = __toESM(require("./triggers"));
40
+ var import_instructions = __toESM(require("./instructions"));
59
41
  function sleep(ms) {
60
42
  return new Promise((resolve) => {
61
43
  setTimeout(resolve, ms);
62
44
  });
63
45
  }
64
- async function getApp({
65
- autoStart = true,
66
- cleanDb = true,
67
- plugins = [],
68
- ...options
69
- } = {}) {
70
- return createMockServer({
71
- ...options,
72
- autoStart,
73
- cleanDb,
46
+ async function getApp(options = {}) {
47
+ const { plugins = [], collectionsPath, ...others } = options;
48
+ class TestCollectionPlugin extends import_server.Plugin {
49
+ async load() {
50
+ if (collectionsPath) {
51
+ await this.db.import({ directory: collectionsPath });
52
+ }
53
+ }
54
+ }
55
+ return (0, import_test.createMockServer)({
56
+ ...others,
74
57
  plugins: [
75
58
  [
76
59
  "workflow",
77
60
  {
61
+ triggers: import_triggers.default,
78
62
  instructions: import_instructions.default,
79
63
  functions: import_functions.default
80
64
  }
81
65
  ],
82
- WorkflowTestPlugin,
66
+ "workflow-test",
67
+ TestCollectionPlugin,
83
68
  ...plugins
84
69
  ]
85
70
  });
86
71
  }
87
72
  class WorkflowTestPlugin extends import_server.Plugin {
88
73
  async load() {
89
- await this.db.import({
90
- directory: import_path.default.resolve(__dirname, "collections")
91
- });
74
+ await this.importCollections(import_path.default.resolve(__dirname, "collections"));
92
75
  }
93
76
  }
94
77
  // Annotate the CommonJS export names for ESM import in node:
@@ -8,7 +8,7 @@ declare const _default: {
8
8
  };
9
9
  };
10
10
  error: {
11
- run(node: any, input: any, processor: any): any;
11
+ run(node: any, input: any, processor: any): never;
12
12
  };
13
13
  pending: {
14
14
  run(node: any, input: any, processor: any): {
@@ -33,7 +33,6 @@ var instructions_default = {
33
33
  error: {
34
34
  run(node, input, processor) {
35
35
  throw new Error("definite error");
36
- return null;
37
36
  }
38
37
  },
39
38
  pending: {
@@ -0,0 +1,20 @@
1
+ declare const _default: {
2
+ syncTrigger: {
3
+ new (workflow: any): {
4
+ readonly workflow: any;
5
+ on(): void;
6
+ off(): void;
7
+ sync: boolean;
8
+ validateEvent(): boolean;
9
+ };
10
+ };
11
+ asyncTrigger: {
12
+ new (workflow: any): {
13
+ readonly workflow: any;
14
+ on(): void;
15
+ off(): void;
16
+ validateEvent(): boolean;
17
+ };
18
+ };
19
+ };
20
+ export default _default;
@@ -0,0 +1,49 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var triggers_exports = {};
19
+ __export(triggers_exports, {
20
+ default: () => triggers_default
21
+ });
22
+ module.exports = __toCommonJS(triggers_exports);
23
+ var triggers_default = {
24
+ syncTrigger: class {
25
+ constructor(workflow) {
26
+ this.workflow = workflow;
27
+ }
28
+ on() {
29
+ }
30
+ off() {
31
+ }
32
+ sync = true;
33
+ validateEvent() {
34
+ return true;
35
+ }
36
+ },
37
+ asyncTrigger: class {
38
+ constructor(workflow) {
39
+ this.workflow = workflow;
40
+ }
41
+ on() {
42
+ }
43
+ off() {
44
+ }
45
+ validateEvent() {
46
+ return true;
47
+ }
48
+ }
49
+ };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@nocobase/plugin-workflow-test",
3
3
  "displayName": "Workflow: test kit",
4
4
  "displayName.zh-CN": "工作流:测试工具包",
5
- "version": "0.18.0-alpha.9",
5
+ "version": "0.19.0-alpha.10",
6
6
  "license": "AGPL-3.0",
7
7
  "main": "dist/server/index.js",
8
8
  "types": "./dist/server/index.d.ts",
@@ -11,5 +11,5 @@
11
11
  "@nocobase/server": "0.x",
12
12
  "@nocobase/test": "0.x"
13
13
  },
14
- "gitHead": "34ca0df4eede2e83fc86297b0fe19eba970e2b1b"
14
+ "gitHead": "d09d81eba67339da36bcec27939a85b35d180770"
15
15
  }
@@ -377,6 +377,7 @@ export class AggregateNode {
377
377
  linkedDataTableDataRadio: Locator;
378
378
  collectionDropDown: Locator;
379
379
  aggregatedFieldDropDown: Locator;
380
+ distinctCheckBox: Locator;
380
381
  submitButton: Locator;
381
382
  cancelButton: Locator;
382
383
  addNodeButton: Locator;
@@ -399,6 +400,9 @@ export class AggregateNode {
399
400
  this.aggregatedFieldDropDown = page.locator(
400
401
  'input.ant-select-selection-search-input[role="combobox"][aria-haspopup="listbox"]',
401
402
  );
403
+ this.distinctCheckBox = page
404
+ .getByLabel('block-item-Checkbox-workflows-Distinct')
405
+ .locator('input.ant-checkbox-input[type="checkbox"]');
402
406
  this.submitButton = page.getByLabel('action-Action-Submit-workflows');
403
407
  this.cancelButton = page.getByLabel('action-Action-Cancel-workflows');
404
408
  this.addNodeButton = page.getByLabel(`add-button-aggregate-${nodeName}`, { exact: true });
@@ -431,11 +435,11 @@ export class ManualNode {
431
435
  this.assigneesDropDown = page.getByTestId('select-single');
432
436
  this.configureUserInterfaceButton = page.getByRole('button', { name: 'Configure user interface' });
433
437
  this.addBlockButton = page.getByLabel('schema-initializer-Grid-AddBlockButton-workflows');
434
- this.triggerDataMenu = page.getByLabel('Data blocks-triggerData');
435
- this.nodeDataMenu = page.getByLabel('nodes', { exact: true });
438
+ this.triggerDataMenu = page.getByRole('menuitem', { name: 'Trigger data' });
439
+ this.nodeDataMenu = page.getByRole('menuitem', { name: 'Node result right' });
436
440
  this.customFormMenu = page.getByRole('menuitem', { name: 'Custom form' });
437
- this.createRecordFormMenu = page.getByRole('menuitem', { name: 'Create record form' });
438
- this.updateRecordFormMenu = page.getByRole('menuitem', { name: 'Update record form' });
441
+ this.createRecordFormMenu = page.getByRole('menuitem', { name: 'Create record form right' });
442
+ this.updateRecordFormMenu = page.getByRole('menuitem', { name: 'Update record form right' });
439
443
  this.submitButton = page.getByLabel('action-Action-Submit-workflows');
440
444
  this.cancelButton = page.getByLabel('action-Action-Cancel-workflows');
441
445
  this.addNodeButton = page.getByLabel(`add-button-manual-${nodeName}`, { exact: true });
@@ -450,6 +454,7 @@ export class ConditionYesNode {
450
454
  basicRadio: Locator;
451
455
  mathRadio: Locator;
452
456
  formulaRadio: Locator;
457
+ conditionExpressionEditBox: Locator;
453
458
  submitButton: Locator;
454
459
  cancelButton: Locator;
455
460
  addNodeButton: Locator;
@@ -460,6 +465,7 @@ export class ConditionYesNode {
460
465
  this.nodeConfigure = page
461
466
  .getByLabel(`Condition-${nodeName}`, { exact: true })
462
467
  .getByRole('button', { name: 'Configure' });
468
+ this.conditionExpressionEditBox = page.getByLabel('textbox');
463
469
  // await page.getByLabel('variable-constant').first().click();
464
470
  // await page.getByLabel('variable-button').first().click();
465
471
  // await page.getByLabel('select-operator-calc').first().click();
@@ -483,6 +489,7 @@ export class ConditionBranchNode {
483
489
  basicRadio: Locator;
484
490
  mathRadio: Locator;
485
491
  formulaRadio: Locator;
492
+ conditionExpressionEditBox: Locator;
486
493
  submitButton: Locator;
487
494
  cancelButton: Locator;
488
495
  addNoBranchNode: Locator;
@@ -495,6 +502,7 @@ export class ConditionBranchNode {
495
502
  this.nodeConfigure = page
496
503
  .getByLabel(`Condition-${nodeName}`, { exact: true })
497
504
  .getByRole('button', { name: 'Configure' });
505
+ this.conditionExpressionEditBox = page.getByLabel('textbox');
498
506
  this.submitButton = page.getByLabel('action-Action-Submit-workflows');
499
507
  this.cancelButton = page.getByLabel('action-Action-Cancel-workflows');
500
508
  this.addNodeButton = page.getByLabel(`add-button-condition-${nodeName}`, { exact: true });
@@ -506,6 +514,56 @@ export class ConditionBranchNode {
506
514
  }
507
515
  }
508
516
 
517
+ export class SQLNode {
518
+ readonly page: Page;
519
+ node: Locator;
520
+ nodeTitle: Locator;
521
+ nodeConfigure: Locator;
522
+ sqlEditBox: Locator;
523
+ submitButton: Locator;
524
+ cancelButton: Locator;
525
+ addNodeButton: Locator;
526
+ constructor(page: Page, nodeName: string) {
527
+ this.page = page;
528
+ this.node = page.getByLabel(`SQL action-${nodeName}`, { exact: true });
529
+ this.nodeTitle = page.getByLabel(`SQL action-${nodeName}`, { exact: true }).getByRole('textbox');
530
+ this.nodeConfigure = page
531
+ .getByLabel(`SQL action-${nodeName}`, { exact: true })
532
+ .getByRole('button', { name: 'Configure' });
533
+ this.sqlEditBox = page.getByLabel('block-item-WorkflowVariableRawTextArea-workflows-SQL').getByRole('textbox');
534
+ this.submitButton = page.getByLabel('action-Action-Submit-workflows');
535
+ this.cancelButton = page.getByLabel('action-Action-Cancel-workflows');
536
+ this.addNodeButton = page.getByLabel(`add-button-sql-${nodeName}`, { exact: true });
537
+ }
538
+ }
539
+
540
+ export class ParallelBranchNode {
541
+ readonly page: Page;
542
+ node: Locator;
543
+ nodeTitle: Locator;
544
+ nodeConfigure: Locator;
545
+ addBranchButton: Locator;
546
+ allSucceededRadio: Locator;
547
+ anySucceededRadio: Locator;
548
+ anySucceededOrFailedRadio: Locator;
549
+ submitButton: Locator;
550
+ cancelButton: Locator;
551
+ addNodeButton: Locator;
552
+ constructor(page: Page, nodeName: string) {
553
+ this.page = page;
554
+ this.node = page.getByLabel(`Parallel branch-${nodeName}`, { exact: true });
555
+ this.nodeTitle = page.locator('textarea').filter({ hasText: nodeName });
556
+ this.nodeConfigure = page.getByLabel(`Parallel branch-${nodeName}`).getByRole('button', { name: 'Configure' });
557
+ this.addBranchButton = page.getByLabel(`add-button-parallel-${nodeName}-add-branch`, { exact: true });
558
+ this.allSucceededRadio = page.getByLabel('All succeeded', { exact: true });
559
+ this.anySucceededRadio = page.getByLabel('Any succeeded', { exact: true });
560
+ this.anySucceededOrFailedRadio = page.getByLabel('Any succeeded or failed', { exact: true });
561
+ this.submitButton = page.getByLabel('action-Action-Submit-workflows');
562
+ this.cancelButton = page.getByLabel('action-Action-Cancel-workflows');
563
+ this.addNodeButton = page.getByLabel(`add-button-parallel-${nodeName}`, { exact: true });
564
+ }
565
+ }
566
+
509
567
  export default module.exports = {
510
568
  CreateWorkFlow,
511
569
  EditWorkFlow,
@@ -525,4 +583,6 @@ export default module.exports = {
525
583
  ManualNode,
526
584
  ConditionYesNode,
527
585
  ConditionBranchNode,
586
+ SQLNode,
587
+ ParallelBranchNode,
528
588
  };
@@ -605,6 +605,44 @@ export const apiGetList = async (collectionName: string) => {
605
605
  return await result.json();
606
606
  };
607
607
 
608
+ // 查询业务表list
609
+ export const apiFilterList = async (collectionName: string, filter: string) => {
610
+ const api = await request.newContext({
611
+ storageState: process.env.PLAYWRIGHT_AUTH_FILE,
612
+ });
613
+ const state = await api.storageState();
614
+ const headers = getHeaders(state);
615
+ const result = await api.get(`/api/${collectionName}:list?${filter}`, {
616
+ headers,
617
+ });
618
+
619
+ if (!result.ok()) {
620
+ throw new Error(await result.text());
621
+ }
622
+ /*
623
+ {
624
+ "data": [
625
+ {
626
+ "id": 1,
627
+ "createdAt": "2023-12-12T02:43:53.793Z",
628
+ "updatedAt": "2023-12-12T05:41:33.300Z",
629
+ "key": "fzk3j2oj4el",
630
+ "title": "a11",
631
+ "enabled": true,
632
+ "description": null
633
+ }
634
+ ],
635
+ "meta": {
636
+ "count": 1,
637
+ "page": 1,
638
+ "pageSize": 20,
639
+ "totalPage": 1
640
+ }
641
+ }
642
+ */
643
+ return await result.json();
644
+ };
645
+
608
646
  // 添加业务表单条数据触发工作流表单事件,triggerWorkflows=key1!field,key2,key3!field.subfield
609
647
  export const apiCreateRecordTriggerFormEvent = async (collectionName: string, triggerWorkflows: string, data: any) => {
610
648
  const api = await request.newContext({
@@ -744,4 +782,5 @@ export default module.exports = {
744
782
  apiGetList,
745
783
  apiCreateRecordTriggerFormEvent,
746
784
  apiSubmitRecordTriggerFormEvent,
785
+ apiFilterList,
747
786
  };
@@ -1,43 +1,22 @@
1
1
  import path from 'path';
2
2
 
3
- import { Plugin, ApplicationOptions } from '@nocobase/server';
4
- import { MockServer, mockServer } from '@nocobase/test';
3
+ import { ApplicationOptions, Plugin } from '@nocobase/server';
4
+ import { MockServer, createMockServer } from '@nocobase/test';
5
5
 
6
- import instructions from './instructions';
7
6
  import functions from './functions';
7
+ import triggers from './triggers';
8
+ import instructions from './instructions';
8
9
 
9
- interface MockServerOptions extends ApplicationOptions {
10
- autoStart?: boolean;
10
+ export interface MockServerOptions extends ApplicationOptions {
11
11
  collectionsPath?: string;
12
- cleanDb?: boolean;
13
12
  }
14
13
 
15
- async function createMockServer({ autoStart, collectionsPath, cleanDb, ...options }: MockServerOptions) {
16
- const app = mockServer(options);
17
-
18
- if (cleanDb) {
19
- await app.cleanDb();
20
- }
21
-
22
- await app.load();
23
-
24
- if (collectionsPath) {
25
- await app.db.import({ directory: collectionsPath });
26
- }
27
-
28
- try {
29
- await app.db.sync();
30
- } catch (error) {
31
- console.error(error);
32
- }
33
-
34
- if (autoStart) {
35
- await app.start();
36
- // await app.runCommand('start', '--quickstart');
37
- }
38
-
39
- return app;
40
- }
14
+ // async function createMockServer(options: MockServerOptions) {
15
+ // const app = mockServer(options);
16
+ // await app.cleanDb();
17
+ // await app.runCommand('start', '--quickstart');
18
+ // return app;
19
+ // }
41
20
 
42
21
  export function sleep(ms: number) {
43
22
  return new Promise((resolve) => {
@@ -45,25 +24,28 @@ export function sleep(ms: number) {
45
24
  });
46
25
  }
47
26
 
48
- export async function getApp({
49
- autoStart = true,
50
- cleanDb = true,
51
- plugins = [],
52
- ...options
53
- }: MockServerOptions = {}): Promise<MockServer> {
27
+ export async function getApp(options: MockServerOptions = {}): Promise<MockServer> {
28
+ const { plugins = [], collectionsPath, ...others } = options;
29
+ class TestCollectionPlugin extends Plugin {
30
+ async load() {
31
+ if (collectionsPath) {
32
+ await this.db.import({ directory: collectionsPath });
33
+ }
34
+ }
35
+ }
54
36
  return createMockServer({
55
- ...options,
56
- autoStart,
57
- cleanDb,
37
+ ...others,
58
38
  plugins: [
59
39
  [
60
40
  'workflow',
61
41
  {
42
+ triggers,
62
43
  instructions,
63
44
  functions,
64
45
  },
65
46
  ],
66
- WorkflowTestPlugin,
47
+ 'workflow-test',
48
+ TestCollectionPlugin,
67
49
  ...plugins,
68
50
  ],
69
51
  });
@@ -71,8 +53,6 @@ export async function getApp({
71
53
 
72
54
  export default class WorkflowTestPlugin extends Plugin {
73
55
  async load() {
74
- await this.db.import({
75
- directory: path.resolve(__dirname, 'collections'),
76
- });
56
+ await this.importCollections(path.resolve(__dirname, 'collections'));
77
57
  }
78
58
  }
@@ -13,7 +13,6 @@ export default {
13
13
  error: {
14
14
  run(node, input, processor) {
15
15
  throw new Error('definite error');
16
- return null;
17
16
  },
18
17
  },
19
18
 
@@ -0,0 +1,19 @@
1
+ export default {
2
+ syncTrigger: class {
3
+ constructor(public readonly workflow) {}
4
+ on() {}
5
+ off() {}
6
+ sync = true;
7
+ validateEvent() {
8
+ return true;
9
+ }
10
+ },
11
+ asyncTrigger: class {
12
+ constructor(public readonly workflow) {}
13
+ on() {}
14
+ off() {}
15
+ validateEvent() {
16
+ return true;
17
+ }
18
+ },
19
+ };