Skip to content

Commit

Permalink
test: add resize config for easy story and e2e resizing
Browse files Browse the repository at this point in the history
  • Loading branch information
nickofthyme committed Nov 8, 2023
1 parent be30c1b commit 3b83f53
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 108 deletions.
13 changes: 13 additions & 0 deletions e2e/page_objects/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,19 @@ export class CommonPage {
strict: false, // should be true but some stories have multiple charts
});
};

setResizeDimensions = (page: Page) => async (dimensions: { height?: string; width?: string }) => {
const el = page.locator('#story-resize-wrapper');
if (!(await el.isVisible())) {
throw new Error('setResizeDimensions was called when no #story-resize-wrapper exists');
}

await el.evaluate((element, { height, width }) => {
console.log({ height, width });
if (height !== undefined) element.style.height = height;
if (width !== undefined) element.style.width = width;
}, dimensions);
};
}

function getSnapshotOptions(options?: ScreenshotDOMElementOptions) {
Expand Down
2 changes: 0 additions & 2 deletions e2e/tests/tooltip.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import { test } from '@playwright/test';

import { common } from '../page_objects/common';

process.env.ENV_URL = 'http://localhost:9002/';

test.describe('Tooltip', () => {
test.describe('Chart Types', () => {
test.describe('Cartesian', () => {
Expand Down
29 changes: 19 additions & 10 deletions e2e_server/server/generate/vrt_page_template.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,24 @@ ReactDOM.render(<VRTPage />, document.getElementById('story-root') as HTMLElemen

function pageTemplate(imports, routes, urls) {
return `
import React, { Suspense } from 'react';
import React, { PropsWithChildren, FC, Suspense, CSSProperties } from 'react';
import { EuiProvider } from '@elastic/eui';
import { ThemeIdProvider, BackgroundIdProvider } from '../../storybook/use_base_theme';
import { useGlobalsParameters } from '../server/mocks/use_global_parameters';
import { StoryContext } from '../../storybook/types';
const ResizeWrapper: FC<PropsWithChildren<{ resize?: boolean | CSSProperties }>> = ({ resize, children }) => resize ? (
<div id="story-resize-wrapper" style={resize === true ? {} : resize}>
{ children }
</div>
) : (<>{children}</>)
export function VRTPage() {
const {
themeId,
backgroundId,
toggles,
resize,
setParams,
} = useGlobalsParameters();
const urlParams = new URL(window.location.toString()).searchParams;
Expand Down Expand Up @@ -84,15 +91,17 @@ export function VRTPage() {
}
return (
<EuiProvider colorMode={colorMode}>
<ThemeIdProvider value={themeId as any}>
<BackgroundIdProvider value={backgroundId}>
<Suspense fallback={<div>Loading...</div>}>
${routes.join('\n ')}
</Suspense>
</BackgroundIdProvider>
</ThemeIdProvider>
</EuiProvider>
<ResizeWrapper resize={resize}>
<EuiProvider colorMode={colorMode}>
<ThemeIdProvider value={themeId as any}>
<BackgroundIdProvider value={backgroundId}>
<Suspense fallback={<div>Loading...</div>}>
${routes.join('\n ')}
</Suspense>
</BackgroundIdProvider>
</ThemeIdProvider>
</EuiProvider>
</ResizeWrapper>
);
}
Expand Down
8 changes: 6 additions & 2 deletions e2e_server/server/mocks/use_global_parameters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@

import { useMemo, useState } from 'react';

import type { StoryGlobals } from './../../../storybook/types';
import type { StoryGlobals, StoryParameters } from './../../../storybook/types';
import { BackgroundParameter } from '../../../storybook/node_modules/storybook-addon-background-toggle';
import { ThemeParameter } from '../../../storybook/node_modules/storybook-addon-theme-toggle';
import { storybookParameters as globalParams } from '../../../storybook/parameters';
import { ThemeId } from '../../../storybook/use_base_theme';

type Parameters = BackgroundParameter & ThemeParameter;
type Parameters = BackgroundParameter & ThemeParameter & Pick<StoryParameters, 'resize'>;

const themeParams = globalParams.theme!;
const backgroundParams = globalParams.background!;
Expand Down Expand Up @@ -48,13 +48,15 @@ interface GlobalParameters {
themeId: StoryGlobals['theme'];
backgroundId: StoryGlobals['background'];
toggles: StoryGlobals['toggles'];
resize: StoryParameters['resize'];
setParams(params: URLSearchParams, parameters?: Parameters): void;
}

export function useGlobalsParameters(): GlobalParameters {
const [themeId, setThemeId] = useState<string>(ThemeId.Light);
const [backgroundId, setBackgroundId] = useState<string | undefined>();
const [togglesJSON, setTogglesJSON] = useState<string>('{}');
const [resize, setResize] = useState<StoryParameters['resize']>(false);

/**
* Handles setting global context values. Stub for theme and background addons
Expand All @@ -67,6 +69,7 @@ export function useGlobalsParameters(): GlobalParameters {
setThemeId(themeIdFromParams);
setTogglesJSON(JSON.stringify(globals.toggles ?? '{}'));
applyThemeCSS(themeIdFromParams);
setResize(parameters?.resize);
}

// using toggles object creates an infinite update loop, thus using JSON state.
Expand All @@ -76,6 +79,7 @@ export function useGlobalsParameters(): GlobalParameters {
themeId,
backgroundId,
toggles,
resize,
setParams,
};
}
Expand Down
65 changes: 30 additions & 35 deletions storybook/stories/metric/1_basic.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,40 +117,35 @@ export const Example: ChartsStory = (_, { title: storyTitle, description }) => {

const configuredData = [[numberTextSwitch ? numericData : textualData]];
return (
<div
style={{
resize: 'both',
padding: '0px',
overflow: 'auto',
height: '200px',
width: '200px',
maxWidth: '100%',
maxHeight: '80vh',
}}
>
<Chart title={storyTitle} description={description}>
<Settings
baseTheme={useBaseTheme()}
onElementClick={([d]) => {
if (isMetricElementEvent(d)) {
const { rowIndex, columnIndex } = d;
onEventClickAction(
`row:${rowIndex} col:${columnIndex} value:${configuredData[rowIndex][columnIndex].value}`,
);
}
}}
onElementOver={([d]) => {
if (isMetricElementEvent(d)) {
const { rowIndex, columnIndex } = d;
onEventOverAction(
`row:${rowIndex} col:${columnIndex} value:${configuredData[rowIndex][columnIndex].value}`,
);
}
}}
onElementOut={() => onEventOutAction('out')}
/>
<Metric id="1" data={configuredData} />
</Chart>
</div>
<Chart title={storyTitle} description={description}>
<Settings
baseTheme={useBaseTheme()}
onElementClick={([d]) => {
if (isMetricElementEvent(d)) {
const { rowIndex, columnIndex } = d;
onEventClickAction(
`row:${rowIndex} col:${columnIndex} value:${configuredData[rowIndex][columnIndex].value}`,
);
}
}}
onElementOver={([d]) => {
if (isMetricElementEvent(d)) {
const { rowIndex, columnIndex } = d;
onEventOverAction(
`row:${rowIndex} col:${columnIndex} value:${configuredData[rowIndex][columnIndex].value}`,
);
}
}}
onElementOut={() => onEventOutAction('out')}
/>
<Metric id="1" data={configuredData} />
</Chart>
);
};

Example.parameters = {
resize: {
height: '200px',
width: '200px',
},
};
81 changes: 35 additions & 46 deletions storybook/stories/test_cases/11_resize_debounce.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,57 +37,46 @@ export const Example: ChartsStory = (_, { title, description }) => {
const resizeDebounce = number('resizeDebounce (ms)', 10, { min: 0, step: 20 });
const cardinality = number('cardinality', 100, { min: 1, max: maxCardinality });
return (
<div
style={{
resize: 'both',
padding: '0px',
overflow: 'auto',
height: '100%',
width: '100%',
maxWidth: '100%',
maxHeight: '100vh',
}}
>
<Chart title={title} description={description}>
<Settings
showLegend
resizeDebounce={resizeDebounce}
onResize={action('onResize')}
onRenderChange={action('onRenderChange')}
baseTheme={useBaseTheme()}
/>
<Axis
id="bottom"
position={Position.Bottom}
style={{
tickLine: { visible: true, size: 0.0001, padding: 4 },
tickLabel: {
alignment: { horizontal: Position.Left, vertical: Position.Bottom },
padding: 0,
offset: { x: 0, y: 0 },
},
}}
timeAxisLayerCount={3}
/>
<Axis id="left" position={Position.Left} />
<Chart title={title} description={description}>
<Settings
showLegend
resizeDebounce={resizeDebounce}
onResize={action('onResize')}
onRenderChange={action('onRenderChange')}
baseTheme={useBaseTheme()}
/>
<Axis
id="bottom"
position={Position.Bottom}
style={{
tickLine: { visible: true, size: 0.0001, padding: 4 },
tickLabel: {
alignment: { horizontal: Position.Left, vertical: Position.Bottom },
padding: 0,
offset: { x: 0, y: 0 },
},
}}
timeAxisLayerCount={3}
/>
<Axis id="left" position={Position.Left} />

<BarSeries
id="Sensor 1"
enableHistogramMode
xScaleType={ScaleType.Time}
yScaleType={ScaleType.Linear}
xAccessor="t"
yAccessors={['v']}
splitSeriesAccessors={['cat']}
stackAccessors={['yes']}
data={data.flatMap(({ t, values }) => values.slice(0, cardinality).map(({ v, cat }) => ({ t, v, cat })))}
/>
</Chart>
</div>
<BarSeries
id="Sensor 1"
enableHistogramMode
xScaleType={ScaleType.Time}
yScaleType={ScaleType.Linear}
xAccessor="t"
yAccessors={['v']}
splitSeriesAccessors={['cat']}
stackAccessors={['yes']}
data={data.flatMap(({ t, values }) => values.slice(0, cardinality).map(({ v, cat }) => ({ t, v, cat })))}
/>
</Chart>
);
};

Example.parameters = {
markdown: `The \`resizeDebounce\` option on the \`Settings\` spec provides control over the eagerness of the chart to re-render upon resize. A value of \`0\` will remove the debounce altogether.
You can play with the cardinality and debounce time to see how the debouncing affects the chart render timing`,
resize: true,
};
35 changes: 24 additions & 11 deletions storybook/story_wrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,35 @@
import { EuiProvider, EuiMarkdownFormat, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiText } from '@elastic/eui';
import { DecoratorFunction } from '@storybook/addons';
import classNames from 'classnames';
import React from 'react';
import React, { FC, PropsWithChildren } from 'react';

import { StoryGlobals, StoryParameters } from './types';
import { ThemeId, ThemeIdProvider, BackgroundIdProvider } from './use_base_theme';

const ResizeWrapper: FC<PropsWithChildren<{ resize: StoryParameters['resize'] }>> = ({ resize, children }) =>
resize ? (
<div id="story-resize-wrapper" style={resize === true ? {} : resize}>
{children}
</div>
) : (
<>{children}</>
);

export const StoryWrapper: DecoratorFunction<JSX.Element> = (Story, context) => {
if (!Story) return <div>No Story</div>;

const { globals, parameters } = context;
const globals = (context.globals as StoryGlobals) ?? {};
const parameters = (context.parameters as StoryParameters) ?? {};

const themeId = globals?.theme ?? ThemeId.Light;
const backgroundId = globals?.background;
const themeId = (globals.theme as ThemeId) ?? ThemeId.Light;
const backgroundId = globals.background;
const {
showHeader = false,
showChartTitle = false,
showChartDescription = false,
showChartBoundary = false,
} = globals?.toggles ?? {};
const markdown = parameters?.markdown;
} = globals.toggles ?? {};
const { markdown, resize } = parameters;
const colorMode = themeId.includes('light') ? 'light' : 'dark';

return (
Expand Down Expand Up @@ -56,11 +67,13 @@ export const StoryWrapper: DecoratorFunction<JSX.Element> = (Story, context) =>

<EuiFlexItem grow={false}>
<div id="story-root" className={classNames({ showChartBoundary })}>
<Story
{...context}
title={showChartTitle ? context.kind : undefined}
description={showChartDescription ? context.name : undefined}
/>
<ResizeWrapper resize={resize}>
<Story
{...context}
title={showChartTitle ? context.kind : undefined}
description={showChartDescription ? context.name : undefined}
/>
</ResizeWrapper>
</div>
</EuiFlexItem>
{markdown && (
Expand Down
9 changes: 9 additions & 0 deletions storybook/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,15 @@ body {
}
}

#story-resize-wrapper {
resize: both;
height: 100%;
width: 100%;
overflow: auto;
max-width: 100%;
max-height: 80vh;
}

#story-header {
padding: 20px 40px 16px;
}
Expand Down
8 changes: 6 additions & 2 deletions storybook/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,26 @@

import type { Parameters as SBParameters } from '@storybook/addons';
import { ArgTypes, Args, StoryContext as SBStoryContext } from '@storybook/react';
import { ReactElement } from 'react';
import { CSSProperties, ReactElement } from 'react';
import { StoryBackgroundParameter, BackgroundGlobals } from 'storybook-addon-background-toggle';
import { StoryThemeParameter, ThemeGlobals } from 'storybook-addon-theme-toggle';
import { StoryTogglesParameter, TogglesGlobals } from 'storybook-addon-toggles';

/**
* Parameter accessible at the story level
*/
type StoryParameters = SBParameters &
export type StoryParameters = SBParameters &
StoryThemeParameter &
StoryBackgroundParameter &
StoryTogglesParameter & {
/**
* Renders markdown content below story
*/
markdown?: string;
/**
* Defines resize wrapper under `#story-root` to define
*/
resize?: boolean | CSSProperties;
};
export type StoryGlobals = ThemeGlobals & BackgroundGlobals & TogglesGlobals;

Expand Down

0 comments on commit 3b83f53

Please sign in to comment.