From 41ded6459255f80caf58c9d7ee268b290657b48a Mon Sep 17 00:00:00 2001 From: Michael Behrisch <m.behrisch@uu.nl> Date: Sat, 5 Feb 2022 21:03:49 +0100 Subject: [PATCH] test(vis-rawjsonview): :sparkles: adds storybook with three test cases Provides one idea how to handle redux and data state driven testing in storybook. Adds three test cases (1) with data (2) without data both handled in redux, (3) loading with an animated spinner --- .../PoahVis/PoahVis.stories.tsx | 2 +- .../RawJSONVis/raw-jsonvis.module.scss | 26 +++++++ .../RawJSONVis/raw-jsonvis.stories.tsx | 73 +++++++++++++++++++ .../visualisations/RawJSONVis/raw-jsonvis.tsx | 25 ++++++- .../store/src/lib/graphQueryResultSlice.ts | 11 ++- 5 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 apps/graphpolaris/src/web/components/visualisations/RawJSONVis/raw-jsonvis.stories.tsx diff --git a/apps/graphpolaris/src/web/components/visualisations/PoahVis/PoahVis.stories.tsx b/apps/graphpolaris/src/web/components/visualisations/PoahVis/PoahVis.stories.tsx index 6835ce79f..da885542e 100644 --- a/apps/graphpolaris/src/web/components/visualisations/PoahVis/PoahVis.stories.tsx +++ b/apps/graphpolaris/src/web/components/visualisations/PoahVis/PoahVis.stories.tsx @@ -7,7 +7,7 @@ export default { * See https://storybook.js.org/docs/react/configure/overview#configure-story-loading * to learn how to generate automatic titles */ - title: 'NodeLink', + title: 'PoahVis', component: PoahVis, decorators: [(story) => <div style={{ padding: '3rem' }}>{story()}</div>], } as ComponentMeta<typeof PoahVis>; diff --git a/apps/graphpolaris/src/web/components/visualisations/RawJSONVis/raw-jsonvis.module.scss b/apps/graphpolaris/src/web/components/visualisations/RawJSONVis/raw-jsonvis.module.scss index e69de29bb..b78e903dd 100644 --- a/apps/graphpolaris/src/web/components/visualisations/RawJSONVis/raw-jsonvis.module.scss +++ b/apps/graphpolaris/src/web/components/visualisations/RawJSONVis/raw-jsonvis.module.scss @@ -0,0 +1,26 @@ +// svg { +// width: 3.75em; +// animation: 1.5s spin ease infinite; +// } + +.rotating { + width: 3.75em; + animation: 1.5s spin ease infinite; +} + +.ring { + fill: white; + stroke: hsla(341, 97%, 59%, 0.3); + stroke-width: 2; +} + +.ball { + fill: #fc2f70; + stroke: none; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} diff --git a/apps/graphpolaris/src/web/components/visualisations/RawJSONVis/raw-jsonvis.stories.tsx b/apps/graphpolaris/src/web/components/visualisations/RawJSONVis/raw-jsonvis.stories.tsx new file mode 100644 index 000000000..023117373 --- /dev/null +++ b/apps/graphpolaris/src/web/components/visualisations/RawJSONVis/raw-jsonvis.stories.tsx @@ -0,0 +1,73 @@ +import React from 'react'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { RawJSONVis } from './raw-jsonvis'; + +import { Provider } from 'react-redux'; +import { configureStore, createSlice } from '@reduxjs/toolkit'; + +// import * as TaskListStories from './TaskList.stories'; +import graphQueryResultSlice, { + assignNewGraphQueryResult, + resetGraphQueryResults, +} from '../../../../../../../libs/shared/data-access/store/src/lib/graphQueryResultSlice'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/react/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'RawJSONVIS', + component: RawJSONVis, + decorators: [ + (story) => ( + <div style={{ padding: '3rem' }}> + <Provider store={Mockstore}>{story()}</Provider> + </div> + ), + ], +} as ComponentMeta<typeof RawJSONVis>; + +const Template: ComponentStory<typeof RawJSONVis> = (args) => ( + <RawJSONVis {...args} /> +); + +// A super-simple mock of a redux store +const Mockstore = configureStore({ + reducer: { + graphQueryResult: graphQueryResultSlice, + }, +}); + +export const TestWithData = Template.bind({}); +TestWithData.args = { + loading: false, +}; +TestWithData.play = async () => { + const dispatch = Mockstore.dispatch; + dispatch( + assignNewGraphQueryResult({ + nodes: [ + { id: 'agent/007', attributes: { name: 'Daniel Craig' } }, + { id: 'villain', attributes: { name: 'Le Chiffre' } }, + ], + links: [], + }) + ); +}; + +export const Loading = Template.bind({}); +Loading.args = { + loading: true, +}; + +export const Empty = Template.bind({}); +Empty.args = { + // Shaping the stories through args composition. + // Inherited data coming from the Loading story. + ...Loading.args, + loading: false, +}; +Empty.play = async () => { + const dispatch = Mockstore.dispatch; + dispatch(resetGraphQueryResults()); +}; diff --git a/apps/graphpolaris/src/web/components/visualisations/RawJSONVis/raw-jsonvis.tsx b/apps/graphpolaris/src/web/components/visualisations/RawJSONVis/raw-jsonvis.tsx index 2a87441e8..d9e482322 100644 --- a/apps/graphpolaris/src/web/components/visualisations/RawJSONVis/raw-jsonvis.tsx +++ b/apps/graphpolaris/src/web/components/visualisations/RawJSONVis/raw-jsonvis.tsx @@ -1,10 +1,12 @@ import { useGraphQueryResult } from '@graphpolaris/shared/data-access/store'; -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import ReactJSONView from 'react-json-view'; import './raw-jsonvis.module.scss'; /* eslint-disable-next-line */ -export interface RawJSONVisProps {} +export interface RawJSONVisProps { + loading?: boolean; +} export const RawJSONVis = React.memo((props: RawJSONVisProps) => { const graphQueryResult = useGraphQueryResult(); @@ -20,8 +22,27 @@ export const RawJSONVis = React.memo((props: RawJSONVisProps) => { }; }, []); + const loading = props.loading; + return ( <div style={{ overflowY: 'auto' }}> + {loading == true && ( + <div + style={{ + marginTop: '40px', + paddingLeft: '30px', + }} + > + <svg + className="rotating" + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 50 50" + > + <circle className="ring" cx="25" cy="25" r="20"></circle> + <circle className="ball" cx="25" cy="5" r="3.5"></circle> + </svg> + </div> + )} <div style={{ marginTop: '40px', diff --git a/libs/shared/data-access/store/src/lib/graphQueryResultSlice.ts b/libs/shared/data-access/store/src/lib/graphQueryResultSlice.ts index b610dd4a4..fba385b6a 100644 --- a/libs/shared/data-access/store/src/lib/graphQueryResultSlice.ts +++ b/libs/shared/data-access/store/src/lib/graphQueryResultSlice.ts @@ -39,7 +39,7 @@ export interface GraphQueryResult { } // Define the initial state using that type -const initialState: GraphQueryResult = { +export const initialState: GraphQueryResult = { nodes: [], edges: [], nodeTypes: [], @@ -70,10 +70,17 @@ export const graphQueryResultSlice = createSlice({ state.edges = action.payload.links; state.nodeTypes = nodeTypes; }, + resetGraphQueryResults: (state) => { + // Assign new state + state.nodes = []; + state.edges = []; + state.nodeTypes = []; + }, }, }); -export const { assignNewGraphQueryResult } = graphQueryResultSlice.actions; +export const { assignNewGraphQueryResult, resetGraphQueryResults } = + graphQueryResultSlice.actions; // Other code such as selectors can use the imported `RootState` type export const selectGraphQueryResult = (state: RootState) => -- GitLab