diff --git a/cypress/e2e/10-undo-redo.cy.ts b/cypress/e2e/10-undo-redo.cy.ts index 28c99ac313..541da069c4 100644 --- a/cypress/e2e/10-undo-redo.cy.ts +++ b/cypress/e2e/10-undo-redo.cy.ts @@ -38,7 +38,7 @@ describe('Undo/Redo', () => { it('should undo/redo adding node in the middle', () => { WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME); WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME); - WorkflowPage.actions.addNodeBetweenFirstTwoNodes(CODE_NODE_NAME); + WorkflowPage.actions.addNodeBetweenNodes(SCHEDULE_TRIGGER_NODE_NAME, CODE_NODE_NAME, SET_NODE_NAME) WorkflowPage.actions.zoomToFit(); WorkflowPage.actions.hitUndo(); WorkflowPage.getters.canvasNodes().should('have.have.length', 2); diff --git a/cypress/e2e/12-canvas.cy.ts b/cypress/e2e/12-canvas.cy.ts index 343b63354c..c88e62035d 100644 --- a/cypress/e2e/12-canvas.cy.ts +++ b/cypress/e2e/12-canvas.cy.ts @@ -3,6 +3,7 @@ import { CODE_NODE_NAME, SCHEDULE_TRIGGER_NODE_NAME, SET_NODE_NAME, + HTTP_REQUEST_NODE_NAME, } from './../constants'; import { WorkflowPage as WorkflowPageClass } from '../pages/workflow'; @@ -61,14 +62,16 @@ describe('Canvas Actions', () => { it('should add note between two connected nodes', () => { WorkflowPage.actions.addNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME); WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME); - WorkflowPage.actions.addNodeBetweenFirstTwoNodes(SET_NODE_NAME); - WorkflowPage.getters.canvasNodes().should('have.length', 3); - WorkflowPage.getters.nodeConnections().should('have.length', 2); + WorkflowPage.actions.addNodeToCanvas(SET_NODE_NAME); + WorkflowPage.actions.zoomToFit(); + WorkflowPage.actions.addNodeBetweenNodes(CODE_NODE_NAME, SET_NODE_NAME, HTTP_REQUEST_NODE_NAME); + WorkflowPage.getters.canvasNodes().should('have.length', 4); + WorkflowPage.getters.nodeConnections().should('have.length', 3); // And last node should be pushed to the right WorkflowPage.getters .canvasNodes() .last() - .should('have.attr', 'style', 'left: 640px; top: 260px;'); + .should('have.attr', 'style', 'left: 860px; top: 260px;'); }); it('should delete node using node action button', () => { diff --git a/cypress/pages/workflow.ts b/cypress/pages/workflow.ts index f17ad0144c..d1e90e815c 100644 --- a/cypress/pages/workflow.ts +++ b/cypress/pages/workflow.ts @@ -80,6 +80,10 @@ export class WorkflowPage extends BasePage { nodeCreatorItems: () => cy.getByTestId('item-iterator-item'), ndvParameters: () => cy.getByTestId('parameter-item'), nodeCredentialsLabel: () => cy.getByTestId('credentials-label'), + getConnectionBetweenNodes: (sourceNodeName: string, targetNodeName: string) => + cy.get(`.jtk-connector[data-source-node="${sourceNodeName}"][data-target-node="${targetNodeName}"]`), + getConnectionActionsBetweenNodes: (sourceNodeName: string, targetNodeName: string) => + cy.get(`.connection-actions[data-source-node="${sourceNodeName}"][data-target-node="${targetNodeName}"]`), }; actions = { visit: () => { @@ -170,10 +174,14 @@ export class WorkflowPage extends BasePage { executeWorkflow: () => { this.getters.executeWorkflowButton().click(); }, - addNodeBetweenFirstTwoNodes: (nodeName: string) => { - this.getters.nodeConnections().first().realHover(); - cy.get('.connection-actions .add').first().click({ force: true }); - this.actions.addNodeToCanvas(nodeName, false); + addNodeBetweenNodes: (sourceNodeName: string, targetNodeName: string, newNodeName: string) => { + this.getters.getConnectionBetweenNodes(sourceNodeName, targetNodeName).first().realHover(); + this.getters.getConnectionActionsBetweenNodes(sourceNodeName, targetNodeName).find('.add').first().click({ force: true }); + this.actions.addNodeToCanvas(newNodeName, false); + }, + deleteNodeBetweenNodes: (sourceNodeName: string, targetNodeName: string, newNodeName: string) => { + this.getters.getConnectionBetweenNodes(sourceNodeName, targetNodeName).first().realHover(); + this.getters.getConnectionActionsBetweenNodes(sourceNodeName, targetNodeName).find('.delete').first().click({ force: true }); }, }; } diff --git a/packages/editor-ui/src/utils/nodeViewUtils.ts b/packages/editor-ui/src/utils/nodeViewUtils.ts index 9b8e5d8e0e..b3a4f50fcc 100644 --- a/packages/editor-ui/src/utils/nodeViewUtils.ts +++ b/packages/editor-ui/src/utils/nodeViewUtils.ts @@ -3,7 +3,7 @@ import { isNumber } from '@/utils'; import { NODE_OUTPUT_DEFAULT_KEY, STICKY_NODE_TYPE, QUICKSTART_NOTE_NAME } from '@/constants'; import { EndpointStyle, IBounds, INodeUi, XYPosition } from '@/Interface'; import { ArrayAnchorSpec, ConnectorSpec, OverlaySpec, PaintStyle } from '@jsplumb/common'; -import { Endpoint, Connection } from '@jsplumb/core'; +import { Endpoint, Connection, ConnectionEstablishedParams } from '@jsplumb/core'; import { N8nConnector } from '@/plugins/connectors/N8nCustomConnector'; import { closestNumberDivisibleBy } from '@/utils'; import { @@ -741,6 +741,21 @@ export const moveBackInputLabelPosition = (targetEndpoint: Endpoint) => { } }; +export const addConnectionTestData = ( + source: HTMLElement, + target: HTMLElement, + el: HTMLElement | undefined, +) => { + // TODO: Only do this if running in test mode + const sourceNodeName = source.getAttribute('data-name')?.toString(); + const targetNodeName = target.getAttribute('data-name')?.toString(); + + if (el && sourceNodeName && targetNodeName) { + el.setAttribute('data-source-node', sourceNodeName); + el.setAttribute('data-target-node', targetNodeName); + } +}; + export const addConnectionActionsOverlay = ( connection: Connection, onDelete: Function, @@ -756,15 +771,13 @@ export const addConnectionActionsOverlay = ( const deleteButton = document.createElement('button'); div.classList.add(OVERLAY_CONNECTION_ACTIONS_ID); + addConnectionTestData(component.source, component.target, div); addButton.classList.add('add'); deleteButton.classList.add('delete'); - addButton.innerHTML = getIcon('plus'); deleteButton.innerHTML = getIcon('trash'); - addButton.addEventListener('click', () => onAdd()); deleteButton.addEventListener('click', () => onDelete()); - // We have to manually trigger connection mouse events because the overlay // is not part of the connection element div.addEventListener('mouseout', () => @@ -773,7 +786,6 @@ export const addConnectionActionsOverlay = ( div.addEventListener('mouseover', () => connection.instance.fire(EVENT_CONNECTION_MOUSEOVER, component), ); - div.appendChild(addButton); div.appendChild(deleteButton); return div; diff --git a/packages/editor-ui/src/views/NodeView.vue b/packages/editor-ui/src/views/NodeView.vue index 22ee4d3679..6f82056eb0 100644 --- a/packages/editor-ui/src/views/NodeView.vue +++ b/packages/editor-ui/src/views/NodeView.vue @@ -2182,6 +2182,15 @@ export default mixins( }); }, ); + setTimeout(() => { + NodeViewUtils.addConnectionTestData( + info.source, + info.target, + 'canvas' in info.connection.connector + ? (info.connection.connector.canvas as HTMLElement) + : undefined, + ); + }, 0); } } catch (e) { console.error(e); // eslint-disable-line no-console