feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { injectable } from 'inversify';
|
||||
|
||||
import { type EncapsulateApiService } from '../src/api';
|
||||
import { complexMock } from './workflow.mock';
|
||||
|
||||
@injectable()
|
||||
export class MockEncapsulateApiService implements EncapsulateApiService {
|
||||
encapsulateWorkflow() {
|
||||
return Promise.resolve({ workflowId: 'mockWorkflowId' });
|
||||
}
|
||||
validateWorkflow() {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
getWorkflow(_spaceId: string, _workflowId: string) {
|
||||
return Promise.resolve(complexMock);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ContainerModule, injectable } from 'inversify';
|
||||
import {
|
||||
createFreeHistoryPlugin,
|
||||
FormModelV2,
|
||||
type FlowNodeEntity,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
import {
|
||||
FlowNodeFormData,
|
||||
createNodeContainerModules,
|
||||
createNodeEntityDatas,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
import {
|
||||
FlowDocumentContainerModule,
|
||||
FlowDocumentContribution,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
import {
|
||||
PlaygroundMockTools,
|
||||
PlaygroundContext,
|
||||
bindContributions,
|
||||
Playground,
|
||||
loadPlugins,
|
||||
EntityManagerContribution,
|
||||
type EntityManager,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
import {
|
||||
type WorkflowDocument,
|
||||
WorkflowDocumentContainerModule,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
import { createWorkflowVariablePlugins } from '@coze-workflow/variable';
|
||||
import { WorkflowNodesService } from '@coze-workflow/nodes';
|
||||
import { StandardNodeType } from '@coze-workflow/base/types';
|
||||
import { ValidationService } from '@coze-workflow/base/services';
|
||||
|
||||
import { WorkflowEncapsulateContainerModule } from '../src/workflow-encapsulate-container-module';
|
||||
import { EncapsulateValidatorsContainerModule } from '../src/validators';
|
||||
import {
|
||||
EncapsulateWorkflowJSONValidator,
|
||||
type EncapsulateValidateResult,
|
||||
} from '../src/validate';
|
||||
import { EncapsulateApiService } from '../src/api';
|
||||
import { MockValidationService } from './validation-service.mock';
|
||||
import { MockEncapsulateApiService } from './api-service.mock';
|
||||
|
||||
@injectable()
|
||||
export class MockPlaygroundContext implements PlaygroundContext {
|
||||
getNodeTemplateInfoByType() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class MockWorkflowEncapsulateValidator
|
||||
implements EncapsulateWorkflowJSONValidator
|
||||
{
|
||||
validate(_json, _result: EncapsulateValidateResult): void | Promise<void> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class MockWorkflowForm
|
||||
implements FlowDocumentContribution, EntityManagerContribution
|
||||
{
|
||||
registerDocument(document: WorkflowDocument): void {
|
||||
document.registerNodeDatas(...createNodeEntityDatas());
|
||||
document.registerFlowNodes({
|
||||
type: StandardNodeType.SubWorkflow,
|
||||
formMeta: {
|
||||
render: () => null,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
registerEntityManager(entityManager: EntityManager): void {
|
||||
const formModelFactory = (entity: FlowNodeEntity) =>
|
||||
new FormModelV2(entity);
|
||||
entityManager.registerEntityData(
|
||||
FlowNodeFormData,
|
||||
() =>
|
||||
({
|
||||
formModelFactory,
|
||||
}) as any,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-params
|
||||
const TestModule = new ContainerModule((bind, _unbind, _isBound, rebind) => {
|
||||
rebind(PlaygroundContext).to(MockPlaygroundContext);
|
||||
|
||||
rebind(EncapsulateApiService)
|
||||
.to(MockEncapsulateApiService)
|
||||
.inSingletonScope();
|
||||
bind(ValidationService).to(MockValidationService).inSingletonScope();
|
||||
bindContributions(bind, MockWorkflowEncapsulateValidator, [
|
||||
EncapsulateWorkflowJSONValidator,
|
||||
]);
|
||||
|
||||
bind(WorkflowNodesService).toSelf().inSingletonScope();
|
||||
bindContributions(bind, MockWorkflowForm, [
|
||||
FlowDocumentContribution,
|
||||
EntityManagerContribution,
|
||||
]);
|
||||
});
|
||||
|
||||
export function createContainer() {
|
||||
const container = PlaygroundMockTools.createContainer([
|
||||
FlowDocumentContainerModule,
|
||||
WorkflowDocumentContainerModule,
|
||||
WorkflowEncapsulateContainerModule,
|
||||
EncapsulateValidatorsContainerModule,
|
||||
...createNodeContainerModules(),
|
||||
TestModule,
|
||||
]);
|
||||
const playground = container.get(Playground);
|
||||
|
||||
loadPlugins(
|
||||
[
|
||||
createFreeHistoryPlugin({ enable: true, limit: 50 }),
|
||||
...createWorkflowVariablePlugins({}),
|
||||
],
|
||||
container,
|
||||
);
|
||||
playground.init();
|
||||
return container;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export default {};
|
||||
@@ -0,0 +1,112 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`encapsulate-nodes-service > should decapsulateLayout 1`] = `
|
||||
{
|
||||
"edges": [
|
||||
{
|
||||
"sourceNodeID": "100001",
|
||||
"targetNodeID": "154702",
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "102906",
|
||||
"targetNodeID": "900001",
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "177547",
|
||||
"targetNodeID": "154702",
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "154702",
|
||||
"targetNodeID": "102906",
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "177547",
|
||||
"targetNodeID": "109408",
|
||||
},
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"data": undefined,
|
||||
"id": "100001",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 180,
|
||||
"y": 26.700000000000017,
|
||||
},
|
||||
},
|
||||
"type": "1",
|
||||
},
|
||||
{
|
||||
"data": undefined,
|
||||
"id": "900001",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 1743.609729023942,
|
||||
"y": 176.16991217034956,
|
||||
},
|
||||
},
|
||||
"type": "2",
|
||||
},
|
||||
{
|
||||
"data": undefined,
|
||||
"id": "154702",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 987.7405729256998,
|
||||
"y": 245.06502111375198,
|
||||
},
|
||||
},
|
||||
"type": "3",
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"inputs": {
|
||||
"spaceId": "test_space_id",
|
||||
"workflowId": "test_workflow_id",
|
||||
},
|
||||
},
|
||||
"id": "102906",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 848.7417419605051,
|
||||
"y": -297.0809682834506,
|
||||
},
|
||||
},
|
||||
"type": "9",
|
||||
},
|
||||
{
|
||||
"data": undefined,
|
||||
"id": "177547",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": -125.93331336641754,
|
||||
"y": 357.10168132837816,
|
||||
},
|
||||
},
|
||||
"type": "3",
|
||||
},
|
||||
{
|
||||
"data": undefined,
|
||||
"id": "109408",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 1141.6692827086551,
|
||||
"y": 537.1820787709282,
|
||||
},
|
||||
},
|
||||
"type": "3",
|
||||
},
|
||||
{
|
||||
"data": undefined,
|
||||
"id": "156471",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 984.2265002815602,
|
||||
"y": 712.1169030826604,
|
||||
},
|
||||
},
|
||||
"type": "3",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import {
|
||||
WorkflowDocument,
|
||||
type WorkflowNodeEntity,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { complexMock } from '../workflow.mock';
|
||||
import { createContainer } from '../create-container';
|
||||
import {
|
||||
EncapsulateLinesService,
|
||||
EncapsulateNodesService,
|
||||
} from '../../src/encapsulate';
|
||||
|
||||
describe('encapsulate-lines-service', () => {
|
||||
let workflowDocument: WorkflowDocument;
|
||||
let encapsulateNodesService: EncapsulateNodesService;
|
||||
let encapsulateLinesService: EncapsulateLinesService;
|
||||
|
||||
beforeEach(() => {
|
||||
const container = createContainer();
|
||||
workflowDocument = container.get<WorkflowDocument>(WorkflowDocument);
|
||||
encapsulateLinesService = container.get<EncapsulateLinesService>(
|
||||
EncapsulateLinesService,
|
||||
);
|
||||
encapsulateNodesService = container.get<EncapsulateNodesService>(
|
||||
EncapsulateNodesService,
|
||||
);
|
||||
});
|
||||
|
||||
it('should create empty decapsulate lines', async () => {
|
||||
await workflowDocument.fromJSON(complexMock);
|
||||
const { inputLines, outputLines } =
|
||||
encapsulateLinesService.createDecapsulateLines({
|
||||
node: workflowDocument.getNode('102906') as WorkflowNodeEntity,
|
||||
workflowJSON: {
|
||||
edges: [],
|
||||
nodes: [],
|
||||
},
|
||||
startNodeId: '',
|
||||
endNodeId: '',
|
||||
idsMap: new Map(),
|
||||
});
|
||||
expect(inputLines).toEqual([]);
|
||||
expect(outputLines).toEqual([]);
|
||||
});
|
||||
|
||||
// 解封节点有多个输入,且解封流程start节点有多个输出,不能创建输入连线
|
||||
it('should not create decapsulate input lines', async () => {
|
||||
const json = {
|
||||
...cloneDeep(complexMock),
|
||||
edges: [
|
||||
...complexMock.edges,
|
||||
{
|
||||
sourceNodeID: '100001',
|
||||
targetNodeID: '177547',
|
||||
},
|
||||
],
|
||||
};
|
||||
await workflowDocument.fromJSON(json);
|
||||
|
||||
const sourceNode = workflowDocument.getNode('154702') as WorkflowNodeEntity;
|
||||
|
||||
const { idsMap, startNode, endNode } =
|
||||
await encapsulateNodesService.createDecapsulateNodes(
|
||||
sourceNode,
|
||||
json.nodes,
|
||||
);
|
||||
|
||||
const { inputLines } = encapsulateLinesService.createDecapsulateLines({
|
||||
node: sourceNode,
|
||||
workflowJSON: {
|
||||
nodes: [],
|
||||
edges: json.edges,
|
||||
},
|
||||
startNodeId: startNode.id,
|
||||
endNodeId: endNode.id,
|
||||
idsMap,
|
||||
});
|
||||
|
||||
expect(inputLines).toEqual([]);
|
||||
});
|
||||
|
||||
// 解封节点有多个输出,且解封流程end节点有多个输入,不能创建输出连线
|
||||
it('should not create decapsulate output lines', async () => {
|
||||
const json = {
|
||||
...cloneDeep(complexMock),
|
||||
edges: [
|
||||
...complexMock.edges,
|
||||
{
|
||||
sourceNodeID: '109408',
|
||||
targetNodeID: '900001',
|
||||
},
|
||||
],
|
||||
};
|
||||
await workflowDocument.fromJSON(json);
|
||||
|
||||
const sourceNode = workflowDocument.getNode('177547') as WorkflowNodeEntity;
|
||||
|
||||
const { idsMap, startNode, endNode } =
|
||||
await encapsulateNodesService.createDecapsulateNodes(
|
||||
sourceNode,
|
||||
json.nodes,
|
||||
);
|
||||
|
||||
const { outputLines } = encapsulateLinesService.createDecapsulateLines({
|
||||
node: sourceNode,
|
||||
workflowJSON: {
|
||||
nodes: [],
|
||||
edges: json.edges,
|
||||
},
|
||||
startNodeId: startNode.id,
|
||||
endNodeId: endNode.id,
|
||||
idsMap,
|
||||
});
|
||||
|
||||
expect(outputLines).toEqual([]);
|
||||
});
|
||||
|
||||
it('should create decapsulate lines', async () => {
|
||||
await workflowDocument.fromJSON(cloneDeep(complexMock));
|
||||
|
||||
const sourceNode = workflowDocument.getNode('102906') as WorkflowNodeEntity;
|
||||
const { idsMap, startNode, endNode } =
|
||||
await encapsulateNodesService.createDecapsulateNodes(
|
||||
sourceNode,
|
||||
complexMock.nodes,
|
||||
);
|
||||
const { inputLines, outputLines, internalLines } =
|
||||
encapsulateLinesService.createDecapsulateLines({
|
||||
node: sourceNode,
|
||||
workflowJSON: {
|
||||
nodes: [],
|
||||
edges: complexMock.edges,
|
||||
},
|
||||
startNodeId: startNode.id,
|
||||
endNodeId: endNode.id,
|
||||
idsMap,
|
||||
});
|
||||
|
||||
expect(internalLines.length).toEqual(3);
|
||||
expect(inputLines.length).toEqual(1);
|
||||
expect(outputLines.length).toEqual(1);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { describe, beforeEach, it, expect } from 'vitest';
|
||||
import { FlowNodeTransformData } from '@flowgram-adapter/free-layout-editor';
|
||||
import {
|
||||
WorkflowDocument,
|
||||
type WorkflowNodeEntity,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { complexMock } from '../workflow.mock';
|
||||
import { createContainer } from '../create-container';
|
||||
import { EncapsulateNodesService } from '../../src/encapsulate';
|
||||
|
||||
describe('encapsulate-nodes-service', () => {
|
||||
let workflowDocument: WorkflowDocument;
|
||||
let encapsulateNodesService: EncapsulateNodesService;
|
||||
|
||||
beforeEach(() => {
|
||||
const container = createContainer();
|
||||
workflowDocument = container.get<WorkflowDocument>(WorkflowDocument);
|
||||
encapsulateNodesService = container.get<EncapsulateNodesService>(
|
||||
EncapsulateNodesService,
|
||||
);
|
||||
});
|
||||
|
||||
it('should getNodesMiddlePoint', async () => {
|
||||
await workflowDocument.fromJSON(complexMock);
|
||||
|
||||
const nodes = ['109408', '156471'].map(id =>
|
||||
workflowDocument.getNode(id),
|
||||
) as WorkflowNodeEntity[];
|
||||
const point = encapsulateNodesService.getNodesMiddlePoint(nodes);
|
||||
|
||||
expect(point).toEqual({
|
||||
x: 993.4484760125105,
|
||||
y: 489.11299357749374,
|
||||
});
|
||||
});
|
||||
|
||||
it('should getNodesMiddlePoint by json', () => {
|
||||
const point = encapsulateNodesService.getNodesMiddlePoint(
|
||||
complexMock.nodes,
|
||||
);
|
||||
|
||||
expect(point).toEqual({
|
||||
x: 808.8382078287623,
|
||||
y: 207.51796739960494,
|
||||
});
|
||||
});
|
||||
|
||||
it('should createDecapsulateNode', async () => {
|
||||
await workflowDocument.fromJSON(complexMock);
|
||||
const json = {
|
||||
id: '1',
|
||||
type: 'test',
|
||||
meta: {
|
||||
position: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
},
|
||||
blocks: [
|
||||
{
|
||||
id: '2',
|
||||
type: 'test',
|
||||
meta: {
|
||||
position: {
|
||||
x: 5,
|
||||
y: 6,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const idsMap = new Map<string, string>();
|
||||
const node = await encapsulateNodesService.createDecapsulateNode(
|
||||
json,
|
||||
{
|
||||
x: 170,
|
||||
y: 16.700000000000017,
|
||||
},
|
||||
idsMap,
|
||||
);
|
||||
expect(node.id).not.toBe('1');
|
||||
expect(node.flowNodeType).toBe(json.type);
|
||||
const transformData = node.getData(FlowNodeTransformData);
|
||||
expect(transformData.position).toEqual({ x: 170, y: 16.700000000000017 });
|
||||
|
||||
const child = node.collapsedChildren[0];
|
||||
expect(child.id).not.toBe('2');
|
||||
expect(child.flowNodeType).toBe(json.blocks[0].type);
|
||||
const childTransformData = child.getData(FlowNodeTransformData);
|
||||
expect(childTransformData.position).toEqual({
|
||||
x: 175,
|
||||
y: 22.700000000000017,
|
||||
});
|
||||
|
||||
expect(idsMap.get('1')).toBe(node.id);
|
||||
expect(idsMap.get('2')).toBe(child.id);
|
||||
});
|
||||
|
||||
it('should decapsulateLayout', async () => {
|
||||
await workflowDocument.fromJSON(complexMock);
|
||||
await encapsulateNodesService.decapsulateLayout(
|
||||
workflowDocument.getNode('100001') as WorkflowNodeEntity,
|
||||
[complexMock.nodes[1], complexMock.nodes[2], complexMock.nodes[3]],
|
||||
);
|
||||
const json = await workflowDocument.toJSON();
|
||||
expect(json).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { describe, beforeEach } from 'vitest';
|
||||
import {
|
||||
WorkflowDocument,
|
||||
WorkflowSelectService,
|
||||
type WorkflowNodeEntity,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { complexMock } from '../workflow.mock';
|
||||
import { createContainer } from '../create-container';
|
||||
import {
|
||||
EncapsulateService,
|
||||
type EncapsulateSuccessResult,
|
||||
} from '../../src/encapsulate';
|
||||
|
||||
describe('encapsulate-service', () => {
|
||||
let workflowDocument: WorkflowDocument;
|
||||
let encapsulateService: EncapsulateService;
|
||||
let workflowSelectService: WorkflowSelectService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const container = createContainer();
|
||||
workflowDocument = container.get<WorkflowDocument>(WorkflowDocument);
|
||||
workflowSelectService = container.get<WorkflowSelectService>(
|
||||
WorkflowSelectService,
|
||||
);
|
||||
encapsulateService = container.get<EncapsulateService>(EncapsulateService);
|
||||
|
||||
await workflowDocument.fromJSON(complexMock);
|
||||
});
|
||||
|
||||
it('should can encapsulate', () => {
|
||||
expect(encapsulateService.canEncapsulate()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should can decapsulate', () => {
|
||||
const node = workflowDocument.getNode('102906') as WorkflowNodeEntity;
|
||||
expect(encapsulateService.canDecapsulate(node)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should encapsulate nodes', async () => {
|
||||
['102906', '154702'].forEach(id =>
|
||||
workflowSelectService.toggleSelect(
|
||||
workflowDocument.getNode(id) as WorkflowNodeEntity,
|
||||
),
|
||||
);
|
||||
|
||||
const res =
|
||||
(await encapsulateService.encapsulate()) as EncapsulateSuccessResult;
|
||||
|
||||
if (!res.success) {
|
||||
console.log(res);
|
||||
}
|
||||
|
||||
expect(res.success).toBeTruthy();
|
||||
expect(res.subFlowNode).toBeDefined();
|
||||
expect(res.inputLines.length).toEqual(2);
|
||||
res.inputLines.forEach(line => {
|
||||
expect(line.to).toBe(res.subFlowNode);
|
||||
});
|
||||
expect(res.outputLines.length).toEqual(1);
|
||||
res.outputLines.forEach(line => {
|
||||
expect(line.from).toBe(res.subFlowNode);
|
||||
});
|
||||
|
||||
expect(workflowSelectService.selectedNodes.length).toEqual(1);
|
||||
expect(workflowSelectService.selectedNodes[0]).toBe(res.subFlowNode);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,98 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`encapsulate-generate-service > should generate sub workflow node 1`] = `
|
||||
{
|
||||
"data": {
|
||||
"inputs": {
|
||||
"spaceId": "1",
|
||||
"workflowId": "1",
|
||||
"workflowVersion": "v0.0.1",
|
||||
},
|
||||
"nodeMeta": {
|
||||
"description": "test",
|
||||
"icon": undefined,
|
||||
"isImageflow": false,
|
||||
"title": "test",
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`encapsulate-generate-service > should generate workflow json 1`] = `
|
||||
{
|
||||
"edges": [
|
||||
{
|
||||
"sourceNodeID": "154702",
|
||||
"targetNodeID": "102906",
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "100001",
|
||||
"targetNodeID": "154702",
|
||||
},
|
||||
{
|
||||
"sourceNodeID": "102906",
|
||||
"targetNodeID": "900001",
|
||||
},
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"data": {
|
||||
"nodeMeta": {},
|
||||
"outputs": [],
|
||||
},
|
||||
"id": "100001",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
},
|
||||
},
|
||||
"type": "1",
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"inputs": {
|
||||
"inputParameters": [],
|
||||
"terminatePlan": "returnVariables",
|
||||
},
|
||||
"nodeMeta": {},
|
||||
},
|
||||
"id": "900001",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 1000,
|
||||
"y": 0,
|
||||
},
|
||||
},
|
||||
"type": "2",
|
||||
},
|
||||
{
|
||||
"data": {},
|
||||
"id": "154702",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 918.2411574431025,
|
||||
"y": 109.52852376445134,
|
||||
},
|
||||
},
|
||||
"type": "3",
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"inputs": {
|
||||
"spaceId": "test_space_id",
|
||||
"workflowId": "test_workflow_id",
|
||||
},
|
||||
},
|
||||
"id": "102906",
|
||||
"meta": {
|
||||
"position": {
|
||||
"x": 779.2423264779079,
|
||||
"y": -161.54447093414998,
|
||||
},
|
||||
},
|
||||
"type": "9",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { describe, beforeEach, it, expect } from 'vitest';
|
||||
import {
|
||||
WorkflowDocument,
|
||||
type WorkflowNodeEntity,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { complexMock } from '../workflow.mock';
|
||||
import { createContainer } from '../create-container';
|
||||
import {
|
||||
EncapsulateGenerateService,
|
||||
type GenerateSubWorkflowNodeOptions,
|
||||
} from '../../src/generate';
|
||||
|
||||
describe('encapsulate-generate-service', () => {
|
||||
let encapsulateGenerateService: EncapsulateGenerateService;
|
||||
let workflowDocument: WorkflowDocument;
|
||||
beforeEach(async () => {
|
||||
const container = createContainer();
|
||||
workflowDocument = container.get<WorkflowDocument>(WorkflowDocument);
|
||||
encapsulateGenerateService = container.get<EncapsulateGenerateService>(
|
||||
EncapsulateGenerateService,
|
||||
);
|
||||
|
||||
await workflowDocument.fromJSON(complexMock);
|
||||
});
|
||||
|
||||
it('should generate workflow json', async () => {
|
||||
const nodes = ['102906', '154702'].map(id =>
|
||||
workflowDocument.getNode(id),
|
||||
) as WorkflowNodeEntity[];
|
||||
const res = await encapsulateGenerateService.generateWorkflowJSON(nodes);
|
||||
expect(res).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should generate sub workflow node', async () => {
|
||||
const options: GenerateSubWorkflowNodeOptions = {
|
||||
workflowId: '1',
|
||||
name: 'test',
|
||||
desc: 'test',
|
||||
spaceId: '1',
|
||||
};
|
||||
const res =
|
||||
await encapsulateGenerateService.generateSubWorkflowNode(options);
|
||||
expect(res).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import 'reflect-metadata';
|
||||
vi.mock('@coze-arch/i18n', () => ({
|
||||
I18n: {
|
||||
t: vi.fn(),
|
||||
},
|
||||
}));
|
||||
vi.mock('@coze-arch/bot-flags', () => ({
|
||||
getFlags: () => ({
|
||||
'bot.automation.encapsulate': true,
|
||||
}),
|
||||
}));
|
||||
vi.mock('@coze-arch/coze-design', () => ({
|
||||
Typography: {
|
||||
Text: vi.fn(),
|
||||
},
|
||||
withField: vi.fn(),
|
||||
}));
|
||||
vi.mock('@coze-workflow/components', () => ({}));
|
||||
|
||||
vi.stubGlobal('IS_DEV_MODE', true);
|
||||
vi.stubGlobal('IS_OVERSEA', false);
|
||||
vi.stubGlobal('IS_BOE', false);
|
||||
vi.stubGlobal('REGION', 'cn');
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { beforeEach, describe, expect, it } from 'vitest';
|
||||
import {
|
||||
WorkflowDocument,
|
||||
type WorkflowNodeEntity,
|
||||
type WorkflowNodeJSON,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { complexMock } from '../workflow.mock';
|
||||
import { createContainer } from '../create-container';
|
||||
import { getNodePoint } from '../../src/utils';
|
||||
|
||||
describe('get-node-point', () => {
|
||||
let workflowDocument: WorkflowDocument;
|
||||
beforeEach(() => {
|
||||
const container = createContainer();
|
||||
workflowDocument = container.get<WorkflowDocument>(WorkflowDocument);
|
||||
});
|
||||
|
||||
it('should get empty node point', () => {
|
||||
const node: WorkflowNodeJSON = {
|
||||
type: 'test',
|
||||
id: '1',
|
||||
};
|
||||
const point = getNodePoint(node);
|
||||
|
||||
expect(point).toEqual({ x: 0, y: 0 });
|
||||
});
|
||||
|
||||
it('should get node point by entity', async () => {
|
||||
await workflowDocument.fromJSON(complexMock);
|
||||
const node = workflowDocument.getNode('900001') as WorkflowNodeEntity;
|
||||
const point = getNodePoint(node);
|
||||
expect(point).toEqual({ x: 1674.1103135413448, y: 40.63341482104891 });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { describe, it, beforeEach, expect } from 'vitest';
|
||||
import {
|
||||
WorkflowDocument,
|
||||
type WorkflowNodeEntity,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { complexMock } from '../workflow.mock';
|
||||
import { createContainer } from '../create-container';
|
||||
import { getSubWorkflowInfo } from '../../src/utils';
|
||||
|
||||
describe('get-sub-workflow-info', () => {
|
||||
let workflowDocument: WorkflowDocument;
|
||||
beforeEach(() => {
|
||||
const container = createContainer();
|
||||
workflowDocument = container.get<WorkflowDocument>(WorkflowDocument);
|
||||
});
|
||||
|
||||
it('should get sub workflow info', async () => {
|
||||
await workflowDocument.fromJSON(complexMock);
|
||||
expect(
|
||||
getSubWorkflowInfo(
|
||||
workflowDocument.getNode('102906') as WorkflowNodeEntity,
|
||||
),
|
||||
).toEqual({
|
||||
spaceId: 'test_space_id',
|
||||
workflowId: 'test_workflow_id',
|
||||
});
|
||||
|
||||
expect(
|
||||
getSubWorkflowInfo(
|
||||
workflowDocument.getNode('154702') as WorkflowNodeEntity,
|
||||
),
|
||||
).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { type WorkflowNodeJSON } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { setNodePosition } from '../../src/utils';
|
||||
|
||||
describe('set-node-position', () => {
|
||||
it('should set node position', () => {
|
||||
const node: WorkflowNodeJSON = {
|
||||
type: 'test',
|
||||
id: '1',
|
||||
};
|
||||
setNodePosition(node, {
|
||||
x: 10,
|
||||
y: 10,
|
||||
});
|
||||
|
||||
expect(node.meta?.position).toEqual({ x: 10, y: 10 });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`EncapsulateValidateResult > should add different source error 1`] = `
|
||||
[
|
||||
{
|
||||
"code": "1001",
|
||||
"message": "test",
|
||||
},
|
||||
{
|
||||
"code": "1001",
|
||||
"message": "test",
|
||||
"source": "1",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`EncapsulateValidateResult > should get errors 1`] = `
|
||||
[
|
||||
{
|
||||
"code": "1001",
|
||||
"message": "test",
|
||||
},
|
||||
]
|
||||
`;
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { describe, it, beforeEach, expect } from 'vitest';
|
||||
import { StandardNodeType } from '@coze-workflow/base/types';
|
||||
|
||||
import { createContainer } from '../create-container';
|
||||
import { EncapsulateValidateManager } from '../../src/validate';
|
||||
|
||||
describe('encapsulate-validate-manager', () => {
|
||||
let encapsulateValidateManager: EncapsulateValidateManager;
|
||||
beforeEach(() => {
|
||||
const container = createContainer();
|
||||
encapsulateValidateManager = container.get<EncapsulateValidateManager>(
|
||||
EncapsulateValidateManager,
|
||||
);
|
||||
});
|
||||
|
||||
it('should register validator', () => {
|
||||
const validators = encapsulateValidateManager.getNodeValidators();
|
||||
expect(validators.length > 0).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should register nodes validators', () => {
|
||||
const validators = encapsulateValidateManager.getNodesValidators();
|
||||
expect(validators.length > 0).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should get validators by type', () => {
|
||||
const validators = encapsulateValidateManager.getNodeValidatorsByType(
|
||||
StandardNodeType.Start,
|
||||
);
|
||||
expect(validators.length > 0).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should register workflow json validators', () => {
|
||||
const validators = encapsulateValidateManager.getWorkflowJSONValidators();
|
||||
expect(validators.length > 0).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
import { createContainer } from '../create-container';
|
||||
import {
|
||||
EncapsulateValidateResultFactory,
|
||||
type EncapsulateValidateResult,
|
||||
EncapsulateValidateErrorCode,
|
||||
} from '../../src/validate';
|
||||
|
||||
describe('EncapsulateValidateResult', () => {
|
||||
let encapsulateValidateResult: EncapsulateValidateResult;
|
||||
let encapsulateValidateResultFactory: EncapsulateValidateResultFactory;
|
||||
beforeEach(() => {
|
||||
const container = createContainer();
|
||||
encapsulateValidateResultFactory =
|
||||
container.get<EncapsulateValidateResultFactory>(
|
||||
EncapsulateValidateResultFactory,
|
||||
);
|
||||
encapsulateValidateResult = encapsulateValidateResultFactory();
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(encapsulateValidateResult).toBeDefined();
|
||||
});
|
||||
|
||||
it('should be different instance', () => {
|
||||
expect(encapsulateValidateResultFactory()).not.toBe(
|
||||
encapsulateValidateResult,
|
||||
);
|
||||
});
|
||||
|
||||
it('should add error', () => {
|
||||
encapsulateValidateResult.addError({
|
||||
code: EncapsulateValidateErrorCode.NO_START_END,
|
||||
message: 'test',
|
||||
});
|
||||
expect(encapsulateValidateResult.hasError()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should add different source error', () => {
|
||||
encapsulateValidateResult.addError({
|
||||
code: EncapsulateValidateErrorCode.NO_START_END,
|
||||
message: 'test',
|
||||
});
|
||||
|
||||
encapsulateValidateResult.addError({
|
||||
code: EncapsulateValidateErrorCode.NO_START_END,
|
||||
message: 'test',
|
||||
source: '1',
|
||||
});
|
||||
expect(encapsulateValidateResult.getErrors()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should get errors', () => {
|
||||
encapsulateValidateResult.addError({
|
||||
code: EncapsulateValidateErrorCode.NO_START_END,
|
||||
message: 'test',
|
||||
});
|
||||
expect(encapsulateValidateResult.getErrors()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should has error code', () => {
|
||||
encapsulateValidateResult.addError({
|
||||
code: EncapsulateValidateErrorCode.NO_START_END,
|
||||
message: 'test',
|
||||
});
|
||||
expect(
|
||||
encapsulateValidateResult.hasErrorCode(
|
||||
EncapsulateValidateErrorCode.NO_START_END,
|
||||
),
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { injectable } from 'inversify';
|
||||
|
||||
@injectable()
|
||||
export class MockValidationService {
|
||||
validateNode(node) {
|
||||
return { hasError: false } as any;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import {
|
||||
WorkflowDocument,
|
||||
type WorkflowNodeEntity,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { complexMock } from '../workflow.mock';
|
||||
import { createContainer } from '../create-container';
|
||||
import {
|
||||
EncapsulateValidateErrorCode,
|
||||
EncapsulateValidateService,
|
||||
} from '../../src/validate';
|
||||
|
||||
describe('input-lines', () => {
|
||||
let encapsulateValidateService: EncapsulateValidateService;
|
||||
let workflowDocument: WorkflowDocument;
|
||||
beforeEach(async () => {
|
||||
const container = createContainer();
|
||||
encapsulateValidateService = container.get<EncapsulateValidateService>(
|
||||
EncapsulateValidateService,
|
||||
);
|
||||
workflowDocument = container.get<WorkflowDocument>(WorkflowDocument);
|
||||
await workflowDocument.fromJSON(complexMock);
|
||||
});
|
||||
|
||||
it('should validate without error', async () => {
|
||||
const nodes = ['102906', '154702'].map(id =>
|
||||
workflowDocument.getNode(id),
|
||||
) as WorkflowNodeEntity[];
|
||||
const res = await encapsulateValidateService.validate(nodes);
|
||||
expect(res.hasError()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should validate two input ports return error', async () => {
|
||||
const nodes = ['109408', '154702'].map(id =>
|
||||
workflowDocument.getNode(id),
|
||||
) as WorkflowNodeEntity[];
|
||||
const res = await encapsulateValidateService.validate(nodes);
|
||||
expect(
|
||||
res.hasErrorCode(EncapsulateValidateErrorCode.ENCAPSULATE_LINES),
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { StandardNodeType } from '@coze-workflow/base';
|
||||
import { WorkflowDocument } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { baseMock } from '../workflow.mock';
|
||||
import { createContainer } from '../create-container';
|
||||
import {
|
||||
EncapsulateValidateErrorCode,
|
||||
EncapsulateValidateService,
|
||||
} from '../../src/validate';
|
||||
|
||||
describe('loop-nodes', () => {
|
||||
let encapsulateValidateService: EncapsulateValidateService;
|
||||
let workflowDocument: WorkflowDocument;
|
||||
beforeEach(() => {
|
||||
const container = createContainer();
|
||||
encapsulateValidateService = container.get<EncapsulateValidateService>(
|
||||
EncapsulateValidateService,
|
||||
);
|
||||
workflowDocument = container.get<WorkflowDocument>(WorkflowDocument);
|
||||
workflowDocument.fromJSON(baseMock);
|
||||
});
|
||||
|
||||
it('should validate loop nodes error', async () => {
|
||||
const breakNode = await workflowDocument.createWorkflowNodeByType(
|
||||
StandardNodeType.Break,
|
||||
);
|
||||
const res = await encapsulateValidateService.validate([breakNode]);
|
||||
|
||||
expect(
|
||||
res.hasErrorCode(EncapsulateValidateErrorCode.INVALID_LOOP_NODES),
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import {
|
||||
WorkflowDocument,
|
||||
type WorkflowNodeEntity,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { complexMock } from '../workflow.mock';
|
||||
import { createContainer } from '../create-container';
|
||||
import {
|
||||
EncapsulateValidateErrorCode,
|
||||
EncapsulateValidateService,
|
||||
} from '../../src/validate';
|
||||
|
||||
describe('output-lines', () => {
|
||||
let encapsulateValidateService: EncapsulateValidateService;
|
||||
let workflowDocument: WorkflowDocument;
|
||||
beforeEach(async () => {
|
||||
const container = createContainer();
|
||||
encapsulateValidateService = container.get<EncapsulateValidateService>(
|
||||
EncapsulateValidateService,
|
||||
);
|
||||
workflowDocument = container.get<WorkflowDocument>(WorkflowDocument);
|
||||
await workflowDocument.fromJSON(complexMock);
|
||||
});
|
||||
|
||||
it('should validate two output ports return error', async () => {
|
||||
await workflowDocument.createWorkflowNode({
|
||||
id: 'output1',
|
||||
type: 'test',
|
||||
});
|
||||
await workflowDocument.createWorkflowNode({
|
||||
id: 'output2',
|
||||
type: 'test',
|
||||
});
|
||||
workflowDocument.linesManager.createLine({
|
||||
from: '154702',
|
||||
to: 'output1',
|
||||
});
|
||||
workflowDocument.linesManager.createLine({
|
||||
from: 'output1',
|
||||
to: 'output2',
|
||||
});
|
||||
const nodes = ['154702', '102906'].map(id =>
|
||||
workflowDocument.getNode(id),
|
||||
) as WorkflowNodeEntity[];
|
||||
const res = await encapsulateValidateService.validate(nodes);
|
||||
expect(
|
||||
res.hasErrorCode(EncapsulateValidateErrorCode.ENCAPSULATE_LINES),
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import {
|
||||
WorkflowDocument,
|
||||
type WorkflowNodeEntity,
|
||||
} from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { complexMock } from '../workflow.mock';
|
||||
import { createContainer } from '../create-container';
|
||||
import {
|
||||
EncapsulateValidateErrorCode,
|
||||
EncapsulateValidateService,
|
||||
} from '../../src/validate';
|
||||
|
||||
describe('ports', () => {
|
||||
let encapsulateValidateService: EncapsulateValidateService;
|
||||
let workflowDocument: WorkflowDocument;
|
||||
beforeEach(async () => {
|
||||
const container = createContainer();
|
||||
encapsulateValidateService = container.get<EncapsulateValidateService>(
|
||||
EncapsulateValidateService,
|
||||
);
|
||||
workflowDocument = container.get<WorkflowDocument>(WorkflowDocument);
|
||||
await workflowDocument.fromJSON(complexMock);
|
||||
});
|
||||
|
||||
it('should validate no input ports return error', async () => {
|
||||
const nodes = ['100001', '177547'].map(id =>
|
||||
workflowDocument.getNode(id),
|
||||
) as WorkflowNodeEntity[];
|
||||
const res = await encapsulateValidateService.validate(nodes);
|
||||
expect(
|
||||
res.hasErrorCode(EncapsulateValidateErrorCode.INVALID_PORTS),
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should validate no output ports return error', async () => {
|
||||
const nodes = ['109408', '156471'].map(id =>
|
||||
workflowDocument.getNode(id),
|
||||
) as WorkflowNodeEntity[];
|
||||
const res = await encapsulateValidateService.validate(nodes);
|
||||
expect(
|
||||
res.hasErrorCode(EncapsulateValidateErrorCode.INVALID_PORTS),
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { WorkflowDocument } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
import { baseMock } from '../workflow.mock';
|
||||
import { createContainer } from '../create-container';
|
||||
import {
|
||||
EncapsulateValidateErrorCode,
|
||||
EncapsulateValidateService,
|
||||
} from '../../src/validate';
|
||||
|
||||
describe('start-end', () => {
|
||||
let encapsulateValidateService: EncapsulateValidateService;
|
||||
let workflowDocument: WorkflowDocument;
|
||||
beforeEach(async () => {
|
||||
const container = createContainer();
|
||||
encapsulateValidateService = container.get<EncapsulateValidateService>(
|
||||
EncapsulateValidateService,
|
||||
);
|
||||
workflowDocument = container.get<WorkflowDocument>(WorkflowDocument);
|
||||
await workflowDocument.fromJSON(baseMock);
|
||||
});
|
||||
|
||||
it('should validate return no-start-end error', async () => {
|
||||
const startNode = workflowDocument.getNode('1')!;
|
||||
const res = await encapsulateValidateService.validate([startNode]);
|
||||
|
||||
expect(
|
||||
res.hasErrorCode(EncapsulateValidateErrorCode.NO_START_END),
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { StandardNodeType } from '@coze-workflow/base/types';
|
||||
import { type WorkflowJSON } from '@flowgram-adapter/free-layout-editor';
|
||||
|
||||
export const baseMock = {
|
||||
nodes: [
|
||||
{
|
||||
id: '1',
|
||||
type: StandardNodeType.Start,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: StandardNodeType.End,
|
||||
},
|
||||
],
|
||||
edges: [],
|
||||
};
|
||||
|
||||
/**
|
||||
* start(100001) -> 154702 -> 102906 -> end(900001)
|
||||
* 177547 -> 154702
|
||||
* 177547 -> 109408
|
||||
*/
|
||||
export const complexMock: WorkflowJSON = {
|
||||
nodes: [
|
||||
{
|
||||
id: '100001',
|
||||
type: '1',
|
||||
meta: {
|
||||
position: {
|
||||
x: 180,
|
||||
y: 26.700000000000017,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '900001',
|
||||
type: '2',
|
||||
meta: {
|
||||
position: {
|
||||
x: 1674.1103135413448,
|
||||
y: 40.63341482104891,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '154702',
|
||||
type: '3',
|
||||
meta: {
|
||||
position: {
|
||||
x: 918.2411574431025,
|
||||
y: 109.52852376445134,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '102906',
|
||||
type: StandardNodeType.SubWorkflow,
|
||||
data: {
|
||||
inputs: {
|
||||
spaceId: 'test_space_id',
|
||||
workflowId: 'test_workflow_id',
|
||||
},
|
||||
},
|
||||
meta: {
|
||||
position: {
|
||||
x: 779.2423264779079,
|
||||
y: -161.54447093414998,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '177547',
|
||||
type: '3',
|
||||
meta: {
|
||||
position: {
|
||||
x: -56.433897883820265,
|
||||
y: 221.56518397907752,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '109408',
|
||||
type: '3',
|
||||
meta: {
|
||||
position: {
|
||||
x: 1072.169867226058,
|
||||
y: 401.6455814216276,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '156471',
|
||||
type: '3',
|
||||
meta: {
|
||||
position: {
|
||||
x: 914.727084798963,
|
||||
y: 576.5804057333598,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
edges: [
|
||||
{
|
||||
sourceNodeID: '102906',
|
||||
targetNodeID: '900001',
|
||||
},
|
||||
{
|
||||
sourceNodeID: '100001',
|
||||
targetNodeID: '154702',
|
||||
},
|
||||
{
|
||||
sourceNodeID: '177547',
|
||||
targetNodeID: '154702',
|
||||
},
|
||||
{
|
||||
sourceNodeID: '154702',
|
||||
targetNodeID: '102906',
|
||||
},
|
||||
{
|
||||
sourceNodeID: '177547',
|
||||
targetNodeID: '109408',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const loopJSON: WorkflowJSON = {
|
||||
nodes: [
|
||||
...complexMock.nodes,
|
||||
{
|
||||
id: 'loop_0',
|
||||
type: 'loop',
|
||||
meta: {
|
||||
position: { x: 1200, y: 0 },
|
||||
},
|
||||
blocks: [
|
||||
{
|
||||
id: 'break_0',
|
||||
type: 'break',
|
||||
meta: {
|
||||
position: { x: 0, y: 0 },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'variable_0',
|
||||
type: 'variable',
|
||||
meta: {
|
||||
position: { x: 400, y: 0 },
|
||||
},
|
||||
},
|
||||
],
|
||||
edges: [
|
||||
{
|
||||
sourceNodeID: 'break_0',
|
||||
targetNodeID: 'variable_0',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
edges: [...complexMock.edges],
|
||||
};
|
||||
Reference in New Issue
Block a user