diff --git a/README.md b/README.md index b165f7ac..6b854a2e 100644 --- a/README.md +++ b/README.md @@ -38,8 +38,8 @@ const BasicGraph = () => ( - `onConnect`: connect handler - `onLoad`: editor load handler - `onMove`: move handler -- `nodeTypes`: object with [node types](#node-types) -- `edgeTypes`: object with [edge types](#edge-types) +- `nodeTypes`: object with [node types](#node-types--custom-nodes) +- `edgeTypes`: object with [edge types](#edge-types--custom-edges) - `style`: css style passed to the wrapper - `connectionLineType`: connection line type = `straight` or `bezier` - `connectionLineStyle`: connection style as svg attributes @@ -55,7 +55,7 @@ const BasicGraph = () => ( ## Nodes -There are three different [node types](#node-types) (`default`, `input`, `output`) you can use. You can also create [custom nodes](#custom-nodes). +There are three different [node types](#node-types--custom-nodes) (`default`, `input`, `output`) you can use. You can also create [custom nodes](#node-types--custom-nodes). Node example: `{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } }` @@ -63,13 +63,13 @@ Node example: `{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { - `id`: string *(required)* - `position`: { x: number, y: number } *(required)* -- `data`: {} (required if you are using a standard type, otherwise depends on your implementation) +- `data`: {} *(required if you are using a standard type, otherwise depends on your implementation)* - `type`: 'input' | 'output' | 'default' or a custom one you implemented - `style`: css properties ## Edges -There are three [edge types](#edge-types) (`straight`, `default`, `step`) you can use. The default type is `default`. You can also create [custom edges](#custom-edges). +There are three [edge types](#edge-types--custom-edges) (`straight`, `default`, `step`) you can use. The default type is `default`. You can also create [custom edges](#edge-types--custom-edges). Edge example: `{ id: 'e1-2', type: 'straight', source: '1', target: '2', animated: true }` @@ -107,7 +107,7 @@ You can now use type `special` for a node. The `default`, `input` and `output` types will be still available except you overwrite one of them. You can find an example of how to implement a custom node in [custom nodes example](example/src/CustomNodes). -# Edge Types / Custom Edges +## Edge Types / Custom Edges The standard edge types are `straight`, `default` and `step`. The default edge types object looks like this: diff --git a/cypress/integration/flow/basic.spec.js b/cypress/integration/flow/basic.spec.js index d6a58afe..13b99544 100644 --- a/cypress/integration/flow/basic.spec.js +++ b/cypress/integration/flow/basic.spec.js @@ -15,7 +15,7 @@ describe('Basic Graph Rendering', () => { expect(gridStroke).to.equal('#eee'); }); - it('selects a node', () => { + it('selects a node by click', () => { cy.get('.react-flow__node:first').click().should('have.class', 'selected'); }); @@ -24,7 +24,7 @@ describe('Basic Graph Rendering', () => { cy.get('.react-flow__node:first').should('not.have.class', 'selected'); }); - it('selects an edge', () => { + it('selects an edge by click', () => { cy.get('.react-flow__edge:first').click().should('have.class', 'selected'); }); @@ -33,6 +33,22 @@ describe('Basic Graph Rendering', () => { cy.get('.react-flow__edge:first').should('not.have.class', 'selected'); }); + it('selects one node with a selection', () => { + cy.get('body') + .type('{shift}', { release: false }) + .get('.react-flow__selectionpane') + .trigger('mousedown', 'topLeft', { which: 1, force: true }) + .trigger('mousemove', 800, 75, { which: 1 }) + .trigger('mouseup', 'bottomRight', { force: true }) + .get('.react-flow__node') + .first() + .should('have.class', 'selected') + .get('.react-flow__node') + .last() + .should('have.not.class', 'selected') + .get('.react-flow__nodesselection-rect'); + }); + it('selects all nodes', () => { cy.get('body') .type('{shift}', { release: false }) diff --git a/cypress/integration/flow/empty.spec.js b/cypress/integration/flow/empty.spec.js index 7cfd68f3..54f514a0 100644 --- a/cypress/integration/flow/empty.spec.js +++ b/cypress/integration/flow/empty.spec.js @@ -7,11 +7,58 @@ describe('Empty Flow Rendering', () => { cy.get('.react-flow__edge').should('not.exist'); }); + it('renders empty selection', () => { + cy.get('body') + .type('{shift}', { release: false }) + .get('.react-flow__selectionpane') + .trigger('mousedown', 'topLeft', { which: 1, force: true }) + .trigger('mousemove', 'bottomRight', { which: 1 }) + .trigger('mouseup', 'bottomRight', { force: true }) + }); + it('renders a control panel', () => { cy.get('.react-flow__controls'); }); - it('renders a mini map', () => { + it('uses zoom in control', () => { + cy.get('.react-flow__controls-zoomin').click(); + }); + + it('uses zoom out control', () => { + cy.get('.react-flow__controls-zoomout').click(); + }); + + it('uses fit view control', () => { + cy.get('.react-flow__controls-fitview').click(); + }); + + it('renders an empty mini map', () => { cy.get('.react-flow__minimap'); + cy.get('.react-flow__minimap-node').should('not.exist'); + }); + + it('adds two nodes', () => { + cy.contains('add node').click(); + cy.contains('add node').click(); + }); + + it('connects nodes', () => { + cy.get('.react-flow__node') + .first() + .find('.react-flow__handle.source') + .trigger('mousedown', { which: 1 }); + + cy.get('.react-flow__node') + .last() + .find('.react-flow__handle.target') + .trigger('mousemove') + .trigger('mouseup', { force: true }); + + cy.get('.react-flow__edge').should('have.length', 1); + }); + + it('renders mini map with two nodes', () => { + cy.get('.react-flow__minimap'); + cy.get('.react-flow__minimap-node').should('have.length', 2); }); });