feat(workflow): 移除工作流操作类型的触发事件 (#1561)
Reviewed-on: daoyoucloud/tachybase#1561 Reviewed-by: sealday <zhanglin@daoyoucloud.com> Co-authored-by: bai.zixv <bai.zixv@foxmail.com> Co-committed-by: bai.zixv <bai.zixv@foxmail.com>
This commit is contained in:
parent
569dbf2423
commit
04cd8135ca
@ -4,7 +4,6 @@ import { Registry } from '@tachybase/utils/client';
|
|||||||
|
|
||||||
import { WorkflowLink } from './components/WorkflowLink';
|
import { WorkflowLink } from './components/WorkflowLink';
|
||||||
import { ExecutionPage } from './ExecutionPage';
|
import { ExecutionPage } from './ExecutionPage';
|
||||||
import { PluginActionTrigger } from './features/action-trigger';
|
|
||||||
import { PluginAggregate } from './features/aggregate';
|
import { PluginAggregate } from './features/aggregate';
|
||||||
import PluginApproval from './features/approval';
|
import PluginApproval from './features/approval';
|
||||||
import PluginWorkflowDataMappingClient from './features/data-mapping';
|
import PluginWorkflowDataMappingClient from './features/data-mapping';
|
||||||
@ -86,7 +85,6 @@ export class PluginWorkflow extends Plugin {
|
|||||||
await this.pm.add(PluginDaynamicCalculation);
|
await this.pm.add(PluginDaynamicCalculation);
|
||||||
await this.pm.add(PluginDelay);
|
await this.pm.add(PluginDelay);
|
||||||
await this.pm.add(PluginAggregate);
|
await this.pm.add(PluginAggregate);
|
||||||
await this.pm.add(PluginActionTrigger);
|
|
||||||
await this.pm.add(PluginWorkflowJsonParseClient);
|
await this.pm.add(PluginWorkflowJsonParseClient);
|
||||||
await this.pm.add(PluginWorkflowJSParseClient);
|
await this.pm.add(PluginWorkflowJSParseClient);
|
||||||
await this.pm.add(PluginWorkflowDataMappingClient);
|
await this.pm.add(PluginWorkflowDataMappingClient);
|
||||||
|
@ -1,134 +0,0 @@
|
|||||||
import {
|
|
||||||
SchemaInitializerItemType,
|
|
||||||
useCollectionDataSource,
|
|
||||||
useCollectionManager_deprecated,
|
|
||||||
useCompile,
|
|
||||||
} from '@tachybase/client';
|
|
||||||
import { useForm } from '@tachybase/schema';
|
|
||||||
|
|
||||||
import { CollectionBlockInitializer } from '../../components';
|
|
||||||
import { useWorkflowAnyExecuted } from '../../hooks';
|
|
||||||
import { lang, NAMESPACE, tval } from '../../locale';
|
|
||||||
import { Trigger } from '../../triggers';
|
|
||||||
import { getCollectionFieldOptions } from '../../variable';
|
|
||||||
|
|
||||||
export class ActionTrigger extends Trigger {
|
|
||||||
title = tval('Action event(deprecated)');
|
|
||||||
description = `{{t("Triggers after specific operations on data are submitted, such as create, update, delete, etc., or directly submitting a record to the workflow.", { ns: "${NAMESPACE}" })}}`;
|
|
||||||
fieldset = {
|
|
||||||
collection: {
|
|
||||||
type: 'string',
|
|
||||||
required: true,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'DataSourceCollectionCascader',
|
|
||||||
'x-disabled': '{{ useWorkflowAnyExecuted() }}',
|
|
||||||
title: `{{t("Collection", { ns: "${NAMESPACE}" })}}`,
|
|
||||||
description: `{{t("Which collection record belongs to.", { ns: "${NAMESPACE}" })}}`,
|
|
||||||
'x-reactions': [
|
|
||||||
{
|
|
||||||
target: 'appends',
|
|
||||||
effects: ['onFieldValueChange'],
|
|
||||||
fulfill: {
|
|
||||||
state: {
|
|
||||||
value: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
appends: {
|
|
||||||
type: 'array',
|
|
||||||
title: `{{t("Associations to use", { ns: "${NAMESPACE}" })}}`,
|
|
||||||
description: `{{t("Please select the associated fields that need to be accessed in subsequent nodes. With more than two levels of to-many associations may cause performance issue, please use with caution.", { ns: "workflow" })}}`,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'AppendsTreeSelect',
|
|
||||||
'x-component-props': {
|
|
||||||
title: 'Preload associations',
|
|
||||||
multiple: true,
|
|
||||||
useCollection() {
|
|
||||||
const { values } = useForm();
|
|
||||||
return values?.collection;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'x-reactions': [
|
|
||||||
{
|
|
||||||
dependencies: ['collection'],
|
|
||||||
fulfill: {
|
|
||||||
state: {
|
|
||||||
visible: '{{!!$deps[0]}}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
scope = {
|
|
||||||
useCollectionDataSource,
|
|
||||||
useWorkflowAnyExecuted,
|
|
||||||
};
|
|
||||||
isActionTriggerable = (config, context) => {
|
|
||||||
return ['create', 'update', 'customize:update', 'customize:triggerWorkflows'].includes(context.action);
|
|
||||||
};
|
|
||||||
useVariables(config, options) {
|
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
||||||
const compile = useCompile();
|
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
||||||
const { getCollectionFields } = useCollectionManager_deprecated();
|
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
||||||
const langTriggerData = lang('Trigger data');
|
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
||||||
const langUserSubmittedForm = lang('User submitted action');
|
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
||||||
const langRoleSubmittedForm = lang('Role of user submitted action');
|
|
||||||
const rootFields = [
|
|
||||||
{
|
|
||||||
collectionName: config.collection,
|
|
||||||
name: 'data',
|
|
||||||
type: 'hasOne',
|
|
||||||
target: config.collection,
|
|
||||||
uiSchema: {
|
|
||||||
title: langTriggerData,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
collectionName: 'users',
|
|
||||||
name: 'user',
|
|
||||||
type: 'hasOne',
|
|
||||||
target: 'users',
|
|
||||||
uiSchema: {
|
|
||||||
title: langUserSubmittedForm,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'roleName',
|
|
||||||
uiSchema: {
|
|
||||||
title: langRoleSubmittedForm,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const result = getCollectionFieldOptions({
|
|
||||||
// depth,
|
|
||||||
appends: ['data', 'user', ...(config.appends?.map((item) => `data.${item}`) || [])],
|
|
||||||
...options,
|
|
||||||
fields: rootFields,
|
|
||||||
compile,
|
|
||||||
getCollectionFields,
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
useInitializers(config): SchemaInitializerItemType | null {
|
|
||||||
if (!config.collection) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: 'triggerData',
|
|
||||||
type: 'item',
|
|
||||||
key: 'triggerData',
|
|
||||||
title: `{{t("Trigger data", { ns: "${NAMESPACE}" })}}`,
|
|
||||||
Component: CollectionBlockInitializer,
|
|
||||||
collection: config.collection,
|
|
||||||
dataPath: '$context.data',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,676 +0,0 @@
|
|||||||
import {
|
|
||||||
apiCreateRecordTriggerFormEvent,
|
|
||||||
apiCreateWorkflow,
|
|
||||||
apiDeleteWorkflow,
|
|
||||||
apiGetDataSourceCount,
|
|
||||||
apiGetWorkflow,
|
|
||||||
apiUpdateWorkflowTrigger,
|
|
||||||
appendJsonCollectionName,
|
|
||||||
FormEventTriggerNode,
|
|
||||||
generalWithNoRelationalFields,
|
|
||||||
WorkflowListRecords,
|
|
||||||
} from '@tachybase/plugin-workflow-test/e2e';
|
|
||||||
import { expect, test } from '@tachybase/test/e2e';
|
|
||||||
import { dayjs } from '@tachybase/utils';
|
|
||||||
|
|
||||||
import { faker } from '@faker-js/faker';
|
|
||||||
|
|
||||||
test.describe('Configuration page to configure the Trigger node', () => {
|
|
||||||
test('Form Submit Button Binding Workflow Add Data Trigger', async ({
|
|
||||||
page,
|
|
||||||
mockPage,
|
|
||||||
mockCollections,
|
|
||||||
mockRecords,
|
|
||||||
}) => {
|
|
||||||
//数据表后缀标识
|
|
||||||
const triggerNodeAppendText = faker.string.alphanumeric(5);
|
|
||||||
|
|
||||||
//创建触发器节点数据表
|
|
||||||
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
|
|
||||||
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
|
|
||||||
const triggerNodeFieldName = 'orgname';
|
|
||||||
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
|
|
||||||
await mockCollections(
|
|
||||||
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
|
|
||||||
.collections,
|
|
||||||
);
|
|
||||||
//添加工作流
|
|
||||||
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
||||||
const workflowData = {
|
|
||||||
current: true,
|
|
||||||
options: { deleteExecutionOnStatus: [] },
|
|
||||||
title: workFlowName,
|
|
||||||
type: 'action',
|
|
||||||
enabled: true,
|
|
||||||
};
|
|
||||||
const workflow = await apiCreateWorkflow(workflowData);
|
|
||||||
const workflowObj = JSON.parse(JSON.stringify(workflow));
|
|
||||||
const workflowId = workflowObj.id;
|
|
||||||
|
|
||||||
//配置工作流触发器
|
|
||||||
await page.goto(`admin/workflow/workflows/${workflowId}`);
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
const formEventTriggerNode = new FormEventTriggerNode(page, workFlowName, triggerNodeCollectionName);
|
|
||||||
await formEventTriggerNode.nodeConfigure.click();
|
|
||||||
await formEventTriggerNode.collectionDropDown.click();
|
|
||||||
await page.getByRole('menuitemcheckbox', { name: 'Main right' }).click();
|
|
||||||
await page.getByRole('menuitemcheckbox', { name: triggerNodeCollectionDisplayName }).click();
|
|
||||||
await formEventTriggerNode.submitButton.click();
|
|
||||||
|
|
||||||
//配置录入数据区块
|
|
||||||
const newPage = mockPage();
|
|
||||||
await newPage.goto();
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
await page.getByLabel('schema-initializer-Grid-page:addBlock').hover();
|
|
||||||
await page.getByRole('menuitem', { name: 'table Table' }).hover();
|
|
||||||
const dataSourcesCount = await apiGetDataSourceCount();
|
|
||||||
if (dataSourcesCount > 1) {
|
|
||||||
await page.getByRole('menuitem', { name: 'Main right' }).hover();
|
|
||||||
}
|
|
||||||
await page.getByRole('menuitem', { name: `${triggerNodeCollectionDisplayName}` }).click();
|
|
||||||
|
|
||||||
// 移开鼠标,关闭菜单
|
|
||||||
await page.mouse.move(300, 0);
|
|
||||||
|
|
||||||
await page.getByText('Configure columns').hover();
|
|
||||||
await page.getByText(triggerNodeFieldDisplayName).click();
|
|
||||||
await page.getByText('Configure actions').hover();
|
|
||||||
await page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch').click();
|
|
||||||
await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).toBeEnabled();
|
|
||||||
await page.getByLabel(`action-Action-Add new-create-${triggerNodeCollectionName}-table`).click();
|
|
||||||
await page.getByLabel(`schema-initializer-Grid-popup:addNew:addBlock-${triggerNodeCollectionName}`).hover();
|
|
||||||
await page.getByRole('menuitem', { name: 'form Form' }).click();
|
|
||||||
// 移开鼠标,关闭菜单
|
|
||||||
await page.mouse.move(300, 0);
|
|
||||||
await page
|
|
||||||
.getByLabel(`schema-initializer-ActionBar-createForm:configureActions-${triggerNodeCollectionName}`)
|
|
||||||
.hover();
|
|
||||||
await page.getByRole('menuitem', { name: 'Submit' }).click();
|
|
||||||
// 绑定工作流
|
|
||||||
await page.getByLabel(`schema-initializer-Grid-form:configureFields-${triggerNodeCollectionName}`).hover();
|
|
||||||
await page.getByRole('menuitem', { name: `${triggerNodeFieldDisplayName}` }).click();
|
|
||||||
await page.mouse.move(300, 0);
|
|
||||||
await page.getByLabel(`action-Action-Submit-submit-${triggerNodeCollectionName}-form`).hover();
|
|
||||||
await page
|
|
||||||
.getByRole('button', {
|
|
||||||
name: `designer-schema-settings-Action-actionSettings:createSubmit-${triggerNodeCollectionName}`,
|
|
||||||
})
|
|
||||||
.hover();
|
|
||||||
await page.getByRole('menuitem', { name: 'Bind workflows' }).click();
|
|
||||||
await page.getByRole('button', { name: 'plus Add workflow' }).click();
|
|
||||||
await page.getByRole('button', { name: 'Select workflow' }).click();
|
|
||||||
await page.getByRole('option', { name: workFlowName }).click();
|
|
||||||
await page.getByRole('button', { name: 'Submit', exact: true }).click();
|
|
||||||
|
|
||||||
// 2、测试步骤:进入“数据区块”-“添加”按钮,填写表单,点击“确定”按钮
|
|
||||||
const fieldData = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
|
|
||||||
await page.getByRole('textbox').fill(fieldData);
|
|
||||||
await page.getByLabel(`action-Action-Submit-submit-${triggerNodeCollectionName}-form`, { exact: true }).click();
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
await page.waitForTimeout(1000);
|
|
||||||
// 3、预期结果:触发次数为1
|
|
||||||
const getWorkflow = await apiGetWorkflow(workflowId);
|
|
||||||
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
|
|
||||||
const getWorkflowExecuted = getWorkflowObj.executed;
|
|
||||||
expect(getWorkflowExecuted).toBe(1);
|
|
||||||
|
|
||||||
// 4、后置处理:删除工作流
|
|
||||||
await apiDeleteWorkflow(workflowId);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Form Submit to Workflow Button Add Data Trigger', async ({ page, mockPage, mockCollections, mockRecords }) => {
|
|
||||||
//数据表后缀标识
|
|
||||||
const triggerNodeAppendText = faker.string.alphanumeric(5);
|
|
||||||
|
|
||||||
//创建触发器节点数据表
|
|
||||||
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
|
|
||||||
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
|
|
||||||
const triggerNodeFieldName = 'orgname';
|
|
||||||
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
|
|
||||||
await mockCollections(
|
|
||||||
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
|
|
||||||
.collections,
|
|
||||||
);
|
|
||||||
//添加工作流
|
|
||||||
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
||||||
const workflowData = {
|
|
||||||
current: true,
|
|
||||||
options: { deleteExecutionOnStatus: [] },
|
|
||||||
title: workFlowName,
|
|
||||||
type: 'action',
|
|
||||||
enabled: true,
|
|
||||||
};
|
|
||||||
const workflow = await apiCreateWorkflow(workflowData);
|
|
||||||
const workflowObj = JSON.parse(JSON.stringify(workflow));
|
|
||||||
const workflowId = workflowObj.id;
|
|
||||||
|
|
||||||
//配置工作流触发器
|
|
||||||
await page.goto(`admin/workflow/workflows/${workflowId}`);
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
const formEventTriggerNode = new FormEventTriggerNode(page, workFlowName, triggerNodeCollectionName);
|
|
||||||
await formEventTriggerNode.nodeConfigure.click();
|
|
||||||
await formEventTriggerNode.collectionDropDown.click();
|
|
||||||
await page.getByRole('menuitemcheckbox', { name: 'Main right' }).click();
|
|
||||||
await page.getByRole('menuitemcheckbox', { name: triggerNodeCollectionDisplayName }).click();
|
|
||||||
await formEventTriggerNode.submitButton.click();
|
|
||||||
|
|
||||||
//配置录入数据区块
|
|
||||||
const newPage = mockPage();
|
|
||||||
await newPage.goto();
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
await page.getByLabel('schema-initializer-Grid-page:addBlock').hover();
|
|
||||||
await page.getByRole('menuitem', { name: 'table Table' }).hover();
|
|
||||||
const dataSourcesCount = await apiGetDataSourceCount();
|
|
||||||
if (dataSourcesCount > 1) {
|
|
||||||
await page.getByRole('menuitem', { name: 'Main right' }).hover();
|
|
||||||
}
|
|
||||||
await page.getByRole('menuitem', { name: `${triggerNodeCollectionDisplayName}` }).click();
|
|
||||||
|
|
||||||
// 移开鼠标,关闭菜单
|
|
||||||
await page.mouse.move(300, 0);
|
|
||||||
|
|
||||||
await page.getByText('Configure columns').hover();
|
|
||||||
await page.getByText(triggerNodeFieldDisplayName).click();
|
|
||||||
await page.getByText('Configure actions').hover();
|
|
||||||
await page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch').click();
|
|
||||||
await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).toBeEnabled();
|
|
||||||
|
|
||||||
await page.getByLabel(`action-Action-Add new-create-${triggerNodeCollectionName}-table`).click();
|
|
||||||
await page.getByLabel(`schema-initializer-Grid-popup:addNew:addBlock-${triggerNodeCollectionName}`).hover();
|
|
||||||
await page.getByRole('menuitem', { name: 'form Form' }).click();
|
|
||||||
|
|
||||||
// 移开鼠标,关闭菜单
|
|
||||||
await page.mouse.move(300, 0);
|
|
||||||
|
|
||||||
// 绑定工作流
|
|
||||||
await page
|
|
||||||
.getByLabel(`schema-initializer-ActionBar-createForm:configureActions-${triggerNodeCollectionName}`)
|
|
||||||
.hover();
|
|
||||||
await page.getByRole('menuitem', { name: 'Customize' }).hover();
|
|
||||||
await page.getByRole('menuitem', { name: 'Submit to workflow' }).click();
|
|
||||||
await page.getByLabel(`schema-initializer-Grid-form:configureFields-${triggerNodeCollectionName}`).hover();
|
|
||||||
await page.getByRole('menuitem', { name: `${triggerNodeFieldDisplayName}` }).click();
|
|
||||||
await page.mouse.move(300, 0);
|
|
||||||
await page.getByRole('button', { name: 'Submit to workflow' }).hover();
|
|
||||||
await page
|
|
||||||
.getByRole('button', {
|
|
||||||
name: `designer-schema-settings-Action-Action.Designer-${triggerNodeCollectionName}`,
|
|
||||||
})
|
|
||||||
.hover();
|
|
||||||
await page.getByRole('menuitem', { name: 'Bind workflows' }).click();
|
|
||||||
await page.getByRole('button', { name: 'plus Add workflow' }).click();
|
|
||||||
await page.getByRole('button', { name: 'Select workflow' }).click();
|
|
||||||
await page.getByRole('option', { name: workFlowName }).click();
|
|
||||||
await page.getByRole('button', { name: 'Submit', exact: true }).click();
|
|
||||||
|
|
||||||
// 2、测试步骤:进入“数据区块”-“添加”按钮,填写表单,点击“确定”按钮
|
|
||||||
const fieldData = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
|
|
||||||
await page.getByRole('textbox').fill(fieldData);
|
|
||||||
await page
|
|
||||||
.getByLabel(`action-Action-Submit to workflow-customize:triggerWorkflows-${triggerNodeCollectionName}-form`)
|
|
||||||
.click();
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
await page.waitForTimeout(1000);
|
|
||||||
// 3、预期结果:触发次数为1
|
|
||||||
const getWorkflow = await apiGetWorkflow(workflowId);
|
|
||||||
const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
|
|
||||||
const getWorkflowExecuted = getWorkflowObj.executed;
|
|
||||||
expect(getWorkflowExecuted).toBe(1);
|
|
||||||
|
|
||||||
// 4、后置处理:删除工作流
|
|
||||||
await apiDeleteWorkflow(workflowId);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe('Configuration Page Path Jump Workflow Management Page', () => {
|
|
||||||
test('Action event Workflow Configuration Page Path Jump Workflow Management Page', async ({
|
|
||||||
page,
|
|
||||||
mockPage,
|
|
||||||
mockCollections,
|
|
||||||
mockRecords,
|
|
||||||
}) => {
|
|
||||||
//数据表后缀标识
|
|
||||||
const triggerNodeAppendText = faker.string.alphanumeric(5);
|
|
||||||
|
|
||||||
//创建触发器节点数据表
|
|
||||||
// const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
|
|
||||||
// const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
|
|
||||||
// const triggerNodeFieldName = 'orgname';
|
|
||||||
// const triggerNodeFieldDisplayName = '公司名称(单行文本)';
|
|
||||||
// await mockCollections(appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText).collections);
|
|
||||||
//添加工作流
|
|
||||||
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
||||||
const workflowData = {
|
|
||||||
current: true,
|
|
||||||
options: { deleteExecutionOnStatus: [] },
|
|
||||||
title: workFlowName,
|
|
||||||
type: 'action',
|
|
||||||
enabled: true,
|
|
||||||
};
|
|
||||||
const workflow = await apiCreateWorkflow(workflowData);
|
|
||||||
const workflowObj = JSON.parse(JSON.stringify(workflow));
|
|
||||||
const workflowId = workflowObj.id;
|
|
||||||
|
|
||||||
//配置工作流触发器
|
|
||||||
await page.goto(`admin/workflow/workflows/${workflowId}`);
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
|
|
||||||
// 2、测试步骤:跳转到工作流管理页面
|
|
||||||
await page.getByRole('link', { name: 'Workflow' }).click();
|
|
||||||
|
|
||||||
// 3、预期结果:跳转路径正确
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
|
|
||||||
|
|
||||||
// 4、后置处理:删除工作流
|
|
||||||
await apiDeleteWorkflow(workflowId);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Action event Workflow History Version Configuration Page Path Jump Workflow Management Page', async ({
|
|
||||||
page,
|
|
||||||
mockPage,
|
|
||||||
mockCollections,
|
|
||||||
mockRecords,
|
|
||||||
}) => {
|
|
||||||
//数据表后缀标识
|
|
||||||
const triggerNodeAppendText = faker.string.alphanumeric(5);
|
|
||||||
|
|
||||||
//创建触发器节点数据表
|
|
||||||
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
|
|
||||||
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
|
|
||||||
const triggerNodeFieldName = 'orgname';
|
|
||||||
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
|
|
||||||
await mockCollections(
|
|
||||||
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
|
|
||||||
.collections,
|
|
||||||
);
|
|
||||||
//添加工作流
|
|
||||||
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
||||||
const workflowData = {
|
|
||||||
current: true,
|
|
||||||
options: { deleteExecutionOnStatus: [] },
|
|
||||||
title: workFlowName,
|
|
||||||
type: 'action',
|
|
||||||
enabled: true,
|
|
||||||
};
|
|
||||||
const workflow = await apiCreateWorkflow(workflowData);
|
|
||||||
const workflowObj = JSON.parse(JSON.stringify(workflow));
|
|
||||||
const workflowId = workflowObj.id;
|
|
||||||
const WorkflowKey = workflowObj.key;
|
|
||||||
|
|
||||||
//配置工作流触发器
|
|
||||||
const triggerNodeData = { config: { collection: triggerNodeCollectionName, appends: [] } };
|
|
||||||
const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
|
|
||||||
const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
|
|
||||||
|
|
||||||
// 2、测试步骤:添加数据触发工作流
|
|
||||||
const triggerNodeCollectionRecordOne =
|
|
||||||
triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
|
|
||||||
const triggerWorkflows = WorkflowKey;
|
|
||||||
const triggerNodeCollectionRecords = await apiCreateRecordTriggerFormEvent(
|
|
||||||
triggerNodeCollectionName,
|
|
||||||
triggerWorkflows,
|
|
||||||
{ orgname: triggerNodeCollectionRecordOne },
|
|
||||||
);
|
|
||||||
await page.waitForTimeout(1000);
|
|
||||||
|
|
||||||
await page.goto(`admin/workflow/workflows/${workflowId}`);
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
await page.getByLabel('more').click();
|
|
||||||
await page.getByLabel('revision').click();
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
//元素重复
|
|
||||||
await page.getByLabel('version', { exact: true }).click();
|
|
||||||
await page.getByLabel('version-1').click();
|
|
||||||
await page.getByRole('link', { name: 'Workflow' }).click();
|
|
||||||
|
|
||||||
// 3、预期结果:跳转路径正确
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
|
|
||||||
|
|
||||||
// 4、后置处理:删除工作流
|
|
||||||
await apiDeleteWorkflow(workflowId);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Action event Workflow Execution Log Page Path Jump Workflow Management Page', async ({
|
|
||||||
page,
|
|
||||||
mockPage,
|
|
||||||
mockCollections,
|
|
||||||
mockRecords,
|
|
||||||
}) => {
|
|
||||||
//数据表后缀标识
|
|
||||||
const triggerNodeAppendText = faker.string.alphanumeric(5);
|
|
||||||
|
|
||||||
//创建触发器节点数据表
|
|
||||||
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
|
|
||||||
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
|
|
||||||
const triggerNodeFieldName = 'orgname';
|
|
||||||
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
|
|
||||||
await mockCollections(
|
|
||||||
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
|
|
||||||
.collections,
|
|
||||||
);
|
|
||||||
//添加工作流
|
|
||||||
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
||||||
const workflowData = {
|
|
||||||
current: true,
|
|
||||||
options: { deleteExecutionOnStatus: [] },
|
|
||||||
title: workFlowName,
|
|
||||||
type: 'action',
|
|
||||||
enabled: true,
|
|
||||||
};
|
|
||||||
const workflow = await apiCreateWorkflow(workflowData);
|
|
||||||
const workflowObj = JSON.parse(JSON.stringify(workflow));
|
|
||||||
const workflowId = workflowObj.id;
|
|
||||||
const WorkflowKey = workflowObj.key;
|
|
||||||
|
|
||||||
//配置工作流触发器
|
|
||||||
const triggerNodeData = { config: { collection: triggerNodeCollectionName, appends: [] } };
|
|
||||||
const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
|
|
||||||
const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
|
|
||||||
|
|
||||||
// 2、测试步骤:添加数据触发工作流
|
|
||||||
const triggerNodeCollectionRecordOne =
|
|
||||||
triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
|
|
||||||
const triggerWorkflows = WorkflowKey;
|
|
||||||
const triggerNodeCollectionRecords = await apiCreateRecordTriggerFormEvent(
|
|
||||||
triggerNodeCollectionName,
|
|
||||||
triggerWorkflows,
|
|
||||||
{ orgname: triggerNodeCollectionRecordOne },
|
|
||||||
);
|
|
||||||
await page.waitForTimeout(1000);
|
|
||||||
|
|
||||||
await page.goto('/admin/settings/workflow');
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
const workflowListRecords = new WorkflowListRecords(page, workFlowName);
|
|
||||||
await workflowListRecords.executionCountPopup.click();
|
|
||||||
await page.getByText('View').click();
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
await page.getByRole('link', { name: 'Workflow', exact: true }).click();
|
|
||||||
|
|
||||||
// 3、预期结果:跳转路径正确
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
|
|
||||||
|
|
||||||
// 4、后置处理:删除工作流
|
|
||||||
await apiDeleteWorkflow(workflowId);
|
|
||||||
});
|
|
||||||
|
|
||||||
test.skip('Action event Workflow Execution Log Page Path Jump Execution Log Screen', async ({
|
|
||||||
page,
|
|
||||||
mockCollections,
|
|
||||||
mockRecords,
|
|
||||||
}) => {
|
|
||||||
//数据表后缀标识
|
|
||||||
const triggerNodeAppendText = faker.string.alphanumeric(5);
|
|
||||||
|
|
||||||
//创建触发器节点数据表
|
|
||||||
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
|
|
||||||
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
|
|
||||||
const triggerNodeFieldName = 'orgname';
|
|
||||||
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
|
|
||||||
await mockCollections(
|
|
||||||
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
|
|
||||||
.collections,
|
|
||||||
);
|
|
||||||
//添加工作流
|
|
||||||
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
||||||
const workflowData = {
|
|
||||||
current: true,
|
|
||||||
options: { deleteExecutionOnStatus: [] },
|
|
||||||
title: workFlowName,
|
|
||||||
type: 'action',
|
|
||||||
enabled: true,
|
|
||||||
};
|
|
||||||
const workflow = await apiCreateWorkflow(workflowData);
|
|
||||||
const workflowObj = JSON.parse(JSON.stringify(workflow));
|
|
||||||
const workflowId = workflowObj.id;
|
|
||||||
const WorkflowKey = workflowObj.key;
|
|
||||||
|
|
||||||
//配置工作流触发器
|
|
||||||
const triggerNodeData = { config: { collection: triggerNodeCollectionName, appends: [] } };
|
|
||||||
const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
|
|
||||||
const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
|
|
||||||
|
|
||||||
// 2、测试步骤:添加数据触发工作流
|
|
||||||
const triggerNodeCollectionRecordOne =
|
|
||||||
triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
|
|
||||||
const triggerWorkflows = WorkflowKey;
|
|
||||||
const triggerNodeCollectionRecords = await apiCreateRecordTriggerFormEvent(
|
|
||||||
triggerNodeCollectionName,
|
|
||||||
triggerWorkflows,
|
|
||||||
{ orgname: triggerNodeCollectionRecordOne },
|
|
||||||
);
|
|
||||||
await page.waitForTimeout(1000);
|
|
||||||
|
|
||||||
await page.goto('/admin/settings/workflow');
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
const workflowListRecords = new WorkflowListRecords(page, workFlowName);
|
|
||||||
await workflowListRecords.executionCountPopup.click();
|
|
||||||
await page.getByText('View').click();
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
//跳转其他执行日志界面,元素无法定位
|
|
||||||
|
|
||||||
// 3、预期结果:跳转路径正确
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
// expect(page.url()).toBe(`${process.env.APP_BASE_URL}/admin/settings/workflow`);
|
|
||||||
|
|
||||||
// 4、后置处理:删除工作流
|
|
||||||
await apiDeleteWorkflow(workflowId);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe('Configuration page version switching', () => {});
|
|
||||||
|
|
||||||
test.describe('Configuration page disable enable', () => {
|
|
||||||
test('Action event Workflow Add Data Trigger Disable Do Not Trigger', async ({
|
|
||||||
page,
|
|
||||||
mockCollections,
|
|
||||||
mockRecords,
|
|
||||||
}) => {
|
|
||||||
//数据表后缀标识
|
|
||||||
const triggerNodeAppendText = faker.string.alphanumeric(5);
|
|
||||||
|
|
||||||
//创建触发器节点数据表
|
|
||||||
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
|
|
||||||
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
|
|
||||||
const triggerNodeFieldName = 'orgname';
|
|
||||||
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
|
|
||||||
await mockCollections(
|
|
||||||
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
|
|
||||||
.collections,
|
|
||||||
);
|
|
||||||
//添加工作流
|
|
||||||
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
||||||
const workflowData = {
|
|
||||||
current: true,
|
|
||||||
options: { deleteExecutionOnStatus: [] },
|
|
||||||
title: workFlowName,
|
|
||||||
type: 'action',
|
|
||||||
enabled: false,
|
|
||||||
};
|
|
||||||
const workflow = await apiCreateWorkflow(workflowData);
|
|
||||||
const workflowObj = JSON.parse(JSON.stringify(workflow));
|
|
||||||
const workflowId = workflowObj.id;
|
|
||||||
const WorkflowKey = workflowObj.key;
|
|
||||||
|
|
||||||
//配置工作流触发器
|
|
||||||
const triggerNodeData = { config: { collection: triggerNodeCollectionName, appends: [] } };
|
|
||||||
const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
|
|
||||||
const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
|
|
||||||
|
|
||||||
// 2、测试步骤:添加数据触发工作流
|
|
||||||
const triggerNodeCollectionRecordOne =
|
|
||||||
triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
|
|
||||||
const triggerWorkflows = WorkflowKey;
|
|
||||||
const triggerNodeCollectionRecords = await apiCreateRecordTriggerFormEvent(
|
|
||||||
triggerNodeCollectionName,
|
|
||||||
triggerWorkflows,
|
|
||||||
{ orgname: triggerNodeCollectionRecordOne },
|
|
||||||
);
|
|
||||||
await page.waitForTimeout(1000);
|
|
||||||
|
|
||||||
// 3、预期结果:触发次数为1
|
|
||||||
let getWorkflow = await apiGetWorkflow(workflowId);
|
|
||||||
let getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
|
|
||||||
let getWorkflowExecuted = getWorkflowObj.executed;
|
|
||||||
expect(getWorkflowExecuted).toBe(0);
|
|
||||||
|
|
||||||
await page.goto(`admin/workflow/workflows/${workflowId}`);
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
await page.getByRole('switch', { name: 'On Off' }).click();
|
|
||||||
|
|
||||||
await apiCreateRecordTriggerFormEvent(triggerNodeCollectionName, triggerWorkflows, {
|
|
||||||
orgname: triggerNodeCollectionRecordOne + '1',
|
|
||||||
});
|
|
||||||
await page.waitForTimeout(1000);
|
|
||||||
|
|
||||||
getWorkflow = await apiGetWorkflow(workflowId);
|
|
||||||
getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
|
|
||||||
getWorkflowExecuted = getWorkflowObj.executed;
|
|
||||||
expect(getWorkflowExecuted).toBe(1);
|
|
||||||
|
|
||||||
// 4、后置处理:删除工作流
|
|
||||||
await apiDeleteWorkflow(workflowId);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Action event Workflow Add Data Trigger Disable Enable Post Trigger', async ({
|
|
||||||
page,
|
|
||||||
mockCollections,
|
|
||||||
mockRecords,
|
|
||||||
}) => {
|
|
||||||
//数据表后缀标识
|
|
||||||
const triggerNodeAppendText = faker.string.alphanumeric(5);
|
|
||||||
|
|
||||||
//创建触发器节点数据表
|
|
||||||
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
|
|
||||||
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
|
|
||||||
const triggerNodeFieldName = 'orgname';
|
|
||||||
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
|
|
||||||
await mockCollections(
|
|
||||||
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
|
|
||||||
.collections,
|
|
||||||
);
|
|
||||||
//添加工作流
|
|
||||||
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
||||||
const workflowData = {
|
|
||||||
current: true,
|
|
||||||
options: { deleteExecutionOnStatus: [] },
|
|
||||||
title: workFlowName,
|
|
||||||
type: 'action',
|
|
||||||
enabled: true,
|
|
||||||
};
|
|
||||||
const workflow = await apiCreateWorkflow(workflowData);
|
|
||||||
const workflowObj = JSON.parse(JSON.stringify(workflow));
|
|
||||||
const workflowId = workflowObj.id;
|
|
||||||
const WorkflowKey = workflowObj.key;
|
|
||||||
|
|
||||||
//配置工作流触发器
|
|
||||||
const triggerNodeData = { config: { collection: triggerNodeCollectionName, appends: [] } };
|
|
||||||
const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
|
|
||||||
const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
|
|
||||||
|
|
||||||
// 2、测试步骤:添加数据触发工作流
|
|
||||||
const triggerNodeCollectionRecordOne =
|
|
||||||
triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
|
|
||||||
const triggerWorkflows = WorkflowKey;
|
|
||||||
const triggerNodeCollectionRecords = await apiCreateRecordTriggerFormEvent(
|
|
||||||
triggerNodeCollectionName,
|
|
||||||
triggerWorkflows,
|
|
||||||
{ orgname: triggerNodeCollectionRecordOne },
|
|
||||||
);
|
|
||||||
await page.waitForTimeout(1000);
|
|
||||||
|
|
||||||
// 3、预期结果:触发次数为1
|
|
||||||
let getWorkflow = await apiGetWorkflow(workflowId);
|
|
||||||
let getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
|
|
||||||
let getWorkflowExecuted = getWorkflowObj.executed;
|
|
||||||
expect(getWorkflowExecuted).toBe(1);
|
|
||||||
|
|
||||||
await page.goto(`admin/workflow/workflows/${workflowId}`);
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
await page.getByRole('switch', { name: 'On Off' }).click();
|
|
||||||
|
|
||||||
await apiCreateRecordTriggerFormEvent(triggerNodeCollectionName, triggerWorkflows, {
|
|
||||||
orgname: triggerNodeCollectionRecordOne + '1',
|
|
||||||
});
|
|
||||||
await page.waitForTimeout(1000);
|
|
||||||
|
|
||||||
getWorkflow = await apiGetWorkflow(workflowId);
|
|
||||||
getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
|
|
||||||
getWorkflowExecuted = getWorkflowObj.executed;
|
|
||||||
expect(getWorkflowExecuted).toBe(1);
|
|
||||||
|
|
||||||
// 4、后置处理:删除工作流
|
|
||||||
await apiDeleteWorkflow(workflowId);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe('Configuration page execution history', () => {});
|
|
||||||
|
|
||||||
test.describe('Configuration page copy to new version', () => {
|
|
||||||
test('Copy the action event of the Configuration Trigger node', async ({ page, mockCollections, mockRecords }) => {
|
|
||||||
//数据表后缀标识
|
|
||||||
const triggerNodeAppendText = faker.string.alphanumeric(5);
|
|
||||||
|
|
||||||
//创建触发器节点数据表
|
|
||||||
const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
|
|
||||||
const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
|
|
||||||
const triggerNodeFieldName = 'orgname';
|
|
||||||
const triggerNodeFieldDisplayName = '公司名称(单行文本)';
|
|
||||||
await mockCollections(
|
|
||||||
appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
|
|
||||||
.collections,
|
|
||||||
);
|
|
||||||
//添加工作流
|
|
||||||
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
||||||
const workflowData = {
|
|
||||||
current: true,
|
|
||||||
options: { deleteExecutionOnStatus: [] },
|
|
||||||
title: workFlowName,
|
|
||||||
type: 'action',
|
|
||||||
enabled: true,
|
|
||||||
};
|
|
||||||
const workflow = await apiCreateWorkflow(workflowData);
|
|
||||||
const workflowObj = JSON.parse(JSON.stringify(workflow));
|
|
||||||
const workflowId = workflowObj.id;
|
|
||||||
const WorkflowKey = workflowObj.key;
|
|
||||||
|
|
||||||
//配置工作流触发器
|
|
||||||
const triggerNodeData = { config: { collection: triggerNodeCollectionName, appends: [] } };
|
|
||||||
const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
|
|
||||||
const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
|
|
||||||
|
|
||||||
// 2、测试步骤:添加数据触发工作流
|
|
||||||
const triggerNodeCollectionRecordOne =
|
|
||||||
triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
|
|
||||||
const triggerWorkflows = WorkflowKey;
|
|
||||||
const triggerNodeCollectionRecords = await apiCreateRecordTriggerFormEvent(
|
|
||||||
triggerNodeCollectionName,
|
|
||||||
triggerWorkflows,
|
|
||||||
{ orgname: triggerNodeCollectionRecordOne },
|
|
||||||
);
|
|
||||||
await page.waitForTimeout(1000);
|
|
||||||
|
|
||||||
await page.goto(`admin/workflow/workflows/${workflowId}`);
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
await page.getByLabel('more').click();
|
|
||||||
await page.getByLabel('revision').click();
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
|
|
||||||
// 3、预期结果:新版本工作流配置内容同旧版本一样
|
|
||||||
const formEventTriggerNode = new FormEventTriggerNode(page, workFlowName, triggerNodeCollectionName);
|
|
||||||
await formEventTriggerNode.nodeConfigure.click();
|
|
||||||
await expect(
|
|
||||||
page
|
|
||||||
.getByLabel('block-item-DataSourceCollectionCascader-workflows-Collection')
|
|
||||||
.getByText(`Main / ${triggerNodeCollectionDisplayName}`),
|
|
||||||
).toBeVisible();
|
|
||||||
// 4、后置处理:删除工作流
|
|
||||||
await apiDeleteWorkflow(workflowId);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe('Configuration page delete version', () => {});
|
|
||||||
|
|
||||||
test.describe('Node Add Modify Delete', () => {});
|
|
@ -1,179 +0,0 @@
|
|||||||
import {
|
|
||||||
apiCreateRecordTriggerFormEvent,
|
|
||||||
apiCreateWorkflow,
|
|
||||||
apiDeleteWorkflow,
|
|
||||||
apiGetWorkflow,
|
|
||||||
apiUpdateWorkflowTrigger,
|
|
||||||
appendJsonCollectionName,
|
|
||||||
CreateWorkFlow,
|
|
||||||
EditWorkFlow,
|
|
||||||
FormEventTriggerNode,
|
|
||||||
generalWithNoRelationalFields,
|
|
||||||
WorkflowListRecords,
|
|
||||||
} from '@tachybase/plugin-workflow-test/e2e';
|
|
||||||
import { expect, test } from '@tachybase/test/e2e';
|
|
||||||
import { dayjs } from '@tachybase/utils';
|
|
||||||
|
|
||||||
import { faker } from '@faker-js/faker';
|
|
||||||
|
|
||||||
test.describe('Filter', () => {
|
|
||||||
test('filter workflow name', async ({ page }) => {
|
|
||||||
//添加工作流
|
|
||||||
const triggerNodeAppendText = faker.string.alphanumeric(5);
|
|
||||||
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
||||||
const workflowData = {
|
|
||||||
current: true,
|
|
||||||
options: { deleteExecutionOnStatus: [] },
|
|
||||||
title: workFlowName,
|
|
||||||
type: 'action',
|
|
||||||
enabled: true,
|
|
||||||
};
|
|
||||||
const workflow = await apiCreateWorkflow(workflowData);
|
|
||||||
const workflowObj = JSON.parse(JSON.stringify(workflow));
|
|
||||||
const workflowId = workflowObj.id;
|
|
||||||
|
|
||||||
// 2、筛选工作流
|
|
||||||
await page.goto('/admin/settings/workflow');
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
|
|
||||||
await page.getByRole('textbox').fill(workFlowName);
|
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
|
||||||
|
|
||||||
// 3、预期结果:列表中出现筛选的工作流
|
|
||||||
await expect(page.getByText(workFlowName)).toBeAttached();
|
|
||||||
|
|
||||||
// 4、后置处理:删除工作流
|
|
||||||
await apiDeleteWorkflow(workflowId);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe('Add new', () => {
|
|
||||||
test('add new Action event', async ({ page }) => {
|
|
||||||
// 添加工作流
|
|
||||||
await page.goto('/admin/settings/workflow');
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
await page.getByLabel('action-Action-Add new-workflows').click();
|
|
||||||
const createWorkFlow = new CreateWorkFlow(page);
|
|
||||||
const workFlowName = faker.string.alphanumeric(5);
|
|
||||||
await createWorkFlow.name.fill(workFlowName);
|
|
||||||
await createWorkFlow.triggerType.click();
|
|
||||||
await page.getByRole('option', { name: 'Action event' }).click();
|
|
||||||
await page.getByLabel('action-Action-Submit-workflows').click();
|
|
||||||
|
|
||||||
// 3、预期结果:列表中出现新建的工作流
|
|
||||||
await expect(page.getByText(workFlowName)).toBeVisible();
|
|
||||||
|
|
||||||
// 4、后置处理:删除工作流
|
|
||||||
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
|
|
||||||
await page.getByRole('textbox').fill(workFlowName);
|
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
|
||||||
await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName}`).click();
|
|
||||||
await page.getByRole('button', { name: 'OK', exact: true }).click();
|
|
||||||
await expect(page.getByText(workFlowName)).toBeHidden();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe('Sync', () => {});
|
|
||||||
|
|
||||||
test.describe('Delete', () => {
|
|
||||||
test('delete Action event', async ({ page }) => {
|
|
||||||
//添加工作流
|
|
||||||
const triggerNodeAppendText = faker.string.alphanumeric(5);
|
|
||||||
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
||||||
const workflowData = {
|
|
||||||
current: true,
|
|
||||||
options: { deleteExecutionOnStatus: [] },
|
|
||||||
title: workFlowName,
|
|
||||||
type: 'action',
|
|
||||||
enabled: true,
|
|
||||||
};
|
|
||||||
const workflow = await apiCreateWorkflow(workflowData);
|
|
||||||
const workflowObj = JSON.parse(JSON.stringify(workflow));
|
|
||||||
const workflowId = workflowObj.id;
|
|
||||||
|
|
||||||
// 删除工作流
|
|
||||||
await page.goto('/admin/settings/workflow');
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
|
|
||||||
await page.getByRole('textbox').fill(workFlowName);
|
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
|
||||||
await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName}`).click();
|
|
||||||
await page.getByRole('button', { name: 'OK', exact: true }).click();
|
|
||||||
|
|
||||||
// 3、预期结果:列表中出现筛选的工作流
|
|
||||||
await expect(page.getByText(workFlowName)).toBeHidden();
|
|
||||||
|
|
||||||
// 4、后置处理:删除工作流
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe('Edit', () => {
|
|
||||||
test('edit Action event name', async ({ page }) => {
|
|
||||||
//添加工作流
|
|
||||||
const triggerNodeAppendText = faker.string.alphanumeric(5);
|
|
||||||
let workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
||||||
const workflowData = {
|
|
||||||
current: true,
|
|
||||||
options: { deleteExecutionOnStatus: [] },
|
|
||||||
title: workFlowName,
|
|
||||||
type: 'action',
|
|
||||||
enabled: true,
|
|
||||||
};
|
|
||||||
const workflow = await apiCreateWorkflow(workflowData);
|
|
||||||
const workflowObj = JSON.parse(JSON.stringify(workflow));
|
|
||||||
const workflowId = workflowObj.id;
|
|
||||||
|
|
||||||
// 编辑工作流
|
|
||||||
await page.goto('/admin/settings/workflow');
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
await page.getByLabel(`action-Action.Link-Edit-workflows-${workFlowName}`).click();
|
|
||||||
const editWorkFlow = new EditWorkFlow(page, workFlowName);
|
|
||||||
workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
||||||
await editWorkFlow.name.fill(workFlowName);
|
|
||||||
await page.getByLabel('action-Action-Submit-workflows').click();
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
// 3、预期结果:编辑成功,列表中出现编辑后的工作流
|
|
||||||
await expect(page.getByText(workFlowName)).toBeAttached();
|
|
||||||
|
|
||||||
// 4、后置处理:删除工作流
|
|
||||||
await apiDeleteWorkflow(workflowId);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe('Duplicate', () => {
|
|
||||||
test('Duplicate Action event triggers with only unconfigured trigger nodes', async ({ page }) => {
|
|
||||||
//添加工作流
|
|
||||||
const triggerNodeAppendText = faker.string.alphanumeric(5);
|
|
||||||
const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
|
|
||||||
const workflowData = {
|
|
||||||
current: true,
|
|
||||||
options: { deleteExecutionOnStatus: [] },
|
|
||||||
title: workFlowName,
|
|
||||||
type: 'action',
|
|
||||||
enabled: true,
|
|
||||||
};
|
|
||||||
const workflow = await apiCreateWorkflow(workflowData);
|
|
||||||
const workflowObj = JSON.parse(JSON.stringify(workflow));
|
|
||||||
const workflowId = workflowObj.id;
|
|
||||||
|
|
||||||
// 2、复制工作流
|
|
||||||
await page.goto('/admin/settings/workflow');
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
await page.getByLabel(`action-Action.Link-Duplicate-workflows-${workFlowName}`).click();
|
|
||||||
await page.getByLabel(`action-Action-Submit-workflows-${workFlowName}`).click();
|
|
||||||
await page.waitForLoadState('networkidle');
|
|
||||||
// 3、预期结果:列表中出现筛选的工作流
|
|
||||||
await page.getByLabel('action-Filter.Action-Filter-filter-workflows').click();
|
|
||||||
await page.getByRole('textbox').fill(workFlowName);
|
|
||||||
await page.getByRole('button', { name: 'Submit', exact: true }).click();
|
|
||||||
await expect(page.getByText(`${workFlowName} copy`)).toBeAttached();
|
|
||||||
|
|
||||||
// 4、后置处理:删除工作流
|
|
||||||
await page.getByLabel(`action-Action.Link-Delete-workflows-${workFlowName} copy`).click();
|
|
||||||
await page.getByRole('button', { name: 'OK', exact: true }).click();
|
|
||||||
await expect(page.getByText(`${workFlowName} copy`)).toBeHidden();
|
|
||||||
await apiDeleteWorkflow(workflowId);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe('Executed', () => {});
|
|
@ -1,92 +0,0 @@
|
|||||||
import { Plugin, SchemaInitializerItemType } from '@tachybase/client';
|
|
||||||
|
|
||||||
import WorkflowPlugin, { useRecordTriggerWorkflowsActionProps, useTriggerWorkflowsActionProps } from '../..';
|
|
||||||
import { ActionTrigger } from './ActionTrigger';
|
|
||||||
|
|
||||||
const submitToWorkflowActionInitializer: SchemaInitializerItemType = {
|
|
||||||
name: 'submitToWorkflow',
|
|
||||||
title: '{{t("Submit to workflow", { ns: "workflow" })}}',
|
|
||||||
Component: 'CustomizeActionInitializer',
|
|
||||||
schema: {
|
|
||||||
title: '{{t("Submit to workflow", { ns: "workflow" })}}',
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-use-component-props': 'useTriggerWorkflowsActionProps',
|
|
||||||
'x-designer': 'Action.Designer',
|
|
||||||
'x-action-settings': {
|
|
||||||
// assignedValues: {},
|
|
||||||
skipValidator: false,
|
|
||||||
onSuccess: {
|
|
||||||
manualClose: true,
|
|
||||||
redirecting: false,
|
|
||||||
successMessage: '{{t("Submitted successfully")}}',
|
|
||||||
},
|
|
||||||
triggerWorkflows: [],
|
|
||||||
},
|
|
||||||
'x-action': 'customize:triggerWorkflows',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const recordTriggerWorkflowActionInitializer: SchemaInitializerItemType = {
|
|
||||||
name: 'submitToWorkflow',
|
|
||||||
title: '{{t("Submit to workflow", { ns: "workflow" })}}',
|
|
||||||
Component: 'CustomizeActionInitializer',
|
|
||||||
schema: {
|
|
||||||
title: '{{t("Submit to workflow", { ns: "workflow" })}}',
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-use-component-props': 'useRecordTriggerWorkflowsActionProps',
|
|
||||||
'x-designer': 'Action.Designer',
|
|
||||||
'x-action-settings': {
|
|
||||||
onSuccess: {
|
|
||||||
manualClose: true,
|
|
||||||
redirecting: false,
|
|
||||||
successMessage: '{{t("Submitted successfully")}}',
|
|
||||||
},
|
|
||||||
triggerWorkflows: [],
|
|
||||||
},
|
|
||||||
'x-action': 'customize:triggerWorkflows',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const recordTriggerWorkflowActionLinkInitializer = {
|
|
||||||
...recordTriggerWorkflowActionInitializer,
|
|
||||||
schema: {
|
|
||||||
...recordTriggerWorkflowActionInitializer.schema,
|
|
||||||
'x-component': 'Action.Link',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export class PluginActionTrigger extends Plugin {
|
|
||||||
async load() {
|
|
||||||
const workflow = this.app.pm.get('workflow') as WorkflowPlugin;
|
|
||||||
workflow.registerTrigger('action', ActionTrigger);
|
|
||||||
|
|
||||||
this.app.addScopes({
|
|
||||||
useTriggerWorkflowsActionProps,
|
|
||||||
useRecordTriggerWorkflowsActionProps,
|
|
||||||
});
|
|
||||||
|
|
||||||
const FormActionInitializers = this.app.schemaInitializerManager.get('FormActionInitializers');
|
|
||||||
FormActionInitializers.add('customize.submitToWorkflow', submitToWorkflowActionInitializer);
|
|
||||||
|
|
||||||
const CreateFormActionInitializers = this.app.schemaInitializerManager.get('createForm:configureActions');
|
|
||||||
CreateFormActionInitializers.add('customize.submitToWorkflow', submitToWorkflowActionInitializer);
|
|
||||||
|
|
||||||
const UpdateFormActionInitializers = this.app.schemaInitializerManager.get('editForm:configureActions');
|
|
||||||
UpdateFormActionInitializers.add('customize.submitToWorkflow', submitToWorkflowActionInitializer);
|
|
||||||
|
|
||||||
const DetailsActionInitializers = this.app.schemaInitializerManager.get('detailsWithPaging:configureActions');
|
|
||||||
DetailsActionInitializers.add('customize.submitToWorkflow', recordTriggerWorkflowActionInitializer);
|
|
||||||
|
|
||||||
const ReadPrettyFormActionInitializers = this.app.schemaInitializerManager.get('details:configureActions');
|
|
||||||
ReadPrettyFormActionInitializers.add('customize.submitToWorkflow', recordTriggerWorkflowActionInitializer);
|
|
||||||
|
|
||||||
const TableActionColumnInitializers = this.app.schemaInitializerManager.get('table:configureItemActions');
|
|
||||||
TableActionColumnInitializers.add('customize.submitToWorkflow', recordTriggerWorkflowActionLinkInitializer);
|
|
||||||
|
|
||||||
const GridCardItemActionInitializers = this.app.schemaInitializerManager.get('gridCard:configureItemActions');
|
|
||||||
GridCardItemActionInitializers.add('customize.submitToWorkflow', recordTriggerWorkflowActionLinkInitializer);
|
|
||||||
|
|
||||||
const ListItemActionInitializers = this.app.schemaInitializerManager.get('list:configureItemActions');
|
|
||||||
ListItemActionInitializers.add('customize.submitToWorkflow', recordTriggerWorkflowActionLinkInitializer);
|
|
||||||
}
|
|
||||||
}
|
|
@ -28,7 +28,6 @@
|
|||||||
"Workflow will be triggered after submitting succeeded.": "제출 성공 후 워크플로우가 트리거됩니다.",
|
"Workflow will be triggered after submitting succeeded.": "제출 성공 후 워크플로우가 트리거됩니다.",
|
||||||
"Workflow will be triggered after saving succeeded.": "저장 성공 후 워크플로우가 트리거됩니다.",
|
"Workflow will be triggered after saving succeeded.": "저장 성공 후 워크플로우가 트리거됩니다.",
|
||||||
"Workflow will be triggered directly once the button is clicked, without data saving.": "버튼을 클릭하면 데이터 저장 없이 워크플로우가 직접 트리거됩니다.",
|
"Workflow will be triggered directly once the button is clicked, without data saving.": "버튼을 클릭하면 데이터 저장 없이 워크플로우가 직접 트리거됩니다.",
|
||||||
"Submit to workflow": "워크플로우에 제출",
|
|
||||||
"Add workflow": "워크플로우 추가",
|
"Add workflow": "워크플로우 추가",
|
||||||
"Select workflow": "워크플로우 선택",
|
"Select workflow": "워크플로우 선택",
|
||||||
"Trigger data context": "트리거 데이터 컨텍스트",
|
"Trigger data context": "트리거 데이터 컨텍스트",
|
||||||
@ -244,4 +243,4 @@
|
|||||||
"SQL action": "SQL 작업",
|
"SQL action": "SQL 작업",
|
||||||
"Execute a SQL statement in database": "데이터베이스에서 SQL 문을 실행합니다",
|
"Execute a SQL statement in database": "데이터베이스에서 SQL 문을 실행합니다",
|
||||||
"Usage of SQL query result is not supported yet.": "아직 SQL 쿼리 결과의 사용은 지원되지 않습니다."
|
"Usage of SQL query result is not supported yet.": "아직 SQL 쿼리 결과의 사용은 지원되지 않습니다."
|
||||||
}
|
}
|
||||||
|
@ -281,7 +281,6 @@
|
|||||||
"Status": "状态",
|
"Status": "状态",
|
||||||
"String operation": "字符串",
|
"String operation": "字符串",
|
||||||
"Submission may be withdrawn, please try refresh the list.": "提交可能已被撤回,请尝试刷新列表。",
|
"Submission may be withdrawn, please try refresh the list.": "提交可能已被撤回,请尝试刷新列表。",
|
||||||
"Submit to workflow": "提交至工作流",
|
|
||||||
"Submitted": "提交",
|
"Submitted": "提交",
|
||||||
"Succeed and continue": "通过并继续",
|
"Succeed and continue": "通过并继续",
|
||||||
"Succeeded": "成功",
|
"Succeeded": "成功",
|
||||||
|
@ -8,9 +8,7 @@ import LRUCache from 'lru-cache';
|
|||||||
|
|
||||||
import initActions from './actions';
|
import initActions from './actions';
|
||||||
import { EXECUTION_STATUS } from './constants';
|
import { EXECUTION_STATUS } from './constants';
|
||||||
import { PluginActionTrigger } from './features/action-trigger/Plugin';
|
|
||||||
import { PluginAggregate } from './features/aggregate/Plugin';
|
import { PluginAggregate } from './features/aggregate/Plugin';
|
||||||
import PluginWorkflowAPIRegularServer from './features/api-regular/plugin';
|
|
||||||
import PluginWorkflowApproval from './features/approval';
|
import PluginWorkflowApproval from './features/approval';
|
||||||
import PluginWorkflowDataMappingServer from './features/data-mapping/plugin';
|
import PluginWorkflowDataMappingServer from './features/data-mapping/plugin';
|
||||||
import { PluginDelay } from './features/delay/Plugin';
|
import { PluginDelay } from './features/delay/Plugin';
|
||||||
@ -75,7 +73,6 @@ export default class PluginWorkflowServer extends Plugin {
|
|||||||
this.addFeature(PluginDynamicCalculation);
|
this.addFeature(PluginDynamicCalculation);
|
||||||
this.addFeature(PluginDelay);
|
this.addFeature(PluginDelay);
|
||||||
this.addFeature(PluginAggregate);
|
this.addFeature(PluginAggregate);
|
||||||
this.addFeature(PluginActionTrigger);
|
|
||||||
this.addFeature(PluginWorkflowJSONParseServer);
|
this.addFeature(PluginWorkflowJSONParseServer);
|
||||||
this.addFeature(PluginWorkflowJSParseServer);
|
this.addFeature(PluginWorkflowJSParseServer);
|
||||||
this.addFeature(PluginWorkflowDataMappingServer);
|
this.addFeature(PluginWorkflowDataMappingServer);
|
||||||
|
@ -1,156 +0,0 @@
|
|||||||
import { Context as ActionContext, Next } from '@tachybase/actions';
|
|
||||||
import { parseCollectionName } from '@tachybase/data-source-manager';
|
|
||||||
import { Model, modelAssociationByKey } from '@tachybase/database';
|
|
||||||
import Application, { DefaultContext } from '@tachybase/server';
|
|
||||||
|
|
||||||
import { get } from 'lodash';
|
|
||||||
import { BelongsTo, HasOne } from 'sequelize';
|
|
||||||
|
|
||||||
import WorkflowPlugin, { toJSON, Trigger, WorkflowModel } from '../..';
|
|
||||||
|
|
||||||
interface Context extends ActionContext, DefaultContext {}
|
|
||||||
|
|
||||||
export default class extends Trigger {
|
|
||||||
constructor(workflow: WorkflowPlugin) {
|
|
||||||
super(workflow);
|
|
||||||
|
|
||||||
workflow.app.use(this.middleware, { after: 'dataSource' });
|
|
||||||
}
|
|
||||||
|
|
||||||
async triggerAction(context: Context, next: Next) {
|
|
||||||
const { triggerWorkflows } = context.action.params;
|
|
||||||
|
|
||||||
if (!triggerWorkflows) {
|
|
||||||
return context.throw(400);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.status = 202;
|
|
||||||
await next();
|
|
||||||
|
|
||||||
this.trigger(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
middleware = async (context: Context, next: Next) => {
|
|
||||||
const {
|
|
||||||
resourceName,
|
|
||||||
actionName,
|
|
||||||
params: { triggerWorkflows },
|
|
||||||
} = context.action;
|
|
||||||
|
|
||||||
if (resourceName === 'workflows' && actionName === 'trigger') {
|
|
||||||
return this.triggerAction(context, next);
|
|
||||||
}
|
|
||||||
|
|
||||||
await next();
|
|
||||||
|
|
||||||
if (!triggerWorkflows) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!['create', 'update'].includes(actionName)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.trigger(context);
|
|
||||||
};
|
|
||||||
|
|
||||||
private async trigger(context: Context) {
|
|
||||||
const { triggerWorkflows = '', values } = context.action.params;
|
|
||||||
const dataSourceHeader = context.get('x-data-source') || 'main';
|
|
||||||
|
|
||||||
const { currentUser, currentRole } = context.state;
|
|
||||||
const { model: UserModel } = this.workflow.db.getCollection('users');
|
|
||||||
const userInfo = {
|
|
||||||
user: UserModel.build(currentUser).desensitize(),
|
|
||||||
roleName: currentRole,
|
|
||||||
};
|
|
||||||
|
|
||||||
const triggers = triggerWorkflows.split(',').map((trigger) => trigger.split('!'));
|
|
||||||
const workflowRepo = this.workflow.db.getRepository('workflows');
|
|
||||||
const workflows = (
|
|
||||||
await workflowRepo.find({
|
|
||||||
filter: {
|
|
||||||
key: triggers.map((trigger) => trigger[0]),
|
|
||||||
current: true,
|
|
||||||
type: 'action',
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
).filter((workflow) => Boolean(workflow.config.collection));
|
|
||||||
const syncGroup = [];
|
|
||||||
const asyncGroup = [];
|
|
||||||
for (const workflow of workflows) {
|
|
||||||
const { collection, appends = [] } = workflow.config;
|
|
||||||
const [dataSourceName, collectionName] = parseCollectionName(collection);
|
|
||||||
const trigger = triggers.find((trigger) => trigger[0] == workflow.key);
|
|
||||||
const event = [workflow];
|
|
||||||
if (context.action.resourceName !== 'workflows') {
|
|
||||||
if (!context.body) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (dataSourceName !== dataSourceHeader) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const { body: data } = context;
|
|
||||||
for (const row of Array.isArray(data) ? data : [data]) {
|
|
||||||
let payload = row;
|
|
||||||
if (trigger[1]) {
|
|
||||||
const paths = trigger[1].split('.');
|
|
||||||
for (const field of paths) {
|
|
||||||
if (payload.get(field)) {
|
|
||||||
payload = payload.get(field);
|
|
||||||
} else {
|
|
||||||
const association = <HasOne | BelongsTo>modelAssociationByKey(payload, field);
|
|
||||||
payload = await payload[association.accessors.get]();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const model = payload.constructor;
|
|
||||||
if (payload instanceof Model) {
|
|
||||||
if (collectionName !== model.collection.name) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (appends.length) {
|
|
||||||
payload = await model.collection.repository.findOne({
|
|
||||||
filterByTk: payload.get(model.primaryKeyAttribute),
|
|
||||||
appends,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// this.workflow.trigger(workflow, { data: toJSON(payload), ...userInfo });
|
|
||||||
event.push({ data: toJSON(payload), ...userInfo });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const { model, repository } = (<Application>context.app).dataSourceManager.dataSources
|
|
||||||
.get(dataSourceName)
|
|
||||||
.collectionManager.getCollection(collectionName);
|
|
||||||
let data = trigger[1] ? get(values, trigger[1]) : values;
|
|
||||||
const pk = get(data, model.primaryKeyAttribute);
|
|
||||||
if (appends.length && pk != null) {
|
|
||||||
data = await repository.findOne({
|
|
||||||
filterByTk: pk,
|
|
||||||
appends,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// this.workflow.trigger(workflow, {
|
|
||||||
// data,
|
|
||||||
// ...userInfo,
|
|
||||||
// });
|
|
||||||
event.push({ data, ...userInfo });
|
|
||||||
}
|
|
||||||
(workflow.sync ? syncGroup : asyncGroup).push(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const event of syncGroup) {
|
|
||||||
await this.workflow.trigger(event[0], event[1], { httpContext: context });
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const event of asyncGroup) {
|
|
||||||
this.workflow.trigger(event[0], event[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
on(workflow: WorkflowModel) {}
|
|
||||||
|
|
||||||
off(workflow: WorkflowModel) {}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
import { Plugin } from '@tachybase/server';
|
|
||||||
|
|
||||||
import WorkflowPlugin from '../..';
|
|
||||||
import ActionTrigger from './ActionTrigger';
|
|
||||||
|
|
||||||
export class PluginActionTrigger extends Plugin {
|
|
||||||
async load() {
|
|
||||||
const workflowPlugin = this.app.pm.get(WorkflowPlugin) as WorkflowPlugin;
|
|
||||||
workflowPlugin.registerTrigger('action', new ActionTrigger(workflowPlugin));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,619 +0,0 @@
|
|||||||
import Database from '@tachybase/database';
|
|
||||||
import { EXECUTION_STATUS } from '@tachybase/plugin-workflow';
|
|
||||||
import { getApp, sleep } from '@tachybase/plugin-workflow-test';
|
|
||||||
import { MockServer } from '@tachybase/test';
|
|
||||||
|
|
||||||
import Plugin from '..';
|
|
||||||
|
|
||||||
describe('workflow > action-trigger', () => {
|
|
||||||
let app: MockServer;
|
|
||||||
let db: Database;
|
|
||||||
let agent;
|
|
||||||
let PostRepo;
|
|
||||||
let CommentRepo;
|
|
||||||
let WorkflowModel;
|
|
||||||
let UserRepo;
|
|
||||||
let users;
|
|
||||||
let userAgents;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
app = await getApp({
|
|
||||||
plugins: ['users', 'auth', Plugin],
|
|
||||||
});
|
|
||||||
await app.pm.get('auth').install();
|
|
||||||
agent = app.agent();
|
|
||||||
db = app.db;
|
|
||||||
WorkflowModel = db.getCollection('workflows').model;
|
|
||||||
PostRepo = db.getCollection('posts').repository;
|
|
||||||
CommentRepo = db.getCollection('comments').repository;
|
|
||||||
UserRepo = db.getCollection('users').repository;
|
|
||||||
|
|
||||||
users = await UserRepo.create({
|
|
||||||
values: [
|
|
||||||
{ id: 2, nickname: 'a', roles: [{ name: 'root' }] },
|
|
||||||
{ id: 3, nickname: 'b' },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
userAgents = users.map((user) => app.agent().login(user));
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => app.destroy());
|
|
||||||
|
|
||||||
describe('create', () => {
|
|
||||||
it('enabled / disabled', async () => {
|
|
||||||
const workflow = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
config: {
|
|
||||||
collection: 'posts',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const res1 = await userAgents[0].resource('posts').create({
|
|
||||||
values: { title: 't1' },
|
|
||||||
triggerWorkflows: `${workflow.key}`,
|
|
||||||
});
|
|
||||||
expect(res1.status).toBe(200);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const e1 = await workflow.getExecutions();
|
|
||||||
expect(e1.length).toBe(1);
|
|
||||||
expect(e1[0].status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
expect(e1[0].context.data).toMatchObject({ title: 't1' });
|
|
||||||
|
|
||||||
await workflow.update({
|
|
||||||
enabled: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const res2 = await userAgents[0].resource('posts').create({
|
|
||||||
values: { title: 't2' },
|
|
||||||
triggerWorkflows: `${workflow.key}`,
|
|
||||||
});
|
|
||||||
expect(res2.status).toBe(200);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const e2 = await workflow.getExecutions({ order: [['id', 'ASC']] });
|
|
||||||
expect(e2.length).toBe(1);
|
|
||||||
|
|
||||||
await workflow.update({
|
|
||||||
enabled: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const res3 = await userAgents[0].resource('posts').create({
|
|
||||||
values: { title: 't3' },
|
|
||||||
triggerWorkflows: `${workflow.key}`,
|
|
||||||
});
|
|
||||||
expect(res2.status).toBe(200);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const e3 = await workflow.getExecutions({ order: [['id', 'ASC']] });
|
|
||||||
expect(e3.length).toBe(2);
|
|
||||||
expect(e3[1].status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
expect(e3[1].context.data).toMatchObject({ title: 't3' });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('only trigger if params provided matching collection config', async () => {
|
|
||||||
const workflow = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
config: {
|
|
||||||
collection: 'posts',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const res1 = await userAgents[0].resource('posts').create({
|
|
||||||
values: { title: 't1' },
|
|
||||||
triggerWorkflows: `${workflow.key}`,
|
|
||||||
});
|
|
||||||
expect(res1.status).toBe(200);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const e1 = await workflow.getExecutions();
|
|
||||||
expect(e1.length).toBe(1);
|
|
||||||
expect(e1[0].status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
expect(e1[0].context.data).toMatchObject({ title: 't1' });
|
|
||||||
|
|
||||||
await workflow.update({
|
|
||||||
config: {
|
|
||||||
collection: 'comments',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const res2 = await userAgents[0].resource('posts').create({
|
|
||||||
values: { title: 't2' },
|
|
||||||
triggerWorkflows: `${workflow.key}`,
|
|
||||||
});
|
|
||||||
expect(res2.status).toBe(200);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const e2 = await workflow.getExecutions({ order: [['id', 'ASC']] });
|
|
||||||
expect(e2.length).toBe(1);
|
|
||||||
// expect(e2[1].status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
// expect(e2[1].context.data).toMatchObject({ title: 't2' });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('system fields could be accessed', async () => {
|
|
||||||
const workflow = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
config: {
|
|
||||||
collection: 'posts',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const res1 = await userAgents[0].resource('posts').create({
|
|
||||||
values: { title: 't1' },
|
|
||||||
triggerWorkflows: `${workflow.key}`,
|
|
||||||
});
|
|
||||||
expect(res1.status).toBe(200);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const e1 = await workflow.getExecutions();
|
|
||||||
expect(e1.length).toBe(1);
|
|
||||||
expect(e1[0].status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
expect(e1[0].context.data).toHaveProperty('createdAt');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('appends', async () => {
|
|
||||||
const workflow = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
config: {
|
|
||||||
collection: 'posts',
|
|
||||||
appends: ['createdBy'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const res1 = await userAgents[0].resource('posts').create({
|
|
||||||
values: { title: 't1' },
|
|
||||||
triggerWorkflows: `${workflow.key}`,
|
|
||||||
});
|
|
||||||
expect(res1.status).toBe(200);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const e1 = await workflow.getExecutions();
|
|
||||||
expect(e1.length).toBe(1);
|
|
||||||
expect(e1[0].status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
expect(e1[0].context.data).toHaveProperty('createdBy');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('user submitted form', async () => {
|
|
||||||
const workflow = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
config: {
|
|
||||||
collection: 'posts',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const res1 = await userAgents[0].resource('posts').create({
|
|
||||||
values: { title: 't1' },
|
|
||||||
triggerWorkflows: `${workflow.key}`,
|
|
||||||
});
|
|
||||||
expect(res1.status).toBe(200);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e1] = await workflow.getExecutions();
|
|
||||||
expect(e1.status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
expect(e1.context.user).toBeDefined();
|
|
||||||
expect(e1.context.user.id).toBe(users[0].id);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('update', () => {
|
|
||||||
it('trigger after updated', async () => {
|
|
||||||
const workflow = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
config: {
|
|
||||||
collection: 'posts',
|
|
||||||
appends: ['createdBy'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const res1 = await userAgents[0].resource('posts').create({
|
|
||||||
values: { title: 't1' },
|
|
||||||
});
|
|
||||||
expect(res1.status).toBe(200);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const e1 = await workflow.getExecutions();
|
|
||||||
expect(e1.length).toBe(0);
|
|
||||||
|
|
||||||
const res2 = await userAgents[0].resource('posts').update({
|
|
||||||
filterByTk: res1.body.data.id,
|
|
||||||
values: { title: 't2' },
|
|
||||||
triggerWorkflows: `${workflow.key}`,
|
|
||||||
});
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e2] = await workflow.getExecutions();
|
|
||||||
expect(e2.status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
expect(e2.context.data).toHaveProperty('title', 't2');
|
|
||||||
expect(e2.context.data).toHaveProperty('createdBy');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe.skip('destroy', () => {
|
|
||||||
it('trigger after destroyed', async () => {
|
|
||||||
const workflow = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
config: {
|
|
||||||
collection: 'posts',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const p1 = await PostRepo.create({
|
|
||||||
values: { title: 't1' },
|
|
||||||
});
|
|
||||||
const p2 = await PostRepo.create({
|
|
||||||
values: { title: 't2' },
|
|
||||||
});
|
|
||||||
const res1 = await userAgents[0].resource('posts').destroy({
|
|
||||||
filterByTk: p1.id,
|
|
||||||
});
|
|
||||||
expect(res1.status).toBe(200);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const e1 = await workflow.getExecutions();
|
|
||||||
expect(e1.length).toBe(0);
|
|
||||||
|
|
||||||
const res2 = await userAgents[0].resource('posts').destroy({
|
|
||||||
filterByTk: p2.id,
|
|
||||||
triggerWorkflows: `${workflow.key}`,
|
|
||||||
});
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e2] = await workflow.getExecutions();
|
|
||||||
expect(e2.status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
expect(e2.context.data).toBe(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('directly trigger', () => {
|
|
||||||
it('no collection configured should not be triggered', async () => {
|
|
||||||
const workflow = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
});
|
|
||||||
|
|
||||||
const res1 = await userAgents[0].resource('workflows').trigger({
|
|
||||||
values: { title: 't1' },
|
|
||||||
triggerWorkflows: `${workflow.key}`,
|
|
||||||
});
|
|
||||||
expect(res1.status).toBe(202);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const e1s = await workflow.getExecutions();
|
|
||||||
expect(e1s.length).toBe(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('trigger on form data', async () => {
|
|
||||||
const workflow = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
config: {
|
|
||||||
collection: 'posts',
|
|
||||||
appends: ['createdBy'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const res1 = await userAgents[0].resource('workflows').trigger({
|
|
||||||
values: { title: 't1' },
|
|
||||||
triggerWorkflows: `${workflow.key}`,
|
|
||||||
});
|
|
||||||
expect(res1.status).toBe(202);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e1] = await workflow.getExecutions();
|
|
||||||
expect(e1.status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
expect(e1.context.data).toMatchObject({ title: 't1' });
|
|
||||||
expect(e1.context.data.createdBy).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('trigger on record data', async () => {
|
|
||||||
const workflow = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
config: {
|
|
||||||
collection: 'posts',
|
|
||||||
appends: ['createdBy'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const post = await PostRepo.create({
|
|
||||||
values: { title: 't1', createdBy: users[0].id },
|
|
||||||
});
|
|
||||||
|
|
||||||
const res1 = await userAgents[0].resource('workflows').trigger({
|
|
||||||
values: post.toJSON(),
|
|
||||||
triggerWorkflows: `${workflow.key}`,
|
|
||||||
});
|
|
||||||
expect(res1.status).toBe(202);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e1] = await workflow.getExecutions();
|
|
||||||
expect(e1.status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
expect(e1.context.data).toMatchObject({ title: 't1' });
|
|
||||||
expect(e1.context.data).toHaveProperty('createdBy');
|
|
||||||
expect(e1.context.data.createdBy.id).toBe(users[0].id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('multi trigger', async () => {
|
|
||||||
const w1 = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
config: {
|
|
||||||
collection: 'posts',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const w2 = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
config: {
|
|
||||||
collection: 'posts',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const res1 = await userAgents[0].resource('workflows').trigger({
|
|
||||||
values: { title: 't1' },
|
|
||||||
triggerWorkflows: `${w1.key},${w2.key}`,
|
|
||||||
});
|
|
||||||
expect(res1.status).toBe(202);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e1] = await w1.getExecutions();
|
|
||||||
expect(e1.status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
expect(e1.context.data).toMatchObject({ title: 't1' });
|
|
||||||
|
|
||||||
const [e2] = await w2.getExecutions();
|
|
||||||
expect(e2.status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
expect(e2.context.data).toMatchObject({ title: 't1' });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('user submitted form', async () => {
|
|
||||||
const workflow = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
config: {
|
|
||||||
collection: 'posts',
|
|
||||||
appends: ['createdBy'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const res1 = await userAgents[0].resource('posts').create({
|
|
||||||
values: { title: 't1' },
|
|
||||||
triggerWorkflows: `${workflow.key}`,
|
|
||||||
});
|
|
||||||
expect(res1.status).toBe(200);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e1] = await workflow.getExecutions();
|
|
||||||
expect(e1.status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
expect(e1.context.user).toBeDefined();
|
|
||||||
expect(e1.context.user.id).toBe(users[0].id);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('context data path', () => {
|
|
||||||
it('level: 1', async () => {
|
|
||||||
const workflow = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
config: {
|
|
||||||
collection: 'posts',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const res1 = await userAgents[0].resource('workflows').trigger({
|
|
||||||
values: { title: 't1', category: { title: 'c1' } },
|
|
||||||
triggerWorkflows: `${workflow.key}!category`,
|
|
||||||
});
|
|
||||||
expect(res1.status).toBe(202);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e1] = await workflow.getExecutions();
|
|
||||||
expect(e1.status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
expect(e1.context.data).toMatchObject({ title: 'c1' });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('level: 2', async () => {
|
|
||||||
const workflow = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
config: {
|
|
||||||
collection: 'posts',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const res1 = await userAgents[0].resource('workflows').trigger({
|
|
||||||
values: { content: 'comment1', post: { category: { title: 'c1' } } },
|
|
||||||
triggerWorkflows: `${workflow.key}!post.category`,
|
|
||||||
});
|
|
||||||
expect(res1.status).toBe(202);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e1] = await workflow.getExecutions();
|
|
||||||
expect(e1.status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
expect(e1.context.data).toMatchObject({ title: 'c1' });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('workflow key', () => {
|
|
||||||
it('revision', async () => {
|
|
||||||
const w1 = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
config: {
|
|
||||||
collection: 'posts',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const res1 = await userAgents[0].resource('workflows').trigger({
|
|
||||||
values: { title: 't1' },
|
|
||||||
triggerWorkflows: `${w1.key}`,
|
|
||||||
});
|
|
||||||
expect(res1.status).toBe(202);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const [e1] = await w1.getExecutions();
|
|
||||||
expect(e1.status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
expect(e1.context.data).toMatchObject({ title: 't1' });
|
|
||||||
|
|
||||||
const res2 = await userAgents[0].resource('workflows').revision({
|
|
||||||
filterByTk: w1.id,
|
|
||||||
filter: {
|
|
||||||
key: w1.key,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const w2 = await WorkflowModel.findByPk(res2.body.data.id);
|
|
||||||
await w2.update({
|
|
||||||
enabled: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const res3 = await userAgents[0].resource('workflows').trigger({
|
|
||||||
values: { title: 't2' },
|
|
||||||
triggerWorkflows: `${w1.key}`,
|
|
||||||
});
|
|
||||||
expect(res3.status).toBe(202);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const e2 = await w1.getExecutions();
|
|
||||||
expect(e2.length).toBe(1);
|
|
||||||
const e3 = await w2.getExecutions();
|
|
||||||
expect(e3.length).toBe(1);
|
|
||||||
expect(e3[0].status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
expect(e3[0].context.data).toMatchObject({ title: 't2' });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('sync', () => {
|
|
||||||
it('sync form trigger', async () => {
|
|
||||||
const workflow = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
sync: true,
|
|
||||||
config: {
|
|
||||||
collection: 'posts',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const res1 = await userAgents[0].resource('posts').create({
|
|
||||||
values: { title: 't1' },
|
|
||||||
triggerWorkflows: `${workflow.key}`,
|
|
||||||
});
|
|
||||||
expect(res1.status).toBe(200);
|
|
||||||
|
|
||||||
const executions = await workflow.getExecutions();
|
|
||||||
expect(executions.length).toBe(1);
|
|
||||||
expect(executions[0].status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sync and async will all be triggered in one action', async () => {
|
|
||||||
const w1 = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
config: {
|
|
||||||
collection: 'posts',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const w2 = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
sync: true,
|
|
||||||
config: {
|
|
||||||
collection: 'posts',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const res1 = await userAgents[0].resource('posts').create({
|
|
||||||
values: { title: 't1' },
|
|
||||||
triggerWorkflows: [w1.key, w2.key].join(),
|
|
||||||
});
|
|
||||||
expect(res1.status).toBe(200);
|
|
||||||
|
|
||||||
const e1s = await w1.getExecutions();
|
|
||||||
expect(e1s.length).toBe(0);
|
|
||||||
|
|
||||||
const e2s = await w2.getExecutions();
|
|
||||||
expect(e2s.length).toBe(1);
|
|
||||||
expect(e2s[0].status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const e3s = await w1.getExecutions();
|
|
||||||
expect(e3s.length).toBe(1);
|
|
||||||
expect(e3s[0].status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('multiple data source', () => {
|
|
||||||
it('trigger on different data source', async () => {
|
|
||||||
const workflow = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'action',
|
|
||||||
config: {
|
|
||||||
collection: 'another:posts',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const res1 = await userAgents[0].resource('posts').create({
|
|
||||||
values: { title: 't1' },
|
|
||||||
triggerWorkflows: `${workflow.key}`,
|
|
||||||
});
|
|
||||||
expect(res1.status).toBe(200);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const e1s = await workflow.getExecutions();
|
|
||||||
expect(e1s.length).toBe(0);
|
|
||||||
|
|
||||||
// const res2 = await userAgents[0]
|
|
||||||
// .set('x-data-source', 'another')
|
|
||||||
// .resource('posts')
|
|
||||||
// .create({
|
|
||||||
// values: { title: 't2' },
|
|
||||||
// triggerWorkflows: `${workflow.key}`,
|
|
||||||
// });
|
|
||||||
const res2 = await agent
|
|
||||||
.login(users[0])
|
|
||||||
.set('x-data-source', 'another')
|
|
||||||
.post('/api/posts:create')
|
|
||||||
.query({ triggerWorkflows: `${workflow.key}` })
|
|
||||||
.send({ title: 't2' });
|
|
||||||
|
|
||||||
expect(res2.status).toBe(200);
|
|
||||||
|
|
||||||
await sleep(500);
|
|
||||||
|
|
||||||
const e2s = await workflow.getExecutions();
|
|
||||||
expect(e2s.length).toBe(1);
|
|
||||||
expect(e2s[0].status).toBe(EXECUTION_STATUS.RESOLVED);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
Reference in New Issue
Block a user