Skip to content

Commit 0798cdf

Browse files
committed
Merge branch 'master' into FDG-9315
2 parents 6cb10ba + 797a4d7 commit 0798cdf

File tree

2 files changed

+133
-40
lines changed

2 files changed

+133
-40
lines changed
Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
import React from 'react';
2-
import { render, fireEvent } from '@testing-library/react';
3-
import renderer from 'react-test-renderer';
2+
import { render, fireEvent, waitFor } from '@testing-library/react';
43
import BarGraph from './bar';
54
import { staggeredData } from '../helpers/helpersData';
6-
import { ResponsiveBar } from '@nivo/bar';
75
import helpers from './helpers/helpers';
86

9-
class ResizeObserver {
10-
observe() {}
11-
unobserve() {}
12-
disconnect() {}
13-
}
7+
jest.mock('@nivo/bar', () => ({
8+
Bar: jest.fn(({ barComponent: BarComponent, data, indexBy, keys }) => {
9+
return (
10+
<div data-testid="mock-nivo-bar">
11+
{data.map((item, index) => (
12+
<div key={index}>{BarComponent && <BarComponent index={index} value={item[keys[0]]} data={item} />}</div>
13+
))}
14+
</div>
15+
);
16+
}),
17+
}));
18+
19+
jest.mock('./bar-component/bar-component', () => ({ index, value, handleTempValueChange }) => {
20+
return <button data-testid={`custom-bar-trigger-${index}`} onClick={() => handleTempValueChange(index, value)} />;
21+
});
1422

