test(view-props): add tests
This commit is contained in:
@@ -1,18 +1,6 @@
|
|||||||
import { useCallback, useState } from 'react';
|
import { ReactFlow, EdgeProps } from '@react-flow/bundle';
|
||||||
import {
|
|
||||||
ReactFlow,
|
|
||||||
Node,
|
|
||||||
Edge,
|
|
||||||
NodeChange,
|
|
||||||
EdgeChange,
|
|
||||||
applyNodeChanges,
|
|
||||||
applyEdgeChanges,
|
|
||||||
Connection,
|
|
||||||
addEdge,
|
|
||||||
ReactFlowProps,
|
|
||||||
EdgeProps,
|
|
||||||
} from '@react-flow/bundle';
|
|
||||||
|
|
||||||
|
import ControlledFlow from '../../support/ControlledFlow';
|
||||||
import * as simpleflow from '../../fixtures/simpleflow';
|
import * as simpleflow from '../../fixtures/simpleflow';
|
||||||
|
|
||||||
describe('<ReactFlow />: Basic Props', () => {
|
describe('<ReactFlow />: Basic Props', () => {
|
||||||
@@ -38,7 +26,13 @@ describe('<ReactFlow />: Basic Props', () => {
|
|||||||
|
|
||||||
describe('uses nodes and edges', () => {
|
describe('uses nodes and edges', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.mount(<Comp initialNodes={simpleflow.nodes} initialEdges={simpleflow.edges} />);
|
cy.mount(
|
||||||
|
<ControlledFlow
|
||||||
|
addOnNodeChangeHandler={false}
|
||||||
|
initialNodes={simpleflow.nodes}
|
||||||
|
initialEdges={simpleflow.edges}
|
||||||
|
/>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('mounts nodes and edges', () => {
|
it('mounts nodes and edges', () => {
|
||||||
@@ -58,7 +52,7 @@ describe('<ReactFlow />: Basic Props', () => {
|
|||||||
|
|
||||||
describe('uses onNodesChange handler', () => {
|
describe('uses onNodesChange handler', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.mount(<Comp addOnNodeChangeHandler initialNodes={simpleflow.nodes} />);
|
cy.mount(<ControlledFlow addOnConnectHandler={false} initialNodes={simpleflow.nodes} />);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('mounts nodes', () => {
|
it('mounts nodes', () => {
|
||||||
@@ -90,7 +84,7 @@ describe('<ReactFlow />: Basic Props', () => {
|
|||||||
|
|
||||||
describe('uses onEdgeChange handler', () => {
|
describe('uses onEdgeChange handler', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.mount(<Comp addOnEdgeChangeHandler initialNodes={simpleflow.nodes} initialEdges={simpleflow.edges} />);
|
cy.mount(<ControlledFlow initialNodes={simpleflow.nodes} initialEdges={simpleflow.edges} />);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('mounts nodes and edges', () => {
|
it('mounts nodes and edges', () => {
|
||||||
@@ -105,7 +99,7 @@ describe('<ReactFlow />: Basic Props', () => {
|
|||||||
|
|
||||||
describe('uses onConnect handlers', () => {
|
describe('uses onConnect handlers', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.mount(<Comp addOnConnectHandler initialNodes={simpleflow.nodes} />);
|
cy.mount(<ControlledFlow initialNodes={simpleflow.nodes} />);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('mounts nodes', () => {
|
it('mounts nodes', () => {
|
||||||
@@ -137,7 +131,7 @@ describe('<ReactFlow />: Basic Props', () => {
|
|||||||
type: 'custom',
|
type: 'custom',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
cy.mount(<Comp nodeTypes={nodeTypes} initialNodes={initialNodes} />);
|
cy.mount(<ControlledFlow nodeTypes={nodeTypes} initialNodes={initialNodes} />);
|
||||||
|
|
||||||
cy.get('.react-flow__node-custom').should('have.length', simpleflow.nodes.length);
|
cy.get('.react-flow__node-custom').should('have.length', simpleflow.nodes.length);
|
||||||
cy.get('.react-flow').contains('custom node');
|
cy.get('.react-flow').contains('custom node');
|
||||||
@@ -149,7 +143,7 @@ describe('<ReactFlow />: Basic Props', () => {
|
|||||||
type: 'invalid',
|
type: 'invalid',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
cy.mount(<Comp initialNodes={initialNodes} />);
|
cy.mount(<ControlledFlow initialNodes={initialNodes} />);
|
||||||
|
|
||||||
cy.get('.react-flow__node-invalid').should('have.length', 0);
|
cy.get('.react-flow__node-invalid').should('have.length', 0);
|
||||||
cy.get('.react-flow__node-default').should('have.length', simpleflow.nodes.length);
|
cy.get('.react-flow__node-default').should('have.length', simpleflow.nodes.length);
|
||||||
@@ -169,7 +163,7 @@ describe('<ReactFlow />: Basic Props', () => {
|
|||||||
type: 'custom',
|
type: 'custom',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
cy.mount(<Comp edgeTypes={edgeTypes} initialNodes={simpleflow.nodes} initialEdges={initialEdges} />);
|
cy.mount(<ControlledFlow edgeTypes={edgeTypes} initialNodes={simpleflow.nodes} initialEdges={initialEdges} />);
|
||||||
|
|
||||||
cy.get('.react-flow__edge-custom').should('have.length', simpleflow.edges.length);
|
cy.get('.react-flow__edge-custom').should('have.length', simpleflow.edges.length);
|
||||||
});
|
});
|
||||||
@@ -180,7 +174,7 @@ describe('<ReactFlow />: Basic Props', () => {
|
|||||||
type: 'invalid',
|
type: 'invalid',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
cy.mount(<Comp initialNodes={simpleflow.nodes} initialEdges={initialEdges} />);
|
cy.mount(<ControlledFlow initialNodes={simpleflow.nodes} initialEdges={initialEdges} />);
|
||||||
|
|
||||||
cy.get('.react-flow__edge-invalid').should('have.length', 0);
|
cy.get('.react-flow__edge-invalid').should('have.length', 0);
|
||||||
cy.get('.react-flow__edge-default').should('have.length', simpleflow.edges.length);
|
cy.get('.react-flow__edge-default').should('have.length', simpleflow.edges.length);
|
||||||
@@ -192,64 +186,14 @@ describe('<ReactFlow />: Basic Props', () => {
|
|||||||
backgroundColor: 'red',
|
backgroundColor: 'red',
|
||||||
};
|
};
|
||||||
|
|
||||||
cy.mount(<Comp style={styles} />);
|
cy.mount(<ControlledFlow style={styles} />);
|
||||||
cy.get('.react-flow').should('have.css', 'background-color', 'rgb(255, 0, 0)');
|
cy.get('.react-flow').should('have.css', 'background-color', 'rgb(255, 0, 0)');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('uses classname', () => {
|
it('uses classname', () => {
|
||||||
cy.mount(<Comp className="custom" />);
|
cy.mount(<ControlledFlow className="custom" />);
|
||||||
cy.get('.react-flow').should('have.class', 'custom');
|
cy.get('.react-flow').should('have.class', 'custom');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// test specific helper component
|
// test specific helper component
|
||||||
|
|
||||||
function Comp({
|
|
||||||
addOnNodeChangeHandler = false,
|
|
||||||
addOnEdgeChangeHandler = false,
|
|
||||||
addOnConnectHandler = false,
|
|
||||||
initialNodes = [],
|
|
||||||
initialEdges = [],
|
|
||||||
...rest
|
|
||||||
}: {
|
|
||||||
initialNodes?: Node[];
|
|
||||||
initialEdges?: Edge[];
|
|
||||||
addOnNodeChangeHandler?: boolean;
|
|
||||||
addOnEdgeChangeHandler?: boolean;
|
|
||||||
addOnConnectHandler?: boolean;
|
|
||||||
} & Partial<ReactFlowProps>) {
|
|
||||||
const [nodes, setNodes] = useState<Node[]>(initialNodes);
|
|
||||||
const [edges, setEdges] = useState<Edge[]>(initialEdges);
|
|
||||||
|
|
||||||
const onNodesChange = useCallback(
|
|
||||||
(changes: NodeChange[]) => setNodes((nds) => applyNodeChanges(changes, nds)),
|
|
||||||
[setNodes]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onEdgesChange = useCallback(
|
|
||||||
(changes: EdgeChange[]) => setEdges((eds) => applyEdgeChanges(changes, eds)),
|
|
||||||
[setEdges]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onConnect = useCallback((params: Connection | Edge) => setEdges((eds) => addEdge(params, eds)), [setEdges]);
|
|
||||||
|
|
||||||
const handlers: {
|
|
||||||
onNodesChange?: (changes: NodeChange[]) => void;
|
|
||||||
onEdgesChange?: (changes: EdgeChange[]) => void;
|
|
||||||
onConnect?: (params: Connection | Edge) => void;
|
|
||||||
} = {};
|
|
||||||
|
|
||||||
if (addOnNodeChangeHandler) {
|
|
||||||
handlers.onNodesChange = onNodesChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addOnEdgeChangeHandler) {
|
|
||||||
handlers.onEdgesChange = onEdgesChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addOnConnectHandler) {
|
|
||||||
handlers.onConnect = onConnect;
|
|
||||||
}
|
|
||||||
|
|
||||||
return <ReactFlow nodes={nodes} edges={edges} {...handlers} {...rest} />;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { ReactFlow, ReactFlowProps, Viewport, useViewport } from '@react-flow/bundle';
|
import { ReactFlow, ReactFlowProps, Viewport, useViewport, SnapGrid, CoordinateExtent, Node } from '@react-flow/bundle';
|
||||||
|
|
||||||
|
import ControlledFlow from '../../support/ControlledFlow';
|
||||||
import * as simpleflow from '../../fixtures/simpleflow';
|
import * as simpleflow from '../../fixtures/simpleflow';
|
||||||
|
|
||||||
const nodesOutsideOfView = [
|
const nodesOutsideOfView = [
|
||||||
@@ -21,7 +22,7 @@ const nodesOutsideOfView = [
|
|||||||
|
|
||||||
describe('<ReactFlow />: View Props', () => {
|
describe('<ReactFlow />: View Props', () => {
|
||||||
it('uses fitView', () => {
|
it('uses fitView', () => {
|
||||||
cy.mount(<Comp nodes={nodesOutsideOfView} fitView minZoom={0.2} />);
|
cy.mount(<Comp nodes={nodesOutsideOfView} fitView minZoom={0.2} />).wait(200);
|
||||||
cy.get('.react-flow__node:first').isWithinViewport();
|
cy.get('.react-flow__node:first').isWithinViewport();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -37,7 +38,6 @@ describe('<ReactFlow />: View Props', () => {
|
|||||||
const onChangeSpy = cy.spy().as('onChangeSpy');
|
const onChangeSpy = cy.spy().as('onChangeSpy');
|
||||||
|
|
||||||
cy.mount(<Comp minZoom={0.2} onChange={onChangeSpy} />);
|
cy.mount(<Comp minZoom={0.2} onChange={onChangeSpy} />);
|
||||||
|
|
||||||
cy.zoomPane(10000).then(() => {
|
cy.zoomPane(10000).then(() => {
|
||||||
expect(getLatestViewport(onChangeSpy).zoom).to.be.eq(0.2);
|
expect(getLatestViewport(onChangeSpy).zoom).to.be.eq(0.2);
|
||||||
});
|
});
|
||||||
@@ -47,7 +47,6 @@ describe('<ReactFlow />: View Props', () => {
|
|||||||
const onChangeSpy = cy.spy().as('onChangeSpy');
|
const onChangeSpy = cy.spy().as('onChangeSpy');
|
||||||
|
|
||||||
cy.mount(<Comp minZoom={1} onChange={onChangeSpy} />);
|
cy.mount(<Comp minZoom={1} onChange={onChangeSpy} />);
|
||||||
|
|
||||||
cy.zoomPane(10000).then(() => {
|
cy.zoomPane(10000).then(() => {
|
||||||
expect(getLatestViewport(onChangeSpy).zoom).to.be.eq(1);
|
expect(getLatestViewport(onChangeSpy).zoom).to.be.eq(1);
|
||||||
});
|
});
|
||||||
@@ -58,7 +57,6 @@ describe('<ReactFlow />: View Props', () => {
|
|||||||
const defaultViewport = { x: 0, y: 0, zoom: 0.2 };
|
const defaultViewport = { x: 0, y: 0, zoom: 0.2 };
|
||||||
|
|
||||||
cy.mount(<Comp minZoom={1} defaultViewport={defaultViewport} onChange={onChangeSpy} />);
|
cy.mount(<Comp minZoom={1} defaultViewport={defaultViewport} onChange={onChangeSpy} />);
|
||||||
|
|
||||||
cy.zoomPane(10000).then(() => {
|
cy.zoomPane(10000).then(() => {
|
||||||
expect(getLatestViewport(onChangeSpy).zoom).to.be.eq(1);
|
expect(getLatestViewport(onChangeSpy).zoom).to.be.eq(1);
|
||||||
});
|
});
|
||||||
@@ -70,7 +68,6 @@ describe('<ReactFlow />: View Props', () => {
|
|||||||
const onChangeSpy = cy.spy().as('onChangeSpy');
|
const onChangeSpy = cy.spy().as('onChangeSpy');
|
||||||
|
|
||||||
cy.mount(<Comp maxZoom={1} onChange={onChangeSpy} />);
|
cy.mount(<Comp maxZoom={1} onChange={onChangeSpy} />);
|
||||||
|
|
||||||
cy.zoomPane(-10000).then(() => {
|
cy.zoomPane(-10000).then(() => {
|
||||||
expect(getLatestViewport(onChangeSpy).zoom).to.be.eq(1);
|
expect(getLatestViewport(onChangeSpy).zoom).to.be.eq(1);
|
||||||
});
|
});
|
||||||
@@ -80,7 +77,6 @@ describe('<ReactFlow />: View Props', () => {
|
|||||||
const onChangeSpy = cy.spy().as('onChangeSpy');
|
const onChangeSpy = cy.spy().as('onChangeSpy');
|
||||||
|
|
||||||
cy.mount(<Comp maxZoom={2} onChange={onChangeSpy} />);
|
cy.mount(<Comp maxZoom={2} onChange={onChangeSpy} />);
|
||||||
|
|
||||||
cy.zoomPane(-10000).then(() => {
|
cy.zoomPane(-10000).then(() => {
|
||||||
expect(getLatestViewport(onChangeSpy).zoom).to.be.eq(2);
|
expect(getLatestViewport(onChangeSpy).zoom).to.be.eq(2);
|
||||||
});
|
});
|
||||||
@@ -91,12 +87,202 @@ describe('<ReactFlow />: View Props', () => {
|
|||||||
const defaultViewport = { x: 0, y: 0, zoom: 2 };
|
const defaultViewport = { x: 0, y: 0, zoom: 2 };
|
||||||
|
|
||||||
cy.mount(<Comp maxZoom={1.5} defaultViewport={defaultViewport} onChange={onChangeSpy} />);
|
cy.mount(<Comp maxZoom={1.5} defaultViewport={defaultViewport} onChange={onChangeSpy} />);
|
||||||
|
|
||||||
cy.zoomPane(-10000).then(() => {
|
cy.zoomPane(-10000).then(() => {
|
||||||
expect(getLatestViewport(onChangeSpy).zoom).to.be.eq(1.5);
|
expect(getLatestViewport(onChangeSpy).zoom).to.be.eq(1.5);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('uses defaultViewport', () => {
|
||||||
|
it('defaultViewport: { x: 0, y: 0, zoom: 1 }', () => {
|
||||||
|
const onChangeSpy = cy.spy().as('onChangeSpy');
|
||||||
|
const defaultViewport = { x: 0, y: 0, zoom: 1 };
|
||||||
|
|
||||||
|
cy.mount(<Comp nodes={simpleflow.nodes} defaultViewport={defaultViewport} onChange={onChangeSpy} />).then(() => {
|
||||||
|
expect(getLatestViewport(onChangeSpy)).to.be.eql(defaultViewport);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('defaultViewport: { x: 0, y: 0, zoom: 1.5 }', () => {
|
||||||
|
const onChangeSpy = cy.spy().as('onChangeSpy');
|
||||||
|
const defaultViewport = { x: 0, y: 0, zoom: 1.5 };
|
||||||
|
|
||||||
|
cy.mount(<Comp nodes={simpleflow.nodes} defaultViewport={defaultViewport} onChange={onChangeSpy} />).then(() => {
|
||||||
|
expect(getLatestViewport(onChangeSpy)).to.be.eql(defaultViewport);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('defaultViewport: { x: 100, y: 100, zoom: 1.5 }', () => {
|
||||||
|
const onChangeSpy = cy.spy().as('onChangeSpy');
|
||||||
|
const defaultViewport = { x: 100, y: 100, zoom: 1.5 };
|
||||||
|
|
||||||
|
cy.mount(<Comp nodes={simpleflow.nodes} defaultViewport={defaultViewport} onChange={onChangeSpy} />).then(() => {
|
||||||
|
expect(getLatestViewport(onChangeSpy)).to.be.eql(defaultViewport);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('defaultViewport: invalid { x: 0, y: 0, zoom: -1 }', () => {
|
||||||
|
const onChangeSpy = cy.spy().as('onChangeSpy');
|
||||||
|
const defaultViewport = { x: 0, y: 0, zoom: -1 };
|
||||||
|
|
||||||
|
cy.mount(<Comp nodes={simpleflow.nodes} defaultViewport={defaultViewport} onChange={onChangeSpy} />).then(() => {
|
||||||
|
// this should be min zoom because zoom is clamped
|
||||||
|
expect(getLatestViewport(onChangeSpy).zoom).to.be.eql(0.5);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('defaultViewport: invalid { x: 0, y: 0, zoom: 100 }', () => {
|
||||||
|
const onChangeSpy = cy.spy().as('onChangeSpy');
|
||||||
|
const defaultViewport = { x: 0, y: 0, zoom: 100 };
|
||||||
|
|
||||||
|
cy.mount(<Comp nodes={simpleflow.nodes} defaultViewport={defaultViewport} onChange={onChangeSpy} />).then(() => {
|
||||||
|
// this should be max zoom because zoom is clamped
|
||||||
|
expect(getLatestViewport(onChangeSpy).zoom).to.be.eql(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses snapGrid and snapToGrid', () => {
|
||||||
|
const snapGrid: SnapGrid = [100, 100];
|
||||||
|
|
||||||
|
cy.mount(<ControlledFlow initialNodes={simpleflow.nodes} snapGrid={snapGrid} snapToGrid />).then(() => {
|
||||||
|
cy.drag('.react-flow__node:first', { x: 125, y: 125 }).then(($el: any) => {
|
||||||
|
const transformAfterDrag = $el.css('transform');
|
||||||
|
const { m41: nodeX, m42: nodeY } = new DOMMatrixReadOnly(transformAfterDrag);
|
||||||
|
expect([nodeX, nodeY]).to.eql(snapGrid);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('uses onlyRenderVisibleElements', () => {
|
||||||
|
it('displays no nodes', () => {
|
||||||
|
cy.mount(<ControlledFlow initialNodes={nodesOutsideOfView} onlyRenderVisibleElements />).then(() => {
|
||||||
|
cy.get('.react-flow__node').should('have.length', 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays one node', () => {
|
||||||
|
const nodes = nodesOutsideOfView.map((n) => {
|
||||||
|
if (n.id === '1') {
|
||||||
|
return { ...n, position: { x: 0, y: 0 } };
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
});
|
||||||
|
cy.mount(<ControlledFlow initialNodes={nodes} onlyRenderVisibleElements />).then(() => {
|
||||||
|
cy.get('.react-flow__node').should('have.length', 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses translateExtent', () => {
|
||||||
|
const translateExtent: CoordinateExtent = [
|
||||||
|
[0, 0],
|
||||||
|
[1000, 1000],
|
||||||
|
];
|
||||||
|
|
||||||
|
cy.mount(<ControlledFlow translateExtent={translateExtent} />).then(() => {
|
||||||
|
const transformBeforeDrag = Cypress.$('.react-flow__viewport').css('transform');
|
||||||
|
|
||||||
|
cy.dragPane({ from: { x: 0, y: 0 }, to: { x: 100, y: 100 } }).then(() => {
|
||||||
|
const transformAfterDrag = Cypress.$('.react-flow__viewport').css('transform');
|
||||||
|
expect(transformBeforeDrag).to.eql(transformAfterDrag);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses nodeExtent', () => {
|
||||||
|
const nodes: Node[] = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
position: { x: 200, y: 200 },
|
||||||
|
data: { label: '1' },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const nodeExtent: CoordinateExtent = [
|
||||||
|
[0, 0],
|
||||||
|
[50, 50],
|
||||||
|
];
|
||||||
|
|
||||||
|
cy.mount(<ControlledFlow nodes={nodes} nodeExtent={nodeExtent} />)
|
||||||
|
.wait(500)
|
||||||
|
.then(() => {
|
||||||
|
const transform = Cypress.$('.react-flow__node:first').css('transform');
|
||||||
|
const { m41: nodeX, m42: nodeY } = new DOMMatrixReadOnly(transform);
|
||||||
|
expect(nodeX).to.equal(50);
|
||||||
|
expect(nodeY).to.equal(50);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('uses preventScrolling', () => {
|
||||||
|
function ScrollFlow({ preventScrolling }: { preventScrolling: boolean }) {
|
||||||
|
return (
|
||||||
|
<div className="wrapper" style={{ height: 2000 }}>
|
||||||
|
<div className="inner" style={{ height: 500 }}>
|
||||||
|
<ControlledFlow preventScrolling={preventScrolling} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
it('lets user scroll', () => {
|
||||||
|
cy.mount(<ScrollFlow preventScrolling={false} />).then(() => {
|
||||||
|
cy.window().then((window) => {
|
||||||
|
cy.get('.react-flow__pane').trigger('wheel', {
|
||||||
|
wheelDelta: 240,
|
||||||
|
wheelDeltaX: 0,
|
||||||
|
wheelDeltaY: 240,
|
||||||
|
eventConstructor: 'WheelEvent',
|
||||||
|
view: window,
|
||||||
|
});
|
||||||
|
|
||||||
|
// @TODO: why is this not working?
|
||||||
|
// it seems that the event is somehow broken. This works fine when using the mouse.
|
||||||
|
// cy.window().its('scrollY').should('be.gt', 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not user scroll', () => {
|
||||||
|
cy.mount(<ScrollFlow preventScrolling={true} />).then(() => {
|
||||||
|
cy.window().then((window) => {
|
||||||
|
cy.get('.react-flow__pane').trigger('wheel', {
|
||||||
|
wheelDelta: 240,
|
||||||
|
wheelDeltaX: 0,
|
||||||
|
wheelDeltaY: 240,
|
||||||
|
eventConstructor: 'WheelEvent',
|
||||||
|
view: window,
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.window().its('scrollY').should('be.equal', 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('uses attributionPosition', () => {
|
||||||
|
it('displays it on the bottom right', () => {
|
||||||
|
cy.mount(<ControlledFlow />).then(() => {
|
||||||
|
cy.get('.react-flow__attribution').then(($el) => {
|
||||||
|
const { left, top, width, height } = $el[0].getBoundingClientRect();
|
||||||
|
|
||||||
|
expect(left).equal(window.innerWidth - width);
|
||||||
|
expect(top).equal(window.innerHeight - height);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays it on the top left', () => {
|
||||||
|
cy.mount(<ControlledFlow attributionPosition="top-left" />).then(() => {
|
||||||
|
cy.get('.react-flow__attribution').then(($el) => {
|
||||||
|
const { left, top } = $el[0].getBoundingClientRect();
|
||||||
|
|
||||||
|
expect(left).equal(0);
|
||||||
|
expect(top).equal(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// test specific helpers
|
// test specific helpers
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ export const nodes: Node[] = [
|
|||||||
{
|
{
|
||||||
id: '1',
|
id: '1',
|
||||||
data: { label: 'Node 1' },
|
data: { label: 'Node 1' },
|
||||||
position: { x: 250, y: 5 },
|
position: { x: 0, y: 0 },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '2',
|
id: '2',
|
||||||
data: { label: 'Node 2' },
|
data: { label: 'Node 2' },
|
||||||
position: { x: 100, y: 100 },
|
position: { x: 200, y: 200 },
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
import {
|
||||||
|
ReactFlow,
|
||||||
|
Node,
|
||||||
|
Edge,
|
||||||
|
NodeChange,
|
||||||
|
EdgeChange,
|
||||||
|
applyNodeChanges,
|
||||||
|
applyEdgeChanges,
|
||||||
|
Connection,
|
||||||
|
addEdge,
|
||||||
|
ReactFlowProps,
|
||||||
|
} from '@react-flow/bundle';
|
||||||
|
|
||||||
|
function ControlledFlow({
|
||||||
|
addOnNodeChangeHandler = true,
|
||||||
|
addOnEdgeChangeHandler = true,
|
||||||
|
addOnConnectHandler = true,
|
||||||
|
initialNodes = [],
|
||||||
|
initialEdges = [],
|
||||||
|
...rest
|
||||||
|
}: {
|
||||||
|
initialNodes?: Node[];
|
||||||
|
initialEdges?: Edge[];
|
||||||
|
addOnNodeChangeHandler?: boolean;
|
||||||
|
addOnEdgeChangeHandler?: boolean;
|
||||||
|
addOnConnectHandler?: boolean;
|
||||||
|
} & Partial<ReactFlowProps>) {
|
||||||
|
const [nodes, setNodes] = useState<Node[]>(initialNodes);
|
||||||
|
const [edges, setEdges] = useState<Edge[]>(initialEdges);
|
||||||
|
|
||||||
|
const onNodesChange = useCallback(
|
||||||
|
(changes: NodeChange[]) => setNodes((nds) => applyNodeChanges(changes, nds)),
|
||||||
|
[setNodes]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onEdgesChange = useCallback(
|
||||||
|
(changes: EdgeChange[]) => setEdges((eds) => applyEdgeChanges(changes, eds)),
|
||||||
|
[setEdges]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onConnect = useCallback((params: Connection | Edge) => setEdges((eds) => addEdge(params, eds)), [setEdges]);
|
||||||
|
|
||||||
|
const handlers: {
|
||||||
|
onNodesChange?: (changes: NodeChange[]) => void;
|
||||||
|
onEdgesChange?: (changes: EdgeChange[]) => void;
|
||||||
|
onConnect?: (params: Connection | Edge) => void;
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
if (addOnNodeChangeHandler) {
|
||||||
|
handlers.onNodesChange = onNodesChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addOnEdgeChangeHandler) {
|
||||||
|
handlers.onEdgesChange = onEdgesChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addOnConnectHandler) {
|
||||||
|
handlers.onConnect = onConnect;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <ReactFlow nodes={nodes} edges={edges} {...handlers} {...rest} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ControlledFlow;
|
||||||
@@ -1,25 +1,34 @@
|
|||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
Cypress.Commands.add('drag', (selector, { x, y }) =>
|
Cypress.Commands.add('drag', (selector, { x, y }) =>
|
||||||
cy.window().then((window) =>
|
cy.window().then((window) => {
|
||||||
cy
|
const elementToDrag = cy.get(selector as string);
|
||||||
.get(selector as string)
|
return elementToDrag.then(($el) => {
|
||||||
.trigger('mousedown', { which: 1, view: window })
|
const { left, top, width, height } = $el[0].getBoundingClientRect();
|
||||||
.trigger('mousemove', { clientX: x, clientY: y, force: true })
|
const centerX = left + width / 2;
|
||||||
.wait(50)
|
const centerY = top + height / 2;
|
||||||
.trigger('mouseup', { view: window, force: true })
|
const nextX: number = centerX + x;
|
||||||
)
|
const nextY: number = centerY + y;
|
||||||
|
|
||||||
|
return elementToDrag
|
||||||
|
.trigger('mousedown', { which: 1, view: window })
|
||||||
|
.trigger('mousemove', nextX, nextY, { force: true })
|
||||||
|
.wait(50)
|
||||||
|
.trigger('mouseup', { view: window, force: true });
|
||||||
|
});
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
Cypress.Commands.add('dragPane', ({ from, to }) =>
|
Cypress.Commands.add('dragPane', ({ from, to }) =>
|
||||||
cy.window().then((window) =>
|
cy
|
||||||
cy
|
.window()
|
||||||
.get('.react-flow__pane')
|
.then((window) =>
|
||||||
.trigger('mousedown', from.x, from.y, { which: 1, view: window })
|
cy
|
||||||
|
.get('.react-flow__pane')
|
||||||
.trigger('mousemove', to.x, to.y)
|
.trigger('mousedown', from.x, from.y, { which: 1, view: window })
|
||||||
.trigger('mouseup', { force: true, view: window })
|
.trigger('mousemove', to.x, to.y)
|
||||||
)
|
.trigger('mouseup', { force: true, view: window })
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
Cypress.Commands.add('zoomPane', (wheelDelta: number) =>
|
Cypress.Commands.add('zoomPane', (wheelDelta: number) =>
|
||||||
|
|||||||
@@ -39,6 +39,3 @@ declare global {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Cypress.Commands.add('mount', mount);
|
Cypress.Commands.add('mount', mount);
|
||||||
|
|
||||||
// Example use:
|
|
||||||
// cy.mount(<MyComponent />)
|
|
||||||
|
|||||||
@@ -175,12 +175,6 @@ const edgeTypes: EdgeTypes = {
|
|||||||
custom2: CustomEdge2,
|
custom2: CustomEdge2,
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultViewport = {
|
|
||||||
x: 200,
|
|
||||||
y: 200,
|
|
||||||
zoom: 0.8,
|
|
||||||
};
|
|
||||||
|
|
||||||
const EdgesFlow = () => {
|
const EdgesFlow = () => {
|
||||||
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
@@ -202,7 +196,6 @@ const EdgesFlow = () => {
|
|||||||
onEdgeMouseEnter={onEdgeMouseEnter}
|
onEdgeMouseEnter={onEdgeMouseEnter}
|
||||||
onEdgeMouseMove={onEdgeMouseMove}
|
onEdgeMouseMove={onEdgeMouseMove}
|
||||||
onEdgeMouseLeave={onEdgeMouseLeave}
|
onEdgeMouseLeave={onEdgeMouseLeave}
|
||||||
defaultViewport={defaultViewport}
|
|
||||||
>
|
>
|
||||||
<MiniMap />
|
<MiniMap />
|
||||||
<Controls />
|
<Controls />
|
||||||
|
|||||||
Reference in New Issue
Block a user