Skip to content

Commit

Permalink
test(xychart): add BarStack tests (#866)
Browse files Browse the repository at this point in the history
* tes(xychart/BarStack): add tests

* test(xychart/combineBarStackData): add tests

* test(xychart/findNearestStackDatum): add tests

* internal(xychart): remove console logs in tests
  • Loading branch information
williaster authored Oct 15, 2020
1 parent 2a5a8dd commit 9612b6f
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 13 deletions.
11 changes: 8 additions & 3 deletions packages/visx-xychart/src/hooks/useDimensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@ const INITIAL_DIMENSIONS = {
margin: { top: 0, right: 0, bottom: 0, left: 0 },
};

type Dimensions = typeof INITIAL_DIMENSIONS;
export type Dimensions = typeof INITIAL_DIMENSIONS;

/** A hook for accessing and setting memoized width, height, and margin chart dimensions. */
export default function useDimensions(): [Dimensions, (dims: Dimensions) => void] {
const [dimensions, privateSetDimensions] = useState<Dimensions>(INITIAL_DIMENSIONS);
export default function useDimensions(
initialDimensions?: Partial<Dimensions>,
): [Dimensions, (dims: Dimensions) => void] {
const [dimensions, privateSetDimensions] = useState<Dimensions>({
...INITIAL_DIMENSIONS,
...initialDimensions,
});

// expose a setter with better memoization logic
const publicSetDimensions = useCallback(
Expand Down
6 changes: 4 additions & 2 deletions packages/visx-xychart/src/providers/DataProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ import { XYChartTheme } from '../types';
import ThemeContext from '../context/ThemeContext';
import DataContext from '../context/DataContext';
import useDataRegistry from '../hooks/useDataRegistry';
import useDimensions from '../hooks/useDimensions';
import useDimensions, { Dimensions } from '../hooks/useDimensions';
import useScales from '../hooks/useScales';

/** Props that can be passed to initialize/update the provider config. */
export type DataProviderProps<
XScaleConfig extends ScaleConfig<AxisScaleOutput, any, any>,
YScaleConfig extends ScaleConfig<AxisScaleOutput, any, any>
> = {
initialDimensions?: Partial<Dimensions>;
theme?: XYChartTheme;
xScale: XScaleConfig;
yScale: YScaleConfig;
Expand All @@ -26,6 +27,7 @@ export default function DataProvider<
YScaleConfig extends ScaleConfig<AxisScaleOutput>,
Datum extends object
>({
initialDimensions,
theme: propsTheme,
xScale: xScaleConfig,
yScale: yScaleConfig,
Expand All @@ -36,7 +38,7 @@ export default function DataProvider<
// a ThemeProvider is not present.
const contextTheme = useContext(ThemeContext);
const theme = propsTheme || contextTheme;
const [{ width, height, margin }, setDimensions] = useDimensions();
const [{ width, height, margin }, setDimensions] = useDimensions(initialDimensions);
const innerWidth = width - (margin?.left ?? 0) - (margin?.right ?? 0);
const innerHeight = height - (margin?.top ?? 0) - (margin?.bottom ?? 0);

Expand Down
83 changes: 83 additions & 0 deletions packages/visx-xychart/test/components/BarStack.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React, { useContext } from 'react';
import { mount } from 'enzyme';
import { BarStack, BarSeries, DataProvider, DataContext } from '../../src';

const providerProps = {
initialDimensions: { width: 100, height: 100 },
xScale: { type: 'linear' },
yScale: { type: 'linear' },
} as const;

const accessors = {
xAccessor: (d: { x: number }) => d.x,
yAccessor: (d: { y: number }) => d.y,
};

const series1 = {
key: 'bar1',
data: [
{ x: 10, y: 5 },
{ x: 7, y: 5 },
],
...accessors,
};

const series2 = {
key: 'bar2',
data: [
{ x: 10, y: 5 },
{ x: 7, y: 20 },
],
...accessors,
};

describe('<BarStack />', () => {
it('should be defined', () => {
expect(BarSeries).toBeDefined();
});

it('should render rects', () => {
const wrapper = mount(
<DataProvider {...providerProps}>
<svg>
<BarStack horizontal>
<BarSeries dataKey={series1.key} {...series1} />
<BarSeries dataKey={series2.key} {...series2} />
</BarStack>
</svg>
</DataProvider>,
);
expect(wrapper.find('rect')).toHaveLength(4);
});

it('should update scale domain to include stack sums including negative values', () => {
expect.hasAssertions();

function Assertion() {
const { yScale, dataRegistry } = useContext(DataContext);
if (yScale && dataRegistry?.keys().length === 2) {
expect(yScale.domain()).toEqual([-20, 10]);
}
return null;
}

mount(
<DataProvider {...providerProps}>
<svg>
<BarStack>
<BarSeries dataKey={series1.key} {...series1} />
<BarSeries
dataKey={series2.key}
{...series2}
data={[
{ x: 10, y: 5 },
{ x: 7, y: -20 },
]}
/>
</BarStack>
</svg>
<Assertion />
</DataProvider>,
);
});
});
16 changes: 9 additions & 7 deletions packages/visx-xychart/test/mocks/getDataContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,18 @@ const height = 10;
const margin = { top: 0, right: 0, bottom: 0, left: 0 };
const noOp = () => {};

const getDataContext = (
entries?: Parameters<typeof DataRegistry.prototype.registerData>[0],
): DataContextType<any, any, any> => {
function getDataContext(entries?: Parameters<typeof DataRegistry.prototype.registerData>[0]) {
const dataRegistry = new DataRegistry();
if (entries) dataRegistry.registerData(entries);

const mockContext = {
const mockContext: DataContextType<any, any, any> = {
dataRegistry,
registerData: dataRegistry.registerData,
unregisterData: dataRegistry.unregisterData,
registerData: data => {
dataRegistry.registerData(data);
},
unregisterData: keys => {
dataRegistry.unregisterData(keys);
},
xScale: scaleLinear({ domain: [0, 10], range: [0, width] }),
yScale: scaleLinear({ domain: [0, 10], range: [0, height] }),
colorScale: scaleOrdinal({ domain: ['sf', 'ny', 'la'], range: ['purple', 'violet', 'grape'] }),
Expand All @@ -31,6 +33,6 @@ const getDataContext = (
};

return mockContext;
};
}

export default getDataContext;
51 changes: 51 additions & 0 deletions packages/visx-xychart/test/utils/combineBarStackData.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import { BarSeries } from '../../src';
import combineBarStackData from '../../src/utils/combineBarStackData';

const accessors = {
xAccessor: (d: { x: number }) => d.x,
yAccessor: (d: { y: number }) => d.y,
};

const series1 = {
dataKey: 'bar1',
data: [
{ x: 10, y: 5 },
{ x: 7, y: -5 },
],
...accessors,
};

const series2 = {
dataKey: 'bar2',
data: [
{ x: 10, y: 5 },
{ x: 7, y: 20 },
],
...accessors,
};

const seriesChildren = [
<BarSeries key={series1.dataKey} {...series1} />,
<BarSeries key={series2.dataKey} {...series2} />,
];

describe('combineBarStackData', () => {
it('should be defined', () => {
expect(combineBarStackData).toBeDefined();
});

it('should combine data by x stack value when horizontal=false', () => {
expect(combineBarStackData(seriesChildren)).toEqual([
{ stack: 7, bar1: -5, bar2: 20, positiveSum: 20, negativeSum: -5 },
{ stack: 10, bar1: 5, bar2: 5, positiveSum: 10, negativeSum: 0 },
]);
});
it('should combine data by y stack value when horizontal=true', () => {
expect(combineBarStackData(seriesChildren, true)).toEqual([
{ stack: 5, bar1: 10, bar2: 10, positiveSum: 20, negativeSum: 0 },
{ stack: 20, bar1: undefined, bar2: 7, positiveSum: 7, negativeSum: 0 },
{ stack: -5, bar1: 7, bar2: undefined, positiveSum: 7, negativeSum: 0 },
]);
});
});
28 changes: 27 additions & 1 deletion packages/visx-xychart/test/utils/findNearestDatum.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import findNearestDatumX from '../../src/utils/findNearestDatumX';
import findNearestDatumY from '../../src/utils/findNearestDatumY';
import findNearestDatumXY from '../../src/utils/findNearestDatumXY';
import findNearestDatumSingleDimension from '../../src/utils/findNearestDatumSingleDimension';
import { NearestDatumArgs } from '../../lib';
import findNearestStackDatum from '../../src/utils/findNearestStackDatum';
import { BarStackDatum, NearestDatumArgs } from '../../src';

type Datum = { xVal: number; yVal: string };

Expand Down Expand Up @@ -109,3 +110,28 @@ describe('findNearestDatumSingleDimension', () => {
).toEqual({ xVal: 8, yVal: '8' });
});
});

describe('findNearestStackDatum', () => {
it('should be defined', () => {
expect(findNearestStackDatum).toBeDefined();
});

it('should find the nearest datum', () => {
const d1 = { yVal: '🍌' };
const d2 = { yVal: '🚀' };
expect(
findNearestStackDatum(
({
...params,
// type is not technically correct, but coerce for test
} as unknown) as NearestDatumArgs<
AxisScale,
AxisScale,
BarStackDatum<AxisScale, AxisScale>
>,
[d1, d2],
true,
)!.datum,
).toEqual(d2); // nearest datum index=1
});
});

0 comments on commit 9612b6f

Please sign in to comment.