diff --git a/change/@fluentui-react-charting-bda51650-008f-417c-ab0d-62e7dd4a22fd.json b/change/@fluentui-react-charting-bda51650-008f-417c-ab0d-62e7dd4a22fd.json new file mode 100644 index 00000000000000..0614b57ddd3fde --- /dev/null +++ b/change/@fluentui-react-charting-bda51650-008f-417c-ab0d-62e7dd4a22fd.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Improving first render cycle of cartesian chart", + "packageName": "@fluentui/react-charting", + "email": "ankityadav@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-charting/src/components/AreaChart/AreaChart.base.tsx b/packages/react-charting/src/components/AreaChart/AreaChart.base.tsx index 5b6d4bbe68707c..c2fde62eba04f1 100644 --- a/packages/react-charting/src/components/AreaChart/AreaChart.base.tsx +++ b/packages/react-charting/src/components/AreaChart/AreaChart.base.tsx @@ -106,6 +106,7 @@ export class AreaChartBase extends React.Component { diff --git a/packages/react-charting/src/components/AreaChart/AreaChart.test.tsx b/packages/react-charting/src/components/AreaChart/AreaChart.test.tsx index 11ed79e424f940..fb0894f66dd8e6 100644 --- a/packages/react-charting/src/components/AreaChart/AreaChart.test.tsx +++ b/packages/react-charting/src/components/AreaChart/AreaChart.test.tsx @@ -1,7 +1,6 @@ jest.mock('react-dom'); import * as React from 'react'; import { resetIds } from '../../Utilities'; -import * as renderer from 'react-test-renderer'; import { mount, ReactWrapper } from 'enzyme'; import { IAreaChartProps, AreaChart } from './index'; import { IAreaChartState, AreaChartBase } from './AreaChart.base'; @@ -10,9 +9,15 @@ import toJson from 'enzyme-to-json'; // Wrapper of the AreaChart to be tested. let wrapper: ReactWrapper | undefined; +const originalRAF = window.requestAnimationFrame; function sharedBeforeEach() { resetIds(); + jest.useFakeTimers(); + Object.defineProperty(window, 'requestAnimationFrame', { + writable: true, + value: (callback: FrameRequestCallback) => callback(0), + }); } function sharedAfterEach() { @@ -27,6 +32,8 @@ function sharedAfterEach() { if ((global.setTimeout as any).mock) { jest.useRealTimers(); } + jest.useRealTimers(); + window.requestAnimationFrame = originalRAF; } const points: ILineChartPoints[] = [ @@ -69,68 +76,118 @@ const emptyChartPoints = { }; describe('AreaChart snapShot testing', () => { - it('renders Areachart correctly', () => { - const component = renderer.create(); - const tree = component.toJSON(); - expect(tree).toMatchSnapshot(); + beforeEach(() => { + resetIds(); }); + afterEach(() => { + if (wrapper) { + wrapper.unmount(); + wrapper = undefined; + } - it('renders hideLegend hhh correctly', () => { - const component = renderer.create(); - const tree = component.toJSON(); - expect(tree).toMatchSnapshot(); + // Do this after unmounting the wrapper to make sure if any timers cleaned up on unmount are + // cleaned up in fake timers world + // eslint-disable-next-line @typescript-eslint/no-explicit-any + if ((global.setTimeout as any).mock) { + jest.useRealTimers(); + } }); - it('renders hideTooltip correctly', () => { - const component = renderer.create(); - const tree = component.toJSON(); + it('renders Areachart correctly', async () => { + wrapper = mount(); + await new Promise(resolve => setTimeout(resolve)); + wrapper.update(); + const tree = toJson(wrapper, { mode: 'deep' }); expect(tree).toMatchSnapshot(); }); - it('renders enabledLegendsWrapLines correctly', () => { - const component = renderer.create(); - const tree = component.toJSON(); + it('renders hideLegend hhh correctly', async () => { + wrapper = mount(); + await new Promise(resolve => setTimeout(resolve)); + wrapper.update(); + const tree = toJson(wrapper, { mode: 'deep' }); expect(tree).toMatchSnapshot(); }); - it('renders showXAxisLablesTooltip correctly', () => { - const component = renderer.create(); - const tree = component.toJSON(); + it('renders hideTooltip correctly', async () => { + wrapper = mount(); + await new Promise(resolve => setTimeout(resolve)); + wrapper.update(); + const tree = toJson(wrapper, { mode: 'deep' }); expect(tree).toMatchSnapshot(); }); - it('renders wrapXAxisLables correctly', () => { - const component = renderer.create(); - const tree = component.toJSON(); + it('renders enabledLegendsWrapLines correctly', async () => { + wrapper = mount(); + await new Promise(resolve => setTimeout(resolve)); + wrapper.update(); + const tree = toJson(wrapper, { mode: 'deep' }); expect(tree).toMatchSnapshot(); }); - - it('renders yAxisTickFormat correctly', () => { - const component = renderer.create(); - const tree = component.toJSON(); + it('renders yAxisTickFormat correctly', async () => { + wrapper = mount(); + await new Promise(resolve => setTimeout(resolve)); + wrapper.update(); + const tree = toJson(wrapper, { mode: 'deep' }); expect(tree).toMatchSnapshot(); }); - it('renders Areachart with single point correctly', () => { - const component = renderer.create(); - const tree = component.toJSON(); + it('renders Areachart with single point correctly', async () => { + wrapper = mount(); + await new Promise(resolve => setTimeout(resolve)); + wrapper.update(); + const tree = toJson(wrapper, { mode: 'deep' }); expect(tree).toMatchSnapshot(); }); - it('Should render with default colors when line color is not provided', () => { + it('Should render with default colors when line color is not provided', async () => { const lineColor = points[0].color; delete points[0].color; - const component = renderer.create(); - const tree = component.toJSON(); + wrapper = mount(); + await new Promise(resolve => setTimeout(resolve)); + wrapper.update(); + const tree = toJson(wrapper, { mode: 'deep' }); expect(tree).toMatchSnapshot(); points[0].color = lineColor; }); - it('Should not render circles when optimizeLargeData is true', () => { - const component = renderer.create(); - const tree = component.toJSON(); + it('Should not render circles when optimizeLargeData is true', async () => { + wrapper = mount(); + await new Promise(resolve => setTimeout(resolve)); + wrapper.update(); + const tree = toJson(wrapper, { mode: 'deep' }); + expect(tree).toMatchSnapshot(); + }); + + it('renders showXAxisLablesTooltip correctly', async () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + + wrapper = mount(); + await new Promise(resolve => setTimeout(resolve)); + wrapper.update(); + if (wrapper) { + const tree = toJson(wrapper, { mode: 'deep' }); + expect(tree).toMatchSnapshot(); + } + }); + + it('renders wrapXAxisLables correctly', async () => { + const mockGetComputedTextLength = jest.fn().mockReturnValue(100); + + // Replace the original method with the mock implementation + Object.defineProperty( + Object.getPrototypeOf(document.createElementNS('http://www.w3.org/2000/svg', 'tspan')), + 'getComputedTextLength', + { + value: mockGetComputedTextLength, + }, + ); + wrapper = mount(); + await new Promise(resolve => setTimeout(resolve)); + wrapper.update(); + const tree = toJson(wrapper!, { mode: 'deep' }); expect(tree).toMatchSnapshot(); }); }); diff --git a/packages/react-charting/src/components/AreaChart/__snapshots__/AreaChart.test.tsx.snap b/packages/react-charting/src/components/AreaChart/__snapshots__/AreaChart.test.tsx.snap index cbfdec4c2a65b3..adc1d00ad35b35 100644 --- a/packages/react-charting/src/components/AreaChart/__snapshots__/AreaChart.test.tsx.snap +++ b/packages/react-charting/src/components/AreaChart/__snapshots__/AreaChart.test.tsx.snap @@ -36,7 +36,7 @@ exports[`AreaChart - mouse events Should render callout correctly on mouseover 1 > @@ -223,12 +223,6 @@ exports[`AreaChart - mouse events Should render callout correctly on mouseover 1 >