From 8be0337e00fc2bb95ed0d00e6101c03dce0559b3 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 7 Nov 2023 16:19:09 +0100 Subject: [PATCH] refactored react-examples app and created generic test case component --- examples/react/cypress.config.ts | 2 +- examples/react/src/App/index.tsx | 150 ++++++++-------- examples/react/src/app.d.ts | 7 + examples/react/src/generic-tests/Flow.tsx | 29 ++++ .../react/src/generic-tests/edges/general.ts | 163 ++++++++++++++++++ examples/react/src/generic-tests/index.tsx | 17 ++ .../react/src/generic-tests/nodes/general.ts | 1 + 7 files changed, 299 insertions(+), 70 deletions(-) create mode 100644 examples/react/src/app.d.ts create mode 100644 examples/react/src/generic-tests/Flow.tsx create mode 100644 examples/react/src/generic-tests/edges/general.ts create mode 100644 examples/react/src/generic-tests/index.tsx create mode 100644 examples/react/src/generic-tests/nodes/general.ts diff --git a/examples/react/cypress.config.ts b/examples/react/cypress.config.ts index b46eaa76..027bd690 100644 --- a/examples/react/cypress.config.ts +++ b/examples/react/cypress.config.ts @@ -2,7 +2,7 @@ import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { - baseUrl: 'http://localhost:3000', + baseUrl: 'http://localhost:3000/examples', viewportWidth: 1280, viewportHeight: 720, video: false, diff --git a/examples/react/src/App/index.tsx b/examples/react/src/App/index.tsx index b6bc5be7..77344ba2 100644 --- a/examples/react/src/App/index.tsx +++ b/examples/react/src/App/index.tsx @@ -1,5 +1,7 @@ import { useEffect, useState } from 'react'; -import { BrowserRouter, Route, Routes, useLocation, useNavigate } from 'react-router-dom'; +import { BrowserRouter, Outlet, Route, Routes, useLocation, useNavigate } from 'react-router-dom'; + +import GenericTests from '../generic-tests'; import Basic from '../examples/Basic'; import Backgrounds from '../examples/Backgrounds'; @@ -57,232 +59,232 @@ interface IRoute { const routes: IRoute[] = [ { name: 'Basic', - path: '/', + path: 'basic', component: Basic, }, { name: 'Backgrounds', - path: '/backgrounds', + path: 'backgrounds', component: Backgrounds, }, { name: 'Cancel Connection', - path: '/cancel-connection', + path: 'cancel-connection', component: CancelConnection, }, { name: 'Controlled/Uncontrolled', - path: '/controlled-uncontrolled', + path: 'controlled-uncontrolled', component: ControlledUncontrolled, }, { name: 'Controlled Viewport', - path: '/controlled-viewport', + path: 'controlled-viewport', component: ControlledViewport, }, { name: 'Custom Connection Line', - path: '/custom-connectionline', + path: 'custom-connectionline', component: CustomConnectionLine, }, { name: 'Custom Minimap Node', - path: '/custom-minimap-node', + path: 'custom-minimap-node', component: CustomMiniMapNode, }, { name: 'Custom Node', - path: '/custom-node', + path: 'custom-node', component: CustomNode, }, { name: 'Default Nodes', - path: '/default-nodes', + path: 'default-nodes', component: DefaultNodes, }, { name: 'Drag Handle', - path: '/draghandle', + path: 'draghandle', component: DragHandle, }, { name: 'Drag and Drop', - path: '/dragndrop', + path: 'dragndrop', component: DragNDrop, }, { name: 'EasyConnect', - path: '/easy-connect', + path: 'easy-connect', component: EasyConnect, }, { name: 'Edges', - path: '/edges', + path: 'edges', component: Edges, }, { name: 'Edge Renderer', - path: '/edge-renderer', + path: 'edge-renderer', component: EdgeRenderer, }, { name: 'Edge Types', - path: '/edge-types', + path: 'edge-types', component: EdgeTypes, }, { name: 'Edge Routing', - path: '/edge-routing', + path: 'edge-routing', component: EdgeRouting, }, { name: 'Empty', - path: '/empty', + path: 'empty', component: Empty, }, { name: 'Figma', - path: '/figma', + path: 'figma', component: Figma, }, { name: 'Floating Edges', - path: '/floating-edges', + path: 'floating-edges', component: FloatingEdges, }, { name: 'Hidden', - path: '/hidden', + path: 'hidden', component: Hidden, }, { name: 'Interaction', - path: '/interaction', + path: 'interaction', component: Interaction, }, { name: 'Intersection', - path: '/intersection', + path: 'intersection', component: Intersection, }, { name: 'Interactive Minimap', - path: '/interactive-minimap', + path: 'interactive-minimap', component: InteractiveMinimap, }, { name: 'Layouting', - path: '/layouting', + path: 'layouting', component: Layouting, }, { name: 'Multi Flows', - path: '/multiflows', + path: 'multiflows', component: MultiFlows, }, { name: 'Nested Nodes', - path: '/nested-nodes', + path: 'nested-nodes', component: NestedNodes, }, { name: 'Node Type Change', - path: '/nodetype-change', + path: 'nodetype-change', component: NodeTypeChange, }, { name: 'nodeTypes Object Change', - path: '/nodetypesobject-change', + path: 'nodetypesobject-change', component: NodeTypesObjectChange, }, { name: 'NodeToolbar', - path: '/node-toolbar', + path: 'node-toolbar', component: NodeToolbar, }, { name: 'NodeResizer', - path: '/node-resizer', + path: 'node-resizer', component: NodeResizer, }, { name: 'Overview', - path: '/overview', + path: 'overview', component: Overview, }, { name: 'Provider', - path: '/provider', + path: 'provider', component: Provider, }, { name: 'Save/Restore', - path: '/save-restore', + path: 'save-restore', component: SaveRestore, }, { name: 'Stress', - path: '/stress', + path: 'stress', component: Stress, }, { name: 'Subflow', - path: '/subflow', + path: 'subflow', component: Subflow, }, { name: 'Switch Flow', - path: '/switch', + path: 'switch', component: SwitchFlow, }, { name: 'Touch Device', - path: '/touch-device', + path: 'touch-device', component: TouchDevice, }, { name: 'Undirectional', - path: '/undirectional', + path: 'undirectional', component: Undirectional, }, { name: 'Updatable Edge', - path: '/updatable-edge', + path: 'updatable-edge', component: UpdatableEdge, }, { name: 'Update Node', - path: '/update-node', + path: 'update-node', component: UpdateNode, }, { name: 'useNodesInitialized', - path: '/use-nodes-initialized', + path: 'use-nodes-initialized', component: useNodesInitialized, }, { name: 'useOnSelectionChange', - path: '/use-on-selection-change', + path: 'use-on-selection-change', component: UseOnSelectionChange, }, { name: 'useReactFlow', - path: '/usereactflow', + path: 'usereactflow', component: UseReactFlow, }, { name: 'useUpdateNodeInternals', - path: '/useupdatenodeinternals', + path: 'useupdatenodeinternals', component: UseUpdateNodeInternals, }, { name: 'Validation', - path: '/validation', + path: 'validation', component: Validation, }, { name: 'useKeyPress', - path: '/use-key-press', + path: 'use-key-press', component: UseKeyPress, }, ]; @@ -299,28 +301,38 @@ const Header = () => { }, [currentPath]); return ( -
- - React Flow Dev - - -
+ <> +
+ + React Flow Dev + + +
+ + ); }; -export default () => ( - -
- - {routes.map((route) => ( - } /> - ))} - - -); +export default () => { + return ( + <> + + + }> + } /> + {routes.map((route) => ( + } /> + ))} + + } /> + + + + ); +}; diff --git a/examples/react/src/app.d.ts b/examples/react/src/app.d.ts new file mode 100644 index 00000000..1118fb9d --- /dev/null +++ b/examples/react/src/app.d.ts @@ -0,0 +1,7 @@ +import { Edge, Node, ReactFlowProps } from '@xyflow/react'; + +declare global { + interface GenericTestCase { + reactFlowProps: Omit & { nodes: Node[]; edges: Edge[] }; + } +} diff --git a/examples/react/src/generic-tests/Flow.tsx b/examples/react/src/generic-tests/Flow.tsx new file mode 100644 index 00000000..28b38001 --- /dev/null +++ b/examples/react/src/generic-tests/Flow.tsx @@ -0,0 +1,29 @@ +import { useState, useCallback } from 'react'; +import { ReactFlow, Controls, Background, applyNodeChanges, applyEdgeChanges } from '@xyflow/react'; + +type FlowProps = { + generics: GenericTestCase; +}; + +export default ({ generics }: FlowProps) => { + const [nodes, setNodes] = useState(generics.reactFlowProps.nodes); + const [edges, setEdges] = useState(generics.reactFlowProps.edges); + + const onNodesChange = useCallback((changes) => setNodes((nds) => applyNodeChanges(changes, nds)), []); + const onEdgesChange = useCallback((changes) => setEdges((eds) => applyEdgeChanges(changes, eds)), []); + + return ( +
+ + + + +
+ ); +}; diff --git a/examples/react/src/generic-tests/edges/general.ts b/examples/react/src/generic-tests/edges/general.ts new file mode 100644 index 00000000..596c836d --- /dev/null +++ b/examples/react/src/generic-tests/edges/general.ts @@ -0,0 +1,163 @@ +import { MarkerType } from '@xyflow/react'; + +export default { + reactFlowProps: { + fitView: true, + nodes: [ + { + id: '1', + data: { label: '1' }, + position: { x: 0, y: 0 }, + type: 'input', + }, + { + id: '2', + data: { label: '2' }, + position: { x: -100, y: 100 }, + }, + { + id: '3', + data: { label: '3' }, + position: { x: 100, y: 100 }, + }, + { + id: '4', + data: { label: '4' }, + position: { x: -100, y: 200 }, + }, + { + id: '5', + data: { label: '5' }, + position: { x: 100, y: 200 }, + }, + { + id: '6', + data: { label: '6' }, + position: { x: -100, y: 300 }, + }, + { + id: '7', + data: { label: '7' }, + position: { x: 100, y: 300 }, + }, + { + id: '8', + data: { label: '8' }, + position: { x: -100, y: 400 }, + }, + { + id: '9', + data: { label: '9' }, + position: { x: 100, y: 400 }, + }, + { + id: '10', + data: { label: '10' }, + position: { x: -100, y: 500 }, + }, + { + id: '11', + data: { label: '11' }, + position: { x: 100, y: 500 }, + }, + // { + // id: '12', + // data: { label: '12' }, + // position: { x: -100, y: 600 } + // }, + // { + // id: '13', + // data: { label: '13' }, + // position: { x: 100, y: 600 } + // } + ], + edges: [ + { + id: 'edge-with-class', + source: '1', + target: '2', + className: 'edge-class-test', + }, + { + id: 'edge-with-style', + source: '1', + target: '3', + style: { + stroke: 'red', + }, + }, + { + id: 'hidden-edge', + source: '2', + target: '4', + label: 'hidden', + hidden: true, + }, + { + id: 'animated-edge', + source: '3', + target: '5', + label: 'animated', + animated: true, + }, + { + id: 'not-selectable-edge', + source: '4', + target: '6', + label: 'not-selectable', + selectable: false, + }, + { + id: 'not-deletable', + source: '5', + target: '7', + label: 'not-deletable', + deletable: false, + }, + { + id: 'z-index', + source: '6', + target: '8', + label: 'z-index', + zIndex: 3141592, + }, + { + id: 'aria-label', + source: '7', + target: '9', + label: 'aria-label', + ariaLabel: 'aria-label-test', + }, + { + id: 'interaction-width', + source: '8', + target: '10', + label: 'interaction-width', + interactionWidth: 42, + }, + { + id: 'markers', + source: '9', + target: '11', + label: 'markers', + markerEnd: { type: MarkerType.Arrow }, + markerStart: { type: MarkerType.ArrowClosed }, + }, + // { + // id: 'updatable', + // source: '9', + // target: '11', + // label: 'focusable', + // updatable: true + // }, + // { + // id: 'not-focusable', + // + // source: '5', + // target: '7', + // label: 'not-focusable', + // focusable: false + // }, + ], + }, +} satisfies GenericTestCase; diff --git a/examples/react/src/generic-tests/index.tsx b/examples/react/src/generic-tests/index.tsx new file mode 100644 index 00000000..d50e466a --- /dev/null +++ b/examples/react/src/generic-tests/index.tsx @@ -0,0 +1,17 @@ +import { useLocation } from 'react-router-dom'; +import Flow from './Flow'; + +export default () => { + const location = useLocation(); + const files = import.meta.glob('./**/*.ts', { eager: true, import: 'default' }); + + const testCasePath = `.${location.pathname.replace('/tests/generic', '')}.ts`; + + const testCase = files[testCasePath]; + + if (!testCase) { + return
; + } + + return ; +}; diff --git a/examples/react/src/generic-tests/nodes/general.ts b/examples/react/src/generic-tests/nodes/general.ts new file mode 100644 index 00000000..ff8b4c56 --- /dev/null +++ b/examples/react/src/generic-tests/nodes/general.ts @@ -0,0 +1 @@ +export default {};