From 438a318d8f612be8e333b668c8394edbba8c4430 Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 22 Aug 2022 18:23:38 +0200 Subject: [PATCH] test(components): add component tests, use ts for e2e tests --- .../nextjs/cypress.config.js | 7 ++ .../nextjs/cypress/e2e/basic.cy.ts | 28 +++---- .../nextjs/cypress/e2e/controls.cy.ts | 2 + .../nextjs/cypress/e2e/draghandle.cy.ts | 2 + .../nextjs/cypress/e2e/empty.cy.ts | 16 ++-- .../nextjs/cypress/e2e/graph-utils.cy.ts | 27 +++---- .../nextjs/cypress/e2e/hidden.cy.ts | 2 + .../nextjs/cypress/e2e/interaction.cy.ts | 35 +++------ .../nextjs/cypress/e2e/minimap.cy.ts | 38 +++------- examples/nextjs/cypress/fixtures/example.json | 5 ++ .../nextjs/cypress/support/commands.ts | 22 +++--- .../cypress/support/component-index.html | 14 ++++ examples/nextjs/cypress/support/component.ts | 39 ++++++++++ .../nextjs/cypress/support/e2e.ts | 0 examples/nextjs/next.config.js | 9 ++- examples/nextjs/package.json | 5 +- examples/nextjs/styles/globals.css | 3 +- .../nextjs/tests/useOnViewportChange.cy.tsx | 76 +++++++++++++++++++ examples/nextjs/tsconfig.json | 8 +- package.json | 4 +- yarn.lock | 13 ++++ 21 files changed, 243 insertions(+), 112 deletions(-) rename cypress.config.js => examples/nextjs/cypress.config.js (67%) rename cypress/e2e/basic.cy.js => examples/nextjs/cypress/e2e/basic.cy.ts (91%) rename cypress/e2e/controls.cy.js => examples/nextjs/cypress/e2e/controls.cy.ts (99%) rename cypress/e2e/draghandle.cy.js => examples/nextjs/cypress/e2e/draghandle.cy.ts (98%) rename cypress/e2e/empty.cy.js => examples/nextjs/cypress/e2e/empty.cy.ts (69%) rename cypress/e2e/graph-utils.cy.js => examples/nextjs/cypress/e2e/graph-utils.cy.ts (77%) rename cypress/e2e/hidden.cy.js => examples/nextjs/cypress/e2e/hidden.cy.ts (98%) rename cypress/e2e/interaction.cy.js => examples/nextjs/cypress/e2e/interaction.cy.ts (92%) rename cypress/e2e/minimap.cy.js => examples/nextjs/cypress/e2e/minimap.cy.ts (82%) create mode 100644 examples/nextjs/cypress/fixtures/example.json rename cypress/support/commands.js => examples/nextjs/cypress/support/commands.ts (73%) create mode 100644 examples/nextjs/cypress/support/component-index.html create mode 100644 examples/nextjs/cypress/support/component.ts rename cypress/support/e2e.js => examples/nextjs/cypress/support/e2e.ts (100%) create mode 100644 examples/nextjs/tests/useOnViewportChange.cy.tsx diff --git a/cypress.config.js b/examples/nextjs/cypress.config.js similarity index 67% rename from cypress.config.js rename to examples/nextjs/cypress.config.js index 842b7fff..7e24d96b 100644 --- a/cypress.config.js +++ b/examples/nextjs/cypress.config.js @@ -7,4 +7,11 @@ module.exports = defineConfig({ viewportHeight: 720, video: false, }, + + component: { + devServer: { + framework: 'next', + bundler: 'webpack', + }, + }, }); diff --git a/cypress/e2e/basic.cy.js b/examples/nextjs/cypress/e2e/basic.cy.ts similarity index 91% rename from cypress/e2e/basic.cy.js rename to examples/nextjs/cypress/e2e/basic.cy.ts index c43ab716..a08ca021 100644 --- a/cypress/e2e/basic.cy.js +++ b/examples/nextjs/cypress/e2e/basic.cy.ts @@ -29,9 +29,7 @@ describe('Basic Flow Rendering', () => { }); it('selects a node by click', () => { - cy.get('.react-flow__node:first') - .click({ force: true }) - .should('have.class', 'selected'); + cy.get('.react-flow__node:first').click({ force: true }).should('have.class', 'selected'); }); it('deselects node', () => { @@ -40,9 +38,7 @@ describe('Basic Flow Rendering', () => { }); it('selects an edge by click', () => { - cy.get('.react-flow__edge:first') - .click({ force: true }) - .should('have.class', 'selected'); + cy.get('.react-flow__edge:first').click({ force: true }).should('have.class', 'selected'); }); it('deselects edge', () => { @@ -93,17 +89,13 @@ describe('Basic Flow Rendering', () => { }); it('selects an edge', () => { - cy.get('.react-flow__edge:first') - .click({ force: true }) - .should('have.class', 'selected'); + cy.get('.react-flow__edge:first').click({ force: true }).should('have.class', 'selected'); }); it('drags a node', () => { - const styleBeforeDrag = Cypress.$('.react-flow__node:first').css( - 'transform' - ); + const styleBeforeDrag = Cypress.$('.react-flow__node:first').css('transform'); - cy.drag('.react-flow__node:first', { x: 500, y: 25 }).then(($el) => { + cy.drag('.react-flow__node:first', { x: 500, y: 25 }).then(($el: any) => { const styleAfterDrag = $el.css('transform'); expect(styleBeforeDrag).to.not.equal(styleAfterDrag); }); @@ -153,9 +145,7 @@ describe('Basic Flow Rendering', () => { .wait(50) .trigger('mouseup', { force: true, view: win }) .then(() => { - const styleAfterDrag = Cypress.$('.react-flow__viewport').css( - 'transform' - ); + const styleAfterDrag = Cypress.$('.react-flow__viewport').css('transform'); expect(styleBeforeDrag).to.not.equal(styleAfterDrag); }); }); @@ -168,10 +158,10 @@ describe('Basic Flow Rendering', () => { .trigger('wheel', 'topLeft', { deltaY: -200 }) .wait(50) .then(() => { - const styleAfterZoom = Cypress.$('.react-flow__viewport').css( - 'transform' - ); + const styleAfterZoom = Cypress.$('.react-flow__viewport').css('transform'); expect(styleBeforeZoom).to.not.equal(styleAfterZoom); }); }); }); + +export {}; diff --git a/cypress/e2e/controls.cy.js b/examples/nextjs/cypress/e2e/controls.cy.ts similarity index 99% rename from cypress/e2e/controls.cy.js rename to examples/nextjs/cypress/e2e/controls.cy.ts index f38df829..74548f56 100644 --- a/cypress/e2e/controls.cy.js +++ b/examples/nextjs/cypress/e2e/controls.cy.ts @@ -79,3 +79,5 @@ describe('Controls Testing', () => { }); }); }); + +export {}; diff --git a/cypress/e2e/draghandle.cy.js b/examples/nextjs/cypress/e2e/draghandle.cy.ts similarity index 98% rename from cypress/e2e/draghandle.cy.js rename to examples/nextjs/cypress/e2e/draghandle.cy.ts index 498d84d2..259fbf8a 100644 --- a/cypress/e2e/draghandle.cy.js +++ b/examples/nextjs/cypress/e2e/draghandle.cy.ts @@ -28,3 +28,5 @@ describe('DragHandle Flow Rendering', () => { }); }); }); + +export {}; diff --git a/cypress/e2e/empty.cy.js b/examples/nextjs/cypress/e2e/empty.cy.ts similarity index 69% rename from cypress/e2e/empty.cy.js rename to examples/nextjs/cypress/e2e/empty.cy.ts index ce31424f..5f25dcaf 100644 --- a/cypress/e2e/empty.cy.js +++ b/examples/nextjs/cypress/e2e/empty.cy.ts @@ -10,12 +10,15 @@ describe('Empty Flow Rendering', () => { }); it('renders empty selection', () => { + cy.get('.react-flow__renderer').click(); cy.get('body') .type('{shift}', { release: false }) + .wait(50) .get('.react-flow__selectionpane') - .trigger('mousedown', 'topLeft', { which: 1, force: true }) - .trigger('mousemove', 'bottomLeft', { which: 1 }) - .trigger('mouseup', 'bottomLeft', { force: true }); + .trigger('mousedown', 400, 50, { which: 1, force: true }) + .trigger('mousemove', 200, 200, { which: 1 }) + .wait(50) + .trigger('mouseup', 200, 200, { force: true }); cy.get('body').type('{shift}', { release: true }); }); @@ -26,10 +29,7 @@ describe('Empty Flow Rendering', () => { }); it('connects nodes', () => { - cy.get('.react-flow__node') - .first() - .find('.react-flow__handle.source') - .trigger('mousedown', { button: 0 }); + cy.get('.react-flow__node').first().find('.react-flow__handle.source').trigger('mousedown', { button: 0 }); cy.get('.react-flow__node') .last() @@ -40,3 +40,5 @@ describe('Empty Flow Rendering', () => { cy.get('.react-flow__edge').should('have.length', 1); }); }); + +export {}; diff --git a/cypress/e2e/graph-utils.cy.js b/examples/nextjs/cypress/e2e/graph-utils.cy.ts similarity index 77% rename from cypress/e2e/graph-utils.cy.js rename to examples/nextjs/cypress/e2e/graph-utils.cy.ts index 18d9cb2c..6ebded1b 100644 --- a/cypress/e2e/graph-utils.cy.js +++ b/examples/nextjs/cypress/e2e/graph-utils.cy.ts @@ -1,12 +1,6 @@ -import { - isNode, - isEdge, - getOutgoers, - getIncomers, - addEdge, -} from '../../packages/core/dist/react-flow-core.esm.js'; +import { Node, Edge, isNode, isEdge, getOutgoers, getIncomers, addEdge } from '@react-flow/bundle'; -const nodes = [ +const nodes: Node[] = [ { id: '1', type: 'input', @@ -18,7 +12,7 @@ const nodes = [ { id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } }, ]; -const edges = [ +const edges: Edge[] = [ { id: 'e1-2', source: '1', target: '2', animated: true }, { id: 'e1-3', source: '1', target: '3' }, { id: 'e2-3', source: '2', target: '3' }, @@ -54,31 +48,32 @@ describe('Graph Utils Testing', () => { describe('tests addEdge function', () => { it('adds edge', () => { - const newEdge = { source: '1', target: '4' }; + const newEdge: Edge = { source: '1', target: '4', id: 'new-edge-1-4' }; const nextEdges = addEdge(newEdge, edges); expect(nextEdges.length).to.be.equal(edges.length + 1); }); it('tries to add existing edge', () => { - const newEdge = { source: '2', target: '3' }; + const newEdge: Edge = { source: '2', target: '3', id: 'new-edge-2-3' }; const nextEdges = addEdge(newEdge, edges); expect(nextEdges.length).to.be.equal(edges.length); }); it('tries to add invalid edge', () => { - const newEdge = { nosource: '1', notarget: '3' }; + // @ts-ignore + const newEdge: Edge = { nosource: '1', notarget: '3' }; try { addEdge(newEdge, edges); - } catch (e) { + } catch (e: any) { console.log(e.message); - expect(e.message).to.be.equal( - "Can't create edge. An edge needs a source and a target." - ); + expect(e.message).to.be.equal("Can't create edge. An edge needs a source and a target."); } }); }); }); + +export {}; diff --git a/cypress/e2e/hidden.cy.js b/examples/nextjs/cypress/e2e/hidden.cy.ts similarity index 98% rename from cypress/e2e/hidden.cy.js rename to examples/nextjs/cypress/e2e/hidden.cy.ts index 730502f3..2039d742 100644 --- a/cypress/e2e/hidden.cy.js +++ b/examples/nextjs/cypress/e2e/hidden.cy.ts @@ -30,3 +30,5 @@ describe('Hidden Flow Rendering', () => { cy.get('.react-flow__minimap-node').should('not.exist'); }); }); + +export {}; diff --git a/cypress/e2e/interaction.cy.js b/examples/nextjs/cypress/e2e/interaction.cy.ts similarity index 92% rename from cypress/e2e/interaction.cy.js rename to examples/nextjs/cypress/e2e/interaction.cy.ts index 368dd0e1..625ecc57 100644 --- a/cypress/e2e/interaction.cy.js +++ b/examples/nextjs/cypress/e2e/interaction.cy.ts @@ -11,16 +11,12 @@ describe('Interaction Flow Rendering', () => { }); it('tries to select a node by click', () => { - const pointerEvents = Cypress.$('.react-flow__node:first').css( - 'pointer-events' - ); + const pointerEvents = Cypress.$('.react-flow__node:first').css('pointer-events'); expect(pointerEvents).to.equal('none'); }); it('tries to select an edge by click', () => { - const pointerEvents = Cypress.$('.react-flow__edge:first').css( - 'pointer-events' - ); + const pointerEvents = Cypress.$('.react-flow__edge:first').css('pointer-events'); expect(pointerEvents).to.equal('none'); }); @@ -29,24 +25,17 @@ describe('Interaction Flow Rendering', () => { }); it('allows node clicks when enabled', () => { - const pointerEvents = Cypress.$('.react-flow__node:first').css( - 'pointer-events' - ); + const pointerEvents = Cypress.$('.react-flow__node:first').css('pointer-events'); expect(pointerEvents).to.equal('all'); }); it('allows edge clicks when enabled', () => { - const pointerEvents = Cypress.$('.react-flow__edge:first').css( - 'pointer-events' - ); + const pointerEvents = Cypress.$('.react-flow__edge:first').css('pointer-events'); expect(pointerEvents.toLowerCase()).to.equal('visiblestroke'); }); it('tries to do a selection', () => { - cy.get('body') - .type('{shift}', { release: false }) - .get('.react-flow__selectionpane') - .should('not.exist'); + cy.get('body').type('{shift}', { release: false }).get('.react-flow__selectionpane').should('not.exist'); cy.get('body').type('{shift}', { release: true }); }); @@ -87,9 +76,7 @@ describe('Interaction Flow Rendering', () => { }); it('drags a node', () => { - const styleBeforeDrag = Cypress.$('.react-flow__node:first').css( - 'transform' - ); + const styleBeforeDrag = Cypress.$('.react-flow__node:first').css('transform'); cy.drag('.react-flow__node:first', { x: 325, y: 100 }).then(($el) => { const styleAfterDrag = $el.css('transform'); @@ -140,9 +127,7 @@ describe('Interaction Flow Rendering', () => { .trigger('wheel', 'topLeft', { deltaY: 200 }) .wait(50) .then(() => { - const styleAfterZoom = Cypress.$('.react-flow__viewport').css( - 'transform' - ); + const styleAfterZoom = Cypress.$('.react-flow__viewport').css('transform'); expect(styleBeforeZoom).not.to.equal(styleAfterZoom); }); }); @@ -159,10 +144,10 @@ describe('Interaction Flow Rendering', () => { .dblclick() .wait(50) .then(() => { - const styleAfterZoom = Cypress.$('.react-flow__viewport').css( - 'transform' - ); + const styleAfterZoom = Cypress.$('.react-flow__viewport').css('transform'); expect(styleBeforeZoom).not.to.equal(styleAfterZoom); }); }); }); + +export {}; diff --git a/cypress/e2e/minimap.cy.js b/examples/nextjs/cypress/e2e/minimap.cy.ts similarity index 82% rename from cypress/e2e/minimap.cy.js rename to examples/nextjs/cypress/e2e/minimap.cy.ts index a61c2565..668b8b0f 100644 --- a/cypress/e2e/minimap.cy.js +++ b/examples/nextjs/cypress/e2e/minimap.cy.ts @@ -21,19 +21,15 @@ describe('Minimap Testing', () => { }); it('changes zoom level', () => { - const viewBoxBeforeZoom = Cypress.$('.react-flow__minimap').attr('viewBox'); + const viewBoxBeforeZoom = Cypress.$('.react-flow__minimap svg').attr('viewBox'); const maskPathBeforeZoom = Cypress.$('.react-flow__minimap-mask').attr('d'); cy.get('.react-flow__pane') .trigger('wheel', 'topLeft', { deltaY: -200 }) .wait(50) .then(() => { - const viewBoxAfterZoom = Cypress.$('.react-flow__minimap').attr( - 'viewBox' - ); - const maskPathAfterZoom = Cypress.$('.react-flow__minimap-mask').attr( - 'd' - ); + const viewBoxAfterZoom = Cypress.$('.react-flow__minimap svg').attr('viewBox'); + const maskPathAfterZoom = Cypress.$('.react-flow__minimap-mask').attr('d'); expect(viewBoxBeforeZoom).to.not.equal(viewBoxAfterZoom); expect(maskPathBeforeZoom).to.not.equal(maskPathAfterZoom); @@ -41,22 +37,14 @@ describe('Minimap Testing', () => { }); it('changes node position', () => { - const xPosBeforeDrag = Cypress.$('.react-flow__minimap-node:first').attr( - 'x' - ); - const yPosBeforeDrag = Cypress.$('.react-flow__minimap-node:first').attr( - 'y' - ); + const xPosBeforeDrag = Cypress.$('.react-flow__minimap-node:first').attr('x'); + const yPosBeforeDrag = Cypress.$('.react-flow__minimap-node:first').attr('y'); cy.drag('.react-flow__node:first', { x: 500, y: 25 }) .wait(100) .then(() => { - const xPosAfterDrag = Cypress.$('.react-flow__minimap-node:first').attr( - 'x' - ); - const yPosAfterDrag = Cypress.$('.react-flow__minimap-node:first').attr( - 'y' - ); + const xPosAfterDrag = Cypress.$('.react-flow__minimap-node:first').attr('x'); + const yPosAfterDrag = Cypress.$('.react-flow__minimap-node:first').attr('y'); expect(xPosBeforeDrag).to.not.equal(xPosAfterDrag); expect(yPosBeforeDrag).to.not.equal(yPosAfterDrag); @@ -64,7 +52,7 @@ describe('Minimap Testing', () => { }); it('changes node positions via pane drag', () => { - const viewBoxBeforeDrag = Cypress.$('.react-flow__minimap').attr('viewBox'); + const viewBoxBeforeDrag = Cypress.$('.react-flow__minimap svg').attr('viewBox'); const maskPathBeforeDrag = Cypress.$('.react-flow__minimap-mask').attr('d'); // for d3 we have to pass the window to the event @@ -76,12 +64,8 @@ describe('Minimap Testing', () => { .wait(50) .trigger('mouseup', { force: true, view: win }) .then(() => { - const viewBoxAfterDrag = Cypress.$('.react-flow__minimap').attr( - 'viewBox' - ); - const maskPathAfterDrag = Cypress.$('.react-flow__minimap-mask').attr( - 'd' - ); + const viewBoxAfterDrag = Cypress.$('.react-flow__minimap svg').attr('viewBox'); + const maskPathAfterDrag = Cypress.$('.react-flow__minimap-mask').attr('d'); expect(viewBoxBeforeDrag).to.not.equal(viewBoxAfterDrag); expect(maskPathBeforeDrag).to.not.equal(maskPathAfterDrag); @@ -89,3 +73,5 @@ describe('Minimap Testing', () => { }); }); }); + +export {}; diff --git a/examples/nextjs/cypress/fixtures/example.json b/examples/nextjs/cypress/fixtures/example.json new file mode 100644 index 00000000..02e42543 --- /dev/null +++ b/examples/nextjs/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} diff --git a/cypress/support/commands.js b/examples/nextjs/cypress/support/commands.ts similarity index 73% rename from cypress/support/commands.js rename to examples/nextjs/cypress/support/commands.ts index 76707060..b1fa542d 100644 --- a/cypress/support/commands.js +++ b/examples/nextjs/cypress/support/commands.ts @@ -1,3 +1,5 @@ +/// + // *********************************************** // This example commands.js shows you how to // create various custom commands and overwrite @@ -25,14 +27,14 @@ // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) Cypress.Commands.add('drag', (selector, { x, y }) => { - return cy - .window() - .then((window) => - cy - .get(selector) - .trigger('mousedown', { which: 1, view: window }) - .trigger('mousemove', { clientX: x, clientY: y, force: true }) - .wait(50) - .trigger('mouseup', { view: window, force: true }) - ); + return cy.window().then((window) => + cy + .get(selector as string) + .trigger('mousedown', { which: 1, view: window }) + .trigger('mousemove', { clientX: x, clientY: y, force: true }) + .wait(50) + .trigger('mouseup', { view: window, force: true }) + ); }); + +export {}; diff --git a/examples/nextjs/cypress/support/component-index.html b/examples/nextjs/cypress/support/component-index.html new file mode 100644 index 00000000..f2738f28 --- /dev/null +++ b/examples/nextjs/cypress/support/component-index.html @@ -0,0 +1,14 @@ + + + + + + + Components App + +
+ + +
+ + \ No newline at end of file diff --git a/examples/nextjs/cypress/support/component.ts b/examples/nextjs/cypress/support/component.ts new file mode 100644 index 00000000..56d0bd58 --- /dev/null +++ b/examples/nextjs/cypress/support/component.ts @@ -0,0 +1,39 @@ +// *********************************************************** +// 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 { mount } from 'cypress/react18'; + +import '../../styles/globals.css'; +import '../../styles/rf-style.css'; + +declare global { + namespace Cypress { + interface Chainable { + mount: typeof mount; + drag: (selector: string, { x, y }: { x: number; y: number }) => Cypress.Chainable>; + } + } +} + +Cypress.Commands.add('mount', mount); + +// Example use: +// cy.mount() diff --git a/cypress/support/e2e.js b/examples/nextjs/cypress/support/e2e.ts similarity index 100% rename from cypress/support/e2e.js rename to examples/nextjs/cypress/support/e2e.ts diff --git a/examples/nextjs/next.config.js b/examples/nextjs/next.config.js index cf743d8a..6a800c67 100755 --- a/examples/nextjs/next.config.js +++ b/examples/nextjs/next.config.js @@ -1,9 +1,16 @@ const withPreconstruct = require('@preconstruct/next'); +const { patchWebpackConfig } = require('next-global-css'); /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, - swcMinify: true, + webpack: (config, options) => { + if (process.env.CYPRESS === 'true') { + //Allows importing the global.css file in cypress/support/component.ts + patchWebpackConfig(config, options); + } + return config; + }, }; module.exports = withPreconstruct({ ...nextConfig }); diff --git a/examples/nextjs/package.json b/examples/nextjs/package.json index 4cf86a07..8a5a4d48 100644 --- a/examples/nextjs/package.json +++ b/examples/nextjs/package.json @@ -8,7 +8,8 @@ "copystyles": "cp ../../node_modules/@react-flow/bundle/dist/style.css ./styles/rf-style.css && cp ../../node_modules/@react-flow/bundle/dist/base.css ./styles/rf-base.css", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "cypress": "cypress" }, "dependencies": { "@preconstruct/next": "^4.0.0", @@ -21,8 +22,10 @@ }, "devDependencies": { "@types/dagre": "^0.7.47", + "cypress": "^10.6.0", "eslint": "^8.22.0", "eslint-config-next": "12.2.2", + "next-global-css": "^1.3.1", "postcss": "^8.4.16", "postcss-flexbugs-fixes": "^5.0.2", "postcss-import": "^14.1.0", diff --git a/examples/nextjs/styles/globals.css b/examples/nextjs/styles/globals.css index 024cc379..c8d4a405 100755 --- a/examples/nextjs/styles/globals.css +++ b/examples/nextjs/styles/globals.css @@ -5,7 +5,8 @@ body { html, body, -#__next { +#__next, +#root { margin: 0; height: 100%; } diff --git a/examples/nextjs/tests/useOnViewportChange.cy.tsx b/examples/nextjs/tests/useOnViewportChange.cy.tsx new file mode 100644 index 00000000..2b247598 --- /dev/null +++ b/examples/nextjs/tests/useOnViewportChange.cy.tsx @@ -0,0 +1,76 @@ +import { ReactFlow, useOnViewportChange, Viewport } from '@react-flow/bundle'; + +describe('useOnViewportChange.cy.js', () => { + it('listen to viewport drag', () => { + let startViewport = {}; + let changeViewport = {}; + let endViewport = {}; + + const onStart = (viewport: Viewport) => { + startViewport = viewport; + }; + const onChange = (viewport: Viewport) => { + changeViewport = viewport; + }; + const onEnd = (viewport: Viewport) => { + endViewport = viewport; + }; + + cy.mount( + + + + ); + + cy.window().then((win: any) => { + cy.get('.react-flow__pane') + .trigger('mousedown', 50, 50, { which: 1, view: win }) + .trigger('mousemove', 50, 100) + .trigger('mouseup', { force: true, view: win }) + .then(() => { + expect(startViewport).to.eql({ x: 0, y: 0, zoom: 1 }); + expect(changeViewport).to.not.eql({ x: 0, y: 0, zoom: 1 }); + expect(endViewport).to.eql({ x: 0, y: 50, zoom: 1 }); + }); + }); + }); + + it('handles default viewport', () => { + const defaultViewport = { x: 100, y: 100, zoom: 0.5 }; + let startViewport = {}; + + const onStart = (viewport: Viewport) => { + startViewport = viewport; + }; + + cy.mount( + + + + ); + + cy.window().then((win: any) => { + cy.get('.react-flow__pane') + .trigger('mousedown', 50, 50, { which: 1, view: win }) + .trigger('mousemove', 50, 100) + .trigger('mouseup', { force: true, view: win }) + .then(() => { + expect(startViewport).to.eql(defaultViewport); + }); + }); + }); +}); + +function OnViewportChange({ + onStart, + onChange, + onEnd, +}: { + onStart?: (viewport: Viewport) => void; + onChange?: (viewport: Viewport) => void; + onEnd?: (viewport: Viewport) => void; +}) { + useOnViewportChange({ onStart, onChange, onEnd }); + + return null; +} diff --git a/examples/nextjs/tsconfig.json b/examples/nextjs/tsconfig.json index 94136eff..99710e85 100644 --- a/examples/nextjs/tsconfig.json +++ b/examples/nextjs/tsconfig.json @@ -4,16 +4,16 @@ "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, - "strict": false, + "strict": true, "forceConsistentCasingInFileNames": true, "noEmit": true, - "incremental": true, "esModuleInterop": true, "module": "esnext", - "resolveJsonModule": true, "moduleResolution": "node", + "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve" + "jsx": "preserve", + "incremental": true }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], "exclude": ["node_modules"] diff --git a/package.json b/package.json index b479799f..3d07bead 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,8 @@ "build": "preconstruct build && yarn run packages", "packages": "yarn workspaces foreach --include '@react-flow/**' run build", "test:all": "yarn test:chrome && yarn test:firefox", - "test:chrome": "cypress run --browser chrome", - "test:firefox": "cypress run --browser firefox", + "test:chrome": "cd examples/nextjs && cypress run --browser chrome", + "test:firefox": "cd examples/nextjs && cypress run --browser firefox", "test": "yarn build && start-server-and-test dev:example http://localhost:3000 test:chrome", "release": "changeset publish" }, diff --git a/yarn.lock b/yarn.lock index d8fe076f..3bc1fe46 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2295,6 +2295,7 @@ __metadata: version: 0.0.0-use.local resolution: "@react-flow/background@workspace:packages/background" dependencies: + "@babel/runtime": ^7.18.9 "@react-flow/core": "workspace:*" classcat: ^5.0.3 peerDependencies: @@ -2307,6 +2308,7 @@ __metadata: version: 0.0.0-use.local resolution: "@react-flow/bundle@workspace:packages/bundle" dependencies: + "@babel/runtime": ^7.18.9 "@react-flow/background": "workspace:*" "@react-flow/controls": "workspace:*" "@react-flow/core": "workspace:*" @@ -2327,6 +2329,7 @@ __metadata: version: 0.0.0-use.local resolution: "@react-flow/controls@workspace:packages/controls" dependencies: + "@babel/runtime": ^7.18.9 "@react-flow/core": "workspace:*" autoprefixer: ^10.4.8 classcat: ^5.0.3 @@ -2369,6 +2372,7 @@ __metadata: version: 0.0.0-use.local resolution: "@react-flow/minimap@workspace:packages/minimap" dependencies: + "@babel/runtime": ^7.18.9 "@react-flow/core": "workspace:*" autoprefixer: ^10.4.8 classcat: ^5.0.3 @@ -6923,6 +6927,13 @@ __metadata: languageName: node linkType: hard +"next-global-css@npm:^1.3.1": + version: 1.3.1 + resolution: "next-global-css@npm:1.3.1" + checksum: fdb85e2ea614e17dc2d6f3f5064644346de9458774844f50a398c2b71d3d320717713d6f915fa8b91039956440900e6166a8b1bc19d3091c31aed582495f8a0f + languageName: node + linkType: hard + "next@npm:12.2.2": version: 12.2.2 resolution: "next@npm:12.2.2" @@ -8167,11 +8178,13 @@ __metadata: "@preconstruct/next": ^4.0.0 "@react-flow/bundle": "workspace:*" "@types/dagre": ^0.7.47 + cypress: ^10.6.0 dagre: ^0.8.5 eslint: ^8.22.0 eslint-config-next: 12.2.2 localforage: ^1.10.0 next: 12.2.2 + next-global-css: ^1.3.1 postcss: ^8.4.16 postcss-flexbugs-fixes: ^5.0.2 postcss-import: ^14.1.0