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 {};