mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 20:24:05 -08:00
fix: Save new version of the workflow instead of the previous (no-changelog) (#7428)
Github issue / Community forum post (link here to close automatically):
This commit is contained in:
parent
b6de910cbe
commit
41236b7e08
|
@ -2,6 +2,7 @@ import type express from 'express';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import type { FindOptionsWhere } from 'typeorm';
|
import type { FindOptionsWhere } from 'typeorm';
|
||||||
import { In } from 'typeorm';
|
import { In } from 'typeorm';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
|
@ -36,6 +37,7 @@ export = {
|
||||||
const workflow = req.body;
|
const workflow = req.body;
|
||||||
|
|
||||||
workflow.active = false;
|
workflow.active = false;
|
||||||
|
workflow.versionId = uuid();
|
||||||
|
|
||||||
await replaceInvalidCredentials(workflow);
|
await replaceInvalidCredentials(workflow);
|
||||||
|
|
||||||
|
@ -45,6 +47,14 @@ export = {
|
||||||
|
|
||||||
const createdWorkflow = await createWorkflow(workflow, req.user, role);
|
const createdWorkflow = await createWorkflow(workflow, req.user, role);
|
||||||
|
|
||||||
|
if (isWorkflowHistoryLicensed()) {
|
||||||
|
await Container.get(WorkflowHistoryService).saveVersion(
|
||||||
|
req.user,
|
||||||
|
createdWorkflow,
|
||||||
|
createdWorkflow.id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
await Container.get(ExternalHooks).run('workflow.afterCreate', [createdWorkflow]);
|
await Container.get(ExternalHooks).run('workflow.afterCreate', [createdWorkflow]);
|
||||||
void Container.get(InternalHooks).onWorkflowCreated(req.user, createdWorkflow, true);
|
void Container.get(InternalHooks).onWorkflowCreated(req.user, createdWorkflow, true);
|
||||||
|
|
||||||
|
@ -151,6 +161,7 @@ export = {
|
||||||
const updateData = new WorkflowEntity();
|
const updateData = new WorkflowEntity();
|
||||||
Object.assign(updateData, req.body);
|
Object.assign(updateData, req.body);
|
||||||
updateData.id = id;
|
updateData.id = id;
|
||||||
|
updateData.versionId = uuid();
|
||||||
|
|
||||||
const sharedWorkflow = await getSharedWorkflow(req.user, id);
|
const sharedWorkflow = await getSharedWorkflow(req.user, id);
|
||||||
|
|
||||||
|
@ -179,10 +190,6 @@ export = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isWorkflowHistoryLicensed()) {
|
|
||||||
await Container.get(WorkflowHistoryService).saveVersion(req.user, sharedWorkflow.workflow);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sharedWorkflow.workflow.active) {
|
if (sharedWorkflow.workflow.active) {
|
||||||
try {
|
try {
|
||||||
await workflowRunner.add(sharedWorkflow.workflowId, 'update');
|
await workflowRunner.add(sharedWorkflow.workflowId, 'update');
|
||||||
|
@ -195,6 +202,14 @@ export = {
|
||||||
|
|
||||||
const updatedWorkflow = await getWorkflowById(sharedWorkflow.workflowId);
|
const updatedWorkflow = await getWorkflowById(sharedWorkflow.workflowId);
|
||||||
|
|
||||||
|
if (isWorkflowHistoryLicensed() && updatedWorkflow) {
|
||||||
|
await Container.get(WorkflowHistoryService).saveVersion(
|
||||||
|
req.user,
|
||||||
|
updatedWorkflow,
|
||||||
|
sharedWorkflow.workflowId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
await Container.get(ExternalHooks).run('workflow.afterUpdate', [updateData]);
|
await Container.get(ExternalHooks).run('workflow.afterUpdate', [updateData]);
|
||||||
void Container.get(InternalHooks).onWorkflowSaved(req.user, updateData, true);
|
void Container.get(InternalHooks).onWorkflowSaved(req.user, updateData, true);
|
||||||
|
|
||||||
|
|
|
@ -64,14 +64,14 @@ export class WorkflowHistoryService {
|
||||||
return hist;
|
return hist;
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveVersion(user: User, workflow: WorkflowEntity) {
|
async saveVersion(user: User, workflow: WorkflowEntity, workflowId: string) {
|
||||||
if (isWorkflowHistoryEnabled()) {
|
if (isWorkflowHistoryEnabled()) {
|
||||||
await this.workflowHistoryRepository.insert({
|
await this.workflowHistoryRepository.insert({
|
||||||
authors: user.firstName + ' ' + user.lastName,
|
authors: user.firstName + ' ' + user.lastName,
|
||||||
connections: workflow.connections,
|
connections: workflow.connections,
|
||||||
nodes: workflow.nodes,
|
nodes: workflow.nodes,
|
||||||
versionId: workflow.versionId,
|
versionId: workflow.versionId,
|
||||||
workflowId: workflow.id,
|
workflowId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ import { RoleService } from '@/services/role.service';
|
||||||
import * as utils from '@/utils';
|
import * as utils from '@/utils';
|
||||||
import { listQueryMiddleware } from '@/middlewares';
|
import { listQueryMiddleware } from '@/middlewares';
|
||||||
import { TagService } from '@/services/tag.service';
|
import { TagService } from '@/services/tag.service';
|
||||||
|
import { isWorkflowHistoryLicensed } from './workflowHistory/workflowHistoryHelper.ee';
|
||||||
|
import { WorkflowHistoryService } from './workflowHistory/workflowHistory.service.ee';
|
||||||
|
|
||||||
export const workflowsController = express.Router();
|
export const workflowsController = express.Router();
|
||||||
|
|
||||||
|
@ -99,6 +101,14 @@ workflowsController.post(
|
||||||
throw new ResponseHelper.InternalServerError('Failed to save workflow');
|
throw new ResponseHelper.InternalServerError('Failed to save workflow');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isWorkflowHistoryLicensed()) {
|
||||||
|
await Container.get(WorkflowHistoryService).saveVersion(
|
||||||
|
req.user,
|
||||||
|
savedWorkflow,
|
||||||
|
savedWorkflow.id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (tagIds && !config.getEnv('workflowTagsDisabled') && savedWorkflow.tags) {
|
if (tagIds && !config.getEnv('workflowTagsDisabled') && savedWorkflow.tags) {
|
||||||
savedWorkflow.tags = Container.get(TagService).sortByRequestOrder(savedWorkflow.tags, {
|
savedWorkflow.tags = Container.get(TagService).sortByRequestOrder(savedWorkflow.tags, {
|
||||||
requestOrder: tagIds,
|
requestOrder: tagIds,
|
||||||
|
|
|
@ -301,8 +301,8 @@ export class WorkflowsService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isWorkflowHistoryLicensed()) {
|
if (isWorkflowHistoryLicensed() && workflow.versionId !== shared.workflow.versionId) {
|
||||||
await Container.get(WorkflowHistoryService).saveVersion(user, shared.workflow);
|
await Container.get(WorkflowHistoryService).saveVersion(user, workflow, workflowId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const relations = config.getEnv('workflowTagsDisabled') ? [] : ['tags'];
|
const relations = config.getEnv('workflowTagsDisabled') ? [] : ['tags'];
|
||||||
|
|
|
@ -10,6 +10,9 @@ import * as utils from '../shared/utils/';
|
||||||
import * as testDb from '../shared/testDb';
|
import * as testDb from '../shared/testDb';
|
||||||
import type { INode } from 'n8n-workflow';
|
import type { INode } from 'n8n-workflow';
|
||||||
import { STARTING_NODES } from '@/constants';
|
import { STARTING_NODES } from '@/constants';
|
||||||
|
import { License } from '@/License';
|
||||||
|
import { WorkflowHistoryRepository } from '@/databases/repositories';
|
||||||
|
import Container from 'typedi';
|
||||||
|
|
||||||
let workflowOwnerRole: Role;
|
let workflowOwnerRole: Role;
|
||||||
let owner: User;
|
let owner: User;
|
||||||
|
@ -20,6 +23,11 @@ let workflowRunner: ActiveWorkflowRunner;
|
||||||
|
|
||||||
const testServer = utils.setupTestServer({ endpointGroups: ['publicApi'] });
|
const testServer = utils.setupTestServer({ endpointGroups: ['publicApi'] });
|
||||||
|
|
||||||
|
const licenseLike = utils.mockInstance(License, {
|
||||||
|
isWorkflowHistoryLicensed: jest.fn().mockReturnValue(false),
|
||||||
|
isWithinUsersLimit: jest.fn().mockReturnValue(true),
|
||||||
|
});
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const [globalOwnerRole, globalMemberRole, fetchedWorkflowOwnerRole] = await testDb.getAllRoles();
|
const [globalOwnerRole, globalMemberRole, fetchedWorkflowOwnerRole] = await testDb.getAllRoles();
|
||||||
|
|
||||||
|
@ -40,10 +48,18 @@ beforeAll(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['SharedCredentials', 'SharedWorkflow', 'Tag', 'Workflow', 'Credentials']);
|
await testDb.truncate([
|
||||||
|
'SharedCredentials',
|
||||||
|
'SharedWorkflow',
|
||||||
|
'Tag',
|
||||||
|
'Workflow',
|
||||||
|
'Credentials',
|
||||||
|
WorkflowHistoryRepository,
|
||||||
|
]);
|
||||||
|
|
||||||
authOwnerAgent = testServer.publicApiAgentFor(owner);
|
authOwnerAgent = testServer.publicApiAgentFor(owner);
|
||||||
authMemberAgent = testServer.publicApiAgentFor(member);
|
authMemberAgent = testServer.publicApiAgentFor(member);
|
||||||
|
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
|
@ -678,6 +694,90 @@ describe('POST /workflows', () => {
|
||||||
expect(sharedWorkflow?.role).toEqual(workflowOwnerRole);
|
expect(sharedWorkflow?.role).toEqual(workflowOwnerRole);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should create workflow history version when licensed', async () => {
|
||||||
|
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(true);
|
||||||
|
const payload = {
|
||||||
|
name: 'testing',
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'uuid-1234',
|
||||||
|
parameters: {},
|
||||||
|
name: 'Start',
|
||||||
|
type: 'n8n-nodes-base.start',
|
||||||
|
typeVersion: 1,
|
||||||
|
position: [240, 300],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
connections: {},
|
||||||
|
staticData: null,
|
||||||
|
settings: {
|
||||||
|
saveExecutionProgress: true,
|
||||||
|
saveManualExecutions: true,
|
||||||
|
saveDataErrorExecution: 'all',
|
||||||
|
saveDataSuccessExecution: 'all',
|
||||||
|
executionTimeout: 3600,
|
||||||
|
timezone: 'America/New_York',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await authMemberAgent.post('/workflows').send(payload);
|
||||||
|
|
||||||
|
expect(response.statusCode).toBe(200);
|
||||||
|
|
||||||
|
const { id } = response.body;
|
||||||
|
|
||||||
|
expect(id).toBeDefined();
|
||||||
|
expect(
|
||||||
|
await Container.get(WorkflowHistoryRepository).count({ where: { workflowId: id } }),
|
||||||
|
).toBe(1);
|
||||||
|
const historyVersion = await Container.get(WorkflowHistoryRepository).findOne({
|
||||||
|
where: {
|
||||||
|
workflowId: id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(historyVersion).not.toBeNull();
|
||||||
|
expect(historyVersion!.connections).toEqual(payload.connections);
|
||||||
|
expect(historyVersion!.nodes).toEqual(payload.nodes);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not create workflow history version when not licensed', async () => {
|
||||||
|
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false);
|
||||||
|
const payload = {
|
||||||
|
name: 'testing',
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'uuid-1234',
|
||||||
|
parameters: {},
|
||||||
|
name: 'Start',
|
||||||
|
type: 'n8n-nodes-base.start',
|
||||||
|
typeVersion: 1,
|
||||||
|
position: [240, 300],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
connections: {},
|
||||||
|
staticData: null,
|
||||||
|
settings: {
|
||||||
|
saveExecutionProgress: true,
|
||||||
|
saveManualExecutions: true,
|
||||||
|
saveDataErrorExecution: 'all',
|
||||||
|
saveDataSuccessExecution: 'all',
|
||||||
|
executionTimeout: 3600,
|
||||||
|
timezone: 'America/New_York',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await authMemberAgent.post('/workflows').send(payload);
|
||||||
|
|
||||||
|
expect(response.statusCode).toBe(200);
|
||||||
|
|
||||||
|
const { id } = response.body;
|
||||||
|
|
||||||
|
expect(id).toBeDefined();
|
||||||
|
expect(
|
||||||
|
await Container.get(WorkflowHistoryRepository).count({ where: { workflowId: id } }),
|
||||||
|
).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
test('should not add a starting node if the payload has no starting nodes', async () => {
|
test('should not add a starting node if the payload has no starting nodes', async () => {
|
||||||
const response = await authMemberAgent.post('/workflows').send({
|
const response = await authMemberAgent.post('/workflows').send({
|
||||||
name: 'testing',
|
name: 'testing',
|
||||||
|
@ -834,6 +934,108 @@ describe('PUT /workflows/:id', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should create workflow history version when licensed', async () => {
|
||||||
|
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(true);
|
||||||
|
const workflow = await testDb.createWorkflow({}, member);
|
||||||
|
const payload = {
|
||||||
|
name: 'name updated',
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'uuid-1234',
|
||||||
|
parameters: {},
|
||||||
|
name: 'Start',
|
||||||
|
type: 'n8n-nodes-base.start',
|
||||||
|
typeVersion: 1,
|
||||||
|
position: [240, 300],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'uuid-1234',
|
||||||
|
parameters: {},
|
||||||
|
name: 'Cron',
|
||||||
|
type: 'n8n-nodes-base.cron',
|
||||||
|
typeVersion: 1,
|
||||||
|
position: [400, 300],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
connections: {},
|
||||||
|
staticData: '{"id":1}',
|
||||||
|
settings: {
|
||||||
|
saveExecutionProgress: false,
|
||||||
|
saveManualExecutions: false,
|
||||||
|
saveDataErrorExecution: 'all',
|
||||||
|
saveDataSuccessExecution: 'all',
|
||||||
|
executionTimeout: 3600,
|
||||||
|
timezone: 'America/New_York',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await authMemberAgent.put(`/workflows/${workflow.id}`).send(payload);
|
||||||
|
|
||||||
|
const { id } = response.body;
|
||||||
|
|
||||||
|
expect(response.statusCode).toBe(200);
|
||||||
|
|
||||||
|
expect(id).toBe(workflow.id);
|
||||||
|
expect(
|
||||||
|
await Container.get(WorkflowHistoryRepository).count({ where: { workflowId: id } }),
|
||||||
|
).toBe(1);
|
||||||
|
const historyVersion = await Container.get(WorkflowHistoryRepository).findOne({
|
||||||
|
where: {
|
||||||
|
workflowId: id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(historyVersion).not.toBeNull();
|
||||||
|
expect(historyVersion!.connections).toEqual(payload.connections);
|
||||||
|
expect(historyVersion!.nodes).toEqual(payload.nodes);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not create workflow history when not licensed', async () => {
|
||||||
|
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false);
|
||||||
|
const workflow = await testDb.createWorkflow({}, member);
|
||||||
|
const payload = {
|
||||||
|
name: 'name updated',
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'uuid-1234',
|
||||||
|
parameters: {},
|
||||||
|
name: 'Start',
|
||||||
|
type: 'n8n-nodes-base.start',
|
||||||
|
typeVersion: 1,
|
||||||
|
position: [240, 300],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'uuid-1234',
|
||||||
|
parameters: {},
|
||||||
|
name: 'Cron',
|
||||||
|
type: 'n8n-nodes-base.cron',
|
||||||
|
typeVersion: 1,
|
||||||
|
position: [400, 300],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
connections: {},
|
||||||
|
staticData: '{"id":1}',
|
||||||
|
settings: {
|
||||||
|
saveExecutionProgress: false,
|
||||||
|
saveManualExecutions: false,
|
||||||
|
saveDataErrorExecution: 'all',
|
||||||
|
saveDataSuccessExecution: 'all',
|
||||||
|
executionTimeout: 3600,
|
||||||
|
timezone: 'America/New_York',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await authMemberAgent.put(`/workflows/${workflow.id}`).send(payload);
|
||||||
|
|
||||||
|
const { id } = response.body;
|
||||||
|
|
||||||
|
expect(response.statusCode).toBe(200);
|
||||||
|
|
||||||
|
expect(id).toBe(workflow.id);
|
||||||
|
expect(
|
||||||
|
await Container.get(WorkflowHistoryRepository).count({ where: { workflowId: id } }),
|
||||||
|
).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
test('should update non-owned workflow if owner', async () => {
|
test('should update non-owned workflow if owner', async () => {
|
||||||
const workflow = await testDb.createWorkflow({}, member);
|
const workflow = await testDb.createWorkflow({}, member);
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,8 @@ import { v4 as uuid } from 'uuid';
|
||||||
import { RoleService } from '@/services/role.service';
|
import { RoleService } from '@/services/role.service';
|
||||||
import Container from 'typedi';
|
import Container from 'typedi';
|
||||||
import type { ListQuery } from '@/requests';
|
import type { ListQuery } from '@/requests';
|
||||||
|
import { License } from '@/License';
|
||||||
|
import { WorkflowHistoryRepository } from '@/databases/repositories';
|
||||||
|
|
||||||
let owner: User;
|
let owner: User;
|
||||||
let authOwnerAgent: SuperAgentTest;
|
let authOwnerAgent: SuperAgentTest;
|
||||||
|
@ -20,13 +22,19 @@ const testServer = utils.setupTestServer({ endpointGroups: ['workflows'] });
|
||||||
|
|
||||||
const { objectContaining, arrayContaining, any } = expect;
|
const { objectContaining, arrayContaining, any } = expect;
|
||||||
|
|
||||||
|
const licenseLike = utils.mockInstance(License, {
|
||||||
|
isWorkflowHistoryLicensed: jest.fn().mockReturnValue(false),
|
||||||
|
isWithinUsersLimit: jest.fn().mockReturnValue(true),
|
||||||
|
});
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
owner = await testDb.createOwner();
|
owner = await testDb.createOwner();
|
||||||
authOwnerAgent = testServer.authAgentFor(owner);
|
authOwnerAgent = testServer.authAgentFor(owner);
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await testDb.truncate(['Workflow', 'SharedWorkflow', 'Tag']);
|
await testDb.truncate(['Workflow', 'SharedWorkflow', 'Tag', WorkflowHistoryRepository]);
|
||||||
|
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('POST /workflows', () => {
|
describe('POST /workflows', () => {
|
||||||
|
@ -46,6 +54,96 @@ describe('POST /workflows', () => {
|
||||||
const pinData = await testWithPinData(false);
|
const pinData = await testWithPinData(false);
|
||||||
expect(pinData).toBeNull();
|
expect(pinData).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should create workflow history version when licensed', async () => {
|
||||||
|
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(true);
|
||||||
|
const payload = {
|
||||||
|
name: 'testing',
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'uuid-1234',
|
||||||
|
parameters: {},
|
||||||
|
name: 'Start',
|
||||||
|
type: 'n8n-nodes-base.start',
|
||||||
|
typeVersion: 1,
|
||||||
|
position: [240, 300],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
connections: {},
|
||||||
|
staticData: null,
|
||||||
|
settings: {
|
||||||
|
saveExecutionProgress: true,
|
||||||
|
saveManualExecutions: true,
|
||||||
|
saveDataErrorExecution: 'all',
|
||||||
|
saveDataSuccessExecution: 'all',
|
||||||
|
executionTimeout: 3600,
|
||||||
|
timezone: 'America/New_York',
|
||||||
|
},
|
||||||
|
active: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await authOwnerAgent.post('/workflows').send(payload);
|
||||||
|
|
||||||
|
expect(response.statusCode).toBe(200);
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: { id },
|
||||||
|
} = response.body;
|
||||||
|
|
||||||
|
expect(id).toBeDefined();
|
||||||
|
expect(
|
||||||
|
await Container.get(WorkflowHistoryRepository).count({ where: { workflowId: id } }),
|
||||||
|
).toBe(1);
|
||||||
|
const historyVersion = await Container.get(WorkflowHistoryRepository).findOne({
|
||||||
|
where: {
|
||||||
|
workflowId: id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(historyVersion).not.toBeNull();
|
||||||
|
expect(historyVersion!.connections).toEqual(payload.connections);
|
||||||
|
expect(historyVersion!.nodes).toEqual(payload.nodes);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not create workflow history version when not licensed', async () => {
|
||||||
|
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false);
|
||||||
|
const payload = {
|
||||||
|
name: 'testing',
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'uuid-1234',
|
||||||
|
parameters: {},
|
||||||
|
name: 'Start',
|
||||||
|
type: 'n8n-nodes-base.start',
|
||||||
|
typeVersion: 1,
|
||||||
|
position: [240, 300],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
connections: {},
|
||||||
|
staticData: null,
|
||||||
|
settings: {
|
||||||
|
saveExecutionProgress: true,
|
||||||
|
saveManualExecutions: true,
|
||||||
|
saveDataErrorExecution: 'all',
|
||||||
|
saveDataSuccessExecution: 'all',
|
||||||
|
executionTimeout: 3600,
|
||||||
|
timezone: 'America/New_York',
|
||||||
|
},
|
||||||
|
active: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await authOwnerAgent.post('/workflows').send(payload);
|
||||||
|
|
||||||
|
expect(response.statusCode).toBe(200);
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: { id },
|
||||||
|
} = response.body;
|
||||||
|
|
||||||
|
expect(id).toBeDefined();
|
||||||
|
expect(
|
||||||
|
await Container.get(WorkflowHistoryRepository).count({ where: { workflowId: id } }),
|
||||||
|
).toBe(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('GET /workflows/:id', () => {
|
describe('GET /workflows/:id', () => {
|
||||||
|
@ -318,3 +416,111 @@ describe('GET /workflows', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('PATCH /workflows/:id', () => {
|
||||||
|
test('should create workflow history version when licensed', async () => {
|
||||||
|
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(true);
|
||||||
|
const workflow = await testDb.createWorkflow({}, owner);
|
||||||
|
const payload = {
|
||||||
|
name: 'name updated',
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'uuid-1234',
|
||||||
|
parameters: {},
|
||||||
|
name: 'Start',
|
||||||
|
type: 'n8n-nodes-base.start',
|
||||||
|
typeVersion: 1,
|
||||||
|
position: [240, 300],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'uuid-1234',
|
||||||
|
parameters: {},
|
||||||
|
name: 'Cron',
|
||||||
|
type: 'n8n-nodes-base.cron',
|
||||||
|
typeVersion: 1,
|
||||||
|
position: [400, 300],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
connections: {},
|
||||||
|
staticData: '{"id":1}',
|
||||||
|
settings: {
|
||||||
|
saveExecutionProgress: false,
|
||||||
|
saveManualExecutions: false,
|
||||||
|
saveDataErrorExecution: 'all',
|
||||||
|
saveDataSuccessExecution: 'all',
|
||||||
|
executionTimeout: 3600,
|
||||||
|
timezone: 'America/New_York',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await authOwnerAgent.patch(`/workflows/${workflow.id}`).send(payload);
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: { id },
|
||||||
|
} = response.body;
|
||||||
|
|
||||||
|
expect(response.statusCode).toBe(200);
|
||||||
|
|
||||||
|
expect(id).toBe(workflow.id);
|
||||||
|
expect(
|
||||||
|
await Container.get(WorkflowHistoryRepository).count({ where: { workflowId: id } }),
|
||||||
|
).toBe(1);
|
||||||
|
const historyVersion = await Container.get(WorkflowHistoryRepository).findOne({
|
||||||
|
where: {
|
||||||
|
workflowId: id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(historyVersion).not.toBeNull();
|
||||||
|
expect(historyVersion!.connections).toEqual(payload.connections);
|
||||||
|
expect(historyVersion!.nodes).toEqual(payload.nodes);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not create workflow history version when not licensed', async () => {
|
||||||
|
licenseLike.isWorkflowHistoryLicensed.mockReturnValue(false);
|
||||||
|
const workflow = await testDb.createWorkflow({}, owner);
|
||||||
|
const payload = {
|
||||||
|
name: 'name updated',
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'uuid-1234',
|
||||||
|
parameters: {},
|
||||||
|
name: 'Start',
|
||||||
|
type: 'n8n-nodes-base.start',
|
||||||
|
typeVersion: 1,
|
||||||
|
position: [240, 300],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'uuid-1234',
|
||||||
|
parameters: {},
|
||||||
|
name: 'Cron',
|
||||||
|
type: 'n8n-nodes-base.cron',
|
||||||
|
typeVersion: 1,
|
||||||
|
position: [400, 300],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
connections: {},
|
||||||
|
staticData: '{"id":1}',
|
||||||
|
settings: {
|
||||||
|
saveExecutionProgress: false,
|
||||||
|
saveManualExecutions: false,
|
||||||
|
saveDataErrorExecution: 'all',
|
||||||
|
saveDataSuccessExecution: 'all',
|
||||||
|
executionTimeout: 3600,
|
||||||
|
timezone: 'America/New_York',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await authOwnerAgent.patch(`/workflows/${workflow.id}`).send(payload);
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: { id },
|
||||||
|
} = response.body;
|
||||||
|
|
||||||
|
expect(response.statusCode).toBe(200);
|
||||||
|
|
||||||
|
expect(id).toBe(workflow.id);
|
||||||
|
expect(
|
||||||
|
await Container.get(WorkflowHistoryRepository).count({ where: { workflowId: id } }),
|
||||||
|
).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in a new issue