1523
describe('BarGraph component', () => {
16-
window.ResizeObserver = ResizeObserver;
1724
it('does not render anything if invalid params are detected', () => {
1825
const { queryByTestId } = render(<BarGraph />);
1926
expect(queryByTestId('barGraph')).toBeNull();
@@ -23,47 +30,65 @@ describe('BarGraph component', () => {
2330
const { queryByTestId } = render(<BarGraph graphData={staggeredData} graphIndex="year" valueKeys={['value']} />);
2431
expect(queryByTestId('barGraph')).toBeDefined();
2532
});
26-
27-
// TODO - Nivo not rendering internal chart
28-
it.skip('sets left and bottom axis attributes each to null by default to prevent unwanted tick marks along the axes', async () => {
29-
// let component = renderer.create();
30-
// let instance = null;
31-
// await renderer.act(async () => {
32-
// component = await renderer.create(<BarGraph graphData={staggeredData} graphIndex="year" valueKeys={['value']} />);
33-
// instance = component.root;
34-
// });
35-
//
36-
// const barGraphCanvas = instance.findByType(ResponsiveBar);
37-
// expect(barGraphCanvas.props.axisLeft).toBeNull();
38-
// expect(barGraphCanvas.props.axisBottom).toBeNull();
39-
});
4033
});
4134

4235
describe('BarGraph component - Custom bar graph', () => {
43-
window.ResizeObserver = ResizeObserver;
44-
const barGraph = <BarGraph graphData={staggeredData} graphIndex="year" valueKeys={['value']} useCustomBarComponent />;
36+
const mouseEnterPropSpy = jest.fn();
37+
const mockSetTempValue = jest.fn();
38+
const mockSetTempDate = jest.fn();
4539
const mouseEnterSpy = jest.spyOn(helpers, 'mouseEnterEvent');
4640
const mouseLeaveSpy = jest.spyOn(helpers, 'mouseLeaveEvent');
4741

48-
// TODO - Nivo not rendering internal chart
49-
it.skip('creates a customBarGraph', () => {
50-
// let component = renderer.create();
51-
// renderer.act(() => {
52-
// component = renderer.create(barGraph);
53-
// });
54-
// const instance = component.root;
55-
// const responsiveBar = instance.findByType(ResponsiveBar);
56-
// expect(responsiveBar.props.barComponent).toBeDefined();
42+
const barGraphProps = {
43+
graphData: staggeredData,
44+
graphIndex: 'year',
45+
valueKeys: ['value'],
46+
useCustomBarComponent: true,
47+
mouseEnter: mouseEnterPropSpy,
48+
setTempValue: mockSetTempValue,
49+
setTempDate: mockSetTempDate,
50+
dateField: 'year',
51+
};
52+
53+
beforeEach(() => {
54+
jest.clearAllMocks();
55+
// needed so mouseLeave executes callback
56+
mouseLeaveSpy.mockImplementation((cardId, callback) => {
57+
if (callback && typeof callback === 'function') {
58+
callback();
59+
}
60+
});
5761
});
5862

59-
it('triggers mouseEnter and mouseLeave events', () => {
63+
it('triggers the mouseEnter and mouseLeave events', () => {
6064
jest.clearAllMocks();
61-
const { getByTestId } = render(barGraph);
62-
const container = getByTestId('barGraph');
63-
fireEvent.mouseEnter(container);
65+
const { getByTestId } = render(<BarGraph {...barGraphProps} />);
66+
const chartContainer = getByTestId('barGraph');
67+
fireEvent.mouseEnter(chartContainer);
6468
expect(mouseEnterSpy).toHaveBeenCalledTimes(1);
69+
expect(mouseEnterPropSpy).toHaveBeenCalled();
70+
fireEvent.mouseLeave(chartContainer);
71+
expect(mouseLeaveSpy).toHaveBeenCalledTimes(1);
72+
});
73+
74+
it('calls setTempValue and setTempDate with the correct values when the bar is clicked', async () => {
75+
const { getByTestId } = render(<BarGraph {...barGraphProps} />);
76+
const firstBar = getByTestId('custom-bar-trigger-0');
77+
fireEvent.click(firstBar);
78+
await waitFor(() => {
79+
expect(mockSetTempValue).toHaveBeenCalledWith('500');
80+
expect(mockSetTempDate).toHaveBeenCalledWith('2017');
81+
});
82+
});
6583

66-
fireEvent.mouseLeave(container);
84+
it('resets temp states when mouse leaves the bar', async () => {
85+
const { getByTestId } = render(<BarGraph {...barGraphProps} />);
86+
const chartContainer = getByTestId('barGraph');
87+
fireEvent.mouseLeave(chartContainer);
6788
expect(mouseLeaveSpy).toHaveBeenCalledTimes(1);
89+
await waitFor(() => {
90+
expect(mockSetTempValue).toHaveBeenCalledWith(null);
91+
expect(mockSetTempDate).toHaveBeenCalledWith(null);
92+
});
6893
});
6994
});

src/layouts/explainer/sections/government-revenue/sources-of-federal-revenue/sources-of-revenue-circle-chart/sources-of-revenue-circle-chart.spec.js

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1-
import { render, waitFor } from '@testing-library/react';
1+
import { render, waitFor, fireEvent, act } from '@testing-library/react';
22
import React from 'react';
33
import SourcesOfRevenueCircleChart from './sources-of-revenue-circle-chart';
44
import userEvent from '@testing-library/user-event';
55
import { sourcesOfRevenueCircleChartMatcher } from '../../../../explainer-helpers/government-revenue/government-revenue-test-helper';
66
import { setGlobalFetchMatchingResponse } from '../../../../../../utils/mock-utils';
7+
import Analytics from '../../../../../../utils/analytics/analytics';
8+
9+
// Mock Analytics to track calls
10+
jest.mock('../../../../../../utils/analytics/analytics', () => ({
11+
event: jest.fn(),
12+
}));
713

814
class ResizeObserver {
915
observe() {}
@@ -13,10 +19,12 @@ class ResizeObserver {
1319

1420
describe('Circle chart', () => {
1521
window.ResizeObserver = ResizeObserver;
22+
1623
beforeAll(() => {
1724
jest.spyOn(console, 'warn').mockImplementation(() => {});
1825
setGlobalFetchMatchingResponse(jest, sourcesOfRevenueCircleChartMatcher);
1926
});
27+
2028
afterAll(() => {
2129
jest.resetModules();
2230
global.fetch.mockReset();
@@ -66,4 +74,64 @@ describe('Circle chart', () => {
6674
expect(await getByText('corporate income taxes is $2.43 T', { exact: false })).toBeInTheDocument();
6775
await waitFor(() => expect(getByText('making up 11%', { exact: false })).toBeInTheDocument());
6876
});
77+
78+
it('ignores keyboard interaction if key is not "Enter"', async () => {
79+
const { getAllByText, getByText } = render(<SourcesOfRevenueCircleChart />);
80+
await waitFor(() => expect(getByText('Corporate')).toBeInTheDocument());
81+
82+
const labelText = getByText('Corporate').closest('text');
83+
labelText.focus();
84+
85+
fireEvent.keyPress(labelText, { key: 'A', code: 'KeyA' });
86+
87+
expect(await getAllByText('Individual Income Taxes')).toHaveLength(2);
88+
});
89+
90+
it('updates the header on keyboard "Enter" interaction with a label', async () => {
91+
const { getAllByText, getByText } = render(<SourcesOfRevenueCircleChart />);
92+
await waitFor(() => expect(getByText('Corporate')).toBeInTheDocument());
93+
94+
const labelText = getByText('Corporate').closest('text');
95+
96+
labelText.focus();
97+
fireEvent.keyPress(labelText, { key: 'Enter', code: 'Enter', charCode: 13 });
98+
99+
expect(await getAllByText('Corporate Income Taxes', { exact: false })).toHaveLength(2);
100+
});
101+
102+
it('resets the chart to default view when mouse leaves the chart area', async () => {
103+
const { getAllByText, getByText, getByTestId, getByRole } = render(<SourcesOfRevenueCircleChart />);
104+
await waitFor(() => expect(getByText('Corporate')).toBeInTheDocument());
105+
106+
const corporateIncomeTaxesCircle = getByRole('img').children[1].children[1];
107+
userEvent.hover(corporateIncomeTaxesCircle);
108+
expect(await getAllByText('Corporate Income Taxes', { exact: false })).toHaveLength(3);
109+
110+
const chartParent = getByTestId('chartParent');
111+
userEvent.unhover(chartParent);
112+
113+
expect(await getAllByText('Individual Income Taxes')).toHaveLength(2);
114+
});
115+
116+
it('tracks analytics event on chart hover', async () => {
117+
jest.useFakeTimers();
118+
const { getByTestId, getByText } = render(<SourcesOfRevenueCircleChart />);
119+
await waitFor(() => expect(getByText('Corporate')).toBeInTheDocument());
120+
121+
const chartParent = getByTestId('chartParent');
122+
123+
fireEvent.mouseEnter(chartParent);
124+
125+
act(() => {
126+
jest.advanceTimersByTime(3100);
127+
});
128+
129+
expect(Analytics.event).toHaveBeenCalledWith({
130+
category: 'Explainers',
131+
action: 'Chart Hover',
132+
label: 'Revenue - Sources of Federal Revenue',
133+
});
134+
135+
jest.useRealTimers();
136+
});
69137
});

0 commit comments

Comments
 (0)