@nocobase/flow-engine
Version:
A standalone flow engine for NocoBase, managing workflows, models, and actions.
101 lines (80 loc) • 4.27 kB
text/typescript
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { describe, expect, test, beforeEach } from 'vitest';
import { FlowModel } from '@nocobase/flow-engine';
describe('FlowModel.getFlows sorting and getAutoFlows order', () => {
let TestFlowModel: typeof FlowModel;
let model: FlowModel;
beforeEach(() => {
// use a fresh subclass to isolate class-level registries
TestFlowModel = class extends FlowModel {};
// provide a minimal fake engine to avoid circular deps in tests
const fakeEngine = { getModel: () => undefined } as any;
model = new TestFlowModel({ flowEngine: fakeEngine } as any);
});
test('getFlows returns Map ordered by sort ascending', () => {
// class-level (static) flows
TestFlowModel.registerFlow('flowA', { title: 'A', sort: 10, steps: {} });
TestFlowModel.registerFlow('flowB', { title: 'B', sort: 5, steps: {} });
// instance-level flows
model.registerFlow('flowC', { title: 'C', sort: 7, steps: {} });
model.registerFlow('flowD', { title: 'D', steps: {} }); // default sort => 0
const flows = model.getFlows();
const orderedKeys = Array.from(flows.keys());
expect(orderedKeys).toEqual(['flowD', 'flowB', 'flowC', 'flowA']);
});
test('getAutoFlows keeps getFlows order and filters out manual/on flows', () => {
// class-level
TestFlowModel.registerFlow('flowA', { title: 'A', sort: 10, steps: {} });
TestFlowModel.registerFlow('flowB', { title: 'B', sort: 5, steps: {} });
// instance-level
model.registerFlow('flowD', { title: 'D', steps: {} }); // default 0
model.registerFlow('flowC', { title: 'C', sort: 7, steps: {} });
model.registerFlow('flowE', { title: 'E', sort: 8, steps: {} });
// excluded by filters
model.registerFlow('eventFlow', { title: 'Evt', on: 'click', sort: 1, steps: {} } as any);
model.registerFlow('manualFlow', { title: 'Manual', manual: true, sort: -1, steps: {} });
const getFlowsOrder = Array.from(model.getFlows().keys());
const autoFlowKeys = model.getAutoFlows().map((f) => f.key);
// auto flows should exclude event/manual flows
expect(autoFlowKeys).toEqual(['flowD', 'flowB', 'flowC', 'flowE', 'flowA']);
// relative order should match getFlows order (subset in same sequence)
const filteredGetFlowsOrder = getFlowsOrder.filter((k) => !['eventFlow', 'manualFlow'].includes(k));
expect(autoFlowKeys).toEqual(filteredGetFlowsOrder);
});
test('getFlows tie-breaker: static before instance when sort equal', () => {
// static flow with sort 2
TestFlowModel.registerFlow('static2', { title: 'S2', sort: 2, steps: {} });
// instance flow with same sort 2
model.registerFlow('instance2', { title: 'I2', sort: 2, steps: {} });
const keys = Array.from(model.getFlows().keys());
expect(keys.indexOf('static2')).toBeLessThan(keys.indexOf('instance2'));
});
test('getFlows tie-breaker: parent static before child static when sort equal', () => {
class Parent extends FlowModel {}
class Child extends Parent {}
const fakeEngine = { getModel: () => undefined } as any;
const instance = new Child({ flowEngine: fakeEngine } as any);
Parent.registerFlow('parent', { title: 'P', sort: 3, steps: {} });
Child.registerFlow('child', { title: 'C', sort: 3, steps: {} });
const ordered = Array.from(instance.getFlows().keys());
expect(ordered.indexOf('parent')).toBeLessThan(ordered.indexOf('child'));
});
test('GlobalFlowRegistry.getFlows sorted: parent static before child static on tie', () => {
class P extends FlowModel {}
class C extends P {}
const fakeEngine = { getModel: () => undefined } as any;
const inst = new C({ flowEngine: fakeEngine } as any);
P.registerFlow('p', { steps: {}, sort: 1 });
C.registerFlow('c', { steps: {}, sort: 1 });
const staticFlows = (C as any).globalFlowRegistry.getFlows();
const keys = Array.from(staticFlows.keys());
expect(keys.indexOf('p')).toBeLessThan(keys.indexOf('c'));
});
});