From 982624cf51eb8eb9841dc395862b39403e7cdf0c Mon Sep 17 00:00:00 2001 From: Haris Rozajac <58232930+harisrozajac@users.noreply.github.com> Date: Wed, 26 Jul 2023 12:46:57 -0600 Subject: [PATCH] Explore: Turn ExplorePage.test into unit test (#72022) * Extract logic from ExplorePage to a hook, add a test for the hook; remove ExplorePage test * Remove extracted stuff from ExplorePage * Clean up * Fix minWidth logic --- public/app/features/explore/ExplorePage.tsx | 47 +++------------ .../hooks/useSplitSizeUpdater.test.tsx | 57 +++++++++++++++++++ .../explore/hooks/useSplitSizeUpdater.ts | 47 +++++++++++++++ 3 files changed, 112 insertions(+), 39 deletions(-) create mode 100644 public/app/features/explore/hooks/useSplitSizeUpdater.test.tsx create mode 100644 public/app/features/explore/hooks/useSplitSizeUpdater.ts diff --git a/public/app/features/explore/ExplorePage.tsx b/public/app/features/explore/ExplorePage.tsx index bf0b0920c31..d55a300b348 100644 --- a/public/app/features/explore/ExplorePage.tsx +++ b/public/app/features/explore/ExplorePage.tsx @@ -1,24 +1,24 @@ import { css } from '@emotion/css'; -import { inRange } from 'lodash'; -import React, { useEffect, useState } from 'react'; -import { useWindowSize } from 'react-use'; +import React, { useEffect } from 'react'; import { ErrorBoundaryAlert } from '@grafana/ui'; import { SplitPaneWrapper } from 'app/core/components/SplitPaneWrapper/SplitPaneWrapper'; import { useGrafana } from 'app/core/context/GrafanaContext'; import { useNavModel } from 'app/core/hooks/useNavModel'; import { GrafanaRouteComponentProps } from 'app/core/navigation/types'; -import { useDispatch, useSelector } from 'app/types'; +import { useSelector } from 'app/types'; import { ExploreQueryParams } from 'app/types/explore'; import { ExploreActions } from './ExploreActions'; import { ExplorePaneContainer } from './ExplorePaneContainer'; import { useExplorePageTitle } from './hooks/useExplorePageTitle'; +import { useSplitSizeUpdater } from './hooks/useSplitSizeUpdater'; import { useStateSync } from './hooks/useStateSync'; import { useTimeSrvFix } from './hooks/useTimeSrvFix'; -import { splitSizeUpdateAction } from './state/main'; import { isSplit, selectPanesEntries } from './state/selectors'; +const MIN_PANE_WIDTH = 200; + const styles = { pageScrollbarWrapper: css` width: 100%; @@ -38,13 +38,9 @@ export default function ExplorePage(props: GrafanaRouteComponentProps<{}, Explor // if we were to update the URL on state change, the title would not match the URL. // Ultimately the URL is the single source of truth from which state is derived, the page title is not different useExplorePageTitle(props.queryParams); - const dispatch = useDispatch(); const { keybindings, chrome } = useGrafana(); const navModel = useNavModel('explore'); - const [rightPaneWidthRatio, setRightPaneWidthRatio] = useState(0.5); - const { width: windowWidth } = useWindowSize(); - const minWidth = 200; - const exploreState = useSelector((state) => state.explore); + const { updateSplitSize, widthCalc } = useSplitSizeUpdater(MIN_PANE_WIDTH); const panes = useSelector(selectPanesEntries); const hasSplit = useSelector(isSplit); @@ -59,33 +55,6 @@ export default function ExplorePage(props: GrafanaRouteComponentProps<{}, Explor keybindings.setupTimeRangeBindings(false); }, [keybindings]); - const updateSplitSize = (size: number) => { - const evenSplitWidth = windowWidth / 2; - const areBothSimilar = inRange(size, evenSplitWidth - 100, evenSplitWidth + 100); - if (areBothSimilar) { - dispatch(splitSizeUpdateAction({ largerExploreId: undefined })); - } else { - dispatch( - splitSizeUpdateAction({ - largerExploreId: size > evenSplitWidth ? panes[1][0] : panes[0][0], - }) - ); - } - - setRightPaneWidthRatio(size / windowWidth); - }; - - let widthCalc = 0; - if (hasSplit) { - if (!exploreState.evenSplitPanes && exploreState.maxedExploreId) { - widthCalc = exploreState.maxedExploreId === panes[1][0] ? windowWidth - minWidth : minWidth; - } else if (exploreState.evenSplitPanes) { - widthCalc = Math.floor(windowWidth / 2); - } else if (rightPaneWidthRatio !== undefined) { - widthCalc = windowWidth * rightPaneWidthRatio; - } - } - return (
@@ -93,8 +62,8 @@ export default function ExplorePage(props: GrafanaRouteComponentProps<{}, Explor { + it('dispatches correct action and calculates widthCalc correctly', () => { + const store = configureStore({ + explore: { + ...initialExploreState, + panes: { + left: makeExplorePaneState(), + right: makeExplorePaneState(), + }, + }, + }); + + const minWidth = 200; + + const dispatchMock = jest.fn().mockImplementation(store.dispatch); + + const { result } = renderHook(() => useSplitSizeUpdater(minWidth), { + wrapper: ({ children }: { children: ReactNode }) => ( + {children} + ), + }); + + // 1. Panes have similar width + act(() => { + result.current.updateSplitSize(450); + + expect(dispatchMock).toHaveBeenCalledWith(splitSizeUpdateAction({ largerExploreId: undefined })); + expect(result.current.widthCalc).toBe(512); + }); + + // 2. Left pane is larger + act(() => { + result.current.updateSplitSize(300); + }); + expect(dispatchMock).toHaveBeenCalledWith(splitSizeUpdateAction({ largerExploreId: 'left' })); + expect(result.current.widthCalc).toBe(300); + + // 3. Right pane is larger + act(() => { + result.current.updateSplitSize(700); + }); + expect(dispatchMock).toHaveBeenCalledWith(splitSizeUpdateAction({ largerExploreId: 'right' })); + expect(result.current.widthCalc).toBe(700); + }); +}); diff --git a/public/app/features/explore/hooks/useSplitSizeUpdater.ts b/public/app/features/explore/hooks/useSplitSizeUpdater.ts new file mode 100644 index 00000000000..ea2f6279b8a --- /dev/null +++ b/public/app/features/explore/hooks/useSplitSizeUpdater.ts @@ -0,0 +1,47 @@ +import { inRange } from 'lodash'; +import { useState } from 'react'; +import { useWindowSize } from 'react-use'; + +import { useDispatch, useSelector } from 'app/types'; + +import { splitSizeUpdateAction } from '../state/main'; +import { isSplit, selectPanesEntries } from '../state/selectors'; + +export const useSplitSizeUpdater = (minWidth: number) => { + const dispatch = useDispatch(); + const { width: windowWidth } = useWindowSize(); + const panes = useSelector(selectPanesEntries); + const hasSplit = useSelector(isSplit); + const [rightPaneWidthRatio, setRightPaneWidthRatio] = useState(0.5); + + const exploreState = useSelector((state) => state.explore); + + const updateSplitSize = (size: number) => { + const evenSplitWidth = windowWidth / 2; + const areBothSimilar = inRange(size, evenSplitWidth - 100, evenSplitWidth + 100); + if (areBothSimilar) { + dispatch(splitSizeUpdateAction({ largerExploreId: undefined })); + } else { + dispatch( + splitSizeUpdateAction({ + largerExploreId: size > evenSplitWidth ? panes[1][0] : panes[0][0], + }) + ); + } + + setRightPaneWidthRatio(size / windowWidth); + }; + + let widthCalc = 0; + if (hasSplit) { + if (!exploreState.evenSplitPanes && exploreState.maxedExploreId) { + widthCalc = exploreState.maxedExploreId === panes[1][0] ? windowWidth - minWidth : minWidth; + } else if (exploreState.evenSplitPanes) { + widthCalc = Math.floor(windowWidth / 2); + } else if (rightPaneWidthRatio !== undefined) { + widthCalc = windowWidth * rightPaneWidthRatio; + } + } + + return { updateSplitSize, widthCalc }; +};