diff --git a/examples/nextjs/cypress/components/reactflow/basic-props.cy.tsx b/examples/nextjs/cypress/components/reactflow/basic-props.cy.tsx
index ff57d3d8..d777531e 100644
--- a/examples/nextjs/cypress/components/reactflow/basic-props.cy.tsx
+++ b/examples/nextjs/cypress/components/reactflow/basic-props.cy.tsx
@@ -17,7 +17,7 @@ describe(': Basic Props', () => {
it('drags a node', () => {
const styleBeforeDrag = Cypress.$('.react-flow__node:first').css('transform');
- cy.drag('.react-flow__node:first', { x: 200, y: 25 }).then(($el: any) => {
+ cy.drag('.react-flow__node:first', { x: 200, y: 25 }).then(($el: JQuery) => {
const styleAfterDrag = $el.css('transform');
expect(styleBeforeDrag).to.not.equal(styleAfterDrag);
});
@@ -43,7 +43,7 @@ describe(': Basic Props', () => {
it('can not drag a node', () => {
const styleBeforeDrag = Cypress.$('.react-flow__node:first').css('transform');
- cy.drag('.react-flow__node:first', { x: 200, y: 25 }).then(($el: any) => {
+ cy.drag('.react-flow__node:first', { x: 200, y: 25 }).then(($el: JQuery) => {
const styleAfterDrag = $el.css('transform');
expect(styleBeforeDrag).to.equal(styleAfterDrag);
});
@@ -63,7 +63,7 @@ describe(': Basic Props', () => {
it('drags a node', () => {
const styleBeforeDrag = Cypress.$('.react-flow__node:first').css('transform');
- cy.drag('.react-flow__node:first', { x: 200, y: 25 }).then(($el: any) => {
+ cy.drag('.react-flow__node:first', { x: 200, y: 25 }).then(($el: JQuery) => {
const styleAfterDrag = $el.css('transform');
expect(styleBeforeDrag).to.not.equal(styleAfterDrag);
});
@@ -195,5 +195,3 @@ describe(': Basic Props', () => {
cy.get('.react-flow').should('have.class', 'custom');
});
});
-
-// test specific helper component
diff --git a/examples/nextjs/cypress/components/reactflow/event-handlers.cy.tsx b/examples/nextjs/cypress/components/reactflow/event-handlers.cy.tsx
new file mode 100644
index 00000000..c75e8918
--- /dev/null
+++ b/examples/nextjs/cypress/components/reactflow/event-handlers.cy.tsx
@@ -0,0 +1,168 @@
+import { skipOn } from '@cypress/skip-test';
+
+import { nodes, edges } from '../../fixtures/simpleflow';
+import ControlledFlow from '../../support/ControlledFlow';
+
+describe(': Event handlers', () => {
+ describe('Node event handlers', () => {
+ it('handles onInit', () => {
+ const onInitSpy = cy.spy().as('onInitSpy');
+
+ cy.mount()
+ .wait(100)
+ .then(() => {
+ expect(onInitSpy.callCount).to.be.eq(1);
+ });
+ });
+
+ it('handles onNodeClick', () => {
+ const onNodeClickSpy = cy.spy().as('onNodeClickSpy');
+
+ cy.mount().then(() => {
+ expect(onNodeClickSpy.callCount).to.be.eq(0);
+ cy.get('.react-flow__node:first')
+ .click()
+ .then(() => {
+ expect(onNodeClickSpy.callCount).to.be.eq(1);
+ });
+ });
+ });
+
+ it('handles onNodeDrag handlers', () => {
+ const onNodeDragStart = cy.spy().as('onNodeDragStart');
+ const onNodeDrag = cy.spy().as('onNodeDrag');
+ const onNodeDragStop = cy.spy().as('onNodeDragStop');
+
+ cy.mount(
+
+ ).then(() => {
+ expect(onNodeDragStart.callCount).to.be.eq(0);
+ expect(onNodeDrag.callCount).to.be.eq(0);
+ expect(onNodeDragStop.callCount).to.be.eq(0);
+
+ cy.drag('.react-flow__node:first', { x: 200, y: 0 }).then(() => {
+ expect(onNodeDragStart.callCount).to.be.eq(1);
+ expect(onNodeDrag.callCount).to.be.eq(1);
+ expect(onNodeDragStop.callCount).to.be.eq(1);
+ });
+ });
+ });
+
+ it('handles onNodeMouse handlers', () => {
+ const onNodeMouseEnter = cy.spy().as('onNodeMouseEnter');
+ const onNodeMouseMove = cy.spy().as('onNodeMouseMove');
+ const onNodeMouseLeave = cy.spy().as('onNodeMouseLeave');
+ const onNodeContextMenu = cy.spy().as('onNodeContextMenu');
+ const onNodeDoubleClick = cy.spy().as('onNodeDoubleClick');
+
+ cy.mount(
+
+ )
+ .wait(200)
+ .then(() => {
+ expect(onNodeMouseEnter.callCount).to.be.eq(0);
+ expect(onNodeMouseMove.callCount).to.be.eq(0);
+ expect(onNodeMouseLeave.callCount).to.be.eq(0);
+ expect(onNodeContextMenu.callCount).to.be.eq(0);
+ expect(onNodeDoubleClick.callCount).to.be.eq(0);
+
+ const node = cy.get('.react-flow__node').contains('Node 1');
+
+ node
+ .rightclick()
+ .dblclick()
+ .then(() => {
+ expect(onNodeContextMenu.callCount).to.be.eq(1);
+ expect(onNodeDoubleClick.callCount).to.be.eq(1);
+ });
+
+ skipOn('firefox');
+
+ node
+ .realHover()
+ .realMouseMove(100, 100)
+ .then(() => {
+ expect(onNodeMouseEnter.callCount).to.be.gt(0);
+ expect(onNodeMouseMove.callCount).to.be.gt(0);
+ expect(onNodeMouseLeave.callCount).to.be.gt(0);
+ });
+ });
+ });
+ });
+ describe('Edge event handlers', () => {
+ it('handles onEdgeClick', () => {
+ const onEdgeClick = cy.spy().as('onEdgeClick');
+
+ cy.mount().then(() => {
+ expect(onEdgeClick.callCount).to.be.eq(0);
+ cy.get('.react-flow__edge:first')
+ .click()
+ .then(() => {
+ expect(onEdgeClick.callCount).to.be.eq(1);
+ });
+ });
+ });
+
+ it('handles onEdgeMouse handlers', () => {
+ const onEdgeMouseEnter = cy.spy().as('onEdgeMouseEnter');
+ const onEdgeMouseMove = cy.spy().as('onEdgeMouseMove');
+ const onEdgeMouseLeave = cy.spy().as('onEdgeMouseLeave');
+ const onEdgeContextMenu = cy.spy().as('onEdgeContextMenu');
+ const onEdgeDoubleClick = cy.spy().as('onEdgedoubleClick');
+
+ cy.mount(
+
+ )
+ .wait(200)
+ .then(() => {
+ expect(onEdgeMouseEnter.callCount).to.be.eq(0);
+ expect(onEdgeMouseMove.callCount).to.be.eq(0);
+ expect(onEdgeMouseLeave.callCount).to.be.eq(0);
+ expect(onEdgeContextMenu.callCount).to.be.eq(0);
+ expect(onEdgeDoubleClick.callCount).to.be.eq(0);
+
+ const edge = cy.get('.react-flow__edge:first');
+
+ edge
+ .rightclick()
+ .dblclick()
+ .then(() => {
+ expect(onEdgeContextMenu.callCount).to.be.eq(1);
+ });
+
+ skipOn('firefox');
+
+ edge
+ .realHover()
+ .realMouseMove(100, 100)
+ .then(() => {
+ expect(onEdgeMouseEnter.callCount).to.be.gt(0);
+ expect(onEdgeMouseMove.callCount).to.be.gt(0);
+ expect(onEdgeMouseLeave.callCount).to.be.gt(0);
+ });
+ });
+ });
+ });
+});
diff --git a/examples/nextjs/cypress/components/reactflow/uncontrolled.cy.tsx b/examples/nextjs/cypress/components/reactflow/uncontrolled.cy.tsx
index e0f6cfaa..5a5a264a 100644
--- a/examples/nextjs/cypress/components/reactflow/uncontrolled.cy.tsx
+++ b/examples/nextjs/cypress/components/reactflow/uncontrolled.cy.tsx
@@ -21,7 +21,7 @@ describe(': Uncontrolled Flow', () => {
it('drags a node', () => {
const styleBeforeDrag = Cypress.$('.react-flow__node:first').css('transform');
- cy.drag('.react-flow__node:first', { x: 200, y: 25 }).then(($el: any) => {
+ cy.drag('.react-flow__node:first', { x: 200, y: 25 }).then(($el: JQuery) => {
const styleAfterDrag = $el.css('transform');
expect(styleBeforeDrag).to.not.equal(styleAfterDrag);
});
diff --git a/examples/nextjs/cypress/support/commands.ts b/examples/nextjs/cypress/support/commands.ts
index 972d5d6a..eaca8e6f 100644
--- a/examples/nextjs/cypress/support/commands.ts
+++ b/examples/nextjs/cypress/support/commands.ts
@@ -1,5 +1,3 @@
-///
-
Cypress.Commands.add('drag', (selector, { x, y }) =>
cy.window().then((window) => {
const elementToDrag = cy.get(selector as string);
@@ -11,7 +9,7 @@ Cypress.Commands.add('drag', (selector, { x, y }) =>
const nextY: number = centerY + y;
return elementToDrag
- .trigger('mousedown', { which: 1, view: window })
+ .trigger('mousedown', { view: window })
.trigger('mousemove', nextX, nextY, { force: true })
.wait(50)
.trigger('mouseup', { view: window, force: true });
diff --git a/examples/nextjs/cypress/support/component.ts b/examples/nextjs/cypress/support/component.ts
index a84b87c0..85a19ff0 100644
--- a/examples/nextjs/cypress/support/component.ts
+++ b/examples/nextjs/cypress/support/component.ts
@@ -1,23 +1,9 @@
-// ***********************************************************
-// This example support/component.js is processed and
-// loaded automatically before your test files.
-//
-// This is a great place to put global configuration and
-// behavior that modifies Cypress.
-//
-// You can change the location of this file or turn off
-// automatically serving support files with the
-// 'supportFile' configuration option.
-//
-// You can read more here:
-// https://on.cypress.io/configuration
-// ***********************************************************
+///
+///
+///
-// Import commands.js using ES2015 syntax:
import './commands';
-
-// Alternatively you can use CommonJS syntax:
-// require('./commands')
+import 'cypress-real-events/support';
import { mount } from 'cypress/react18';
import { XYPosition } from 'reactflow';
@@ -26,6 +12,7 @@ import '../../styles/globals.css';
import '../../styles/rf-style.css';
declare global {
+ // eslint-disable-next-line @typescript-eslint/no-namespace
namespace Cypress {
interface Chainable {
mount: typeof mount;
diff --git a/examples/nextjs/package.json b/examples/nextjs/package.json
index f34b365a..be6e7013 100644
--- a/examples/nextjs/package.json
+++ b/examples/nextjs/package.json
@@ -21,8 +21,10 @@
"reactflow": "workspace:*"
},
"devDependencies": {
+ "@cypress/skip-test": "^2.6.1",
"@types/dagre": "^0.7.47",
"cypress": "^10.6.0",
+ "cypress-real-events": "^1.7.1",
"eslint": "^8.22.0",
"eslint-config-next": "12.2.2",
"next-global-css": "^1.3.1",
diff --git a/examples/nextjs/tsconfig.json b/examples/nextjs/tsconfig.json
index 09130c19..8fe71c7d 100644
--- a/examples/nextjs/tsconfig.json
+++ b/examples/nextjs/tsconfig.json
@@ -15,7 +15,7 @@
"jsx": "preserve",
"incremental": true,
"baseUrl": "./",
- "types": ["cypress"]
+ "types": ["cypress", "cypress-real-events"]
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
diff --git a/packages/core/src/hooks/useDrag/index.ts b/packages/core/src/hooks/useDrag/index.ts
index 1d91a3f5..025621d4 100644
--- a/packages/core/src/hooks/useDrag/index.ts
+++ b/packages/core/src/hooks/useDrag/index.ts
@@ -153,7 +153,7 @@ function useDrag({
.filter((event: MouseEvent) => {
const target = event.target as HTMLDivElement;
const isDraggable =
- event.button === 0 &&
+ !event.button &&
(!noDragClassName || !hasSelector(target, `.${noDragClassName}`, nodeRef)) &&
(!handleSelector || hasSelector(target, handleSelector, nodeRef));
diff --git a/yarn.lock b/yarn.lock
index 6813ddbc..838caa84 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1908,6 +1908,13 @@ __metadata:
languageName: node
linkType: hard
+"@cypress/skip-test@npm:^2.6.1":
+ version: 2.6.1
+ resolution: "@cypress/skip-test@npm:2.6.1"
+ checksum: 48ec912f162563ca8657b6f023b701f66ddc29083ed36ae96cd861087c828046c2abb36c6fa0b316bb74941a17b046ac3b143532218e4cdc6d78d7838a64a141
+ languageName: node
+ linkType: hard
+
"@cypress/xvfb@npm:^1.2.4":
version: 1.2.4
resolution: "@cypress/xvfb@npm:1.2.4"
@@ -4330,6 +4337,15 @@ __metadata:
languageName: node
linkType: hard
+"cypress-real-events@npm:^1.7.1":
+ version: 1.7.1
+ resolution: "cypress-real-events@npm:1.7.1"
+ peerDependencies:
+ cypress: ^4.x || ^5.x || ^6.x || ^7.x || ^8.x || ^9.x || ^10.x
+ checksum: b31c2facfa03e01e298926cd0925260b12474770fc1a3ce8998da21818db7e6d9fc2f9eb60d1771aa4ce3c29aca63d04da21e1a63e3bb117b1506a72ab0c3eb1
+ languageName: node
+ linkType: hard
+
"cypress@npm:^10.6.0":
version: 10.6.0
resolution: "cypress@npm:10.6.0"
@@ -8462,9 +8478,11 @@ __metadata:
version: 0.0.0-use.local
resolution: "reactflow-examples@workspace:examples/nextjs"
dependencies:
+ "@cypress/skip-test": ^2.6.1
"@preconstruct/next": ^4.0.0
"@types/dagre": ^0.7.47
cypress: ^10.6.0
+ cypress-real-events: ^1.7.1
dagre: ^0.8.5
eslint: ^8.22.0
eslint-config-next: 12.2.2