Skip to content

Commit

Permalink
test(xychart): add BarGroup + mouseover tests (#871)
Browse files Browse the repository at this point in the history
* test(xychart/mocks): add @visx/event mock

* test(xychart): add BarGroup tests

* test(xychart): add mousemove/out tests to all series

* test(xychart): remove .test. from setupTooltipTest filename

* lint(xychart/setupTooltipTest)
  • Loading branch information
williaster authored Oct 15, 2020
1 parent d6d09c0 commit fd522db
Show file tree
Hide file tree
Showing 8 changed files with 265 additions and 10 deletions.
1 change: 0 additions & 1 deletion packages/visx-xychart/src/components/series/BarGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ export default function BarGroup<
// and let Tooltip find the nearest point among them
dataKeys.forEach(key => {
const entry = dataRegistry.get(key);

if (entry && svgPoint && width && height && showTooltip) {
const datum = (horizontal ? findNearestDatumY : findNearestDatumX)({
point: svgPoint,
Expand Down
3 changes: 3 additions & 0 deletions packages/visx-xychart/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export { default as EventEmitterProvider } from './providers/EventEmitterProvide
export { default as ThemeProvider } from './providers/ThemeProvider';
export { default as TooltipProvider } from './providers/TooltipProvider';

// hooks
export { default as useEventEmitter } from './hooks/useEventEmitter';

// themes
export { default as lightTheme } from './theme/themes/light';
export { default as darkTheme } from './theme/themes/dark';
Expand Down
8 changes: 8 additions & 0 deletions packages/visx-xychart/test/__mocks__/@visx/event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export function localPoint() {
return {
x: 5,
y: 3,
value: () => ({ x: 5, y: 3 }),
toArray: () => [5, 3],
};
}
89 changes: 89 additions & 0 deletions packages/visx-xychart/test/components/BarGroup.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React, { useEffect } from 'react';
import { mount } from 'enzyme';
import { BarGroup, BarSeries, DataProvider, useEventEmitter } from '../../src';
import setupTooltipTest from '../mocks/setupTooltipTest';

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('<BarGroup />', () => {
it('should be defined', () => {
expect(BarSeries).toBeDefined();
});

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

it('should invoke showTooltip/hideTooltip on mousemove/mouseout', () => {
expect.assertions(2);

const showTooltip = jest.fn();
const hideTooltip = jest.fn();

const EventEmitter = () => {
const emit = useEventEmitter();

useEffect(() => {
if (emit) {
// @ts-ignore not a React.MouseEvent
emit('mousemove', new MouseEvent('mousemove'));
expect(showTooltip).toHaveBeenCalledTimes(2); // one per key

// @ts-ignore not a React.MouseEvent
emit('mouseout', new MouseEvent('mouseout'));
expect(showTooltip).toHaveBeenCalled();
}
});

return null;
};

setupTooltipTest(
<>
<BarGroup horizontal>
<BarSeries dataKey={series1.key} {...series1} />
<BarSeries dataKey={series2.key} {...series2} />
</BarGroup>
<EventEmitter />
</>,
{ showTooltip, hideTooltip },
);
});
});
50 changes: 46 additions & 4 deletions packages/visx-xychart/test/components/BarSeries.test.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import React from 'react';
import React, { useContext, useEffect } from 'react';
import { mount } from 'enzyme';
import { DataContext, BarSeries } from '../../src';
import { DataContext, BarSeries, useEventEmitter } from '../../src';
import getDataContext from '../mocks/getDataContext';
import setupTooltipTest from '../mocks/setupTooltipTest';

const series = { key: 'bar', data: [{}, {}], xAccessor: () => 0, yAccessor: () => 10 };

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

it('should render a LinePath', () => {
const series = { key: 'bar', data: [{}, {}], xAccessor: () => 0, yAccessor: () => 10 };
it('should render rects', () => {
const wrapper = mount(
<DataContext.Provider value={getDataContext(series)}>
<svg>
Expand All @@ -19,4 +21,44 @@ describe('<BarSeries />', () => {
);
expect(wrapper.find('rect')).toHaveLength(2);
});

it('should invoke showTooltip/hideTooltip on mousemove/mouseout', () => {
expect.assertions(2);

const showTooltip = jest.fn();
const hideTooltip = jest.fn();

const ConditionalEventEmitter = () => {
const { dataRegistry } = useContext(DataContext);
// BarSeries won't render until its data is registered
// wait for that to emit the events
return dataRegistry?.get(series.key) ? <EventEmitter /> : null;
};

const EventEmitter = () => {
const emit = useEventEmitter();

useEffect(() => {
if (emit) {
// @ts-ignore not a React.MouseEvent
emit('mousemove', new MouseEvent('mousemove'));
expect(showTooltip).toHaveBeenCalledTimes(1);

// @ts-ignore not a React.MouseEvent
emit('mouseout', new MouseEvent('mouseout'));
expect(showTooltip).toHaveBeenCalledTimes(1);
}
});

return null;
};

setupTooltipTest(
<>
<BarSeries dataKey={series.key} {...series} />
<ConditionalEventEmitter />
</>,
{ showTooltip, hideTooltip },
);
});
});
41 changes: 39 additions & 2 deletions packages/visx-xychart/test/components/BarStack.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useContext } from 'react';
import React, { useContext, useEffect } from 'react';
import { mount } from 'enzyme';
import { BarStack, BarSeries, DataProvider, DataContext } from '../../src';
import { BarStack, BarSeries, DataProvider, DataContext, useEventEmitter } from '../../src';
import setupTooltipTest from '../mocks/setupTooltipTest';

const providerProps = {
initialDimensions: { width: 100, height: 100 },
Expand Down Expand Up @@ -80,4 +81,40 @@ describe('<BarStack />', () => {
</DataProvider>,
);
});

it('should invoke showTooltip/hideTooltip on mousemove/mouseout', () => {
expect.assertions(2);

const showTooltip = jest.fn();
const hideTooltip = jest.fn();

const EventEmitter = () => {
const emit = useEventEmitter();

useEffect(() => {
if (emit) {
// @ts-ignore not a React.MouseEvent
emit('mousemove', new MouseEvent('mousemove'));
expect(showTooltip).toHaveBeenCalledTimes(2); // one per key

// @ts-ignore not a React.MouseEvent
emit('mouseout', new MouseEvent('mouseout'));
expect(showTooltip).toHaveBeenCalled();
}
});

return null;
};

setupTooltipTest(
<>
<BarStack horizontal>
<BarSeries dataKey={series1.key} {...series1} />
<BarSeries dataKey={series2.key} {...series2} />
</BarStack>
<EventEmitter />
</>,
{ showTooltip, hideTooltip },
);
});
});
48 changes: 45 additions & 3 deletions packages/visx-xychart/test/components/LineSeries.test.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import React from 'react';
import React, { useContext, useEffect } from 'react';
import { mount } from 'enzyme';
import { LinePath } from '@visx/shape';
import { DataContext, LineSeries } from '../../src';
import { DataContext, LineSeries, useEventEmitter } from '../../src';
import getDataContext from '../mocks/getDataContext';
import setupTooltipTest from '../mocks/setupTooltipTest';

const series = { key: 'line', data: [{}], xAccessor: () => 4, yAccessor: () => 7 };

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

it('should render a LinePath', () => {
const series = { key: 'line', data: [], xAccessor: () => 'x', yAccessor: () => '7' };
const wrapper = mount(
<DataContext.Provider value={getDataContext(series)}>
<svg>
Expand All @@ -21,4 +23,44 @@ describe('<LineSeries />', () => {
// @ts-ignore produces a union type that is too complex to represent.ts(2590)
expect(wrapper.find(LinePath)).toHaveLength(1);
});

it('should invoke showTooltip/hideTooltip on mousemove/mouseout', () => {
expect.assertions(2);

const showTooltip = jest.fn();
const hideTooltip = jest.fn();

const ConditionalEventEmitter = () => {
const { dataRegistry } = useContext(DataContext);
// LineSeries won't render until its data is registered
// wait for that to emit the events
return dataRegistry?.get(series.key) ? <EventEmitter /> : null;
};

const EventEmitter = () => {
const emit = useEventEmitter();

useEffect(() => {
if (emit) {
// @ts-ignore not a React.MouseEvent
emit('mousemove', new MouseEvent('mousemove'));
expect(showTooltip).toHaveBeenCalledTimes(1);

// @ts-ignore not a React.MouseEvent
emit('mouseout', new MouseEvent('mouseout'));
expect(showTooltip).toHaveBeenCalledTimes(1);
}
});

return null;
};

setupTooltipTest(
<>
<LineSeries dataKey={series.key} {...series} />
<ConditionalEventEmitter />
</>,
{ showTooltip, hideTooltip },
);
});
});
35 changes: 35 additions & 0 deletions packages/visx-xychart/test/mocks/setupTooltipTest.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* eslint import/no-extraneous-dependencies: 'off' */
import React from 'react';
import { mount } from 'enzyme';
import { DataProvider, EventEmitterProvider, TooltipContext, TooltipContextType } from '../../src';

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

const defaultTooltipContext = {
tooltipOpen: false,
/* eslint-disable no-undef */
showTooltip: jest.fn(), // eslint doesn't know jest is in context in non-.test file
updateTooltip: jest.fn(),
hideTooltip: jest.fn(),
/* eslint-enable no-undef */
};

// sets up boilerplate context for testing tooltips
export default function setupTooltipTest(
children: React.ReactNode,
tooltipContext?: Partial<TooltipContextType<object>>,
) {
return mount(
<DataProvider {...providerProps}>
<EventEmitterProvider>
<TooltipContext.Provider value={{ ...defaultTooltipContext, ...tooltipContext }}>
<svg>{children}</svg>
</TooltipContext.Provider>
</EventEmitterProvider>
</DataProvider>,
);
}

0 comments on commit fd522db

Please sign in to comment.