2024-01-19 05:44:54 -08:00
|
|
|
|
import { SCHEDULE_TRIGGER_NODE_NAME, EDIT_FIELDS_SET_NODE_NAME } from '../constants';
|
2024-09-18 00:19:33 -07:00
|
|
|
|
import { NDV, WorkflowExecutionsTab, WorkflowPage as WorkflowPageClass } from '../pages';
|
2024-06-25 02:14:02 -07:00
|
|
|
|
import { clearNotifications, errorToast, successToast } from '../pages/notifications';
|
2024-10-21 06:13:09 -07:00
|
|
|
|
import { isCanvasV2 } from '../utils/workflowUtils';
|
2023-02-16 02:41:25 -08:00
|
|
|
|
|
|
|
|
|
const workflowPage = new WorkflowPageClass();
|
2023-11-30 03:12:26 -08:00
|
|
|
|
const executionsTab = new WorkflowExecutionsTab();
|
2023-02-16 02:41:25 -08:00
|
|
|
|
const ndv = new NDV();
|
|
|
|
|
|
2023-02-24 09:07:35 -08:00
|
|
|
|
describe('Execution', () => {
|
2023-05-26 08:15:06 -07:00
|
|
|
|
beforeEach(() => {
|
|
|
|
|
workflowPage.actions.visit();
|
|
|
|
|
});
|
|
|
|
|
|
2023-02-16 02:41:25 -08:00
|
|
|
|
it('should test manual workflow', () => {
|
2024-06-12 23:39:53 -07:00
|
|
|
|
cy.createFixtureWorkflow('Manual_wait_set.json');
|
2023-02-16 02:41:25 -08:00
|
|
|
|
|
|
|
|
|
// Check workflow buttons
|
|
|
|
|
workflowPage.getters.executeWorkflowButton().should('be.visible');
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().should('not.exist');
|
|
|
|
|
workflowPage.getters.stopExecutionButton().should('not.exist');
|
|
|
|
|
workflowPage.getters.stopExecutionWaitingForWebhookButton().should('not.exist');
|
|
|
|
|
|
|
|
|
|
// Execute the workflow
|
|
|
|
|
workflowPage.getters.zoomToFitButton().click();
|
|
|
|
|
workflowPage.getters.executeWorkflowButton().click();
|
|
|
|
|
|
|
|
|
|
// Check workflow buttons
|
|
|
|
|
workflowPage.getters.executeWorkflowButton().get('.n8n-spinner').should('be.visible');
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().should('not.exist');
|
|
|
|
|
workflowPage.getters.stopExecutionButton().should('be.visible');
|
|
|
|
|
workflowPage.getters.stopExecutionWaitingForWebhookButton().should('not.exist');
|
|
|
|
|
|
|
|
|
|
// Check canvas nodes after 1st step (workflow passed the manual trigger node
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Manual')
|
|
|
|
|
.within(() => cy.get('.fa-check'))
|
2023-03-02 07:50:21 -08:00
|
|
|
|
.should('exist');
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Wait')
|
|
|
|
|
.within(() => cy.get('.fa-check').should('not.exist'));
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Wait')
|
|
|
|
|
.within(() => cy.get('.fa-sync-alt'))
|
2023-03-02 07:50:21 -08:00
|
|
|
|
.should('exist');
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Set')
|
|
|
|
|
.within(() => cy.get('.fa-check').should('not.exist'));
|
2023-02-16 02:41:25 -08:00
|
|
|
|
|
|
|
|
|
cy.wait(2000);
|
|
|
|
|
|
|
|
|
|
// Check canvas nodes after 2nd step (waiting node finished its execution and the http request node is about to start)
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Manual')
|
|
|
|
|
.within(() => cy.get('.fa-check'))
|
2023-03-02 07:50:21 -08:00
|
|
|
|
.should('exist');
|
2023-11-28 07:47:28 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Wait')
|
|
|
|
|
.within(() => cy.get('.fa-check'))
|
|
|
|
|
.should('exist');
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Set')
|
|
|
|
|
.within(() => cy.get('.fa-check'))
|
2023-03-02 07:50:21 -08:00
|
|
|
|
.should('exist');
|
2023-02-16 02:41:25 -08:00
|
|
|
|
|
2024-06-25 02:14:02 -07:00
|
|
|
|
successToast().should('be.visible');
|
|
|
|
|
clearNotifications();
|
|
|
|
|
|
2023-02-16 02:41:25 -08:00
|
|
|
|
// Clear execution data
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().should('be.visible');
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().click();
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().should('not.exist');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should test manual workflow stop', () => {
|
2024-06-12 23:39:53 -07:00
|
|
|
|
cy.createFixtureWorkflow('Manual_wait_set.json');
|
2023-02-16 02:41:25 -08:00
|
|
|
|
|
|
|
|
|
// Check workflow buttons
|
|
|
|
|
workflowPage.getters.executeWorkflowButton().should('be.visible');
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().should('not.exist');
|
|
|
|
|
workflowPage.getters.stopExecutionButton().should('not.exist');
|
|
|
|
|
workflowPage.getters.stopExecutionWaitingForWebhookButton().should('not.exist');
|
|
|
|
|
|
|
|
|
|
// Execute the workflow
|
|
|
|
|
workflowPage.getters.zoomToFitButton().click();
|
|
|
|
|
workflowPage.getters.executeWorkflowButton().click();
|
|
|
|
|
|
|
|
|
|
// Check workflow buttons
|
|
|
|
|
workflowPage.getters.executeWorkflowButton().get('.n8n-spinner').should('be.visible');
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().should('not.exist');
|
|
|
|
|
workflowPage.getters.stopExecutionButton().should('be.visible');
|
|
|
|
|
workflowPage.getters.stopExecutionWaitingForWebhookButton().should('not.exist');
|
|
|
|
|
|
|
|
|
|
// Check canvas nodes after 1st step (workflow passed the manual trigger node
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Manual')
|
|
|
|
|
.within(() => cy.get('.fa-check'))
|
2023-03-02 07:50:21 -08:00
|
|
|
|
.should('exist');
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Wait')
|
|
|
|
|
.within(() => cy.get('.fa-check').should('not.exist'));
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Wait')
|
|
|
|
|
.within(() => cy.get('.fa-sync-alt'))
|
2023-03-02 07:50:21 -08:00
|
|
|
|
.should('exist');
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Set')
|
|
|
|
|
.within(() => cy.get('.fa-check').should('not.exist'));
|
2023-02-16 02:41:25 -08:00
|
|
|
|
|
2024-06-25 02:14:02 -07:00
|
|
|
|
successToast().should('be.visible');
|
|
|
|
|
clearNotifications();
|
|
|
|
|
|
2023-08-09 02:12:27 -07:00
|
|
|
|
workflowPage.getters.stopExecutionButton().should('exist');
|
2023-02-16 02:41:25 -08:00
|
|
|
|
workflowPage.getters.stopExecutionButton().click();
|
|
|
|
|
|
|
|
|
|
// Check canvas nodes after workflow stopped
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Manual')
|
|
|
|
|
.within(() => cy.get('.fa-check'))
|
2023-03-02 07:50:21 -08:00
|
|
|
|
.should('exist');
|
2024-10-21 06:13:09 -07:00
|
|
|
|
|
|
|
|
|
if (isCanvasV2()) {
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Wait')
|
|
|
|
|
.within(() => cy.get('.fa-sync-alt').should('not.exist'));
|
|
|
|
|
} else {
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Wait')
|
|
|
|
|
.within(() => cy.get('.fa-sync-alt').should('not.be.visible'));
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Set')
|
|
|
|
|
.within(() => cy.get('.fa-check').should('not.exist'));
|
2023-02-16 02:41:25 -08:00
|
|
|
|
|
2024-06-25 02:14:02 -07:00
|
|
|
|
successToast().should('be.visible');
|
|
|
|
|
|
2023-02-16 02:41:25 -08:00
|
|
|
|
// Clear execution data
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().should('be.visible');
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().click();
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().should('not.exist');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should test webhook workflow', () => {
|
2024-06-12 23:39:53 -07:00
|
|
|
|
cy.createFixtureWorkflow('Webhook_wait_set.json');
|
2023-02-16 02:41:25 -08:00
|
|
|
|
|
|
|
|
|
// Check workflow buttons
|
|
|
|
|
workflowPage.getters.executeWorkflowButton().should('be.visible');
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().should('not.exist');
|
|
|
|
|
workflowPage.getters.stopExecutionButton().should('not.exist');
|
|
|
|
|
workflowPage.getters.stopExecutionWaitingForWebhookButton().should('not.exist');
|
|
|
|
|
|
|
|
|
|
// Execute the workflow
|
|
|
|
|
workflowPage.getters.zoomToFitButton().click();
|
|
|
|
|
workflowPage.getters.executeWorkflowButton().click();
|
|
|
|
|
|
|
|
|
|
// Check workflow buttons
|
|
|
|
|
workflowPage.getters.executeWorkflowButton().get('.n8n-spinner').should('be.visible');
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().should('not.exist');
|
|
|
|
|
workflowPage.getters.stopExecutionButton().should('not.exist');
|
|
|
|
|
workflowPage.getters.stopExecutionWaitingForWebhookButton().should('be.visible');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters.canvasNodes().first().dblclick();
|
|
|
|
|
|
|
|
|
|
ndv.getters.copyInput().click();
|
|
|
|
|
|
|
|
|
|
cy.grantBrowserPermissions('clipboardReadWrite', 'clipboardSanitizedWrite');
|
|
|
|
|
|
|
|
|
|
ndv.getters.backToCanvas().click();
|
|
|
|
|
|
|
|
|
|
cy.readClipboard().then((url) => {
|
|
|
|
|
cy.request({
|
|
|
|
|
method: 'GET',
|
|
|
|
|
url,
|
|
|
|
|
}).then((resp) => {
|
|
|
|
|
expect(resp.status).to.eq(200);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Check canvas nodes after 1st step (workflow passed the manual trigger node
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Webhook')
|
|
|
|
|
.within(() => cy.get('.fa-check'))
|
2023-03-02 07:50:21 -08:00
|
|
|
|
.should('exist');
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Wait')
|
|
|
|
|
.within(() => cy.get('.fa-check').should('not.exist'));
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Wait')
|
|
|
|
|
.within(() => cy.get('.fa-sync-alt'))
|
2023-03-02 07:50:21 -08:00
|
|
|
|
.should('exist');
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Set')
|
|
|
|
|
.within(() => cy.get('.fa-check').should('not.exist'));
|
2023-02-16 02:41:25 -08:00
|
|
|
|
|
|
|
|
|
cy.wait(2000);
|
|
|
|
|
|
|
|
|
|
// Check canvas nodes after 2nd step (waiting node finished its execution and the http request node is about to start)
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Webhook')
|
|
|
|
|
.within(() => cy.get('.fa-check'))
|
2023-03-02 07:50:21 -08:00
|
|
|
|
.should('exist');
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Set')
|
|
|
|
|
.within(() => cy.get('.fa-check'))
|
2023-03-02 07:50:21 -08:00
|
|
|
|
.should('exist');
|
2023-02-16 02:41:25 -08:00
|
|
|
|
|
2024-06-25 02:14:02 -07:00
|
|
|
|
successToast().should('be.visible');
|
|
|
|
|
clearNotifications();
|
|
|
|
|
|
2023-02-16 02:41:25 -08:00
|
|
|
|
// Clear execution data
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().should('be.visible');
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().click();
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().should('not.exist');
|
|
|
|
|
});
|
|
|
|
|
|
2024-10-21 06:13:09 -07:00
|
|
|
|
// FIXME: Canvas V2: Webhook should show waiting state but it doesn't
|
2023-02-16 02:41:25 -08:00
|
|
|
|
it('should test webhook workflow stop', () => {
|
2024-06-12 23:39:53 -07:00
|
|
|
|
cy.createFixtureWorkflow('Webhook_wait_set.json');
|
2023-02-16 02:41:25 -08:00
|
|
|
|
|
|
|
|
|
// Check workflow buttons
|
|
|
|
|
workflowPage.getters.executeWorkflowButton().should('be.visible');
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().should('not.exist');
|
|
|
|
|
workflowPage.getters.stopExecutionButton().should('not.exist');
|
|
|
|
|
workflowPage.getters.stopExecutionWaitingForWebhookButton().should('not.exist');
|
|
|
|
|
|
|
|
|
|
// Execute the workflow
|
|
|
|
|
workflowPage.getters.zoomToFitButton().click();
|
|
|
|
|
workflowPage.getters.executeWorkflowButton().click();
|
|
|
|
|
|
|
|
|
|
// Check workflow buttons
|
|
|
|
|
workflowPage.getters.executeWorkflowButton().get('.n8n-spinner').should('be.visible');
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().should('not.exist');
|
|
|
|
|
workflowPage.getters.stopExecutionButton().should('not.exist');
|
|
|
|
|
workflowPage.getters.stopExecutionWaitingForWebhookButton().should('be.visible');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters.canvasNodes().first().dblclick();
|
|
|
|
|
|
|
|
|
|
ndv.getters.copyInput().click();
|
|
|
|
|
|
|
|
|
|
cy.grantBrowserPermissions('clipboardReadWrite', 'clipboardSanitizedWrite');
|
|
|
|
|
|
|
|
|
|
ndv.getters.backToCanvas().click();
|
|
|
|
|
|
|
|
|
|
cy.readClipboard().then((url) => {
|
|
|
|
|
cy.request({
|
|
|
|
|
method: 'GET',
|
|
|
|
|
url,
|
|
|
|
|
}).then((resp) => {
|
|
|
|
|
expect(resp.status).to.eq(200);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2024-06-25 02:14:02 -07:00
|
|
|
|
successToast().should('be.visible');
|
|
|
|
|
clearNotifications();
|
|
|
|
|
|
2023-03-02 07:50:21 -08:00
|
|
|
|
workflowPage.getters.stopExecutionButton().click();
|
2023-02-16 02:41:25 -08:00
|
|
|
|
// Check canvas nodes after 1st step (workflow passed the manual trigger node
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Webhook')
|
|
|
|
|
.within(() => cy.get('.fa-check'))
|
2023-03-02 07:50:21 -08:00
|
|
|
|
.should('exist');
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Wait')
|
|
|
|
|
.within(() => cy.get('.fa-check').should('not.exist'));
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Wait')
|
|
|
|
|
.within(() => cy.get('.fa-sync-alt'))
|
2023-03-02 07:50:21 -08:00
|
|
|
|
.should('exist');
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Set')
|
|
|
|
|
.within(() => cy.get('.fa-check').should('not.exist'));
|
2023-02-16 02:41:25 -08:00
|
|
|
|
|
|
|
|
|
// Check canvas nodes after workflow stopped
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Webhook')
|
|
|
|
|
.within(() => cy.get('.fa-check'))
|
2023-03-02 07:50:21 -08:00
|
|
|
|
.should('exist');
|
2024-10-21 06:13:09 -07:00
|
|
|
|
|
|
|
|
|
if (isCanvasV2()) {
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Wait')
|
|
|
|
|
.within(() => cy.get('.fa-sync-alt').should('not.exist'));
|
|
|
|
|
} else {
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Wait')
|
|
|
|
|
.within(() => cy.get('.fa-sync-alt').should('not.be.visible'));
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-24 09:07:35 -08:00
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Set')
|
|
|
|
|
.within(() => cy.get('.fa-check').should('not.exist'));
|
2023-02-16 02:41:25 -08:00
|
|
|
|
|
2024-06-25 02:14:02 -07:00
|
|
|
|
successToast().should('be.visible');
|
|
|
|
|
|
2023-02-16 02:41:25 -08:00
|
|
|
|
// Clear execution data
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().should('be.visible');
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().click();
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().should('not.exist');
|
|
|
|
|
});
|
2023-11-30 03:12:26 -08:00
|
|
|
|
|
|
|
|
|
describe('execution preview', () => {
|
|
|
|
|
it('when deleting the last execution, it should show empty state', () => {
|
|
|
|
|
workflowPage.actions.addInitialNodeToCanvas('Manual Trigger');
|
|
|
|
|
workflowPage.actions.executeWorkflow();
|
|
|
|
|
executionsTab.actions.switchToExecutionsTab();
|
|
|
|
|
|
|
|
|
|
executionsTab.actions.deleteExecutionInPreview();
|
|
|
|
|
|
|
|
|
|
executionsTab.getters.successfulExecutionListItems().should('have.length', 0);
|
2024-06-11 01:23:30 -07:00
|
|
|
|
successToast().contains('Execution deleted');
|
2023-11-30 03:12:26 -08:00
|
|
|
|
});
|
|
|
|
|
});
|
2024-01-11 05:03:23 -08:00
|
|
|
|
|
2024-10-21 06:13:09 -07:00
|
|
|
|
// FIXME: Canvas V2: Missing pinned states for `edge-label-wrapper`
|
2024-01-11 05:03:23 -08:00
|
|
|
|
describe('connections should be colored differently for pinned data', () => {
|
|
|
|
|
beforeEach(() => {
|
2024-06-12 23:39:53 -07:00
|
|
|
|
cy.createFixtureWorkflow('Schedule_pinned.json');
|
2024-01-11 05:03:23 -08:00
|
|
|
|
workflowPage.actions.deselectAll();
|
|
|
|
|
workflowPage.getters.zoomToFitButton().click();
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Schedule Trigger', 'Edit Fields')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('have.class', 'pinned')
|
|
|
|
|
.should('not.have.class', 'has-run');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Schedule Trigger', 'Edit Fields1')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('have.class', 'pinned')
|
|
|
|
|
.should('not.have.class', 'has-run');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Edit Fields5', 'Edit Fields6')
|
|
|
|
|
.should('not.have.class', 'success')
|
|
|
|
|
.should('not.have.class', 'pinned');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Edit Fields7', 'Edit Fields9')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('have.class', 'pinned')
|
|
|
|
|
.should('not.have.class', 'has-run');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Edit Fields1', 'Edit Fields2')
|
|
|
|
|
.should('not.have.class', 'success')
|
|
|
|
|
.should('not.have.class', 'pinned');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Edit Fields2', 'Edit Fields3')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('have.class', 'pinned')
|
|
|
|
|
.should('not.have.class', 'has-run');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('when executing the workflow', () => {
|
|
|
|
|
workflowPage.actions.executeWorkflow();
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Schedule Trigger', 'Edit Fields')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('have.class', 'pinned')
|
|
|
|
|
.should('have.class', 'has-run');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Schedule Trigger', 'Edit Fields1')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('have.class', 'pinned')
|
|
|
|
|
.should('have.class', 'has-run');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Edit Fields5', 'Edit Fields6')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('not.have.class', 'pinned')
|
|
|
|
|
.should('not.have.class', 'has-run');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Edit Fields7', 'Edit Fields9')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('have.class', 'pinned')
|
|
|
|
|
.should('have.class', 'has-run');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Edit Fields1', 'Edit Fields2')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('not.have.class', 'pinned')
|
|
|
|
|
.should('not.have.class', 'has-run');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Edit Fields2', 'Edit Fields3')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('have.class', 'pinned')
|
|
|
|
|
.should('have.class', 'has-run');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('when executing a node', () => {
|
|
|
|
|
workflowPage.actions.executeNode('Edit Fields3');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Schedule Trigger', 'Edit Fields')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('have.class', 'pinned')
|
|
|
|
|
.should('have.class', 'has-run');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Schedule Trigger', 'Edit Fields1')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('have.class', 'pinned')
|
|
|
|
|
.should('have.class', 'has-run');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Edit Fields5', 'Edit Fields6')
|
|
|
|
|
.should('not.have.class', 'success')
|
|
|
|
|
.should('not.have.class', 'pinned')
|
|
|
|
|
.should('not.have.class', 'has-run');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Edit Fields7', 'Edit Fields9')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('have.class', 'pinned')
|
|
|
|
|
.should('not.have.class', 'has-run');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Edit Fields1', 'Edit Fields2')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('not.have.class', 'pinned')
|
|
|
|
|
.should('not.have.class', 'has-run');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Edit Fields2', 'Edit Fields3')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('have.class', 'pinned')
|
|
|
|
|
.should('have.class', 'has-run');
|
|
|
|
|
});
|
2024-01-19 05:44:54 -08:00
|
|
|
|
|
|
|
|
|
it('when connecting pinned node by output drag and drop', () => {
|
|
|
|
|
cy.drag(
|
|
|
|
|
workflowPage.getters.getEndpointSelector('output', SCHEDULE_TRIGGER_NODE_NAME),
|
|
|
|
|
[-200, -300],
|
|
|
|
|
);
|
|
|
|
|
workflowPage.getters.nodeCreatorSearchBar().should('be.visible');
|
|
|
|
|
workflowPage.actions.addNodeToCanvas(EDIT_FIELDS_SET_NODE_NAME, false);
|
|
|
|
|
cy.drag('[data-test-id="canvas-node"].jtk-drag-selected', [150, 200], {
|
|
|
|
|
clickToFinish: true,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Schedule Trigger', 'Edit Fields8')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('have.class', 'pinned')
|
|
|
|
|
.should('not.have.class', 'has-run');
|
|
|
|
|
|
|
|
|
|
workflowPage.actions.executeWorkflow();
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Schedule Trigger', 'Edit Fields8')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('have.class', 'pinned')
|
|
|
|
|
.should('have.class', 'has-run');
|
|
|
|
|
|
|
|
|
|
cy.drag(workflowPage.getters.getEndpointSelector('output', 'Edit Fields2'), [-200, -300]);
|
|
|
|
|
workflowPage.getters.nodeCreatorSearchBar().should('be.visible');
|
|
|
|
|
workflowPage.actions.addNodeToCanvas(EDIT_FIELDS_SET_NODE_NAME, false);
|
|
|
|
|
cy.drag('[data-test-id="canvas-node"].jtk-drag-selected', [150, 200], {
|
|
|
|
|
clickToFinish: true,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Edit Fields2', 'Edit Fields11')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('have.class', 'pinned')
|
|
|
|
|
.should('have.class', 'has-run');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('when connecting pinned node after adding an unconnected node', () => {
|
|
|
|
|
workflowPage.actions.addNodeToCanvas(EDIT_FIELDS_SET_NODE_NAME);
|
|
|
|
|
|
|
|
|
|
cy.draganddrop(
|
|
|
|
|
workflowPage.getters.getEndpointSelector('output', SCHEDULE_TRIGGER_NODE_NAME),
|
|
|
|
|
workflowPage.getters.getEndpointSelector('input', 'Edit Fields8'),
|
|
|
|
|
);
|
|
|
|
|
workflowPage.getters.zoomToFitButton().click();
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Schedule Trigger', 'Edit Fields8')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('have.class', 'pinned')
|
|
|
|
|
.should('not.have.class', 'has-run');
|
|
|
|
|
|
|
|
|
|
workflowPage.actions.executeWorkflow();
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Schedule Trigger', 'Edit Fields8')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('have.class', 'pinned')
|
|
|
|
|
.should('have.class', 'has-run');
|
|
|
|
|
|
|
|
|
|
workflowPage.actions.deselectAll();
|
|
|
|
|
workflowPage.actions.addNodeToCanvas(EDIT_FIELDS_SET_NODE_NAME);
|
|
|
|
|
workflowPage.getters.zoomToFitButton().click();
|
|
|
|
|
|
|
|
|
|
cy.draganddrop(
|
|
|
|
|
workflowPage.getters.getEndpointSelector('output', 'Edit Fields7'),
|
|
|
|
|
workflowPage.getters.getEndpointSelector('input', 'Edit Fields11'),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.getConnectionBetweenNodes('Edit Fields7', 'Edit Fields11')
|
|
|
|
|
.should('have.class', 'success')
|
|
|
|
|
.should('have.class', 'pinned')
|
|
|
|
|
.should('have.class', 'has-run');
|
|
|
|
|
});
|
2024-01-11 05:03:23 -08:00
|
|
|
|
});
|
2024-02-16 08:24:07 -08:00
|
|
|
|
|
2024-02-19 04:02:20 -08:00
|
|
|
|
it('should send proper payload for node rerun', () => {
|
2024-11-13 08:10:34 -08:00
|
|
|
|
cy.viewport(1920, 1080);
|
2024-06-12 23:39:53 -07:00
|
|
|
|
cy.createFixtureWorkflow('Multiple_trigger_node_rerun.json', 'Multiple trigger node rerun');
|
2024-02-16 08:24:07 -08:00
|
|
|
|
|
|
|
|
|
workflowPage.getters.zoomToFitButton().click();
|
|
|
|
|
workflowPage.getters.executeWorkflowButton().click();
|
|
|
|
|
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().should('be.visible');
|
|
|
|
|
|
2024-09-18 06:06:36 -07:00
|
|
|
|
cy.intercept('POST', '/rest/workflows/**/run?**').as('workflowRun');
|
2024-02-16 08:24:07 -08:00
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('do something with them')
|
|
|
|
|
.findChildByTestId('execute-node-button')
|
|
|
|
|
.click({ force: true });
|
|
|
|
|
|
|
|
|
|
cy.wait('@workflowRun').then((interception) => {
|
|
|
|
|
expect(interception.request.body).to.have.property('runData').that.is.an('object');
|
2024-05-30 07:53:33 -07:00
|
|
|
|
const expectedKeys = ['When clicking ‘Test workflow’', 'fetch 5 random users'];
|
2024-02-16 08:24:07 -08:00
|
|
|
|
|
2024-06-10 06:49:50 -07:00
|
|
|
|
const { runData } = interception.request.body as Record<string, object>;
|
|
|
|
|
expect(Object.keys(runData)).to.have.lengthOf(expectedKeys.length);
|
|
|
|
|
expect(runData).to.include.all.keys(expectedKeys);
|
2024-02-16 08:24:07 -08:00
|
|
|
|
});
|
|
|
|
|
});
|
2024-02-19 04:02:20 -08:00
|
|
|
|
|
|
|
|
|
it('should send proper payload for manual node run', () => {
|
2024-06-12 23:39:53 -07:00
|
|
|
|
cy.createFixtureWorkflow('Check_manual_node_run_for_pinned_and_rundata.json');
|
2024-02-19 04:02:20 -08:00
|
|
|
|
|
|
|
|
|
workflowPage.getters.zoomToFitButton().click();
|
|
|
|
|
|
2024-09-18 06:06:36 -07:00
|
|
|
|
cy.intercept('POST', '/rest/workflows/**/run?**').as('workflowRun');
|
2024-02-19 04:02:20 -08:00
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('If')
|
|
|
|
|
.findChildByTestId('execute-node-button')
|
|
|
|
|
.click({ force: true });
|
|
|
|
|
|
|
|
|
|
cy.wait('@workflowRun').then((interception) => {
|
|
|
|
|
expect(interception.request.body).not.to.have.property('runData').that.is.an('object');
|
2024-06-12 05:11:39 -07:00
|
|
|
|
expect(interception.request.body).to.have.property('workflowData').that.is.an('object');
|
|
|
|
|
expect(interception.request.body.workflowData)
|
|
|
|
|
.to.have.property('pinData')
|
|
|
|
|
.that.is.an('object');
|
2024-02-19 04:02:20 -08:00
|
|
|
|
const expectedPinnedDataKeys = ['Webhook'];
|
|
|
|
|
|
2024-06-12 05:11:39 -07:00
|
|
|
|
const { pinData } = interception.request.body.workflowData as Record<string, object>;
|
2024-06-10 06:49:50 -07:00
|
|
|
|
expect(Object.keys(pinData)).to.have.lengthOf(expectedPinnedDataKeys.length);
|
|
|
|
|
expect(pinData).to.include.all.keys(expectedPinnedDataKeys);
|
2024-02-19 04:02:20 -08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
workflowPage.getters.clearExecutionDataButton().should('be.visible');
|
|
|
|
|
|
2024-09-18 06:06:36 -07:00
|
|
|
|
cy.intercept('POST', '/rest/workflows/**/run?**').as('workflowRun');
|
2024-02-19 04:02:20 -08:00
|
|
|
|
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('NoOp2')
|
|
|
|
|
.findChildByTestId('execute-node-button')
|
|
|
|
|
.click({ force: true });
|
|
|
|
|
|
|
|
|
|
cy.wait('@workflowRun').then((interception) => {
|
|
|
|
|
expect(interception.request.body).to.have.property('runData').that.is.an('object');
|
2024-06-12 05:11:39 -07:00
|
|
|
|
expect(interception.request.body).to.have.property('workflowData').that.is.an('object');
|
|
|
|
|
expect(interception.request.body.workflowData)
|
|
|
|
|
.to.have.property('pinData')
|
|
|
|
|
.that.is.an('object');
|
2024-02-19 04:02:20 -08:00
|
|
|
|
const expectedPinnedDataKeys = ['Webhook'];
|
|
|
|
|
const expectedRunDataKeys = ['If', 'Webhook'];
|
|
|
|
|
|
2024-06-12 05:11:39 -07:00
|
|
|
|
const { pinData } = interception.request.body.workflowData as Record<string, object>;
|
2024-06-10 06:49:50 -07:00
|
|
|
|
expect(Object.keys(pinData)).to.have.lengthOf(expectedPinnedDataKeys.length);
|
|
|
|
|
expect(pinData).to.include.all.keys(expectedPinnedDataKeys);
|
2024-02-19 04:02:20 -08:00
|
|
|
|
|
2024-06-12 05:11:39 -07:00
|
|
|
|
const { runData } = interception.request.body as Record<string, object>;
|
2024-06-10 06:49:50 -07:00
|
|
|
|
expect(Object.keys(runData)).to.have.lengthOf(expectedRunDataKeys.length);
|
|
|
|
|
expect(runData).to.include.all.keys(expectedRunDataKeys);
|
2024-02-19 04:02:20 -08:00
|
|
|
|
});
|
|
|
|
|
});
|
2024-02-23 02:43:08 -08:00
|
|
|
|
|
|
|
|
|
it('should successfully execute partial executions with nodes attached to the second output', () => {
|
2024-06-12 23:39:53 -07:00
|
|
|
|
cy.createFixtureWorkflow('Test_Workflow_pairedItem_incomplete_manual_bug.json');
|
2024-02-23 02:43:08 -08:00
|
|
|
|
|
2024-09-18 06:06:36 -07:00
|
|
|
|
cy.intercept('POST', '/rest/workflows/**/run?**').as('workflowRun');
|
2024-02-23 02:43:08 -08:00
|
|
|
|
|
|
|
|
|
workflowPage.getters.zoomToFitButton().click();
|
|
|
|
|
workflowPage.getters.executeWorkflowButton().click();
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Test Expression')
|
|
|
|
|
.findChildByTestId('execute-node-button')
|
|
|
|
|
.click({ force: true });
|
|
|
|
|
|
|
|
|
|
// Check toast (works because Cypress waits enough for the element to show after the http request node has finished)
|
|
|
|
|
// Wait for the execution to return.
|
|
|
|
|
cy.wait('@workflowRun');
|
|
|
|
|
// Wait again for the websocket message to arrive and the UI to update.
|
|
|
|
|
cy.wait(100);
|
2024-06-11 01:23:30 -07:00
|
|
|
|
errorToast({ timeout: 1 }).should('not.exist');
|
2024-02-23 02:43:08 -08:00
|
|
|
|
});
|
2024-04-03 04:35:06 -07:00
|
|
|
|
|
|
|
|
|
it('should execute workflow partially up to the node that has issues', () => {
|
2024-06-12 23:39:53 -07:00
|
|
|
|
cy.createFixtureWorkflow('Test_workflow_partial_execution_with_missing_credentials.json');
|
2024-04-03 04:35:06 -07:00
|
|
|
|
|
2024-09-18 06:06:36 -07:00
|
|
|
|
cy.intercept('POST', '/rest/workflows/**/run?**').as('workflowRun');
|
2024-04-03 04:35:06 -07:00
|
|
|
|
|
|
|
|
|
workflowPage.getters.zoomToFitButton().click();
|
|
|
|
|
workflowPage.getters.executeWorkflowButton().click();
|
|
|
|
|
|
|
|
|
|
// Wait for the execution to return.
|
|
|
|
|
cy.wait('@workflowRun');
|
|
|
|
|
|
|
|
|
|
// Check that the previous nodes executed successfully
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('DebugHelper')
|
|
|
|
|
.within(() => cy.get('.fa-check'))
|
|
|
|
|
.should('exist');
|
|
|
|
|
workflowPage.getters
|
|
|
|
|
.canvasNodeByName('Filter')
|
|
|
|
|
.within(() => cy.get('.fa-check'))
|
|
|
|
|
.should('exist');
|
|
|
|
|
|
2024-06-11 01:23:30 -07:00
|
|
|
|
errorToast().should('contain', 'Problem in node ‘Telegram‘');
|
2024-04-03 04:35:06 -07:00
|
|
|
|
});
|
2024-08-30 02:37:24 -07:00
|
|
|
|
|
|
|
|
|
it('should not show pinned data in production execution', () => {
|
|
|
|
|
cy.createFixtureWorkflow('Execution-pinned-data-check.json');
|
|
|
|
|
|
|
|
|
|
workflowPage.getters.zoomToFitButton().click();
|
|
|
|
|
cy.intercept('PATCH', '/rest/workflows/*').as('workflowActivate');
|
|
|
|
|
workflowPage.getters.activatorSwitch().click();
|
|
|
|
|
|
|
|
|
|
cy.wait('@workflowActivate');
|
|
|
|
|
cy.get('body').type('{esc}');
|
|
|
|
|
workflowPage.actions.openNode('Webhook');
|
|
|
|
|
|
|
|
|
|
cy.contains('label', 'Production URL').should('be.visible').click();
|
|
|
|
|
cy.grantBrowserPermissions('clipboardReadWrite', 'clipboardSanitizedWrite');
|
|
|
|
|
cy.get('.webhook-url').click();
|
|
|
|
|
ndv.getters.backToCanvas().click();
|
|
|
|
|
|
|
|
|
|
cy.readClipboard().then((url) => {
|
|
|
|
|
cy.request({
|
|
|
|
|
method: 'GET',
|
|
|
|
|
url,
|
|
|
|
|
}).then((resp) => {
|
|
|
|
|
expect(resp.status).to.eq(200);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
cy.intercept('GET', '/rest/executions/*').as('getExecution');
|
|
|
|
|
executionsTab.actions.switchToExecutionsTab();
|
|
|
|
|
|
|
|
|
|
cy.wait('@getExecution');
|
|
|
|
|
executionsTab.getters
|
|
|
|
|
.workflowExecutionPreviewIframe()
|
|
|
|
|
.should('be.visible')
|
|
|
|
|
.its('0.contentDocument.body')
|
|
|
|
|
.should('not.be.empty')
|
|
|
|
|
|
|
|
|
|
.then(cy.wrap)
|
|
|
|
|
.find('.connection-run-items-label')
|
|
|
|
|
.filter(':contains("5 items")')
|
|
|
|
|
.should('have.length', 2);
|
|
|
|
|
});
|
2023-02-16 02:41:25 -08:00
|
|
|
|
});
|