From 2d3b643f6e48a2a4d894db2cca1434f3d42851aa Mon Sep 17 00:00:00 2001 From: Alex Grozav Date: Tue, 21 Jan 2025 10:30:27 +0200 Subject: [PATCH] test: Update e2e tests for canvas specific actions (no-changelog) (#12614) --- cypress/composables/workflow.ts | 106 +++++++++++- cypress/e2e/12-canvas-actions.cy.ts | 4 + cypress/e2e/12-canvas.cy.ts | 161 ++++++++++++------ .../e2e/30-editor-after-route-changes.cy.ts | 2 +- cypress/pages/workflow.ts | 65 ++++--- cypress/support/commands.ts | 12 +- .../components/ContextMenu/ContextMenu.vue | 4 +- .../canvas/elements/nodes/CanvasNode.vue | 12 +- .../elements/nodes/CanvasNodeRenderer.vue | 12 +- 9 files changed, 283 insertions(+), 95 deletions(-) diff --git a/cypress/composables/workflow.ts b/cypress/composables/workflow.ts index 66782f02cf419..c3177775b47e2 100644 --- a/cypress/composables/workflow.ts +++ b/cypress/composables/workflow.ts @@ -1,6 +1,7 @@ import { getManualChatModal } from './modals/chat-modal'; import { clickGetBackToCanvas, getParameterInputByName } from './ndv'; import { ROUTES } from '../constants'; +import type { OpenContextMenuOptions } from '../types'; /** * Types @@ -24,7 +25,36 @@ export type EndpointType = * Getters */ -export function getAddInputEndpointByType(nodeName: string, endpointType: EndpointType) { +export function getCanvas() { + return cy.getByTestId('canvas'); +} + +export function getCanvasPane() { + return cy.ifCanvasVersion( + () => cy.getByTestId('node-view-background'), + () => getCanvas().find('.vue-flow__pane'), + ); +} + +export function getContextMenu() { + return cy.getByTestId('context-menu').find('.el-dropdown-menu'); +} + +export function getContextMenuAction(action: string) { + return cy.getByTestId(`context-menu-item-${action}`); +} + +export function getInputPlusHandle(nodeName: string) { + return cy.ifCanvasVersion( + () => cy.get(`.add-input-endpoint[data-endpoint-name="${nodeName}"]`), + () => + cy.get( + `[data-test-id="canvas-node-input-handle"][data-node-name="${nodeName}"] [data-test-id="canvas-handle-plus"]`, + ), + ); +} + +export function getInputPlusHandleByType(nodeName: string, endpointType: EndpointType) { return cy.ifCanvasVersion( () => cy.get( @@ -37,6 +67,29 @@ export function getAddInputEndpointByType(nodeName: string, endpointType: Endpoi ); } +export function getOutputPlusHandle(nodeName: string) { + return cy.ifCanvasVersion( + () => cy.get(`.add-output-endpoint[data-endpoint-name="${nodeName}"]`), + () => + cy.get( + `[data-test-id="canvas-node-output-handle"][data-node-name="${nodeName}"] [data-test-id="canvas-handle-plus"]`, + ), + ); +} + +export function getOutputPlusHandleByType(nodeName: string, endpointType: EndpointType) { + return cy.ifCanvasVersion( + () => + cy.get( + `.add-output-endpoint[data-jtk-scope-${endpointType}][data-endpoint-name="${nodeName}"]`, + ), + () => + cy.get( + `[data-test-id="canvas-node-output-handle"][data-connection-type="${endpointType}"][data-node-name="${nodeName}"] [data-test-id="canvas-handle-plus"]`, + ), + ); +} + export function getNodeCreatorItems() { return cy.getByTestId('item-iterator-item'); } @@ -60,6 +113,13 @@ export function getNodeByName(name: string) { ); } +export function getNodeRenderedTypeByName(name: string) { + return cy.ifCanvasVersion( + () => getNodeByName(name), + () => getNodeByName(name).find('[data-canvas-node-render-type]'), + ); +} + export function getWorkflowHistoryCloseButton() { return cy.getByTestId('workflow-history-close-button'); } @@ -85,6 +145,12 @@ export function getConnectionBySourceAndTarget(source: string, target: string) { ); } +export function getConnectionLabelBySourceAndTarget(source: string, target: string) { + return cy + .getByTestId('edge-label') + .filter(`[data-source-node-name="${source}"][data-target-node-name="${target}"]`); +} + export function getNodeCreatorSearchBar() { return cy.getByTestId('node-creator-search-bar'); } @@ -94,10 +160,7 @@ export function getNodeCreatorPlusButton() { } export function getCanvasNodes() { - return cy.ifCanvasVersion( - () => cy.getByTestId('canvas-node'), - () => cy.getByTestId('canvas-node').not('[data-node-type="n8n-nodes-internal.addNodes"]'), - ); + return cy.getByTestId('canvas-node'); } export function getCanvasNodeByName(nodeName: string) { @@ -157,7 +220,7 @@ function connectNodeToParent( parentNodeName: string, exactMatch = false, ) { - getAddInputEndpointByType(parentNodeName, endpointType).click({ force: true }); + getInputPlusHandleByType(parentNodeName, endpointType).click({ force: true }); if (exactMatch) { getNodeCreatorItems() .contains(new RegExp('^' + nodeName + '$', 'g')) @@ -257,3 +320,34 @@ export function deleteNode(name: string) { getCanvasNodeByName(name).first().click(); cy.get('body').type('{del}'); } + +export function openContextMenu( + nodeName?: string, + { method = 'right-click', anchor = 'center' }: OpenContextMenuOptions = {}, +) { + let target; + if (nodeName) { + target = + method === 'right-click' ? getNodeRenderedTypeByName(nodeName) : getNodeByName(nodeName); + } else { + target = getCanvasPane(); + } + + if (method === 'right-click') { + target.rightclick(nodeName ? anchor : 'topLeft', { force: true }); + } else { + target.realHover(); + target.find('[data-test-id="overflow-node-button"]').click({ force: true }); + } + + cy.ifCanvasVersion( + () => {}, + () => { + getContextMenu().should('be.visible'); + }, + ); +} + +export function clickContextMenuAction(action: string) { + getContextMenuAction(action).click(); +} diff --git a/cypress/e2e/12-canvas-actions.cy.ts b/cypress/e2e/12-canvas-actions.cy.ts index e9244a1d12660..e869f2af76ac4 100644 --- a/cypress/e2e/12-canvas-actions.cy.ts +++ b/cypress/e2e/12-canvas-actions.cy.ts @@ -184,7 +184,11 @@ describe('Canvas Actions', () => { .last() .findChildByTestId('execute-node-button') .click({ force: true }); + + successToast().should('have.length', 1); + WorkflowPage.actions.executeNode(CODE_NODE_NAME); + successToast().should('have.length', 2); successToast().should('contain.text', 'Node executed successfully'); }); diff --git a/cypress/e2e/12-canvas.cy.ts b/cypress/e2e/12-canvas.cy.ts index ecfb325de2738..c93180677a66f 100644 --- a/cypress/e2e/12-canvas.cy.ts +++ b/cypress/e2e/12-canvas.cy.ts @@ -7,9 +7,17 @@ import { SWITCH_NODE_NAME, MERGE_NODE_NAME, } from './../constants'; +import { + clickContextMenuAction, + getCanvasNodeByName, + getCanvasNodes, + getConnectionBySourceAndTarget, + getConnectionLabelBySourceAndTarget, + getOutputPlusHandle, + openContextMenu, +} from '../composables/workflow'; import { NDV, WorkflowExecutionsTab } from '../pages'; import { WorkflowPage as WorkflowPageClass } from '../pages/workflow'; -import { isCanvasV2 } from '../utils/workflowUtils'; const WorkflowPage = new WorkflowPageClass(); const ExecutionsTab = new WorkflowExecutionsTab(); @@ -41,27 +49,52 @@ describe('Canvas Node Manipulation and Navigation', () => { NDVDialog.actions.close(); for (let i = 0; i < desiredOutputs; i++) { - WorkflowPage.getters.canvasNodePlusEndpointByName(SWITCH_NODE_NAME, i).click({ force: true }); + cy.ifCanvasVersion( + () => { + WorkflowPage.getters + .canvasNodePlusEndpointByName(SWITCH_NODE_NAME, i) + .click({ force: true }); + }, + () => { + getOutputPlusHandle(SWITCH_NODE_NAME).eq(0).click(); + }, + ); WorkflowPage.getters.nodeCreatorSearchBar().should('be.visible'); WorkflowPage.actions.addNodeToCanvas(EDIT_FIELDS_SET_NODE_NAME, false); WorkflowPage.actions.zoomToFit(); } WorkflowPage.getters.nodeViewBackground().click({ force: true }); - WorkflowPage.getters.canvasNodePlusEndpointByName(`${EDIT_FIELDS_SET_NODE_NAME}3`).click(); + cy.ifCanvasVersion( + () => { + WorkflowPage.getters.canvasNodePlusEndpointByName(`${EDIT_FIELDS_SET_NODE_NAME}3`).click(); + }, + () => { + getOutputPlusHandle(`${EDIT_FIELDS_SET_NODE_NAME}3`).click(); + }, + ); WorkflowPage.actions.addNodeToCanvas(SWITCH_NODE_NAME, false); WorkflowPage.actions.saveWorkflowOnButtonClick(); cy.reload(); cy.waitForLoad(); // Make sure outputless switch was connected correctly - WorkflowPage.getters - .getConnectionBetweenNodes(`${EDIT_FIELDS_SET_NODE_NAME}3`, `${SWITCH_NODE_NAME}1`) - .should('exist'); + cy.ifCanvasVersion( + () => { + WorkflowPage.getters + .getConnectionBetweenNodes(`${EDIT_FIELDS_SET_NODE_NAME}3`, `${SWITCH_NODE_NAME}1`) + .should('exist'); + }, + () => { + getConnectionBySourceAndTarget( + `${EDIT_FIELDS_SET_NODE_NAME}3`, + `${SWITCH_NODE_NAME}1`, + ).should('exist'); + }, + ); // Make sure all connections are there after reload for (let i = 0; i < desiredOutputs; i++) { const setName = `${EDIT_FIELDS_SET_NODE_NAME}${i > 0 ? i : ''}`; - WorkflowPage.getters - .getConnectionBetweenNodes(`${SWITCH_NODE_NAME}`, setName) - .should('exist'); + + getConnectionBySourceAndTarget(`${SWITCH_NODE_NAME}`, setName).should('exist'); } }); @@ -84,14 +117,29 @@ describe('Canvas Node Manipulation and Navigation', () => { ); // Connect Set1 and Set2 to merge - cy.draganddrop( - WorkflowPage.getters.getEndpointSelector('plus', EDIT_FIELDS_SET_NODE_NAME), - WorkflowPage.getters.getEndpointSelector('input', MERGE_NODE_NAME, 0), - ); - cy.draganddrop( - WorkflowPage.getters.getEndpointSelector('plus', `${EDIT_FIELDS_SET_NODE_NAME}1`), - WorkflowPage.getters.getEndpointSelector('input', MERGE_NODE_NAME, 1), + cy.ifCanvasVersion( + () => { + cy.draganddrop( + WorkflowPage.getters.getEndpointSelector('plus', EDIT_FIELDS_SET_NODE_NAME), + WorkflowPage.getters.getEndpointSelector('input', MERGE_NODE_NAME, 0), + ); + cy.draganddrop( + WorkflowPage.getters.getEndpointSelector('plus', `${EDIT_FIELDS_SET_NODE_NAME}1`), + WorkflowPage.getters.getEndpointSelector('input', MERGE_NODE_NAME, 1), + ); + }, + () => { + cy.draganddrop( + WorkflowPage.getters.getEndpointSelector('output', EDIT_FIELDS_SET_NODE_NAME), + WorkflowPage.getters.getEndpointSelector('input', MERGE_NODE_NAME, 0), + ); + cy.draganddrop( + WorkflowPage.getters.getEndpointSelector('output', `${EDIT_FIELDS_SET_NODE_NAME}1`), + WorkflowPage.getters.getEndpointSelector('input', MERGE_NODE_NAME, 1), + ); + }, ); + const checkConnections = () => { WorkflowPage.getters .getConnectionBetweenNodes( @@ -117,10 +165,22 @@ describe('Canvas Node Manipulation and Navigation', () => { WorkflowPage.actions.executeWorkflow(); WorkflowPage.getters.stopExecutionButton().should('not.exist'); + // Make sure all connections are there after save & reload + WorkflowPage.actions.saveWorkflowOnButtonClick(); + cy.reload(); + cy.waitForLoad(); + checkConnections(); + + WorkflowPage.actions.executeWorkflow(); + WorkflowPage.getters.stopExecutionButton().should('not.exist'); + // If the merged set nodes are connected and executed correctly, there should be 2 items in the output of merge node cy.ifCanvasVersion( () => cy.get('[data-label="2 items"]').should('be.visible'), - () => cy.getByTestId('canvas-node-output-handle').contains('2 items').should('be.visible'), + () => + getConnectionLabelBySourceAndTarget(`${EDIT_FIELDS_SET_NODE_NAME}1`, MERGE_NODE_NAME) + .contains('2 items') + .should('be.visible'), ); }); @@ -144,7 +204,10 @@ describe('Canvas Node Manipulation and Navigation', () => { cy.ifCanvasVersion( () => cy.get('.plus-draggable-endpoint').should('have.class', 'ep-success'), - () => cy.getByTestId('canvas-handle-plus').should('have.attr', 'data-plus-type', 'success'), + () => + cy + .getByTestId('canvas-handle-plus-wrapper') + .should('have.attr', 'data-plus-type', 'success'), ); WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME); @@ -212,8 +275,8 @@ describe('Canvas Node Manipulation and Navigation', () => { WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME); cy.wait(500); WorkflowPage.actions.selectAllFromContextMenu(); - WorkflowPage.actions.openContextMenu(); - WorkflowPage.actions.contextMenuAction('delete'); + openContextMenu(); + clickContextMenuAction('delete'); WorkflowPage.getters.canvasNodes().should('have.length', 0); }); @@ -228,41 +291,43 @@ describe('Canvas Node Manipulation and Navigation', () => { WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME); cy.wait(500); WorkflowPage.actions.selectAllFromContextMenu(); - WorkflowPage.actions.openContextMenu(); - WorkflowPage.actions.contextMenuAction('delete'); + openContextMenu(); + clickContextMenuAction('delete'); WorkflowPage.getters.canvasNodes().should('have.length', 0); }); - // FIXME: Canvas V2: Figure out how to test moving of the node it('should move node', () => { WorkflowPage.actions.addNodeToCanvas(MANUAL_TRIGGER_NODE_NAME); WorkflowPage.getters.canvasNodeByName(MANUAL_TRIGGER_NODE_DISPLAY_NAME).click(); WorkflowPage.actions.addNodeToCanvas(CODE_NODE_NAME); WorkflowPage.actions.zoomToFit(); - WorkflowPage.getters - .canvasNodes() + + getCanvasNodes() .last() .then(($node) => { - const { left, top } = $node.position(); - - if (isCanvasV2()) { - cy.drag('.vue-flow__node', [300, 300], { - realMouse: true, - }); - } else { - cy.drag('[data-test-id="canvas-node"].jtk-drag-selected', [50, 150], { - clickToFinish: true, - }); - } - - WorkflowPage.getters - .canvasNodes() + const { x: x1, y: y1 } = $node[0].getBoundingClientRect(); + + cy.ifCanvasVersion( + () => { + cy.drag('[data-test-id="canvas-node"].jtk-drag-selected', [50, 150], { + clickToFinish: true, + }); + }, + () => { + cy.drag(getCanvasNodes().last(), [50, 150], { + realMouse: true, + abs: true, + }); + }, + ); + + getCanvasNodes() .last() .then(($node) => { - const { left: newLeft, top: newTop } = $node.position(); - expect(newLeft).to.be.greaterThan(left); - expect(newTop).to.be.greaterThan(top); + const { x: x2, y: y2 } = $node[0].getBoundingClientRect(); + expect(x2).to.be.greaterThan(x1); + expect(y2).to.be.greaterThan(y1); }); }); }); @@ -369,7 +434,7 @@ describe('Canvas Node Manipulation and Navigation', () => { WorkflowPage.actions.hitDisableNodeShortcut(); WorkflowPage.getters.disabledNodes().should('have.length', 0); WorkflowPage.actions.deselectAll(); - WorkflowPage.getters.canvasNodeByName(MANUAL_TRIGGER_NODE_DISPLAY_NAME).click(); + getCanvasNodeByName(MANUAL_TRIGGER_NODE_DISPLAY_NAME).click(); WorkflowPage.actions.hitDisableNodeShortcut(); WorkflowPage.getters.disabledNodes().should('have.length', 1); WorkflowPage.actions.hitSelectAll(); @@ -378,19 +443,19 @@ describe('Canvas Node Manipulation and Navigation', () => { // Context menu WorkflowPage.actions.hitSelectAll(); - WorkflowPage.actions.openContextMenu(); + openContextMenu(); WorkflowPage.actions.contextMenuAction('toggle_activation'); WorkflowPage.getters.disabledNodes().should('have.length', 0); - WorkflowPage.actions.openContextMenu(); + openContextMenu(); WorkflowPage.actions.contextMenuAction('toggle_activation'); WorkflowPage.getters.disabledNodes().should('have.length', 2); WorkflowPage.actions.deselectAll(); WorkflowPage.getters.canvasNodeByName(MANUAL_TRIGGER_NODE_DISPLAY_NAME).click(); - WorkflowPage.actions.openContextMenu(); + openContextMenu(); WorkflowPage.actions.contextMenuAction('toggle_activation'); WorkflowPage.getters.disabledNodes().should('have.length', 1); WorkflowPage.actions.hitSelectAll(); - WorkflowPage.actions.openContextMenu(); + openContextMenu(); WorkflowPage.actions.contextMenuAction('toggle_activation'); WorkflowPage.getters.disabledNodes().should('have.length', 2); }); @@ -466,7 +531,7 @@ describe('Canvas Node Manipulation and Navigation', () => { WorkflowPage.getters.canvasNodes().should('have.length', 2); WorkflowPage.getters.nodeConnections().should('have.length', 1); }); - // FIXME: Canvas V2: Credentials should show issue on the first open + it('should remove unknown credentials on pasting workflow', () => { cy.fixture('workflow-with-unknown-credentials.json').then((data) => { cy.get('body').paste(JSON.stringify(data)); diff --git a/cypress/e2e/30-editor-after-route-changes.cy.ts b/cypress/e2e/30-editor-after-route-changes.cy.ts index 307c4a9537a0d..89c66d2dab946 100644 --- a/cypress/e2e/30-editor-after-route-changes.cy.ts +++ b/cypress/e2e/30-editor-after-route-changes.cy.ts @@ -57,7 +57,7 @@ const editWorkflowMoreAndActivate = () => { position.left = $element.position().left; }); - cy.drag('[data-test-id="canvas-node"].jtk-drag-selected', [50, 200], { clickToFinish: true }); + cy.drag('[data-test-id="canvas-node"].jtk-drag-selected', [50, 200]); workflowPage.getters .canvasNodes() .last() diff --git a/cypress/pages/workflow.ts b/cypress/pages/workflow.ts index 69a1becc0280f..3552e68e08bcb 100644 --- a/cypress/pages/workflow.ts +++ b/cypress/pages/workflow.ts @@ -1,5 +1,6 @@ import { BasePage } from './base'; import { NodeCreator } from './features/node-creator'; +import { clickContextMenuAction, getCanvasPane, openContextMenu } from '../composables/workflow'; import { META_KEY } from '../constants'; import type { OpenContextMenuOptions } from '../types'; import { getVisibleSelect } from '../utils'; @@ -38,15 +39,7 @@ export class WorkflowPage extends BasePage { nodeCreatorSearchBar: () => cy.getByTestId('node-creator-search-bar'), nodeCreatorPlusButton: () => cy.getByTestId('node-creator-plus-button'), canvasPlusButton: () => cy.getByTestId('canvas-plus-button'), - canvasNodes: () => - cy.ifCanvasVersion( - () => cy.getByTestId('canvas-node'), - () => - cy - .getByTestId('canvas-node') - .not('[data-node-type="n8n-nodes-internal.addNodes"]') - .not('[data-node-type="n8n-nodes-base.stickyNote"]'), - ), + canvasNodes: () => cy.getByTestId('canvas-node'), canvasNodeByName: (nodeName: string) => this.getters.canvasNodes().filter(`:contains(${nodeName})`), nodeIssuesByName: (nodeName: string) => @@ -110,7 +103,7 @@ export class WorkflowPage extends BasePage { disabledNodes: () => cy.ifCanvasVersion( () => cy.get('.node-box.disabled'), - () => cy.get('[data-test-id*="node"][class*="disabled"]'), + () => cy.get('[data-canvas-node-render-type][class*="disabled"]'), ), selectedNodes: () => cy.ifCanvasVersion( @@ -288,71 +281,77 @@ export class WorkflowPage extends BasePage { nodeTypeName?: string, { method = 'right-click', anchor = 'center' }: OpenContextMenuOptions = {}, ) => { - const target = nodeTypeName - ? this.getters.canvasNodeByName(nodeTypeName) - : this.getters.nodeViewBackground(); + cy.ifCanvasVersion( + () => { + const target = nodeTypeName + ? this.getters.canvasNodeByName(nodeTypeName) + : this.getters.nodeViewBackground(); - if (method === 'right-click') { - target.rightclick(nodeTypeName ? anchor : 'topLeft', { force: true }); - } else { - target.realHover(); - target.find('[data-test-id="overflow-node-button"]').click({ force: true }); - } + if (method === 'right-click') { + target.rightclick(nodeTypeName ? anchor : 'topLeft', { force: true }); + } else { + target.realHover(); + target.find('[data-test-id="overflow-node-button"]').click({ force: true }); + } + }, + () => { + openContextMenu(nodeTypeName, { method, anchor }); + }, + ); }, openNode: (nodeTypeName: string) => { this.getters.canvasNodeByName(nodeTypeName).first().dblclick(); }, duplicateNode: (nodeTypeName: string) => { this.actions.openContextMenu(nodeTypeName); - this.actions.contextMenuAction('duplicate'); + clickContextMenuAction('duplicate'); }, deleteNodeFromContextMenu: (nodeTypeName: string) => { this.actions.openContextMenu(nodeTypeName); - this.actions.contextMenuAction('delete'); + clickContextMenuAction('delete'); }, executeNode: (nodeTypeName: string, options?: OpenContextMenuOptions) => { this.actions.openContextMenu(nodeTypeName, options); - this.actions.contextMenuAction('execute'); + clickContextMenuAction('execute'); }, addStickyFromContextMenu: () => { this.actions.openContextMenu(); - this.actions.contextMenuAction('add_sticky'); + clickContextMenuAction('add_sticky'); }, renameNode: (nodeTypeName: string) => { this.actions.openContextMenu(nodeTypeName); - this.actions.contextMenuAction('rename'); + clickContextMenuAction('rename'); }, copyNode: (nodeTypeName: string) => { this.actions.openContextMenu(nodeTypeName); - this.actions.contextMenuAction('copy'); + clickContextMenuAction('copy'); }, contextMenuAction: (action: string) => { this.getters.contextMenuAction(action).click(); }, disableNode: (nodeTypeName: string) => { this.actions.openContextMenu(nodeTypeName); - this.actions.contextMenuAction('toggle_activation'); + clickContextMenuAction('toggle_activation'); }, pinNode: (nodeTypeName: string) => { this.actions.openContextMenu(nodeTypeName); - this.actions.contextMenuAction('toggle_pin'); + clickContextMenuAction('toggle_pin'); }, openNodeFromContextMenu: (nodeTypeName: string) => { this.actions.openContextMenu(nodeTypeName, { method: 'overflow-button' }); - this.actions.contextMenuAction('open'); + clickContextMenuAction('open'); }, selectAllFromContextMenu: () => { this.actions.openContextMenu(); - this.actions.contextMenuAction('select_all'); + clickContextMenuAction('select_all'); }, deselectAll: () => { cy.ifCanvasVersion( () => { this.actions.openContextMenu(); - this.actions.contextMenuAction('deselect_all'); + clickContextMenuAction('deselect_all'); }, - // rightclick doesn't work with vueFlow canvas - () => this.getters.nodeViewBackground().click('topLeft'), + () => getCanvasPane().click('topLeft'), ); }, openExpressionEditorModal: () => { @@ -431,7 +430,7 @@ export class WorkflowPage extends BasePage { pinchToZoom: (steps: number, mode: 'zoomIn' | 'zoomOut' = 'zoomIn') => { cy.window().then((win) => { // Pinch-to-zoom simulates a 'wheel' event with ctrlKey: true (same as zooming by scrolling) - this.getters.nodeView().trigger('wheel', { + this.getters.canvasViewport().trigger('wheel', { force: true, bubbles: true, ctrlKey: true, diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 69d245d01a89d..158fe129ecab4 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -172,6 +172,7 @@ Cypress.Commands.add('drag', (selector, pos, options) => { }; if (options?.realMouse) { element.realMouseDown(); + element.realMouseMove(0, 0); element.realMouseMove(newPosition.x, newPosition.y); element.realMouseUp(); } else { @@ -218,8 +219,15 @@ Cypress.Commands.add('draganddrop', (draggableSelector, droppableSelector, optio const pageY = coords.top + coords.height / 2; if (draggableSelector) { - // We can't use realMouseDown here because it hangs headless run - cy.get(draggableSelector).trigger('mousedown'); + cy.ifCanvasVersion( + () => { + // We can't use realMouseDown here because it hangs headless run + cy.get(draggableSelector).trigger('mousedown'); + }, + () => { + cy.get(draggableSelector).realMouseDown(); + }, + ); } // We don't chain these commands to make sure cy.get is re-trying correctly cy.get(droppableSelector).realMouseMove(0, 0); diff --git a/packages/editor-ui/src/components/ContextMenu/ContextMenu.vue b/packages/editor-ui/src/components/ContextMenu/ContextMenu.vue index 0fd54b0a73345..2425559e8302e 100644 --- a/packages/editor-ui/src/components/ContextMenu/ContextMenu.vue +++ b/packages/editor-ui/src/components/ContextMenu/ContextMenu.vue @@ -29,7 +29,9 @@ function onActionSelect(item: string) { } function closeMenu(event: MouseEvent) { - event.preventDefault(); + if (event.cancelable) { + event.preventDefault(); + } event.stopPropagation(); contextMenu.close(); } diff --git a/packages/editor-ui/src/components/canvas/elements/nodes/CanvasNode.vue b/packages/editor-ui/src/components/canvas/elements/nodes/CanvasNode.vue index fd231ecc62cca..aee457bfecd13 100644 --- a/packages/editor-ui/src/components/canvas/elements/nodes/CanvasNode.vue +++ b/packages/editor-ui/src/components/canvas/elements/nodes/CanvasNode.vue @@ -16,7 +16,7 @@ import type { CanvasNodeEventBusEvents, CanvasEventBusEvents, } from '@/types'; -import { CanvasConnectionMode } from '@/types'; +import { CanvasNodeRenderType, CanvasConnectionMode } from '@/types'; import NodeIcon from '@/components/NodeIcon.vue'; import { useNodeTypesStore } from '@/stores/nodeTypes.store'; import CanvasNodeToolbar from '@/components/canvas/elements/nodes/CanvasNodeToolbar.vue'; @@ -107,6 +107,14 @@ const classes = computed(() => ({ ...Object.fromEntries([...nodeClasses.value].map((c) => [c, true])), })); +const renderType = computed(() => props.data.render.type); + +const dataTestId = computed(() => + [CanvasNodeRenderType.StickyNote, CanvasNodeRenderType.AddNodes].includes(renderType.value) + ? undefined + : 'canvas-node', +); + /** * Event bus */ @@ -330,7 +338,7 @@ onBeforeUnmount(() => {